MuckyFoot-UrbanChaos/fallen/Source/pcom.cpp
2017-05-20 11:14:17 +10:00

15105 lines
302 KiB
C++

//
// Person commands and high-level AI
//
#include "game.h"
#include "collide.h"
#include "c:\fallen\headers\pcom.h"
#include "eway.h"
#include "mav.h"
#include "statedef.h"
#include "combat.h"
#include "sound.h"
#include "overlay.h"
#include "frontend.h"
#include "interfac.h"
#include "balloon.h"
#include "road.h"
#include "wand.h"
#include "guns.h"
#include "animate.h"
#include "ware.h"
#include "mfx.h"
#include "cnet.h"
#include "fc.h"
#include "ob.h"
#include "spark.h"
#ifndef PSX
#include "panel.h"
#endif
#include "memory.h"
extern UBYTE stealth_debug;
#ifndef PSX
extern BOOL allow_debug_keys;
#endif
//
// local prototypes
//
extern UBYTE combo_display;
void push_into_attack_group_at_angle(Thing *p_person,SLONG gang,SLONG reqd_angle);
SLONG remove_from_gang_attack(Thing *p_person,Thing *p_target);
void PCOM_set_person_ai_flee_person(Thing *p_person,Thing *p_scary);
void DriveCar(Thing* p_person);
void ParkCar(Thing* p_person);
void DriveBike(Thing* p_person);
void ParkBike(Thing* p_person);
//
// externs
//
extern SLONG people_allowed_to_hit_each_other(Thing *p_victim,Thing *p_agressor);
extern SLONG am_i_a_thug(Thing *p_person);
extern SLONG person_normal_animate(Thing *p_person);
extern SLONG dist_to_target_pelvis(Thing *p_person_a,Thing *p_person_b);
extern void set_person_recircle(Thing *p_person);
extern void FC_kill_player_cam(Thing *p_thing);
extern UBYTE GAME_cut_scene;
extern SLONG is_person_dead(Thing *p_person);
extern SLONG is_person_ko(Thing *p_person);
extern SLONG person_has_gun_out(Thing *p_person);
extern SLONG is_person_guilty(Thing *p_person);
extern UBYTE vehicle_random[];
extern SLONG there_is_a_los_mav( // From collide.cpp
SLONG x1, SLONG y1, SLONG z1,
SLONG x2, SLONG y2, SLONG z2);
#ifndef PSX
CBYTE *PCOM_ai_state_name[PCOM_AI_STATE_NUMBER] =
{
"Player",
"Normal",
"Investigating",
"Searching",
"Killing",
"Sleeping",
"Flee Place",
"Flee Person",
"Following",
"Navtokil",
"Homesick",
"Lookaround",
"Findcar",
"Deactivate bomb",
"Leave car",
"Snipe",
"Warmhands",
"Findbike",
"Knocked out",
"Taunt",
"Arrest",
"Talking",
"Grappled",
"Enter car as passenger",
"Aimless",
"Hands up",
"Summon",
"Get item"
};
CBYTE *PCOM_ai_substate_name[PCOM_AI_SUBSTATE_NUMBER] =
{
"None",
"Suprised",
"Walkover",
"Look",
"Punching",
"Kicking",
"Leg-it!",
"Hunting",
"Aiming",
"No more ammo",
"Goto car",
"Get in car",
"Goto bomb",
"Cut wires",
"Park car",
"Leave car",
"Goto fire",
"Warm up",
"Goto bike",
"Hunt Slide",
"Talk ask",
"Talk tell",
"Talk listen",
"Hitching",
"Start summon",
"Mid summon",
"Draw h2h",
"Can't find",
"Waiting"
};
CBYTE *PCOM_ai_name[PCOM_AI_NUMBER] =
{
"player",
"civillian",
"guard",
"assasin",
"boss",
"cop",
"gang",
"doorman",
"bodyguard",
"driver",
"bomb-disposer",
"biker",
"fight test",
"bully",
"cop driver",
"suicide",
"flee player",
"kill colour",
"M.I.B.",
"Bane",
"Hypochondria",
"Shoot dead"
};
CBYTE *PCOM_bent_name[PCOM_BENT_NUMBER] =
{
"Lazy ",
"Diligent ",
"Gang ",
"Fight-back ",
"Kill-just-the-player ",
"Robotic ",
"Restricted ",
"Player-kill"
};
CBYTE *PCOM_move_name[PCOM_MOVE_NUMBER] =
{
"NULL",
"Still",
"PATROL",
"PATROL_RAND",
"WANDER",
"FOLLOW",
"WARM_HANDS",
"FOLLOW_ON_SEE",
"DANCE",
"HANDS_UP",
"TIED_UP",
};
#endif
//
// The movement states a person can be in.
//
#define PCOM_MOVE_STATE_PLAYER 0 // This is a player.
#define PCOM_MOVE_STATE_STILL 1
#define PCOM_MOVE_STATE_GOTO_XZ 2
#define PCOM_MOVE_STATE_GOTO_WAYPOINT 3
#define PCOM_MOVE_STATE_GOTO_THING 4
#define PCOM_MOVE_STATE_PAUSE 5
#define PCOM_MOVE_STATE_ANIMATION 6 // Doing some animation-related thing.
#define PCOM_MOVE_STATE_CIRCLE 7 // Circle around the person- to beat him up.
#define PCOM_MOVE_STATE_DRIVETO 8 // Driving a car to a waypoint.
#define PCOM_MOVE_STATE_FOLLOW 9
#define PCOM_MOVE_STATE_PARK_CAR 10 // Park a car at a waypoint.
#define PCOM_MOVE_STATE_DRIVE_DOWN 11 // Driving down a road.
#define PCOM_MOVE_STATE_BIKETO 12 // Driving a bike to a waypoint.
#define PCOM_MOVE_STATE_PARK_BIKE 13 // Park a bike.
#define PCOM_MOVE_STATE_BIKE_DOWN 14 // Biking down a road.
#define PCOM_MOVE_STATE_GRAPPLE 15 // Circle around the person- to beat him up.
#define PCOM_MOVE_STATE_GOTO_THING_SLIDE 16
#define PCOM_MOVE_STATE_WAIT_CIRCLE 17 // Doing some animation-related thing.
#define PCOM_MOVE_STATE_PARK_CAR_ON_ROAD 18 // Parking a car as you drive down the road.
#define PCOM_MOVE_STATE_NUMBER 19
#define PCOM_MOVE_SPEED_WALK PERSON_SPEED_WALK
#define PCOM_MOVE_SPEED_RUN PERSON_SPEED_RUN
#define PCOM_MOVE_SPEED_SNEAK PERSON_SPEED_SNEAK
#define PCOM_MOVE_SPEED_YOMP PERSON_SPEED_YOMP
#define PCOM_MOVE_SPEED_SPRINT PERSON_SPEED_SPRINT
#ifndef PSX
CBYTE *PCOM_move_state_name[] =
{
"Player",
"Still",
"Goto XZ",
"Goto waypoint",
"Goto thing",
"Pause",
"Animation",
"Circle",
"Driveto",
"Follow",
"Park car",
"Drive down",
"Biketo",
"Park bike",
"Bike down",
"Number",
"Grapple",
"goto thing slide",
"wait circle",
"Unused",
"Unused",
"Unused"
};
#endif
//
// While mavigating, a person is either running/walking to a point or
// doing an action.
//
#define PCOM_MOVE_SUBSTATE_NONE 0
#define PCOM_MOVE_SUBSTATE_GOTO 1
#define PCOM_MOVE_SUBSTATE_ACTION 2
#define PCOM_MOVE_SUBSTATE_GUNAWAY 3
#define PCOM_MOVE_SUBSTATE_GUNOUT 4
#define PCOM_MOVE_SUBSTATE_PUNCH 5
#define PCOM_MOVE_SUBSTATE_KICK 6
#define PCOM_MOVE_SUBSTATE_SHOOT 7
#define PCOM_MOVE_SUBSTATE_ANIM 8
#define PCOM_MOVE_SUBSTATE_GETINCAR 9
#define PCOM_MOVE_SUBSTATE_3PTURN 10
#define PCOM_MOVE_SUBSTATE_WAIT 11
#define PCOM_MOVE_SUBSTATE_LEAVECAR 12
#define PCOM_MOVE_SUBSTATE_ARREST 13
#define PCOM_MOVE_SUBSTATE_LOSMAV 14
#define PCOM_MOVE_FLAG_AVOID_LEFT (1 << 0)
#define PCOM_MOVE_FLAG_AVOID_RIGHT (1 << 1)
//
// What to do when we leave a car
//
#define PCOM_EXCAR_NORMAL 0 // Substate and arg ignored
#define PCOM_EXCAR_FLEE_PERSON 1 // 'arg' is the person to flee from.
#define PCOM_EXCAR_ARREST_PERSON 2 // 'arg' is the person to arrest.
#define PCOM_EXCAR_NAVTOKILL 3 // 'arg' is the person to kill.
//
// The distance from a point somebody must be to count as having
// arrived there.
//
#define PCOM_ARRIVE_DIST (0x40)
//
// The pause counter uses this many ticks-per-gameturn and ticks-per-second.
//
#define PCOM_TICKS_PER_TURN 16
#define PCOM_TICKS_PER_SEC (16 * 20)
//
// This is an array of people with PCOM_AI_GANG sorted by their colour.
//
#define PCOM_MAX_GANG_PEOPLE 64
THING_INDEX PCOM_gang_person[PCOM_MAX_GANG_PEOPLE];
SLONG PCOM_gang_person_upto;
typedef struct
{
UBYTE index;
UBYTE number;
} PCOM_Gang;
#define PCOM_MAX_GANGS 16
PCOM_Gang PCOM_gang[PCOM_MAX_GANGS];
//
// For when we are looking for things.
//
#define PCOM_MAX_FIND 16
UWORD PCOM_found[PCOM_MAX_FIND];
SLONG PCOM_found_num;
//
// Prototypes...
//
void PCOM_set_person_ai_homesick(Thing *p_person);
SLONG person_holding_2handed(Thing *p_person);
void PCOM_init(void)
{
//
// Clear all our gang info.
//
// ASSERT(0);
memset(PCOM_gang, 0, sizeof(PCOM_Gang) * PCOM_MAX_GANGS);
PCOM_gang_person_upto = 0;
}
void PCOM_add_gang_member(THING_INDEX person, UBYTE group)
{
SLONG i;
PCOM_Gang *pg;
ASSERT(WITHIN(group, 0, PCOM_MAX_GANGS - 1));
ASSERT(WITHIN(PCOM_gang_person_upto, 0, PCOM_MAX_GANG_PEOPLE - 1));
if(PCOM_gang_person_upto>=PCOM_MAX_GANG_PEOPLE)
{
return;
}
// Mike added this assert, and it shouldn't be here, apparently.
//if(TO_THING(person)->Genus.Person->PersonType==PERSON_COP)
// ASSERT(0);
if(TO_THING(person)->Genus.Person->PersonType==PERSON_CIV)
ASSERT(0);
pg = &PCOM_gang[group];
//
// Do we need to shove anybody along?
//
if (pg->index + pg->number == PCOM_gang_person_upto)
{
//
// No need to shove anyone along.
//
PCOM_gang_person[PCOM_gang_person_upto] = person;
pg->number += 1;
PCOM_gang_person_upto += 1;
}
else
{
//
// Shove along all the other indices...
//
for (i = PCOM_gang_person_upto - 1; i >= pg->index + pg->number; i--)
{
PCOM_gang_person[i + 1] = PCOM_gang_person[i];
}
for (i = 0; i < PCOM_MAX_GANGS; i++)
{
if (i == group)
{
continue;
}
if (PCOM_gang[i].index >= pg->index + pg->number)
{
PCOM_gang[i].index += 1;
}
}
//
// Insert our person in the gap.
//
PCOM_gang_person[pg->index + pg->number] = person;
pg->number += 1;
PCOM_gang_person_upto += 1;
}
}
//
// Returns TRUE if a fake wandering person should attack Darci.
//
SLONG PCOM_should_fake_person_attack_darci(Thing *p_person)
{
Thing *darci = NET_PERSON(0);
if (darci->Genus.Person->Ware)
{
//
// Don't attack Darci when she's in a warehouse.
//
return FALSE;
}
if (EWAY_stop_player_moving())
{
//
// In a cutscene...
//
return FALSE;
}
if (p_person->Genus.Person->PersonType == PERSON_COP)
{
//
// Cops always attack the thugs!
//
return TRUE;
}
PCOM_found_num = THING_find_sphere(
darci->WorldPos.X >> 8,
darci->WorldPos.Y >> 8,
darci->WorldPos.Z >> 8,
0x600,
PCOM_found,
PCOM_MAX_FIND,
1 << CLASS_PERSON);
SLONG i;
Thing *p_found;
for (i = 0; i < PCOM_found_num ; i++)
{
p_found = TO_THING(PCOM_found[i]);
if (p_found->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
continue;
}
switch(p_found->Genus.Person->PersonType)
{
case PERSON_THUG_RASTA:
case PERSON_THUG_GREY:
case PERSON_THUG_RED:
case PERSON_MIB1:
case PERSON_MIB2:
case PERSON_MIB3:
return FALSE;
}
}
return TRUE;
}
//
// returns shoot delay in 10ths of a second
//
//
// not really PCOM_ becasue used by players elsewhere
//
SLONG get_rate_of_fire(Thing *p_person)
{
Thing *p_special;
if (p_person->Genus.Person->PersonType == PERSON_MIB1 ||
p_person->Genus.Person->PersonType == PERSON_MIB2 ||
p_person->Genus.Person->PersonType == PERSON_MIB3)
{
//
// MIB are ninja shooting machines with built-in AK47s.
//
return 20;
}
if(p_person->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
return 20;
}
else
if (p_person->Genus.Person->SpecialUse)
{
p_special = TO_THING(p_person->Genus.Person->SpecialUse);
switch (p_special->Genus.Special->SpecialType)
{
case SPECIAL_SHOTGUN: return 30;
case SPECIAL_AK47: return 25;
case SPECIAL_GRENADE: return 20;
default:
//
// This isn't a weapon you shoot!
//
return 0;
}
}
else
{
return 0 ; // not a gun
}
}
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
//
//
//
// @@@@@@@
// @ @ @ @
// @ @ @ @
// @ @@@ @@ @ @@ @@@ @@@@
// @ @ @ @ @ @ @ @ @
// @ @ @ @@@@ @ @@@ @@@ @
// @ @ @ @ @ @ @ @ @
// @ @ @ @@@ @ @@@@ @@@ @@@
//
//
//
// @@ @
// @ @ @
// @ @ @
// @ @ @ @
// @@@ @ @ @ @ @@@ @@@ @@ @ @ @
// @ @ @ @@ @ @ @ @ @ @ @@ @ @
// @ @ @ @ @ @ @ @ @ @ @ @ @
// @ @ @ @ @ @ @ @ @ @ @ @
// @ @@@ @ @ @@@ @@ @ @@ @ @ @
SLONG person_has_gun_or_grenade_out(Thing *p_person)
{
if (p_person->Genus.Person->Flags&FLAG_PERSON_GUN_OUT)
{
return(SPECIAL_GUN);
}
if (!p_person->Genus.Person->SpecialUse)
{
return FALSE;
}
{
Thing *p_special = TO_THING(p_person->Genus.Person->SpecialUse);
if (p_special->Genus.Special->SpecialType == SPECIAL_SHOTGUN ||
p_special->Genus.Special->SpecialType == SPECIAL_AK47 ||
p_special->Genus.Special->SpecialType == SPECIAL_GRENADE)
{
return(p_special->Genus.Special->SpecialType);
}
}
return FALSE;
}
//
//
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
//
// Returns the amount of time given in tenth's of a second.
//
inline SLONG PCOM_get_duration(SLONG tenths)
{
SLONG ans;
ans = tenths * (PCOM_TICKS_PER_SEC / 10);
return ans;
}
//
// approximate
//
inline SLONG PCOM_get_duration100(SLONG hun)
{
SLONG ans;
ans = hun * (PCOM_TICKS_PER_SEC / 100);
return ans;
}
//
// Returns a random amount of time between the start and end given
// in tenths of a second.
//
SLONG PCOM_get_random_duration(SLONG min, SLONG max)
{
SLONG ans;
if (max <= min)
{
return min;
}
//
// Convert from 10ths of second to our tick stuff.
//
min = min * (PCOM_TICKS_PER_SEC / 10);
max = max * (PCOM_TICKS_PER_SEC / 10);
ans = min + Random() % (max - min);
return ans;
}
//
// Returns the angle for the given MAV_DIR
//
UWORD PCOM_get_angle_for_dir(SLONG dir)
{
static UWORD dir_to_angle[4]=
{
512,
512+1024,
0,
1024
};
SLONG angle;
ASSERT(WITHIN(dir, 0, 3));
angle = dir_to_angle[dir];
return angle;
}
//
// Returns a small vector in the given MAV_DIR
//
void PCOM_get_dx_dz_for_dir(SLONG dir, SLONG *dx, SLONG *dz)
{
SLONG ans_x;
SLONG ans_z;
SLONG angle = PCOM_get_angle_for_dir(dir);
ans_x = COS(angle) >> 11;
ans_z = SIN(angle) >> 11;
*dx = ans_x;
*dz = ans_z;
}
//
// Returns the distance between two people- includes y spacing.
//
SLONG PCOM_get_dist_between(Thing *p_person_a, Thing *p_person_b)
{
SLONG ax;
SLONG ay;
SLONG az;
if (p_person_a->Class == CLASS_PERSON)
{
calc_sub_objects_position(
p_person_a,
p_person_a->Draw.Tweened->AnimTween,
SUB_OBJECT_PELVIS,
&ax,
&ay,
&az);
}
else
{
ax = 0;
ay = 0;
az = 0;
}
ax += p_person_a->WorldPos.X >> 8;
ay += p_person_a->WorldPos.Y >> 8;
az += p_person_a->WorldPos.Z >> 8;
SLONG bx;
SLONG by;
SLONG bz;
if (p_person_b->Class == CLASS_PERSON)
{
calc_sub_objects_position(
p_person_b,
p_person_b->Draw.Tweened->AnimTween,
SUB_OBJECT_PELVIS,
&bx,
&by,
&bz);
}
else
{
bx = 0;
by = 0;
bz = 0;
}
bx += p_person_b->WorldPos.X >> 8;
by += p_person_b->WorldPos.Y >> 8;
bz += p_person_b->WorldPos.Z >> 8;
SLONG dx = abs(ax - bx);
SLONG dy = abs(ay - by);
SLONG dz = abs(az - bz);
SLONG dist = QDIST2(dx,dz);
if (dy >= 0x80)
{
//
// Must be on a different level- that counts as being very far away.
//
dist += dy << 2;
}
return dist;
}
//
// Returns how far a person is from home.
//
SLONG PCOM_get_dist_from_home(Thing *p_person)
{
SLONG home_x = (p_person->Genus.Person->HomeX << 0);// + 0x80;
SLONG home_z = (p_person->Genus.Person->HomeZ << 0);// + 0x80;
SLONG dx = abs((p_person->WorldPos.X >> 8) - home_x);
SLONG dz = abs((p_person->WorldPos.Z >> 8) - home_z);
SLONG dist = QDIST2(dx,dz);
return dist;
}
//
// Returns TRUE if you can try to do a fastnav to the given person.
//
SLONG PCOM_should_i_try_to_los_mav_to_person(Thing *p_person, Thing *p_target)
{
if (p_target->Class == CLASS_PERSON)
{
if (p_target->State == STATE_CLIMB_LADDER ||
p_target->State == STATE_CLIMBING ||
p_target->State == STATE_DANGLING ||
p_target->State == STATE_JUMPING)
{
return FALSE;
}
SLONG dx = abs(p_target->WorldPos.X - p_person->WorldPos.X);
SLONG dy = abs(p_target->WorldPos.Y - p_person->WorldPos.Y);
SLONG dz = abs(p_target->WorldPos.Z - p_person->WorldPos.Z);
if (dx < 0x30000 && dz < 0x30000 && dy < 0x10000)
{
return TRUE;
}
}
return FALSE;
}
//
// Gives the UBYTE mapsquare position you navigate to, to
// go to the given person.
//
void PCOM_get_person_navsquare(
Thing *p_person,
SLONG *map_dest_x,
SLONG *map_dest_z)
{
ASSERT(p_person->Class == CLASS_PERSON);
SLONG ans_x = p_person->WorldPos.X;
SLONG ans_z = p_person->WorldPos.Z;
if (p_person->State == STATE_CLIMB_LADDER ||
p_person->State == STATE_CLIMBING ||
p_person->State == STATE_DANGLING ||
p_person->State == STATE_JUMPING)
{
if (p_person->State == STATE_CLIMBING)
{
ASSERT(WITHIN(p_person->Genus.Person->OnFacet, 1, next_dfacet - 1));
if (dfacets[p_person->Genus.Person->OnFacet].FacetType == STOREY_TYPE_FENCE_BRICK)
{
//
// This person won't be able to climb over the fence...
//
goto dont_mav_in_front_of_the_person;
}
}
//
// Navigate to the square in front of the person.
//
SLONG dx = SIN(p_person->Draw.Tweened->Angle);
SLONG dz = COS(p_person->Draw.Tweened->Angle);
ans_x -= dx;
ans_z -= dz;
//
// Make it two squares for jumping...
//
if (p_person->State == STATE_JUMPING)
{
ans_x -= dx;
ans_z -= dz;
}
}
else
if (is_person_ko(p_person))
{
SLONG pelvis_x;
SLONG pelvis_y;
SLONG pelvis_z;
//
// Go to the pelvis position.
//
calc_sub_objects_position(
p_person,
p_person->Draw.Tweened->AnimTween,
SUB_OBJECT_PELVIS,
&pelvis_x,
&pelvis_y,
&pelvis_z);
pelvis_x <<= 8;
pelvis_z <<= 8;
pelvis_x += p_person->WorldPos.X;
pelvis_z += p_person->WorldPos.Z;
ans_x = pelvis_x;
ans_z = pelvis_z;
}
dont_mav_in_front_of_the_person:;
*map_dest_x = ans_x >> 16;
*map_dest_z = ans_z >> 16;
}
//
// Gives the UBYTE mapsquare position you navigate to be
// get to the door of the given vehicle.
//
void PCOM_get_vehicle_navsquare(
Thing *p_vehicle,
SLONG *map_dest_x,
SLONG *map_dest_z,
SLONG i_am_a_passenger,
Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG ix1;
SLONG iz1;
SLONG dist1;
SLONG ix2;
SLONG iz2;
SLONG dist2;
extern void get_car_enter_xz(Thing *p_vehicle,SLONG door, SLONG *cx,SLONG *cz);
//
// Go to the nearest door.
//
get_car_enter_xz(p_vehicle,0,&ix1,&iz1);
dx = abs((p_person->WorldPos.X >> 8) - ix1);
dz = abs((p_person->WorldPos.Z >> 8) - iz1);
dist1 = QDIST2(dx,dz);
get_car_enter_xz(p_vehicle,1,&ix2,&iz2);
dx = abs((p_person->WorldPos.X >> 8) - ix2);
dz = abs((p_person->WorldPos.Z >> 8) - iz2);
dist2 = QDIST2(dx,dz);
//
// (ix,iz) is now the position of the door.
//
if (dist1 < dist2)
{
*map_dest_x = ix1 >> 8;
*map_dest_z = iz1 >> 8;
}
else
{
*map_dest_x = ix2 >> 8;
*map_dest_z = iz2 >> 8;
}
#ifndef TARGET_DC
#ifndef NDEBUG
#ifndef PSX
AENG_world_line(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
32,
0x000000,
*map_dest_x,
p_person->WorldPos.Y >> 8,
*map_dest_z,
0,
0xff0000,
TRUE);
#endif
#endif
#endif
}
//
// Positions the given person so he is in a good position to sit
// on the prim. If 'dont_teleport' then if the person is too far
// from where he want to sit, this function returns FALSE and
// the person isn't moved.
//
SLONG PCOM_position_person_to_sit_on_prim(
Thing *p_person,
SLONG prim,
SLONG prim_x,
SLONG prim_y,
SLONG prim_z,
SLONG prim_yaw,
SLONG dont_teleport)
{
ASSERT(p_person->Class == CLASS_PERSON);
SLONG dx;
SLONG dz;
SLONG away;
PrimInfo *pi = get_prim_info(prim);
GameCoord newpos;
dx = SIN(prim_yaw & 2047) >> 8;
dz = COS(prim_yaw & 2047) >> 8;
p_person->Draw.Tweened->Angle = prim_yaw & 2047;
away = pi->minz;
away -= 0x20;
newpos.X = (prim_x << 8) + dx * away;
newpos.Z = (prim_z << 8) + dz * away;
if (dont_teleport)
{
//
// Make sure we aren't too far from where we are going to teleport to.
//
dx = abs(newpos.X - p_person->WorldPos.X);
dz = abs(newpos.Z - p_person->WorldPos.Z);
if (dx + dz > 0x5000)
{
return FALSE;
}
}
newpos.Y = /*PAP_calc_map_height_at(newpos.X >> 8, newpos.Z >> 8)*/ prim_y << 8;
move_thing_on_map(p_person, &newpos);
return TRUE;
}
//
// Returns the place a person should be running from- only
// call while fleeing.
//
void PCOM_get_flee_from_pos(
Thing *p_person,
SLONG *from_x,
SLONG *from_z)
{
SLONG ans_x;
SLONG ans_z;
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_FLEE_PLACE:
ans_x = (((p_person->Genus.Person->pcom_ai_arg >> 8) & 0xff) << 8) + 0x80;
ans_z = (((p_person->Genus.Person->pcom_ai_arg >> 0) & 0xff) << 8) + 0x80;
break;
case PCOM_AI_STATE_FLEE_PERSON:
ans_x = TO_THING(p_person->Genus.Person->pcom_ai_arg)->WorldPos.X >> 8;
ans_z = TO_THING(p_person->Genus.Person->pcom_ai_arg)->WorldPos.Z >> 8;
break;
default:
ASSERT(0);
break;
}
*from_x = ans_x;
*from_z = ans_z;
}
//
// Returns a movement person's destination.
//
void PCOM_get_person_dest(
Thing *p_person,
SLONG *dest_x,
SLONG *dest_z)
{
SLONG ans_x;
SLONG ans_y;
SLONG ans_z;
Thing *p_thing;
ans_x = p_person->WorldPos.X >> 8;
ans_z = p_person->WorldPos.Z >> 8;
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
break;
case PCOM_MOVE_STATE_GOTO_XZ:
ans_x = (p_person->Genus.Person->pcom_move_arg >> 8) & 0xff;
ans_z = (p_person->Genus.Person->pcom_move_arg >> 0) & 0xff;
ans_x <<= 8;
ans_z <<= 8;
ans_x += 0x80;
ans_z += 0x80;
break;
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
EWAY_get_position(
p_person->Genus.Person->pcom_move_arg,
&ans_x,
&ans_y,
&ans_z);
break;
case PCOM_MOVE_STATE_GOTO_THING:
p_thing = TO_THING(p_person->Genus.Person->pcom_move_arg);
switch(p_thing->Class)
{
case CLASS_PERSON:
PCOM_get_person_navsquare(
p_thing,
&ans_x,
&ans_z);
break;
case CLASS_VEHICLE:
PCOM_get_vehicle_navsquare(
p_thing,
&ans_x,
&ans_z,
p_thing->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HITCH,
p_person);
break;
default:
//
// Use the position of the thing by default.
//
ans_x = p_thing->WorldPos.X >> 16;
ans_z = p_thing->WorldPos.Z >> 16;
break;
}
ans_x <<= 8;
ans_z <<= 8;
ans_x += 0x80;
ans_z += 0x80;
break;
case PCOM_MOVE_STATE_PAUSE:
break;
case PCOM_MOVE_STATE_DRIVETO:
case PCOM_MOVE_STATE_BIKETO:
EWAY_get_position(
p_person->Genus.Person->pcom_move_arg,
&ans_x,
&ans_y,
&ans_z);
break;
case PCOM_MOVE_STATE_DRIVE_DOWN:
case PCOM_MOVE_STATE_BIKE_DOWN:
case PCOM_MOVE_STATE_PARK_CAR_ON_ROAD:
ROAD_get_dest(
p_person->Genus.Person->pcom_move_arg >> 8,
p_person->Genus.Person->pcom_move_arg & 0xff,
&ans_x,
&ans_z);
break;
case PCOM_MOVE_STATE_PARK_CAR:
case PCOM_MOVE_STATE_PARK_BIKE:
//
// Trying to stop...
//
break;
default:
ASSERT(0);
break;
}
*dest_x = ans_x;
*dest_z = ans_z;
return;
}
//
// The position for the given person's MAV_Action
//
void PCOM_get_mav_action_pos(
Thing *p_person,
SLONG *dest_x,
SLONG *dest_z)
{
ASSERT(p_person->Genus.Person->pcom_move_substate != PCOM_MOVE_SUBSTATE_LOSMAV);
SLONG dx;
SLONG dz;
SLONG ans_x = (p_person->Genus.Person->pcom_move_ma.dest_x << 8) + 0x80;
SLONG ans_z = (p_person->Genus.Person->pcom_move_ma.dest_z << 8) + 0x80;
if (p_person->Genus.Person->pcom_move_ma.action != MAV_ACTION_GOTO)
{
//
// Take the direction of the MAV_Action into account.
//
PCOM_get_dx_dz_for_dir(
p_person->Genus.Person->MA.dir,
&dx,
&dz);
ans_x += dx;
ans_z += dz;
}
*dest_x = ans_x;
*dest_z = ans_z;
}
//
// Returns TRUE if the person is carrying any sort of gun.
//
SLONG PCOM_person_has_any_sort_of_gun(Thing *p_person)
{
if (p_person->Flags & FLAGS_HAS_GUN)
{
return TRUE;
}
if (person_has_special(p_person, SPECIAL_SHOTGUN) ||
person_has_special(p_person, SPECIAL_AK47) ||
person_has_special(p_person, SPECIAL_GRENADE))
{
return TRUE;
}
if (p_person->Genus.Person->PersonType == PERSON_MIB1 ||
p_person->Genus.Person->PersonType == PERSON_MIB2 ||
p_person->Genus.Person->PersonType == PERSON_MIB3)
{
return TRUE;
}
return FALSE;
}
//
// Returns TRUE if the person has gun and ammo to use with it.
//
SLONG PCOM_person_has_any_sort_of_h2h(Thing *p_person)
{
if(person_has_special(p_person, SPECIAL_KNIFE))
{
return(SPECIAL_KNIFE);
}
else
if(person_has_special(p_person, SPECIAL_BASEBALLBAT))
{
return(SPECIAL_BASEBALLBAT);
}
else
{
return(0);
}
}
SLONG PCOM_person_has_any_sort_of_gun_with_ammo(Thing *p_person)
{
Thing *p_special;
if (p_person->Flags & FLAGS_HAS_GUN)
{
if (p_person->Genus.Person->Ammo)
{
return TRUE;
}
}
if (p_person->Genus.Person->PersonType == PERSON_MIB1 ||
p_person->Genus.Person->PersonType == PERSON_MIB2 ||
p_person->Genus.Person->PersonType == PERSON_MIB3)
{
return TRUE;
}
// lazy MARK!
if ((p_special = person_has_special(p_person, SPECIAL_SHOTGUN)) ||
(p_special = person_has_special(p_person, SPECIAL_AK47)) ||
(p_special = person_has_special(p_person, SPECIAL_GRENADE)))
{
if (p_special->Genus.Special->ammo)
{
return TRUE;
}
}
return FALSE;
}
//
// Returns TRUE if there are people waiting to get into the given car
// near the car.
//
SLONG PCOM_are_there_people_who_want_to_enter(Thing *p_vehicle)
{
SLONG i;
SLONG num_found;
Thing *p_found;
num_found = THING_find_sphere(
p_vehicle->WorldPos.X >> 8,
p_vehicle->WorldPos.Y >> 8,
p_vehicle->WorldPos.Z >> 8,
0x400,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_PERSON);
for (i = 0; i < num_found; i++)
{
p_found = TO_THING(THING_array[i]);
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FINDCAR ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HITCH)
{
Thing *p_vehin = TO_THING(p_found->Genus.Person->pcom_ai_arg);
if (p_vehin == p_vehicle)
{
return TRUE;
}
}
}
return FALSE;
}
SLONG PCOM_person_doing_nothing_important(Thing *p_person)
{
if(p_person->State==STATE_DYING||p_person->State==STATE_DEAD||p_person->State==STATE_CARRY)
return(FALSE);
if (p_person->State == STATE_MOVEING && (p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER || p_person->SubState == SUB_STATE_SIMPLE_ANIM))
{
if (p_person->Draw.Tweened->CurrentAnim == ANIM_SIT_DOWN ||
p_person->Draw.Tweened->CurrentAnim == ANIM_SIT_IDLE)
{
//
// If they're sitting down...
//
return TRUE;
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
if(p_person->Genus.Person->pcom_ai==PCOM_AI_COP_DRIVER &&(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING) &&p_person->Genus.Person->pcom_move==PCOM_MOVE_WANDER)
return(TRUE);
if(p_person->Genus.Person->Flags & (FLAG_PERSON_NON_INT_M|FLAG_PERSON_NON_INT_C))
return(FALSE);
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_GOTO_XZ:
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
case PCOM_MOVE_STATE_GOTO_THING:
if (p_person->Genus.Person->pcom_move_substate == PCOM_MOVE_SUBSTATE_ACTION)
{
//
// In the middle of doing a complicated moving.
//
return FALSE;
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
if(p_person->Genus.Person->pcom_ai==PCOM_AI_COP_DRIVER &&(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING) &&p_person->Genus.Person->pcom_move==PCOM_MOVE_WANDER)
return TRUE;
if (p_person->State == STATE_IDLE ||
p_person->State == STATE_GOTOING ||
p_person->State == STATE_NORMAL)
{
return TRUE;
}
if (p_person->State == STATE_GUN &&
p_person->SubState == SUB_STATE_AIM_GUN)
{
//
// Gun out... might be doing something important!
//
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
return TRUE;
}
}
if (p_person->State == STATE_MOVEING)
{
if (p_person->SubState == SUB_STATE_SIMPLE_ANIM ||
p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER)
{
return TRUE;
}
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING)
{
return TRUE;
}
return FALSE;
}
//
// Returns TRUE if the person has any kind of gun in his hand- ready to shoot.
//
SLONG PCOM_person_has_gun_in_hand(Thing *p_person)
{
if (p_person->Genus.Person->PersonType == PERSON_MIB1 ||
p_person->Genus.Person->PersonType == PERSON_MIB2 ||
p_person->Genus.Person->PersonType == PERSON_MIB3)
{
//
// MIB are ninja shooting machines with built-in AK47s!
//
return TRUE;
}
if (p_person->State == STATE_GUN &&
p_person->SubState == SUB_STATE_DRAW_GUN)
{
//
// Still drawing a weapon.
//
return FALSE;
}
if (p_person->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
return TRUE;
}
if (p_person->Genus.Person->SpecialUse)
{
Thing *p_special = TO_THING(p_person->Genus.Person->SpecialUse);
if (p_special->Genus.Special->SpecialType == SPECIAL_SHOTGUN ||
p_special->Genus.Special->SpecialType == SPECIAL_AK47 ||
p_special->Genus.Special->SpecialType == SPECIAL_GRENADE)
{
return TRUE;
}
}
return FALSE;
}
//
// Returns TRUE if the target has a gun pointed at you!
//
SLONG PCOM_target_could_shoot_me(Thing *p_person, Thing *p_shooter)
{
if(can_a_see_b(p_shooter,p_person))
if (PCOM_person_has_gun_in_hand(p_shooter))
{
SLONG dangle = get_dangle(p_shooter, p_person);
#define PCOM_SHOOTME_DANGLE 256
if (dangle < PCOM_SHOOTME_DANGLE ||
dangle > 2048 - PCOM_SHOOTME_DANGLE)
{
return TRUE;
}
}
return FALSE;
}
//
// Returns the distance of the person from the point.
//
SLONG PCOM_person_dist_from(
Thing *p_person,
SLONG world_x,
SLONG world_z)
{
SLONG dx = abs((p_person->WorldPos.X >> 8) - world_x);
SLONG dz = abs((p_person->WorldPos.Z >> 8) - world_z);
SLONG dist = QDIST2(dx,dz);
return dist;
}
//
// Finds a place near the given person where somebody might be
// hiding. Returns NULL if it couldn't find anywhere.
//
SLONG PCOM_find_hiding_place(
Thing *p_person,
SLONG *hide_x,
SLONG *hide_z)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG score;
SLONG ndx;
SLONG ndz;
SLONG ndist;
SLONG mid_x = p_person->WorldPos.X >> 16;
SLONG mid_z = p_person->WorldPos.Z >> 16;
SLONG mx;
SLONG mz;
SLONG best_x = 0;
SLONG best_z = 0;
SLONG best_score = -INFINITY;
SLONG x1 = (p_person->WorldPos.X >> 8);
SLONG y1 = (p_person->WorldPos.Y >> 8) + 0x60;
SLONG z1 = (p_person->WorldPos.Z >> 8);
SLONG x2;
SLONG y2;
SLONG z2;
MAV_Action ma;
PAP_Hi *ph;
for (dx = -5; dx <= 5; dx++)
for (dz = -5; dz <= 5; dz++)
{
mx = mid_x + dx;
mz = mid_z + dz;
if (WITHIN(mx, 0, PAP_SIZE_HI - 1) &&
WITHIN(mz, 0, PAP_SIZE_HI - 1))
{
ph = &PAP_2HI(mx,mz);
if (ph->Flags & PAP_FLAG_HIDDEN)
{
//
// Inside a building.
//
}
else
{
dist = abs(dx) + abs(dz);
if (dist >= 2)
{
//
// Could we see someone standing on this square?
//
x2 = (mx << 8) + 0x80;
z2 = (mz << 8) + 0x80;
y2 = PAP_calc_height_at(x2,z2) + 0x60;
if (there_is_a_los(
x1, y1, z1,
x2, y2, z2,
0))
{
//
// We can see this square- there isn't anyone hiding here.
//
}
else
{
ma = MAV_do(
x1 >> 8,
z1 >> 8,
x2 >> 8,
z2 >> 8,
MAV_CAPS_DARCI);
if (MAV_do_found_dest)
{
//
// Somebody could be hiding here.
//
ndx = ma.dest_x - mid_x;
ndz = ma.dest_z - mid_z;
ndist = abs(ndx) + abs(ndz);
if (ndist > dist + 2)
{
//
// Its a very round-about way to get there.
//
}
else
{
score = 0x1000 - (Random() % (dist << 4));
if (score > best_score)
{
best_x = x2;
best_z = z2;
best_score = score;
}
}
}
}
}
}
}
}
*hide_x = best_x;
*hide_z = best_z;
return (best_score > -INFINITY);
}
SLONG PCOM_player_is_doing_something_naughty(Thing *darci)
{
SLONG map_x;
SLONG map_z;
//
// She isn't allowed to be fighting anyone.
//
if (darci->Genus.Person->Mode == PERSON_MODE_FIGHT)
{
return TRUE;
}
/*
//
// She isn't allowed to be on a naughty square- or trying to get to a
// naughty square.
//
map_x = darci->WorldPos.X >> 16;
map_z = darci->WorldPos.Z >> 16;
if (PAP_2HI(map_x,map_z).Flags & PAP_FLAG_NAUGHTY)
{
return TRUE;
}
if (darci->Genus.Person->Action == ACTION_CLIMBING)
{
SLONG dx;
SLONG dz;
//
// Is Darci climbing into somewhere naughty?
//
dx = -SIN(darci->Draw.Tweened->Angle);
dz = -COS(darci->Draw.Tweened->Angle);
map_x = darci->WorldPos.X + dx >> 16;
map_z = darci->WorldPos.Z + dz >> 16;
if (PAP_2HI(map_x,map_z).Flags & PAP_FLAG_NAUGHTY)
{
return TRUE;
}
}
*/
return FALSE;
}
//
// Makes everyone in this person's gang help the person in
// his fight (if they can see him).
//
void PCOM_set_person_ai_kill_person(Thing *p_person, Thing *p_target, SLONG alert_gang = TRUE); // These two functions call eachother!
void PCOM_alert_my_gang_to_a_fight(Thing *p_person, Thing *p_target)
{
SLONG i;
PCOM_Gang *pg;
Thing *p_gang;
ASSERT(WITHIN(p_person->Genus.Person->pcom_colour, 0, PCOM_MAX_GANGS - 1));
ASSERT(p_person->Genus.Person->pcom_bent & PCOM_BENT_GANG);
pg = &PCOM_gang[p_person->Genus.Person->pcom_colour];
for (i = 0; i < pg->number; i++)
{
p_gang = TO_THING(PCOM_gang_person[pg->index + i]); //PCOM_gang_person[pg->index + i]==0 error pg->index=2 pg->number=3 i=2
if(p_gang->Class==CLASS_PERSON)
if (p_gang != p_person)
{
SLONG dx = p_gang->WorldPos.X - p_target->WorldPos.X ;
SLONG dz = p_gang - p_target;
if (!(p_gang->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
if (p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_SEARCHING ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_TAUNT ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING)
{
if(p_target->Genus.Person->PersonType==PERSON_DARCI)
{
if(p_gang->Genus.Person->PersonType==PERSON_CIV)
{
ASSERT(0);
}
if(p_gang->Genus.Person->PersonType==PERSON_COP)
{
ASSERT(0);
}
}
//
// This person isn't doing anything important. He can help in the fight.
//
PCOM_set_person_ai_kill_person(p_gang, p_target, FALSE);
}
}
}
}
SLONG am_i_a_thug(Thing *p_person);
void PCOM_alert_my_gang_to_flee(Thing *p_person, Thing *p_target)
{
SLONG i;
PCOM_Gang *pg;
Thing *p_gang;
ASSERT(WITHIN(p_person->Genus.Person->pcom_colour, 0, PCOM_MAX_GANGS - 1));
ASSERT(p_person->Genus.Person->pcom_bent & PCOM_BENT_GANG);
pg = &PCOM_gang[p_person->Genus.Person->pcom_colour];
for (i = 0; i < pg->number; i++)
{
p_gang = TO_THING(PCOM_gang_person[pg->index + i]); //PCOM_gang_person[pg->index + i]==0 error pg->index=2 pg->number=3 i=2
if(p_gang->Class==CLASS_PERSON)
if(!am_i_a_thug(p_person)||(!(p_gang->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)))
if (p_gang != p_person)
{
if (!(p_gang->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
if (p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_SEARCHING ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_TAUNT ||
p_gang->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING)
{
//
// This person isn't doing anything important. He can run away
//
PCOM_set_person_ai_flee_person(p_gang, p_target);
}
}
}
}
// ========================================================
//
// SET PEOPLE MOVE STATES
//
// ========================================================
void PCOM_set_person_move_still(Thing *p_person)
{
//
// Make the person stand still.
//
set_person_idle(p_person);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_set_person_move_mav_to_xz(Thing *p_person, SLONG dest_x, SLONG dest_z, SLONG speed)
{
SLONG caps;
SLONG goal_x;
SLONG goal_z;
SLONG start_x;
SLONG start_y;
SLONG start_z;
/*
calc_sub_objects_position(
p_person,
p_person->Draw.Tweened->AnimTween,
SUB_OBJECT_LEFT_FOOT,
&start_x,
&start_y,
&start_z);
start_x += p_person->WorldPos.X >> 8;
start_z += p_person->WorldPos.Z >> 8;
start_x >>= 8;
start_z >>= 8;
*/
start_x = p_person->WorldPos.X >> 16;
start_z = p_person->WorldPos.Z >> 16;
//
// We can only go to mapsquares.
//
dest_x >>= 8;
dest_z >>= 8;
//
// Store the destination.
//
p_person->Genus.Person->pcom_move_arg = (dest_x << 8) | (dest_z);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GOTO_XZ;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_counter = 0;
//
// What is this person's caps?
//
caps = (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED) ? MAV_CAPS_GOTO : MAV_CAPS_DARCI;
if (p_person->Genus.Person->pcom_ai == PCOM_AI_CIV)
{
if ((p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL && p_person->Genus.Person->pcom_move == PCOM_MOVE_WANDER) ||
(p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PLACE || p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PERSON))
{
//
// If this person is in a good place for a wandering civ, then he
// isn't allowed to jump/vault/climb ladders.
//
if (WAND_square_is_wander(p_person->WorldPos.X >> 16, p_person->WorldPos.Z >> 16))
{
//
// Restricted wandering capability.
//
caps = MAV_CAPS_GOTO;
}
}
}
UWORD nav_into_ware = NULL;
UBYTE nav_outof_ware = FALSE;
UBYTE nav_inside_ware = FALSE;
//
// If you are scared and in a warehouse- always run to the exit.
//
if ((p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PLACE ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PERSON))
{
if (p_person->Genus.Person->Ware)
{
nav_outof_ware = TRUE;
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK)
{
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_HOME_IN_WAREHOUSE)
{
nav_into_ware = WARE_which_contains(
p_person->Genus.Person->HomeX >> 8,
p_person->Genus.Person->HomeZ >> 8);
}
}
if (nav_into_ware && p_person->Genus.Person->Ware)
{
//
// We want to navigate to a warehouse and we are already in one.
//
if (nav_into_ware == p_person->Genus.Person->Ware)
{
//
// We are alreay in the right warehouse!
//
nav_into_ware = NULL;
nav_inside_ware = TRUE;
}
else
{
//
// We are in the wrong warehouse!
//
nav_outof_ware = TRUE;
nav_into_ware = FALSE;
}
}
if (nav_outof_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_exit(
p_person,
caps);
}
else
if (nav_into_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_enter(
p_person,
nav_into_ware,
caps);
}
else
if (nav_inside_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_inside(
p_person,
dest_x,
dest_z,
caps);
}
else
{
//
// Do the mavigate.
//
p_person->Genus.Person->pcom_move_ma = MAV_do(
start_x,
start_z,
dest_x,
dest_z,
caps);
}
//
// Our first goal.
//
PCOM_get_mav_action_pos(
p_person,
&goal_x,
&goal_z);
//
// Get going.
//
set_person_goto_xz(
p_person,
goal_x,
goal_z,
speed);
}
void PCOM_set_person_move_mav_to_thing(Thing *p_person, Thing *p_target, SLONG speed)
{
SLONG goal_x;
SLONG goal_z;
SLONG start_x;
SLONG start_y;
SLONG start_z;
calc_sub_objects_position(
p_person,
p_person->Draw.Tweened->AnimTween,
SUB_OBJECT_LEFT_FOOT,
&start_x,
&start_y,
&start_z);
start_x += p_person->WorldPos.X >> 8;
start_z += p_person->WorldPos.Z >> 8;
start_x >>= 8;
start_z >>= 8;
SLONG dest_x;
SLONG dest_z;
UBYTE nav_outof_ware = FALSE;
UBYTE nav_inside_ware = FALSE;
SLONG nav_into_ware = NULL;
UBYTE caps = (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED) ? MAV_CAPS_GOTO : MAV_CAPS_DARCI;
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GOTO_THING;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_move_counter = 0;
//
// We might have to do warehouse navigation.
//
if (p_person->Genus.Person->Ware)
{
if (p_target->Class != CLASS_PERSON)
{
//
// We should navigate out of the warehouse.
//
nav_outof_ware = TRUE;
}
else
if (p_target->Genus.Person->Ware != p_person->Genus.Person->Ware)
{
//
// The person we are mavigating to is inside a different warehouse
// to me. Leave the one we are in.
//
nav_outof_ware = TRUE;
}
else
{
//
// Our target and I are in the same warehouse.
//
nav_inside_ware = TRUE;
}
}
else
if (p_target->Class == CLASS_PERSON && p_target->Genus.Person->Ware)
{
//
// We are not in a warehouse but our target is. Navigate to the
// warehouse our target is in.
//
nav_into_ware = p_target->Genus.Person->Ware;
}
//
// Do the mavigation call we require.
//
if (nav_into_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_enter(
p_person,
nav_into_ware,
caps);
}
else
if (nav_outof_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_exit(
p_person,
caps);
}
else
{
if (!nav_inside_ware && PCOM_should_i_try_to_los_mav_to_person(p_person, p_target))
{
//
// We could try going into 'run towards the person' mode.
//
if (!there_is_a_los_mav(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y + 0x4000 >> 8,
p_person->WorldPos.Z >> 8,
p_target->WorldPos.X >> 8,
p_target->WorldPos.Y + 0x4000 >> 8,
p_target->WorldPos.Z >> 8))
{
//
// Try just running towards the person and hoping!
//
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_LOSMAV;
//
// Get going.
//
set_person_goto_xz(
p_person,
p_target->WorldPos.X >> 8,
p_target->WorldPos.Z >> 8,
speed);
return;
}
}
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
dest_x >>= 8;
dest_z >>= 8;
//
// Stop it crashing when naving to a vehicle off the map (MikeD)
//
SATURATE(dest_x, 0, PAP_SIZE_HI - 1);
SATURATE(dest_z, 0, PAP_SIZE_HI - 1);
//
// Do the mavigate.
//
if (nav_inside_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_inside(
p_person,
dest_x,
dest_z,
caps);
}
else
{
p_person->Genus.Person->pcom_move_ma = MAV_do(
start_x,
start_z,
dest_x,
dest_z,
caps);
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL)
{
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED)
{
if (!MAV_do_found_dest)
{
//
// This person can't nav to his target... make him go home.
//
PCOM_set_person_ai_homesick(p_person);
return;
}
}
}
//
// Our first goal.
//
PCOM_get_mav_action_pos(
p_person,
&goal_x,
&goal_z);
//
// Get going.
//
set_person_goto_xz(
p_person,
goal_x,
goal_z,
speed);
}
void PCOM_set_person_move_mav_to_waypoint(Thing *p_person, SLONG waypoint, SLONG speed)
{
SLONG goal_x;
SLONG goal_z;
SLONG dest_x;
SLONG dest_y;
SLONG dest_z;
SLONG start_x;
SLONG start_y;
SLONG start_z;
calc_sub_objects_position(
p_person,
p_person->Draw.Tweened->AnimTween,
SUB_OBJECT_LEFT_FOOT,
&start_x,
&start_y,
&start_z);
start_x += p_person->WorldPos.X >> 8;
start_z += p_person->WorldPos.Z >> 8;
start_x >>= 8;
start_z >>= 8;
UBYTE caps = (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED) ? MAV_CAPS_GOTO : MAV_CAPS_DARCI;
UBYTE eware = EWAY_get_warehouse(waypoint);
UBYTE nav_outof_ware = FALSE;
UBYTE nav_inside_ware = FALSE;
SLONG nav_into_ware = NULL;
//
// We can only go to mapsquares.
//
EWAY_get_position(
waypoint,
&dest_x,
&dest_y,
&dest_z);
dest_x >>= 8;
dest_z >>= 8;
//
// Store the destination.
//
p_person->Genus.Person->pcom_move_arg = waypoint;
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GOTO_WAYPOINT;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_counter = 0;
//
// We might have to do a warehouse navigation.
//
if (p_person->Genus.Person->Ware)
{
if (eware != p_person->Genus.Person->Ware)
{
nav_outof_ware = TRUE;
}
else
{
//
// The waypoint and the person are inside the same warehouse.
//
nav_inside_ware = TRUE;
}
}
else
{
if (eware)
{
//
// We are not in a warehouse but our target is.
//
nav_into_ware = eware;
}
}
//
// Do the mavigation call we require.
//
if (nav_into_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_enter(
p_person,
nav_into_ware,
caps);
}
else
if (nav_outof_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_exit(
p_person,
caps);
}
else
{
//
// Do the mavigate.
//
if (nav_inside_ware)
{
p_person->Genus.Person->pcom_move_ma = WARE_mav_inside(
p_person,
dest_x,
dest_z,
caps);
}
else
{
p_person->Genus.Person->pcom_move_ma = MAV_do(
start_x,
start_z,
dest_x,
dest_z,
caps);
}
}
//
// Our first goal.
//
PCOM_get_mav_action_pos(
p_person,
&goal_x,
&goal_z);
//
// Get going.
//
set_person_goto_xz(
p_person,
goal_x,
goal_z,
speed);
}
void PCOM_set_person_move_runaway(
Thing *p_person,
SLONG from_x,
SLONG from_z)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG goal_x;
SLONG goal_z;
SLONG dest_x;
SLONG dest_z;
SLONG dist_me;
SLONG dist_from;
SLONG tries = 0;
while(1)
{
//
// Work out a place to MAV to that will (probably) make us run away.
//
dx = (p_person->WorldPos.X >> 8) - from_x;
dz = (p_person->WorldPos.Z >> 8) - from_z;
dist = abs(dx) + abs(dz) + 1;
dx = (dx << 13) / dist;
dz = (dz << 13) / dist;
dx += (Random() & 0x7ff);
dz += (Random() & 0x7ff);
dx -= 0x400;
dz -= 0x400;
goal_x = (p_person->WorldPos.X >> 8) + dx;
goal_z = (p_person->WorldPos.Z >> 8) + dz;
//
// Stay on the map.
//
if (goal_x < 0) {goal_x = -goal_x;}
if (goal_z < 0) {goal_z = -goal_z;}
if (goal_x > (PAP_SIZE_HI << PAP_SHIFT_HI)) {goal_x = 2 * (PAP_SIZE_HI << PAP_SHIFT_HI) - goal_x;}
if (goal_z > (PAP_SIZE_HI << PAP_SHIFT_HI)) {goal_z = 2 * (PAP_SIZE_HI << PAP_SHIFT_HI) - goal_z;}
//
// Get going to that place.
//
PCOM_set_person_move_mav_to_xz(
p_person,
goal_x,
goal_z,
PCOM_MOVE_SPEED_RUN);
//
// Has this made us start running towards what we are scared of?
//
PCOM_get_mav_action_pos(
p_person,
&dest_x,
&dest_z);
dx = abs((p_person->WorldPos.X >> 8) - dest_x);
dz = abs((p_person->WorldPos.Z >> 8) - dest_z);
dist_me = QDIST2(dx,dz);
dx = abs(from_x - dest_x);
dz = abs(from_z - dest_z);
dist_from = QDIST2(dx,dz);
if (dist_from < dist_me)
{
//
// Running towards what we are scared of!
//
tries += 1;
if (tries < 3)
{
//
// Have another go.
//
}
else
{
//
// Give up trying to find somewhere good to run to.
//
break;
}
}
else
{
//
// We are running away properly.
//
break;
}
}
}
//
// For a person in a vehicle this function sets the pcom_move_substate to
// either PCOM_MOVE_SUBSTATE_GOTO or PCOM_MOVE_SUBSTATE_3PTURN depending on
// the angle of the vehicle relative to the direction they want to go in.
//
void PCOM_set_person_substate_goto_or_3pturn(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dest_x;
SLONG dest_z;
SLONG wangle;
SLONG dangle;
Thing *p_vehicle;
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
//
// What direction do we want the car to face?
//
dx = dest_x - (p_vehicle->WorldPos.X >> 8);
dz = dest_z - (p_vehicle->WorldPos.Z >> 8);
wangle = calc_angle(dx,dz);
wangle += 1024;
wangle &= 2047;
dangle = wangle - p_vehicle->Genus.Vehicle->Angle;
if (dangle < -1024) {dangle += 2048;}
if (dangle > +1024) {dangle -= 2048;}
if (abs(dangle) > 750)
{
//
// Do a three-point turn.
//
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_3PTURN;
}
else
{
//
// Just go there.
//
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
}
}
//
// Like the last function, but never does a 3-point turn - so we always go
// towards whichever node is ahead. Can only be used for DRIVE_DOWN, not DRIVE_TO.
//
void PCOM_set_person_substate_goto(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dest_x;
SLONG dest_z;
SLONG wangle;
SLONG dangle;
Thing *p_vehicle;
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
//
// What direction do we want the car to face?
//
dx = dest_x - (p_vehicle->WorldPos.X >> 8);
dz = dest_z - (p_vehicle->WorldPos.Z >> 8);
wangle = calc_angle(dx,dz);
wangle += 1024;
wangle &= 2047;
dangle = wangle - p_vehicle->Genus.Vehicle->Angle;
if (dangle < -1024) {dangle += 2048;}
if (dangle > +1024) {dangle -= 2048;}
if (abs(dangle) > 750)
{
// switch the road nodes around
p_person->Genus.Person->pcom_move_arg = (p_person->Genus.Person->pcom_move_arg << 8) | (p_person->Genus.Person->pcom_move_arg >> 8);
}
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
}
void PCOM_set_person_move_driveto(Thing *p_person, SLONG waypoint)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_DRIVETO;
p_person->Genus.Person->pcom_move_arg = waypoint;
p_person->Genus.Person->pcom_move_counter = 0;
//
// We have to decide whether to drive there or do a three point turn.
//
PCOM_set_person_substate_goto_or_3pturn(p_person);
}
void PCOM_set_person_move_park_car(Thing *p_person, SLONG waypoint)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PARK_CAR;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_arg = waypoint;
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_set_person_move_drive_down(Thing *p_person, SLONG n1, SLONG n2)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_DRIVE_DOWN;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_arg = (n1 << 8) | n2;
p_person->Genus.Person->pcom_move_counter = 0;
//
// We have to decide whether to drive there or do a three point turn.
//
PCOM_set_person_substate_goto(p_person);
}
//
// If you are driving down a road- this function will park you on the
// road. If you are driving towards a waypoint, it will just stop you
// straight away.
//
void PCOM_set_person_move_park_car_on_road(Thing *p_person)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_DRIVE_DOWN)
{
//
// Stop near the edge of the road.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PARK_CAR_ON_ROAD;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_counter = 0;
//
// The 'pcom_move_arg' is the same because that contains the nodes of the road
// we are driving along.
//
}
else
{
//
// Stop where you are.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PARK_CAR;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_arg = NULL;
p_person->Genus.Person->pcom_move_counter = 0;
}
}
#ifdef BIKE
void PCOM_set_person_move_biketo(Thing *p_person, SLONG waypoint)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_BIKETO;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_arg = waypoint;
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_set_person_move_park_bike(Thing *p_person, SLONG waypoint)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PARK_BIKE;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_arg = waypoint;
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_set_person_move_bike_down(Thing *p_person, SLONG n1, SLONG n2)
{
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_BIKE_DOWN;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_arg = (n1 << 8) | n2;
p_person->Genus.Person->pcom_move_counter = 0;
}
#endif
void PCOM_set_person_move_goto_thing_slide(Thing *p_person, Thing *p_target)
{
//
// Start sliding!
//
if(am_i_a_thug(p_person))
{
//
// only arrest thugs performing slide attacks?
//
PCOM_call_cop_to_arrest_me(p_person,1);
}
set_person_sliding_tackle(p_person, p_target);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GOTO_THING_SLIDE;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_renav(Thing *p_person)
{
SLONG dest_x;
SLONG dest_y;
SLONG dest_z;
Thing *p_target;
//
// What are we doing?
//
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_GOTO_XZ:
dest_x = (p_person->Genus.Person->pcom_move_arg >> 8) & 0xff;
dest_z = (p_person->Genus.Person->pcom_move_arg >> 0) & 0xff;
dest_x <<= 8;
dest_z <<= 8;
dest_x += 0x80;
dest_z += 0x80;
PCOM_set_person_move_mav_to_xz(
p_person,
dest_x,
dest_z,
p_person->Genus.Person->GotoSpeed);
break;
case PCOM_MOVE_STATE_GOTO_THING:
p_target = TO_THING(p_person->Genus.Person->pcom_move_arg);
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
p_person->Genus.Person->GotoSpeed);
break;
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
PCOM_set_person_move_mav_to_waypoint(
p_person,
p_person->Genus.Person->pcom_move_arg,
p_person->Genus.Person->GotoSpeed);
break;
default:
ASSERT(0);
break;
}
}
//
// Returns TRUE if a person has finished navigating.
//
SLONG PCOM_finished_nav(Thing *p_person)
{
SLONG dest_x;
SLONG dest_z;
if (p_person->State == STATE_IDLE)
{
//
// Although this person hasn't arrived, he isn't doing
// anything so I guess he's finished!
//
return TRUE;
}
if (p_person->State == STATE_DANGLING)
{
//
// Can't stop in the middle of a complicated manouvre!
//
return FALSE;
}
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
dest_x &= 0xffffff00;
dest_z &= 0xffffff00;
dest_x |= 0x80;
dest_z |= 0x80;
SLONG dist = PCOM_person_dist_from(
p_person,
dest_x,
dest_z);
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING)
{
return (dist < 0x60);
}
else
if (p_person->Genus.Person->SlideOdd > 20)
{
//
// This person has been sliding for a while. If we pretend
// he's arrived where he wants to go- maybe he'll stop.
//
if (dist < 0x100)
{
p_person->Genus.Person->SlideOdd = 1;
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return (dist < PCOM_ARRIVE_DIST);
}
}
//
// Make the person stand still.
//
void PCOM_set_person_move_pause(Thing *p_person)
{
set_person_idle(p_person);
//
// Remember what we are doing and for how long.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PAUSE;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Sets the person doing an animation.
//
void PCOM_set_person_move_animation(Thing *p_person, SLONG anim)
{
set_person_do_a_simple_anim(p_person, anim);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ANIM;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes the person do a punch move.
//
void PCOM_set_person_move_punch(Thing *p_person)
{
turn_to_target_and_punch(p_person);
//
// Punching is effectively doing an animation.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_WAIT_CIRCLE;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_PUNCH;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes the person do a kick move.
//
void PCOM_set_person_move_kick(Thing *p_person)
{
turn_to_target_and_kick(p_person);
//
// Kicking is effectively doing an animation.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_WAIT_CIRCLE;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_KICK;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes the person bend down to pick up a special.
//
void PCOM_set_person_move_pickup_special(Thing *p_person, Thing *p_special)
{
set_person_special_pickup(p_person);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ANIM;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes the person do an arrest!
//
UWORD find_arrestee (Thing *p_person);
void set_person_arrest(Thing *p_person, SLONG who_to_arrest);
void PCOM_set_person_move_arrest(Thing *p_person)
{
UWORD index;
index = PCOM_person_wants_to_kill(p_person);
if (index == NULL)
{
index = find_arrestee(p_person);
}
if (index)
{
set_person_arrest(p_person, index);
//
// Arresting is effectively doing an animation.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_WAIT_CIRCLE;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ARREST;
p_person->Genus.Person->pcom_move_counter = 0;
}
else
{
PCOM_set_person_move_still(p_person);
}
}
//
// Makes the person draw his gun.
//
void PCOM_set_person_move_draw_gun(Thing *p_person)
{
Thing *p_special;
//
// Draws a shotgun/AK47 in favour of a pistol.
//
if ((p_special = person_has_special(p_person, SPECIAL_SHOTGUN)) && p_special->Genus.Special->ammo)
{
set_person_draw_item(p_person, SPECIAL_SHOTGUN);
}
else
if ((p_special = person_has_special(p_person, SPECIAL_AK47)) && p_special->Genus.Special->ammo)
{
set_person_draw_item(p_person, SPECIAL_AK47);
}
else
if ((p_special = person_has_special(p_person, SPECIAL_GRENADE)) && p_special->Genus.Special->ammo)
{
set_person_draw_item(p_person, SPECIAL_GRENADE);
}
else
{
set_person_draw_gun(p_person);
}
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GUNOUT;
p_person->Genus.Person->pcom_move_counter = 0;
}
void PCOM_set_person_move_draw_h2h(Thing *p_person,SLONG special)
{
Thing *p_special;
{
set_person_draw_item(p_person,special);
}
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GUNOUT;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes the person put away his gun.
//
void PCOM_set_person_move_gun_away(Thing *p_person)
{
if (p_person->Genus.Person->SpecialUse)
{
p_person->Genus.Person->SpecialUse = NULL;
p_person->Draw.Tweened->PersonID&= ~0xe0;
//p_person->Draw.Tweened->PersonID = 0;
set_person_idle(p_person);
}
else
{
set_person_gun_away(p_person);
}
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GUNAWAY;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes a person shoot his gun.
//
void PCOM_set_person_move_shoot(Thing *p_person)
{
set_person_shoot(p_person,1);
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_SHOOT;
p_person->Genus.Person->pcom_move_counter = 0;
// CONSOLE_text("shoot");
}
//
// do cardinal points first then
//
UBYTE gang_angle_priority[]={0,2,6,4,1,7,3,5};
extern SLONG get_gangattack(Thing *p_person);
void check_players_gang(Thing *p_target)
{
SLONG gang;
SLONG c0,count=0;
Thing *p_person;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return;
for(c0=0;c0<4;c0++)
{
if(gang_attacks[gang].Perp[c0])
{
p_person=TO_THING(gang_attacks[gang].Perp[c0]);
#ifndef PSX
// AENG_world_line_infinite(p_target->WorldPos.X>>8,p_target->WorldPos.Y>>8,p_target->WorldPos.Z>>8,3,0xffffff,p_person->WorldPos.X>>8,p_person->WorldPos.Y>>8,p_person->WorldPos.Z>>8,0,0xffffff,1);
#endif
if(p_person->Genus.Person->PlayerID)
{
//
// a player attacking me
//
if(p_person->Genus.Person->Mode!=PERSON_MODE_FIGHT)
{
remove_from_gang_attack(p_person,p_target);
}
}
}
}
}
UWORD count_gang(Thing *p_target)
{
SLONG gang;
SLONG c0,count=0;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return(0);
for(c0=0;c0<4;c0++)
{
if(gang_attacks[gang].Perp[c0])
{
Thing *p_person;
p_person=TO_THING(gang_attacks[gang].Perp[c0]);
#ifndef PSX
// AENG_world_line_infinite(p_target->WorldPos.X>>8,p_target->WorldPos.Y>>8,p_target->WorldPos.Z>>8,7,0xffff,p_person->WorldPos.X>>8,p_person->WorldPos.Y>>8,p_person->WorldPos.Z>>8,2,0xff0000,1);
#endif
count++;
}
}
return(count);
}
extern SLONG dist_to_target(Thing *p_person_a,Thing *p_person_b);
UWORD get_any_gang_member(Thing *p_target)
{
SLONG gang;
SLONG c0,count=0,ret;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return(0);
for(c0=0;c0<4;c0++)
{
if(ret=gang_attacks[gang].Perp[c0])
{
if(dist_to_target(p_target,TO_THING(ret))<512)
{
// ASSERT(TO_THING(ret)->State!=STATE_DEAD);
// ASSERT(TO_THING(ret)->State!=STATE_DYING||(TO_THING(ret)->Genus.Person->Flags&FLAG_PERSON_KO));
return(ret);
}
}
}
return(0);
}
UWORD get_nearest_gang_member(Thing *p_target)
{
SLONG gang;
SLONG c0,count=0,ret;
SLONG bdist=99999999,best_targ=0,dist;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return(0);
for(c0=0;c0<4;c0++)
{
if(ret=gang_attacks[gang].Perp[c0])
{
if(!is_person_ko(TO_THING(ret)))
if((dist=dist_to_target(p_target,TO_THING(ret)))<bdist)
{
best_targ=ret;
bdist=dist;
}
}
}
return(best_targ);
}
UWORD find_target_from_gang(Thing *p_target)
{
SLONG gang;
SLONG c0,perp;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return(0);
if(perp=gang_attacks[gang].Perp[0])
return(perp);
if(perp=gang_attacks[gang].Perp[1])
return(perp);
if(perp=gang_attacks[gang].Perp[3])
return(perp);
if(perp=gang_attacks[gang].Perp[2])
return(perp);
return(0);
}
SLONG remove_from_gang_attack(Thing *p_person,Thing *p_target)
{
SLONG gang;
SLONG c0;
SLONG removed=0;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return(0);
for(c0=0;c0<4;c0++)
{
if(gang_attacks[gang].Perp[c0]==THING_NUMBER(p_person))
{
//
// I'm allready in his list
//
gang_attacks[gang].Perp[c0]=0; //remove myself
removed=1;
}
}
return(removed);
}
void scare_gang_attack(Thing *p_target)
{
SLONG gang;
SLONG c0;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return;
for(c0=0;c0<4;c0++)
{
if(gang_attacks[gang].Perp[c0])
{
//
// I'm allready in his list
//
TO_THING(gang_attacks[gang].Perp[c0])->Genus.Person->Agression=-55;
}
}
}
void reset_gang_attack(Thing *p_target)
{
UWORD perps[4];
Thing *p_person;
UWORD gang;
SLONG c0;
gang=p_target->Genus.Person->GangAttack;
if(gang==0)
return;
for(c0=0;c0<4;c0++)
{
perps[c0]=gang_attacks[gang].Perp[c0];
gang_attacks[gang].Perp[c0]=0;
}
for(c0=0;c0<4;c0++)
{
SLONG dx,dz,reqd_angle;
if(perps[c0])
{
p_person=TO_THING(perps[c0]);
dx = p_target->WorldPos.X - p_person->WorldPos.X >> 8;
dz = p_target->WorldPos.Z - p_person->WorldPos.Z >> 8;
//
// The angle between us and our target- where we want to push
// into the gang structure.
//
reqd_angle = calc_angle(dx,dz)+256;
reqd_angle &= 2047;
reqd_angle >>= 9;
push_into_attack_group_at_angle(p_person,(SLONG)gang,reqd_angle);
}
}
}
void process_gang_attack(Thing *p_person,Thing *p_target)
{
SLONG gang;
SLONG c0;
SLONG left,right,lleft,rright;
SLONG me;
SLONG attack_count=0;
me=THING_NUMBER(p_person);
gang=p_target->Genus.Person->GangAttack;
if(p_person->SubState==SUB_STATE_CIRCLING_CIRCLE)
{
//
// I am attacking, if there's more than me attacking then make me backoff
//
for(c0=0;c0<4;c0++)
{
SLONG perp;
perp=gang_attacks[gang].Perp[c0];
if(perp && perp!=me)
{
switch(TO_THING(perp)->SubState)
{
case SUB_STATE_CIRCLING_CIRCLE:
TO_THING(perp)->Genus.Person->Agression=-100;
attack_count++;
break;
}
}
}
/*
if(attack_count>=1)
{
p_person->Genus.Person->Agression=-60;
}
*/
}
return;
/*
for(c0=0;c0<4;c0++)
{
if(gang_attacks[gang].Perp[c0]==me)
{
left=gang_attacks[gang].Perp[(c0-1)&3];
right=gang_attacks[gang].Perp[(c0+1)&3];
if(left==0 && right==0)
return;
if(left==0&& right)
{
lleft=gang_attacks[gang].Perp[(c0-2)&3];
if(lleft==0)
{
gang_attacks[gang].Perp[c0]=0;
p_person->Genus.Person->AttackAngle=(c0-1)&3;
gang_attacks[gang].Perp[(c0-1)&3]=me;
//
// change pos so make me backoff
//
p_person->Genus.Person->Agression=-60-(c0<<2);
}
}
else
if(left&&right==0)
{
rright=gang_attacks[gang].Perp[(c0+2)&3];
if(rright==0)
{
gang_attacks[gang].Perp[c0]=0;
p_person->Genus.Person->AttackAngle=(c0+1)&3;
ASSERT(gang_attacks[gang].Perp[(c0+1)&3]==0);
gang_attacks[gang].Perp[(c0+1)&3]=me;
//
// change pos so make me backoff
//
p_person->Genus.Person->Agression=-60-(c0<<2);
}
}
return;
}
}
*/
}
void push_into_attack_group_at_angle(Thing *p_person,SLONG gang,SLONG reqd_angle)
{
SLONG c0=4;
Thing *p_copy;
MSG_add("try push in at %d [%d %d %d %d %d %d %d %d] \n",reqd_angle,gang_attacks[gang].Perp[0],gang_attacks[gang].Perp[1],gang_attacks[gang].Perp[2],gang_attacks[gang].Perp[3],gang_attacks[gang].Perp[4],gang_attacks[gang].Perp[5],gang_attacks[gang].Perp[6],gang_attacks[gang].Perp[7]);
if(gang_attacks[gang].Perp[(reqd_angle)&3]!=0)
for(c0=1;c0<=2;c0++)
{
ASSERT(gang_attacks[gang].Perp[(reqd_angle+c0)&3]!=THING_NUMBER(p_person));
ASSERT(gang_attacks[gang].Perp[(reqd_angle-c0)&3]!=THING_NUMBER(p_person));
if(gang_attacks[gang].Perp[(reqd_angle+c0)&3]==0)
{
//
// go pos
//
MSG_add(" push in at position %d shoving %d peeps ",reqd_angle,c0);
while(c0>0)
{
//
// shunt everyone arround the circle
//
gang_attacks[gang].Perp[(reqd_angle+c0)&3]=gang_attacks[gang].Perp[(reqd_angle+c0-1)&3];
p_copy=TO_THING(gang_attacks[gang].Perp[(reqd_angle+c0-1)&3]);
p_copy->Genus.Person->AttackAngle=(reqd_angle+c0)&3;
c0--;
}
break;
}
else
if(gang_attacks[gang].Perp[(reqd_angle-c0+8)&3]==0)
{
//
// go neg
//
MSG_add(" push in at position %d shoving NEG %d peeps ",reqd_angle,c0);
while(c0>0)
{
//
// shunt everyone arround the circle
//
gang_attacks[gang].Perp[(reqd_angle-c0+8)&3]=gang_attacks[gang].Perp[(reqd_angle-c0+1+8)&3];
p_copy=TO_THING(gang_attacks[gang].Perp[(reqd_angle-c0+1+8)&3]);
p_copy->Genus.Person->AttackAngle=(reqd_angle-c0+8)&3;
c0--;
}
// gang_attacks[gang].Perp[(reqd_angle+c0)&3]=THING_NUMBER(p_person);
break;
}
if(c0==4)
MSG_add("FAILED to push in\n");
}
//
// everywhere is full so use the angle you want with someone else there as well
// or everyone has been pushed round to make room for you.
gang_attacks[gang].Perp[reqd_angle&3]=THING_NUMBER(p_person);
p_person->Genus.Person->AttackAngle=reqd_angle;
}
void PCOM_new_gang_attack(Thing *p_person, Thing *p_target)
{
SLONG gang;
SLONG c0;
SLONG reqd_angle;
SLONG dx;
SLONG dz;
SLONG angle;
dx = p_target->WorldPos.X - p_person->WorldPos.X >> 8;
dz = p_target->WorldPos.Z - p_person->WorldPos.Z >> 8;
//
// The angle between us and our target- where we want to push
// into the gang structure.
//
reqd_angle = calc_angle(dx,dz);
reqd_angle &= 2047;
reqd_angle >>= 9;
//
// Mike's new addition to the circeling system based on alloting angles
// to bad guys. Each target holds a structure for where each attacker should be.
//
if (p_target->Genus.Person->GangAttack == 0)
{
//
// Create the gang structure for this target if she hasn't got one already.
//
gang = get_gangattack(p_target);
}
else
{
gang = p_target->Genus.Person->GangAttack;
}
//
// Make sure we are not already in targets person gang attack structure.
//
for (c0 = 0; c0 < 4; c0++)
{
if (gang_attacks[gang].Perp[c0] == THING_NUMBER(p_person))
{
//
// I'm allready in her list.
//
gang_attacks[gang].Perp[c0] = 0; //remove myself
}
}
//
// Now slot yourself into the gang structure.
//
if (gang_attacks[gang].Perp[reqd_angle] == 0)
{
//
// my best angle is available hoorah
//
gang_attacks[gang].Perp[reqd_angle] = THING_NUMBER(p_person);
p_person->Genus.Person->AttackAngle = reqd_angle;
}
else
{
//
// no room so push in
//
push_into_attack_group_at_angle(
p_person,
gang,
reqd_angle);
}
}
//
// Makes the person circle around a target.
//
void PCOM_set_person_move_circle(Thing *p_person, Thing *p_target)
{
set_person_circle(p_person, p_target);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_CIRCLE;
p_person->Genus.Person->pcom_move_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_move_counter = 0;
PCOM_new_gang_attack(p_person, p_target);
}
//
// Makes a person get in a car.
//
void PCOM_set_person_move_getincar(Thing *p_person, Thing *p_vehicle, SLONG am_i_a_passenger, SLONG door)
{
ASSERT(door == 0 || door == 1);
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
if (am_i_a_passenger)
{
set_person_passenger_in_vehicle(p_person, p_vehicle, door);
}
else
{
set_person_enter_vehicle(p_person, p_vehicle, door);
}
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GETINCAR;
p_person->Genus.Person->pcom_move_arg = THING_NUMBER(p_vehicle);
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Makes a person leave the car he is in.
//
void PCOM_set_person_move_leavecar(Thing *p_person)
{
ASSERT(p_person->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER));
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
set_person_exit_vehicle(p_person);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_LEAVECAR;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Go back to do what you normally do.
//
extern void PCOM_set_person_ai_navtokill(Thing *p_person, Thing *p_target);
void PCOM_set_person_ai_normal(Thing *p_person)
{
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
}
//
// If a person gets knocked out (by some external event like a car or shockwave)
// then call this function. It put a person in a state where they wait until
// recovered and then go back to doing their normal thing.
//
void PCOM_set_person_ai_knocked_out(Thing *p_person)
{
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_KNOCKEDOUT;
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ANIM;
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Make a cop try to arrest some naughty people.
//
void PCOM_set_person_ai_arrest(Thing *p_person, Thing *p_target)
{
if(p_target->Genus.Person->PersonType==PERSON_DARCI)
ASSERT(0);
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_ARREST;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Look at who you are arresting.
//
set_face_thing(
p_person,
p_target);
// MFX_play_thing(THING_NUMBER(p_person),S_HELLOALLOALLO,MFX_REPLACE,p_person);
MFX_play_thing(THING_NUMBER(p_person),SOUND_Range(S_COP_ARREST_START,S_COP_ARREST_END),MFX_REPLACE,p_person);
PCOM_set_person_move_mav_to_thing(p_person, p_target, PCOM_MOVE_SPEED_RUN);
}
void PCOM_set_person_ai_kill_person(Thing *p_person, Thing *p_target, SLONG alert_gang)
{
if(p_person->Genus.Person->PersonType==PERSON_CIV)
{
ASSERT(0);
}
if(p_target->Genus.Person->PersonType==PERSON_DARCI)
{
if(p_person->Genus.Person->PersonType==PERSON_COP)
ASSERT(0);
}
if ((p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
return;
if(am_i_a_thug(p_person))
{
//
// only arrest thugs?
//
if(!am_i_a_thug(p_target)) //thug kills innocent
PCOM_call_cop_to_arrest_me(p_person,1);
}
/*
//
// We are too busy with someone else
//
if(p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING)
return;
if(p_person->Genus.Person->State == STATE_CIRCLING)
return;
*/
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
//
// Face the target.
//
set_face_thing(p_person, p_target);
if (p_target->Genus.Person->PlayerID)
{
//
// Wants to hit the player
//
track_enemy(p_person);
}
//
// Circle around our target.
//
PCOM_set_person_move_circle(p_person, p_target);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_KILLING;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
//
// Tell our target she is under attack.
//
if (alert_gang)
{
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_GANG)
{
//
// Alert other people in our gang. Let them know to
// help me now I am in a fight.
//
PCOM_alert_my_gang_to_a_fight(p_person, p_target);
}
}
//
// Tell the low-level person system that this person has a target...
//
p_person->Genus.Person->Target = THING_NUMBER(p_target);
}
void PCOM_set_person_ai_homesick(Thing *p_person)
{
SLONG home_x = (p_person->Genus.Person->HomeX << 0);// + 0x80;
SLONG home_z = (p_person->Genus.Person->HomeZ << 0);// + 0x80;
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
p_person->Genus.Person->Target = NULL;
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_HOMESICK;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
PCOM_set_person_move_mav_to_xz(
p_person,
home_x,
home_z,
PCOM_MOVE_SPEED_WALK);
}
void PCOM_set_person_ai_leavecar(Thing *p_person, SLONG excar_state, SLONG excar_substate, SLONG excar_arg)
{
Thing *p_vehicle;
ASSERT(p_person->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER));
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
//
// This is what we are doing now...
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_LEAVECAR;
p_person->Genus.Person->pcom_ai_arg = 0;
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// And this is what we'll do once we've got out of the car.
//
p_person->Genus.Person->pcom_ai_excar_state = excar_state;
p_person->Genus.Person->pcom_ai_excar_substate = excar_substate;
p_person->Genus.Person->pcom_ai_excar_arg = excar_arg;
if (p_vehicle->Velocity && (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING))
{
//
// Park the car.
//
PCOM_set_person_move_park_car_on_road(p_person);
}
else
{
//
// Get out of the car.
//
PCOM_set_person_move_leavecar(p_person);
}
}
//
// Makes the person go off and investiage an odd event.
//
void PCOM_set_person_ai_investigate(
Thing *p_person,
SLONG odd_x,
SLONG odd_z)
{
if ((p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
return;
//
// Remember what we are doing.
//
// FC_cam[1].focus=p_person;
// ASSERT(0);
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
odd_x >>= 8;
odd_z >>= 8;
p_person->Genus.Person->pcom_ai_arg = (odd_x << 8) | (odd_z);
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_INVESTIGATING;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_SUPRISED;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Turn to face the unusual sound.
//
set_face_pos(
p_person,
(odd_x << 8) + 0x80,
(odd_z << 8) + 0x80);
//
// Start off starting blankly at the sound.
//
PCOM_set_person_move_still(p_person);
}
//
// Makes the person try to run away.
//
void PCOM_set_person_ai_flee_place(
Thing *p_person,
SLONG scary_x, // The place where the scary thing is.
SLONG scary_z)
{
if ((p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
return;
//
// Make this person scream in terror!
//
/*
play_quick_wave(
p_person,
S_ARGH,
WAVE_PLAY_INTERUPT);
*/
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PLACE &&
p_person->Genus.Person->pcom_ai_substate == PCOM_AI_SUBSTATE_LEGIT)
{
//
// Just update where we are running from.
//
scary_x >>= 8;
scary_z >>= 8;
p_person->Genus.Person->pcom_ai_arg = (scary_x << 8) | (scary_z);
return;
}
//
// Remember what we are doing.
//
scary_x >>= 8;
scary_z >>= 8;
p_person->Genus.Person->pcom_ai_arg = (scary_x << 8) | (scary_z);
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_FLEE_PLACE;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_SUPRISED;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Turn to face the unusual thing.
//
set_face_pos(
p_person,
(scary_x << 8) + 0x80,
(scary_z << 8) + 0x80);
if (p_person->State == STATE_HIT_RECOIL)
{
//
// Have to wait to finish recoiling...
//
}
else
{
//
// Start off starting blankly at the sound.
//
PCOM_set_person_move_still(p_person);
}
}
void PCOM_set_person_ai_flee_person(Thing *p_person,Thing *p_scary)
{
if (p_person->Genus.Person->pcom_ai != PCOM_AI_FLEE_PLAYER)
{
if(am_i_a_thug(p_person)&&((p_person->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)))
{
return;
}
}
if (p_person->Genus.Person->pcom_ai == PCOM_AI_CIV)
{
//
// Civs remember who scared them.
//
p_person->Genus.Person->pcom_ai_memory = THING_NUMBER(p_scary);
if (p_person->Genus.Person->pcom_ai_state != PCOM_AI_STATE_FLEE_PERSON)
{
//
// Make this person scream in terror!
//
// MFX_play_thing(THING_NUMBER(p_person),S_ARGH,MFX_REPLACE,p_person);
}
}
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
//
// If this person is in a car, then they must get out first.
//
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_ai_leavecar(p_person, PCOM_EXCAR_FLEE_PERSON, 0, THING_NUMBER(p_scary));
return;
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PERSON &&
p_person->Genus.Person->pcom_ai_substate == PCOM_AI_SUBSTATE_LEGIT)
{
//
// Just update who we are running from.
//
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_scary);
return;
}
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_scary);
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_FLEE_PERSON;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_SUPRISED;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Turn to face the scary person.
//
set_face_pos(
p_person,
p_scary->WorldPos.X >> 8,
p_scary->WorldPos.Z >> 8);
if (p_person->State == STATE_HIT_RECOIL)
{
//
// Have to wait to finish recoiling...
//
}
else
{
//
// Start off starting blankly at the dangerous person.
//
PCOM_set_person_move_still(p_person);
}
}
void PCOM_set_person_ai_aimless(Thing *p_person)
{
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_AIMLESS;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
}
//
// Goes into NAVTOKILL mode but starts off trying to shoot the target.
//
void PCOM_set_person_ai_navtokill_shoot(Thing *p_person, Thing *p_target)
{
if(p_target->Genus.Person->PersonType==PERSON_DARCI)
{
if(p_person->Genus.Person->PersonType==PERSON_COP)
ASSERT(0);
}
if(p_person->Genus.Person->PersonType==PERSON_CIV)
{
ASSERT(0);
}
PCOM_set_person_move_still(p_person);
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NAVTOKILL;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_AIMING;
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->Target = THING_NUMBER(p_target);
}
SLONG PCOM_target_sprinting_towards_me(Thing *p_person, Thing *p_target)
{
SLONG dangle = get_dangle(p_target, p_person);
if (p_target->Genus.Person->Mode == PERSON_MODE_SPRINT)
{
#define PCOM_SPRINTATME_DANGLE 512
if (dangle < PCOM_SPRINTATME_DANGLE ||
dangle > 2048 - PCOM_SPRINTATME_DANGLE)
{
return TRUE;
}
}
return FALSE;
}
void PCOM_set_person_ai_navtokill(Thing *p_person, Thing *p_target)
{
if(p_target->Genus.Person->PersonType==PERSON_DARCI)
{
if(p_person->Genus.Person->PersonType==PERSON_COP)
ASSERT(0);
}
if(p_person->Genus.Person->PersonType==PERSON_CIV)
{
// ASSERT(0);
}
if ((p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
return;
if(am_i_a_thug(p_person))
{
//
// only arrest thugs?
//
if(!am_i_a_thug(p_target)) //thug kills innocent
PCOM_call_cop_to_arrest_me(p_person,1);
}
PCOM_set_person_move_mav_to_thing(p_person, p_target, PCOM_MOVE_SPEED_RUN);
if (PCOM_target_could_shoot_me(p_person, p_target) )
{
//
// What shall we do... run away, shoot back, or try and beat him up anyway?
//
if (PCOM_person_has_any_sort_of_gun(p_person) ||(am_i_a_thug(p_person)&&(p_person->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)))
{
PCOM_set_person_ai_navtokill_shoot(p_person, p_target);
return;
}
else
{
//
// Gun vs no gun...
//
// if(!am_i_a_thug(p_person)||(!(p_gang->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)))
if ((Random() & 0x4) && !(p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER) && (p_person->Genus.Person->PersonType!=PERSON_COP))
{
PCOM_set_person_ai_flee_person(p_person, p_target);
return;
}
}
}
else
if (PCOM_target_sprinting_towards_me(p_person, p_target))
{
if (PCOM_person_has_any_sort_of_gun(p_person))
{
PCOM_set_person_ai_navtokill_shoot(p_person, p_target);
return;
}
}
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED)
{
//
// If you are restricted movement and you can't get to your
// target for certain then give up and go back to your normal
// routine.
//
if (!MAV_do_found_dest)
{
PCOM_set_person_ai_normal(p_person);
return;
}
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NAVTOKILL;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->Target = THING_NUMBER(p_target);
}
void PCOM_set_person_ai_follow(Thing *p_person, Thing *p_target)
{
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
PCOM_set_person_move_mav_to_thing(p_person, p_target, PERSON_SPEED_RUN);
if (p_target->Genus.Person->PlayerID && p_person->Genus.Person->pcom_move == PCOM_MOVE_FOLLOW)
{
//
// If a following person is going to have great difficulty finding
// the player- then make the person start wandering around.
//
if (p_person->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD ||
p_person->Genus.Person->pcom_ai == PCOM_AI_CIV)
{
SLONG dx = p_person->WorldPos.X - p_target->WorldPos.X >> 8;
SLONG dy = p_person->WorldPos.Y - p_target->WorldPos.Y >> 8;
SLONG dz = p_person->WorldPos.Z - p_target->WorldPos.Z >> 8;
SLONG dist = abs(dx) + abs(dz) + abs(dy + dy);
if (dist > 0x600)
{
if (!MAV_do_found_dest)
{
//
// Dont try to follow the player if it's going to be
// too difficult!
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_CANTFIND;
return;
}
}
}
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_FOLLOWING;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_counter = 0;
}
void PCOM_set_person_ai_findcar(Thing *p_person, UWORD car)
{
SLONG speed;
Thing *p_car;
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
if (car == NULL)
{
SLONG i;
SLONG dx;
SLONG dz;
SLONG num;
SLONG dist;
SLONG best_dist = INFINITY;
//
// Look for a nearby car we can use.
//
num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0xc00,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_VEHICLE);
for (i = 0; i < num; i++)
{
p_car = TO_THING(THING_array[i]);
ASSERT(p_car->Class == CLASS_VEHICLE);
if (p_car->Genus.Vehicle->Driver)
{
//
// Car already driven by someone.
//
}
else
if (p_car->State == STATE_DEAD)
{
//
// Car is damaged.
//
}
else
if (p_car->Genus.Vehicle->key != SPECIAL_NONE && !person_has_special(p_person, p_car->Genus.Vehicle->key))
{
//
// This car is locked and we don't have the key.
//
}
else
{
dx = abs(p_car->WorldPos.X - p_person->WorldPos.X);
dz = abs(p_car->WorldPos.Z - p_person->WorldPos.Z);
dist = dx + dz;
if (dist < best_dist)
{
best_dist = dist;
car = THING_array[i];
}
}
}
}
if (car == NULL)
{
//
// Couldn't find a car- start wandering around aimlessly.
//
PCOM_set_person_ai_aimless(p_person);
}
else
{
//
// Start navigating to the car door.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_FINDCAR;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GOTOCAR;
p_person->Genus.Person->pcom_ai_arg = car;
p_person->Genus.Person->pcom_ai_counter = 0;
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
speed = PERSON_SPEED_WALK;
}
else
{
speed = PERSON_SPEED_RUN;
}
PCOM_set_person_move_mav_to_thing(
p_person,
TO_THING(car),
speed);
}
}
#ifdef BIKE
void PCOM_set_person_ai_findbike(Thing *p_person)
{
SLONG bike;
SLONG speed;
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
//
// Look for a nearby bike.
//
bike = THING_find_nearest(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0xc00,
1 << CLASS_BIKE);
if (bike == NULL || TO_THING(bike)->Genus.Bike->mode != BIKE_MODE_PARKED)
{
//
// Couldn't find a car- start wandering around aimlessly.
//
PCOM_set_person_ai_aimless(p_person);
}
else
{
Thing *p_bike = TO_THING(bike);
//
// If someone is driving the bike. Kill them so you can get onto it!
//
if (p_bike->Genus.Bike->driver)
{
ASSERT(TO_THING(p_bike->Genus.Bike->driver)->Class == CLASS_PERSON);
//
// This flag tell PCOM_process_killing() that this biker is killing
// someone to nick his bike- rather than just to kill him.
//
p_person->Genus.Person->Flags |= FLAG_PERSON_KILL_WITH_A_PURPOSE;
PCOM_set_person_ai_kill_person(p_person, TO_THING(p_bike->Genus.Bike->driver));
}
else
{
//
// Start navigating to the bike.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_FINDBIKE;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GOTOBIKE;
p_person->Genus.Person->pcom_ai_arg = bike;
p_person->Genus.Person->pcom_ai_counter = 0;
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
speed = PERSON_SPEED_WALK;
}
else
{
speed = PERSON_SPEED_RUN;
}
PCOM_set_person_move_mav_to_thing(
p_person,
TO_THING(bike),
speed);
}
}
}
#endif
void PCOM_set_person_ai_bdeactivate(Thing *p_person, Thing *p_bomb)
{
SLONG speed;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_BDEACTIVATE;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_bomb);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GOTOBOMB;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Start navigating to the bomb.
//
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
speed = PERSON_SPEED_WALK;
}
else
{
speed = PERSON_SPEED_RUN;
}
PCOM_set_person_move_mav_to_thing(
p_person,
p_bomb,
speed);
}
void PCOM_set_person_ai_snipe(Thing *p_person, Thing *p_target)
{
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
#ifndef NDEBUG
//
// All snipers must have a gun!
//
if (!PCOM_person_has_any_sort_of_gun(p_person))
{
#ifndef NDEBUG
CONSOLE_text("Sniper doesn't have a gun. I'll give him one anyway.");
#endif
p_person->Flags |= FLAGS_HAS_GUN;
}
#endif
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_SNIPE;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LOOK;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_counter = 0;
// PCOM_set_person_move_still(p_person);
PCOM_set_person_move_draw_gun(p_person);
}
void PCOM_set_person_ai_warm_hands(Thing *p_person)
{
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_WARM_HANDS;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GOTOFIRE;
p_person->Genus.Person->pcom_ai_arg = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_pause(p_person);
}
void PCOM_set_person_ai_hands_up(Thing *p_person, Thing *p_cop)
{
UWORD anim;
//
// Face the person you are being aimed at by
//
set_face_thing(p_person, p_cop);
//
// Which anim shall we do?
//
PCOM_set_person_move_animation(p_person, ANIM_HANDS_UP);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_HANDS_UP;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_cop);
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->Flags |= FLAG_PERSON_NO_RETURN_TO_NORMAL;
}
void PCOM_set_person_ai_talk_to(Thing *p_person, Thing *p_person_talked_at, UBYTE talk_substate, UBYTE stay_looking_at_eachother)
{
UWORD anim;
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
//
// Face the person you are talking to.
//
set_face_thing(p_person, p_person_talked_at);
//
// Which anim shall we do?
//
switch(talk_substate)
{
case PCOM_AI_SUBSTATE_TALK_ASK: anim = ANIM_TALK_ASK; break;
case PCOM_AI_SUBSTATE_TALK_TELL: anim = ANIM_TALK_TELL; break;
case PCOM_AI_SUBSTATE_TALK_LISTEN: anim = ANIM_TALK_LISTEN; break;
default:
ASSERT(0);
break;
}
if(person_holding_2handed(p_person)&& p_person->Genus.Person->PersonType!=PERSON_ROPER)
anim=ANIM_SHOTGUN_IDLE;
PCOM_set_person_move_animation(p_person, anim);
//
// Remember what we are doing.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_TALK;
p_person->Genus.Person->pcom_ai_substate = talk_substate;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_person_talked_at);
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->Flags &= ~FLAG_PERSON_NO_RETURN_TO_NORMAL;
if (stay_looking_at_eachother)
{
p_person->Genus.Person->Flags |= FLAG_PERSON_NO_RETURN_TO_NORMAL;
}
}
void PCOM_set_person_ai_hitch(Thing *p_person, Thing *p_vehicle)
{
SLONG speed;
if (p_person->Genus.Person->Target)
{
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
//
// Start navigating to the car door.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_HITCH;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GOTOCAR;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_vehicle);
p_person->Genus.Person->pcom_ai_counter = 0;
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
speed = PERSON_SPEED_WALK;
}
else
{
speed = PERSON_SPEED_RUN;
}
PCOM_set_person_move_mav_to_thing(
p_person,
p_vehicle,
speed);
}
//
// Makes a person start taunting someone.
//
void PCOM_set_person_ai_taunt(Thing *p_person, Thing *p_target)
{
if ((p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
return;
//
// cops shouldnt taunt, I've seen them do it with my own eyes MIKED
//
if(p_person->Genus.Person->PersonType==PERSON_COP)
return;
if(p_person->SubState==SUB_STATE_GRAPPLEE || p_person->SubState == SUB_STATE_GRAPPLE_HELD)
{
//
// No taunt if your being grappled
//
return;
}
//
// People can taunt in the middle of a fight!
//
if (p_person->Genus.Person->Target)
{
//
// I disagree you should concentrate on the job MikeD.
//
//return;
remove_from_gang_attack(p_person,TO_THING(p_person->Genus.Person->Target));
}
if (PCOM_target_could_shoot_me(p_person, p_target))
{
//
// What shall we do... run away, shoot back, or try and beat him up anyway?
//
if (PCOM_person_has_any_sort_of_gun(p_person)||(Random()&3)==0)
{
PCOM_set_person_ai_navtokill_shoot(p_person, p_target);
return;
}
else
{
//
// Gun vs no gun...
//
if (Random() & 0x4)
{
PCOM_set_person_ai_flee_person(p_person, p_target);
return;
}
}
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_TAUNT;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_target);
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Look at who you are taunting.
//
set_face_thing(
p_person,
p_target);
// MFX_play_thing(THING_NUMBER(p_person),S_WANKER,MFX_REPLACE,p_person);
PCOM_set_person_move_animation(p_person, ANIM_WANKER);
}
//
// The people the summoner is going to use!
//
#ifdef PSX
#define PCOM_SUMMON_NUM_BODIES 2
#else
#define PCOM_SUMMON_NUM_BODIES 4
#endif
UWORD PCOM_summon[PCOM_SUMMON_NUM_BODIES];
void PCOM_set_person_ai_summon(Thing *p_person)
{
SLONG i;
SLONG num;
SLONG bodies;
//
// Look around for the bodies...
//
num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x800,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_PERSON);
//
// Clear out the body array.
//
memset(PCOM_summon, 0, sizeof(PCOM_summon));
bodies = 0;
for (i = 0; i < num; i++)
{
Thing *p_found = TO_THING(THING_array[i]);
ASSERT(p_found->Class == CLASS_PERSON);
if (p_found->Genus.Person->pcom_ai == PCOM_AI_NONE ||
p_found->Genus.Person->pcom_ai == PCOM_AI_SUICIDE)
{
if (p_found->Genus.Person->PlayerID == 0)
{
//
// This person will do!
//
ASSERT(WITHIN(bodies, 0, PCOM_SUMMON_NUM_BODIES - 1));
PCOM_summon[bodies] = THING_array[i];
bodies += 1;
if (bodies == PCOM_SUMMON_NUM_BODIES)
{
//
// Found all our bodies!
//
break;
}
}
}
}
//
// Start floating!
//
set_person_float_up(p_person);
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_SUMMON;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_SUMMON_START;
}
//
// Returns an item this person should pick up or NULL if this
// person is not near enough an item or already has one.
//
extern BOOL PersonIsMIB(Thing* p_person);
/*
BOOL PersonIsMIB(Thing* p_person)
{
return (p_person->Genus.Person->PersonType == PERSON_MIB1 ||
p_person->Genus.Person->PersonType == PERSON_MIB2 ||
p_person->Genus.Person->PersonType == PERSON_MIB3);
};
*/
BOOL PersonIsMIB(Thing* p_person);
Thing *PCOM_is_there_an_item_i_should_get(Thing *p_person)
{
UWORD ans;
if (PersonIsMIB(p_person))
{
//
// MIBs have an ak47 for an arm.
//
return NULL;
}
if (p_person->Genus.Person->SpecialList || (p_person->Flags & FLAGS_HAS_GUN))
{
//
// This person has a special or a gun, so he doesn't
// need to pick up anything... even health!
//
return NULL;
}
if (p_person->Genus.Person->Ware)
{
//
// People in warehouses don't pickup specials...
//
return NULL;
}
ans = THING_find_nearest(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x300,
1 << CLASS_SPECIAL);
if (ans)
{
Thing *p_special = TO_THING(ans);
switch(p_special->Genus.Special->SpecialType)
{
case SPECIAL_GUN:
case SPECIAL_SHOTGUN:
case SPECIAL_AK47:
case SPECIAL_BASEBALLBAT:
case SPECIAL_KNIFE:
//
// These are the special types we can pickup.
//
break;
default:
return NULL;
}
//
// Only pick up the special if the person can navigate to it ok.
//
if (!there_is_a_los_mav(
p_person ->WorldPos.X >> 8,
p_person ->WorldPos.Y + 0x4000 >> 8,
p_person ->WorldPos.Z >> 8,
p_special->WorldPos.X >> 8,
p_special->WorldPos.Y + 0x4000 >> 8,
p_special->WorldPos.Z >> 8))
{
return p_special;
}
}
return NULL;
}
void PCOM_set_person_ai_getitem(Thing *p_person, Thing *p_special, SLONG move_speed, SLONG excar_state, SLONG excar_arg)
{
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_GETITEM;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = THING_NUMBER(p_special);
p_person->Genus.Person->pcom_ai_excar_state = excar_state;
p_person->Genus.Person->pcom_ai_excar_substate = NULL;
p_person->Genus.Person->pcom_ai_excar_arg = excar_arg;
PCOM_set_person_move_mav_to_xz(
p_person,
p_special->WorldPos.X >> 8,
p_special->WorldPos.Z >> 8,
move_speed);
}
void PCOM_process_getitem(Thing *p_person)
{
Thing *p_special = TO_THING(p_person->Genus.Person->pcom_ai_arg);
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_ANIMATION:
break;
case PCOM_MOVE_STATE_GOTO_XZ:
//
// Near enough to the special yet?
//
if ((PTIME(p_person) & 0x3)==0)
{
if (PCOM_finished_nav(p_person))
{
//
// Bend down to pick up the special.
//
if (p_special->Flags & FLAGS_ON_MAPWHO)
{
PCOM_set_person_move_pickup_special(p_person, p_special);
}
else
{
//
// Someone must have got the special!
//
PCOM_set_person_move_pause(p_person);
}
}
}
break;
case PCOM_MOVE_STATE_PAUSE:
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(10))
{
//
// Fall through!
//
}
else
{
break;
}
case PCOM_MOVE_STATE_STILL:
//
// Go back to doing what
//
switch(p_person->Genus.Person->pcom_ai_excar_state)
{
case PCOM_EXCAR_NORMAL:
PCOM_set_person_ai_normal(p_person);
break;
case PCOM_EXCAR_NAVTOKILL:
PCOM_set_person_ai_navtokill(p_person, TO_THING(p_person->Genus.Person->pcom_ai_excar_arg));
break;
default:
ASSERT(0);
break;
}
break;
default:
//
// Emergency! I don't know what I'm doing!
//
ASSERT(0);
PCOM_set_person_ai_normal(p_person);
break;
}
}
void PCOM_process_summon(Thing *p_person)
{
SLONG i;
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_SUMMON_START:
if (p_person->SubState == SUB_STATE_FLOAT_BOB)
{
//
// Make everyone else start floating!
//
for (i = 0; i < PCOM_SUMMON_NUM_BODIES; i++)
{
if (PCOM_summon[i])
{
Thing *p_summon = TO_THING(PCOM_summon[i]);
set_person_float_up(p_summon);
SPARK_Pinfo p1;
SPARK_Pinfo p2;
static UBYTE limb[4] =
{
SUB_OBJECT_LEFT_HAND,
SUB_OBJECT_RIGHT_HAND,
SUB_OBJECT_LEFT_FOOT,
SUB_OBJECT_RIGHT_FOOT,
};
p1.type = SPARK_TYPE_LIMB;
p1.flag = 0;
p1.person = THING_NUMBER(p_person);
p1.limb = limb[i];
p2.type = SPARK_TYPE_LIMB;
p2.flag = 0;
p2.person = THING_NUMBER(p_summon);
p2.limb = SUB_OBJECT_PELVIS;
SPARK_create(
&p1,
&p2,
255);
}
}
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_SUMMON_FLOAT;
p_person->Genus.Person->pcom_ai_counter = 0;
}
break;
case PCOM_AI_SUBSTATE_SUMMON_FLOAT:
if (p_person->Genus.Person->pcom_ai_counter > PCOM_get_duration(50))
{
for (i = 0; i < PCOM_SUMMON_NUM_BODIES; i++)
{
if (PCOM_summon[i])
{
Thing *p_summon = TO_THING(PCOM_summon[i]);
SPARK_Pinfo p1;
SPARK_Pinfo p2;
static UBYTE limb[4] =
{
SUB_OBJECT_LEFT_HAND,
SUB_OBJECT_RIGHT_HAND,
SUB_OBJECT_LEFT_FOOT,
SUB_OBJECT_RIGHT_FOOT,
};
p1.type = SPARK_TYPE_LIMB;
p1.flag = 0;
p1.person = THING_NUMBER(p_person);
p1.limb = limb[i];
p2.type = SPARK_TYPE_LIMB;
p2.flag = 0;
p2.person = THING_NUMBER(p_summon);
p2.limb = SUB_OBJECT_PELVIS;
SPARK_create(
&p1,
&p2,
255);
}
}
p_person->Genus.Person->pcom_ai_counter = 0;
}
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
//
// We use the move counter for how long the player has been in the same
// place near us for!
//
{
Thing *darci = NET_PERSON(0);
SLONG dx;
SLONG dz;
dx = abs(darci->WorldPos.X - p_person->WorldPos.X);
dz = abs(darci->WorldPos.Z - p_person->WorldPos.Z);
if (QDIST2(dx,dz) < 0x60000)
{
if ((darci->WorldPos.X >> 16) != (p_person->Genus.Person->pcom_ai_arg >> 8))
{
p_person->Genus.Person->pcom_move_counter >>= 1;
}
if ((darci->WorldPos.Z >> 16) != (p_person->Genus.Person->pcom_ai_arg & 0xff))
{
p_person->Genus.Person->pcom_move_counter >>= 1;
}
p_person->Genus.Person->pcom_ai_arg = darci->WorldPos.Z >> 16;
p_person->Genus.Person->pcom_ai_arg |= (darci->WorldPos.X >> 16) & 0xff;
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
else
{
p_person->Genus.Person->pcom_move_counter = 0;
}
if (p_person->Genus.Person->pcom_move_counter >= PCOM_get_duration(20))
{
//
// Electrocute Darci!
//
if (darci->State == STATE_IDLE ||
darci->State == STATE_MOVEING ||
darci->State == STATE_GUN)
{
//
// Electrocute her!
//
set_person_recoil(darci, ANIM_HIT_FRONT_MID, 0);
darci->Genus.Person->Health -= 25;
SPARK_Pinfo p1;
SPARK_Pinfo p2;
p1.type = SPARK_TYPE_LIMB;
p1.flag = 0;
p1.person = THING_NUMBER(p_person);
p1.limb = SUB_OBJECT_PELVIS;
p2.type = SPARK_TYPE_LIMB;
p2.flag = 0;
p2.person = THING_NUMBER(darci);
p2.limb = SUB_OBJECT_PELVIS;
SPARK_create(
&p1,
&p2,
50);
p_person->Genus.Person->pcom_move_counter = 0;
}
}
}
break;
default:
ASSERT(0);
break;
}
}
THING_INDEX PCOM_create_person(
SLONG type,
SLONG colour,
SLONG group,
SLONG ai,
SLONG ai_other,
SLONG ai_skill,
SLONG move,
SLONG move_follow,
SLONG bent,
SLONG pcom_has,
SLONG drop,
SLONG pcom_zone,
SLONG world_x,
SLONG world_y,
SLONG world_z,
SLONG yaw,
SLONG random,
ULONG flag1,
ULONG flag2)
{
if (pcom_has & (PCOM_HAS_SHOTGUN | PCOM_HAS_KNIFE | PCOM_HAS_BASEBALLBAT))
{
// type = PERSON_DARCI; //EWAY_SUBTYPE_PLAYER_DARCI;//PERSON_DARCI;
}
if (pcom_has & PCOM_HAS_GUN)
{
if (drop == SPECIAL_GUN)
{
drop = 0;
}
}
if (ai == PCOM_AI_ASSASIN)
{
TRACE("hello");
}
if (ai == PCOM_AI_ASSASIN && move == PCOM_MOVE_WANDER)
{
//
// Make wandering assasins, follow who they are assasinating.
//
move = PCOM_MOVE_FOLLOW;
move_follow = ai_other;
}
// ASSERT(type!=PERSON_CIV);
THING_INDEX p_index = create_person(
type,
random,
world_x,
world_y,
world_z);
if (p_index == NULL)
{
#ifndef PSX
#ifndef NDEBUG
PANEL_new_text(NULL, 10000, "Couldn't create person, PersonType %d ai %s", type, PCOM_ai_name[ai]);
#endif
#endif
}
else
{
Thing *p_person = TO_THING(p_index);
if(type==PERSON_COP)
{
if(ai==PCOM_AI_DRIVER)
ai=PCOM_AI_COP_DRIVER;
}
p_person->Draw.Tweened->Angle = yaw;
p_person->Genus.Person->HomeYaw = yaw >> 3;
p_person->Genus.Person->pcom_colour = colour;
p_person->Genus.Person->pcom_group = group;
p_person->Genus.Person->pcom_ai = ai;
p_person->Genus.Person->pcom_move = move;
p_person->Genus.Person->pcom_bent = bent;
p_person->Genus.Person->drop = drop;
p_person->Genus.Person->pcom_zone = pcom_zone & 0xf;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = NULL;
p_person->Genus.Person->pcom_ai_other = ai_other;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->pcom_move_follow = move_follow;
p_person->Genus.Person->FightRating = 0;
p_person->Genus.Person->Flags|=flag1;
p_person->Genus.Person->Flags2|=flag2;
//
// Change guard in zone to violent youth in zone without telling Simon.
//
if (p_person->Genus.Person->pcom_zone &&
p_person->Genus.Person->pcom_ai == PCOM_AI_GUARD)
{
p_person->Genus.Person->pcom_ai = PCOM_AI_GANG;
}
SET_SKILL(p_person,ai_skill);
if (pcom_has & (PCOM_HAS_SHOTGUN | PCOM_HAS_GUN))
{
// p_person->Genus.Person->pcom_bent |=PCOM_BENT_KILL_ON_SIGHT;
}
if (pcom_has & PCOM_HAS_GUN) {p_person->Flags |= FLAGS_HAS_GUN;}
#if NO_MORE_HAPPY_BALOONS
#if !defined(PSX) && !defined(TARGET_DC)
if (pcom_has & PCOM_HAS_BALLOON) {p_person->Genus.Person->Balloon = BALLOON_create(p_index, BALLOON_TYPE_YELLOW);}
#endif
#endif
if (pcom_has & PCOM_HAS_SHOTGUN)
{
//
// Create a shotgun and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_SHOTGUN,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_SHOTGUN);
}
}
}
if (pcom_has & PCOM_HAS_AK47)
{
//
// Create a shotgun and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_AK47,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_AK47);
}
}
}
if (pcom_has & PCOM_HAS_KNIFE)
{
//
// Create a shotgun and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_KNIFE,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_KNIFE);
}
}
}
if (pcom_has & PCOM_HAS_BASEBALLBAT)
{
//
// Create a baseball bat and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_BASEBALLBAT,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_BASEBALLBAT);
}
}
}
if (pcom_has & PCOM_HAS_GRENADE)
{
//
// Create a grenade and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_GRENADE,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_GRENADE);
}
}
}
if (bent & PCOM_BENT_GANG)
{
PCOM_add_gang_member(p_index, colour);
}
}
return p_index;
}
THING_INDEX PCOM_create_player(
SLONG type,
SLONG pcom_has,
SLONG world_x,
SLONG world_y,
SLONG world_z,
SLONG id,
SLONG yaw)
{
Thing *p_person = create_player(
type,
world_x,
world_y,
world_z,
id);
#ifndef PSX
extern SLONG playing_level(const CBYTE *name);
if (playing_level("skymiss2.ucm"))
#else
if (wad_level==25)
#endif
{
pcom_has |= PCOM_HAS_SHOTGUN;
}
if (p_person)
{
p_person->Draw.Tweened->Angle = yaw;
p_person->Genus.Person->pcom_ai = PCOM_AI_NONE;
p_person->Genus.Person->pcom_move = PCOM_MOVE_STILL;
p_person->Genus.Person->pcom_bent = 0;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_PLAYER;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_PLAYER;
if (pcom_has & PCOM_HAS_GUN) {p_person->Flags |= FLAGS_HAS_GUN;}
if (pcom_has & PCOM_HAS_SHOTGUN)
{
//
// Create a shotgun and give it to the person.
//
Thing *p_special = alloc_special(
SPECIAL_SHOTGUN,
SPECIAL_SUBSTATE_NONE,
0, 0, 0, NULL);
if (p_special)
{
if (should_person_get_item(p_person, p_special))
{
person_get_item (p_person, p_special);
set_person_draw_item(p_person, SPECIAL_SHOTGUN);
}
}
}
#if !defined(PSX) && !defined(TARGET_DC)
if (pcom_has & PCOM_HAS_BALLOON) {p_person->Genus.Person->Balloon = BALLOON_create(THING_NUMBER(p_person), BALLOON_TYPE_YELLOW);}
#endif
return THING_NUMBER(p_person);
}
return NULL;
}
void PCOM_change_person_attributes(
Thing *p_person,
SLONG colour,
SLONG group,
SLONG ai,
SLONG ai_other,
SLONG move,
SLONG move_follow,
SLONG bent,
SLONG yaw)
{
if (is_person_dead(p_person))
{
return;
}
p_person->Genus.Person->pcom_colour = colour;
p_person->Genus.Person->pcom_group = group;
p_person->Genus.Person->pcom_ai = ai;
p_person->Genus.Person->pcom_move = move;
p_person->Genus.Person->pcom_bent = bent;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = NULL;
p_person->Genus.Person->pcom_ai_other = ai_other;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->pcom_move_follow = move_follow;
if(p_person->Genus.Person->pcom_move == PCOM_MOVE_HANDS_UP)
{
void drop_current_gun(Thing *p_person,SLONG change_anim);
drop_current_gun(p_person,0);
}
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_STILL ||
p_person->Genus.Person->pcom_move == PCOM_MOVE_DANCE ||
p_person->Genus.Person->pcom_move == PCOM_MOVE_HANDS_UP ||
p_person->Genus.Person->pcom_move == PCOM_MOVE_TIED_UP)
{
//
// Change this person's home to be where he is now.
//
p_person->Genus.Person->HomeX = p_person->WorldPos.X >> 8;
p_person->Genus.Person->HomeZ = p_person->WorldPos.Z >> 8;
/*
p_person->Genus.Person->HomeYaw = yaw >> 3;
p_person->Draw.Tweened->Angle = yaw;
*/
}
PCOM_set_person_ai_normal(p_person);
}
//
// Returns the zone flags for the place a person is.
//
UBYTE PCOM_get_zone_for_position(Thing *p_person)
{
UBYTE zone;
SLONG dest_x;
SLONG dest_z;
PAP_Hi *ph;
//
// We don't just look at where this person is- we also consider where he is going...
//
PCOM_get_person_navsquare(
p_person,
&dest_x,
&dest_z);
ph = &PAP_2HI(dest_x,dest_z);
ASSERT(PAP_FLAG_ZONE1 == (1 << 10));
zone = ph->Flags >> 10;
return zone;
}
UBYTE PCOM_get_zone_for_position(SLONG x, SLONG z)
{
UBYTE zone;
PAP_Hi *ph;
ph = &PAP_2HI(x >> 8, z >> 8);
ASSERT(PAP_FLAG_ZONE1 == (1 << 10));
zone = ph->Flags >> 10;
return zone;
}
//
// Returns a pointer to a player person you can see who is inside your zone.
//
Thing *PCOM_can_i_see_person_to_attack(Thing *p_person)
{
Thing *p_target = NET_PERSON(0);
if (p_target->State == STATE_DEAD ||
p_target->State == STATE_DYING ||
stealth_debug)
{
return NULL;
}
if (p_person->Genus.Person->pcom_zone)
{
//
// The target must be on the same zone as us.
//
if (PCOM_get_zone_for_position(p_target) & p_person->Genus.Person->pcom_zone)
{
//
// The person is in our zone!
//
}
else
{
//
// Ignore people who aren't in our zone.
//
return NULL;
}
}
if (can_a_see_b(p_person, p_target))
{
return p_target;
}
return NULL;
}
//
// Returns a pointer to a person you can bully or NULL if you can't find
// anyone suitable.
//
Thing *PCOM_can_i_see_person_to_bully(Thing *p_person)
{
SLONG i;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG score;
SLONG best_score = INFINITY;
Thing *best_thing = NULL;
Thing *p_found;
//
// Find all the people near us.
//
PCOM_found_num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x600,
PCOM_found,
PCOM_MAX_FIND,
1 << CLASS_PERSON);
//
// Who is the best person to bully?
//
for (i = 0; i < PCOM_found_num; i++)
{
p_found = TO_THING(PCOM_found[i]);
if (p_found == p_person)
{
//
// Ignore yourself!
//
continue;
}
if (p_found->State == STATE_DEAD ||
p_found->State == STATE_DYING)
{
//
// Ignore dead people.
//
continue;
}
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_ONLY_KILL_PLAYER)
{
if (!p_found->Genus.Person->PlayerID)
{
//
// Only consider players.
//
continue;
}
}
else
{
//
// Only consider wandering civs and players.
//
if (p_found->Genus.Person->pcom_ai == PCOM_AI_CIV &&
p_found->Genus.Person->pcom_move == PCOM_MOVE_WANDER)
{
//
// This is a wandering civ.
//
}
else
if (p_found->Genus.Person->PlayerID)
{
//
// This is the player.
//
}
else
{
//
// This could be someone important the mission.
//
continue;
}
}
if (can_a_see_b(p_person, p_found))
{
//
// Score this person. Lower scores are better.
//
dx = abs(p_person->WorldPos.X - p_found->WorldPos.X);
dy = abs(p_person->WorldPos.Y - p_found->WorldPos.Y);
dz = abs(p_person->WorldPos.Z - p_found->WorldPos.Z);
score = dx + dy + dy + dz; // Difference in y is more important...
if (p_found->Genus.Person->PlayerID)
{
//
// More likely to bully players.
//
score >>= 1;
}
if (best_score > score)
{
best_score = score;
best_thing = p_found;
}
}
}
return best_thing;
}
#ifndef PSX
#define MAX_ARREST_ME 100
#else
#define MAX_ARREST_ME 5
#endif
Thing *arrest_me[MAX_ARREST_ME];
UWORD next_arrest=0;
void init_arrest(void)
{
next_arrest=0;
}
void do_arrests(void)
{
SLONG c0;
for(c0=0;c0<next_arrest;c0++)
{
PCOM_call_cop_to_arrest_me(arrest_me[c0],0);
}
next_arrest=0;
}
SLONG PCOM_call_cop_to_arrest_me(Thing *p_person,SLONG store_it)
{
SLONG i;
Thing *p_found;
SLONG found_cop=0;
#ifdef DEBUG
if(p_person->Genus.Person->PersonType==PERSON_DARCI)
ASSERT(0);
#endif
if(store_it)
{
if(next_arrest>=MAX_ARREST_ME)
{
ASSERT(0);
return(0);
}
arrest_me[next_arrest]=p_person;
next_arrest++;
return(0);
}
//
// Find all the people near us.
//
if(p_person->Genus.Person->PersonType==PERSON_TRAMP)
return(0);
PCOM_found_num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x800,
PCOM_found,
PCOM_MAX_FIND,
(1 << CLASS_PERSON)|(1<<CLASS_VEHICLE));
//
// Who is the best person to arrest me?
//
for (i = 0; i < PCOM_found_num; i++)
{
p_found = TO_THING(PCOM_found[i]);
if (p_found == p_person)
{
//
// Ignore yourself!
//
continue;
}
if (p_found->State == STATE_DEAD ||
p_found->State == STATE_DYING)
{
//
// Ignore dead people.
//
continue;
}
if(p_found->Class==CLASS_VEHICLE)
{
if(p_found->Genus.Vehicle->Driver)
{
p_found=TO_THING(p_found->Genus.Vehicle->Driver);
}
else
{
continue;
}
}
if (p_found->Genus.Person->pcom_ai == PCOM_AI_COP ||
p_found->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
//
// found a cop type person
//
// AENG_world_line_infinite(p_found->WorldPos.X>>8,p_found->WorldPos.Y>>8,p_found->WorldPos.Z>>8,7,0xfffff,p_person->WorldPos.X>>8,p_person->WorldPos.Y>>8,p_person->WorldPos.Z>>8,2,0xff0000,1);
if(PCOM_person_doing_nothing_important(p_found))
switch(p_found->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_INVESTIGATING:
case PCOM_AI_STATE_NORMAL:
case PCOM_AI_STATE_WARM_HANDS:
case PCOM_AI_STATE_HOMESICK:
if (can_a_see_b(p_person, p_found))
{
//
// Make the target wanted by the police.
//
p_person->Genus.Person->Flags |= FLAG_PERSON_FELON;
found_cop=1;
if (p_found->Genus.Person->pcom_ai == PCOM_AI_COP ||p_found->Genus.Person->InCar==0)
{
PCOM_set_person_ai_arrest(p_found, p_person);
}
else
{
//
// Exit the car and once you've got out, arrest the person.
//
PCOM_set_person_ai_leavecar(
p_found,
PCOM_EXCAR_ARREST_PERSON,
0,
THING_NUMBER(p_person));
}
}
break;
}
}
}
return found_cop;
}
/*
Thing *PCOM_can_i_see_person_to_arrest(Thing *p_person)
{
SLONG i;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG score;
SLONG ignore_los = FALSE;
SLONG best_score = INFINITY;
Thing *best_thing = NULL;
Thing *p_found;
//
// Find all the people near us.
//
PCOM_found_num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x600,
PCOM_found,
PCOM_MAX_FIND,
1 << CLASS_PERSON);
//
// Who is the best person to arrest?
//
for (i = 0; i < PCOM_found_num; i++)
{
p_found = TO_THING(PCOM_found[i]);
ignore_los = FALSE; // For people the player is fighting...
try_this_person_too:;
if (p_found == p_person)
{
//
// Ignore yourself!
//
continue;
}
if (p_found->State == STATE_DEAD ||
p_found->State == STATE_DYING)
{
//
// Ignore dead people.
//
continue;
}
if (p_found->Genus.Person->pcom_ai == PCOM_AI_COP ||
p_found->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
//
// Ignore other cops.
//
continue;
}
if ((p_found->Genus.Person->Flags & FLAG_PERSON_FELON) ||
(p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING) ||
(p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL) ||
(p_found->Genus.Person->PlayerID && p_found->Genus.Person->Mode == PERSON_MODE_FIGHT))
{
//
// This person is worth arresting.
//
if (ignore_los || can_a_see_b(p_person, p_found))
{
//
// Score this person. Lower scores are better.
//
dx = abs(p_person->WorldPos.X - p_found->WorldPos.X);
dy = abs(p_person->WorldPos.Y - p_found->WorldPos.Y);
dz = abs(p_person->WorldPos.Z - p_found->WorldPos.Z);
score = dx + dy + dy + dz; // Difference in y is more important...
if (p_found->Genus.Person->PlayerID)
{
//
// Less likely to arrest the player.
//
score <<= 1;
}
if (p_found->Genus.Person->pcom_ai == PCOM_AI_CIV && p_found->Genus.Person->pcom_move == PCOM_MOVE_WANDER)
{
//
// Very unlikely to arrest wandering civs!
//
score <<= 2;
}
if (p_found->Genus.Person->Flags2 & FLAG2_PERSON_GUILTY)
{
//
// Very likely to arrest guilty people.
//
score >>= 2;
}
if (best_score > score)
{
best_score = score;
best_thing = p_found;
}
//
// What if the cop can only see the player fighting but he can't
// see who the player is fighting?
//
if (p_found->Genus.Person->PlayerID)
{
if (p_found->Genus.Person->Target)
{
Thing *p_target;
//
// Try this person too...
//
p_target = TO_THING(p_found->Genus.Person->Target);
ASSERT(p_target->Class == CLASS_PERSON);
p_found = p_target;
ignore_los = TRUE;
goto try_this_person_too;
}
}
}
}
}
return best_thing;
}
*/
//
// Returns a pointer to a player person you can see.
//
Thing *PCOM_can_i_see_person_to_taunt(Thing *p_person)
{
SLONG i;
for (i = 0; i < NO_PLAYERS; i++)
{
Thing *p_target = NET_PERSON(0);
if (p_target->State == STATE_DEAD ||
p_target->State == STATE_DYING ||
stealth_debug)
{
continue;
}
if (can_a_see_b(p_person, p_target))
{
return p_target;
}
}
return NULL;
}
//
// Returns the next waypoint for a person to patrol.
//
SLONG PCOM_get_next_patrol_waypoint(Thing *p_person)
{
SLONG waypoint;
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_PATROL)
{
waypoint = EWAY_find_waypoint(
p_person->Genus.Person->pcom_move_arg + 1,
EWAY_DONT_CARE,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group,
TRUE);
}
else
{
waypoint = EWAY_find_waypoint_rand(
p_person->Genus.Person->pcom_move_arg,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group,
TRUE);
}
return waypoint;
}
//
// Processes a person who doesn't want to move who is in a car or on a bike.
//
void PCOM_process_driving_still(Thing *p_person)
{
ASSERT(p_person->Genus.Person->Flags & (FLAG_PERSON_DRIVING | FLAG_PERSON_BIKING));
Thing *p_vehicle;
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
if (p_vehicle->Velocity != 0)
{
//
// We want to stop the car.
//
PCOM_set_person_move_park_car_on_road(p_person);
}
break;
case PCOM_MOVE_STATE_PARK_CAR:
case PCOM_MOVE_STATE_PARK_BIKE:
if ((p_vehicle->Class == CLASS_VEHICLE && p_vehicle->Velocity == 0)
#ifdef BIKE
||
(p_vehicle->Class == CLASS_BIKE && BIKE_get_speed(p_vehicle) == 0)
#endif
)
{
//
// We have come to a halt.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->pcom_move_counter = 0;
}
break;
default:
ASSERT(0);
break;
}
}
//
// Processes a person driving between waypoints who is either in a car
// or on a bike.
//
void PCOM_process_driving_patrol(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG waypoint;
SLONG dest_x;
SLONG dest_z;
Thing *p_vehicle;
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
//
// Must have just got into the car (or onto the bike)
//
waypoint = EWAY_find_nearest_waypoint(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group);
if (waypoint != EWAY_NO_MATCH)
{
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_move_driveto(p_person, waypoint);
}
#ifdef BIKE
else
{
PCOM_set_person_move_biketo(p_person, waypoint);
}
#else
else
{
ASSERT(0);
}
#endif
}
break;
case PCOM_MOVE_STATE_DRIVETO:
case PCOM_MOVE_STATE_BIKETO:
ASSERT(p_person->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_BIKING));
//
// Have we arrived at our next waypoint yet?
//
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
dx = dest_x - (p_vehicle->WorldPos.X >> 8);
dz = dest_z - (p_vehicle->WorldPos.Z >> 8);
dist = QDIST2(abs(dx),abs(dz));
if (dist < 0x300)
{
if (EWAY_get_delay(p_person->Genus.Person->pcom_move_arg, 0) == 10 * 1000)
{
//
// This waypoint has the maximum delay. That means that the driver
// should stop wanting to move- i.e. he should park here.
//
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_move_park_car(p_person, p_person->Genus.Person->pcom_move_arg);
}
#ifdef BIKE
else
{
PCOM_set_person_move_park_bike(p_person, p_person->Genus.Person->pcom_move_arg);
}
#else
else
{
ASSERT(0);
}
#endif
//
// Dont move anymore.
//
p_person->Genus.Person->pcom_move = PCOM_MOVE_STILL;
}
else
{
//
// Move onto the next waypoint.
//
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_PATROL)
{
waypoint = EWAY_find_waypoint(
p_person->Genus.Person->pcom_move_arg + 1,
EWAY_DONT_CARE,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group,
TRUE);
}
else
{
waypoint = EWAY_find_waypoint_rand(
p_person->Genus.Person->pcom_move_arg,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group,
TRUE);
}
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_move_driveto(p_person, waypoint);
}
#ifdef BIKE
else
{
PCOM_set_person_move_biketo(p_person, waypoint);
}
#else
else
{
ASSERT(0);
}
#endif
}
}
break;
default:
ASSERT(0);
break;
}
}
//
// Processes a person driving or biking aimlessly around the city.
//
void PCOM_process_driving_wander(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG dest_x;
SLONG dest_z;
SLONG n1;
SLONG n2;
SLONG wtn1;
SLONG wtn2;
Thing *p_vehicle;
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
if (p_vehicle->Flags & FLAGS_IN_VIEW)
{
p_person->Genus.Person->sewerbits = 0;
}
else
{
p_person->Genus.Person->sewerbits++;
if (p_person->Genus.Person->sewerbits > 50)
{
SLONG dx,dz;
Thing *p_darci=NET_PERSON(0);
dx=abs((p_person->WorldPos.X-p_darci->WorldPos.X)>>8);
dz=abs((p_person->WorldPos.Z-p_darci->WorldPos.Z)>>8);
if(QDIST2(dx,dz) >= (DRAW_DIST<<8))
{
SLONG x,z,yaw;
extern SLONG WAND_find_good_start_point_for_car(SLONG* posx, SLONG* posz, SLONG* yaw, SLONG anywhere);
if (WAND_find_good_start_point_for_car(&x, &z, &yaw, 0))
{
GameCoord newpos;
newpos.X = x << 8;
newpos.Y = 0; // calculated properly in reinit_vehicle()
newpos.Z = z << 8;
move_thing_on_map(p_vehicle, &newpos);
p_person->Genus.Person->sewerbits = Random() & 15;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL; // re-init the wander
p_person->WorldPos = newpos;
// p_vehicle->Draw.Mesh->Angle = yaw ^ 1024;
Vehicle* veh = p_vehicle->Genus.Vehicle;
veh->Angle = yaw ^ 1024;
#if PSX
{
p_vehicle->Genus.Vehicle->Type=vehicle_random[(Random()&15)];
}
#endif
reinit_vehicle(p_vehicle);
// return;
}
}
}
}
}
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_DRIVE_DOWN:
case PCOM_MOVE_STATE_BIKE_DOWN:
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
if (ROAD_is_end_of_the_line(p_person->Genus.Person->pcom_move_arg & 0xff))
{
//
// Have we gone off the map yet?
//
if (!WITHIN(p_vehicle->WorldPos.X, 0, PAP_SIZE_HI << 16) ||
!WITHIN(p_vehicle->WorldPos.Z, 0, PAP_SIZE_HI << 16))
{
SLONG world_x = p_vehicle->WorldPos.X >> 8;
SLONG world_z = p_vehicle->WorldPos.Z >> 8;
SLONG nrn1;
SLONG nrn2;
SLONG nyaw;
//
// Find another node on the road.
//
ROAD_find_me_somewhere_to_appear(
&world_x,
&world_z,
&nrn1,
&nrn2,
&nyaw);
//
// Re-init the car a bit... otherwise problems can occur due to the
// sudden teleportation...
//
p_vehicle->Genus.Vehicle->oldX[0]=
p_vehicle->Genus.Vehicle->oldX[1]=
p_vehicle->Genus.Vehicle->oldX[2]=
p_vehicle->Genus.Vehicle->oldX[3]=0;
p_vehicle->Genus.Vehicle->oldZ[0]=
p_vehicle->Genus.Vehicle->oldZ[1]=
p_vehicle->Genus.Vehicle->oldZ[2]=
p_vehicle->Genus.Vehicle->oldZ[3]=0;
p_vehicle->Genus.Vehicle->Smokin=0;
//
// Move the vehicle to the new road.
//
GameCoord newpos;
newpos.X = world_x << 8;
newpos.Z = world_z << 8;
newpos.Y = PAP_calc_height_at(world_x,world_z) + 0x40 << 8;
move_thing_on_map(p_vehicle, &newpos);
//
// Pointing in the right direction.
//
if (p_vehicle->Class == CLASS_VEHICLE)
{
p_vehicle->Genus.Vehicle->Angle = nyaw;
}
#ifdef BIKE
else
{
ASSERT(p_vehicle->Class == CLASS_BIKE);
p_vehicle->Genus.Bike->yaw = nyaw;
}
#else
else
{
ASSERT(0);
}
#endif
//
// Remember the new road we are going down.
//
p_person->Genus.Person->pcom_move_arg = nrn1 << 8;
p_person->Genus.Person->pcom_move_arg |= nrn2;
}
}
else
{
//
// Have we reached the end of the road?
//
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
dx = dest_x - (p_vehicle->WorldPos.X >> 8);
dz = dest_z - (p_vehicle->WorldPos.Z >> 8);
dist = QDIST2(abs(dx),abs(dz));
#define LEFT_TURN_DIST 0x380 // distance from junction before left turn
#define RIGHT_TURN_DIST 0x280 // distance from junction before right turn
if (dist < LEFT_TURN_DIST)
{
// find next road to drive down
if (!p_person->Genus.Person->InsideRoom)
{
ROAD_whereto_now(
p_person->Genus.Person->pcom_move_arg >> 8,
p_person->Genus.Person->pcom_move_arg & 0xff,
&wtn1,
&wtn2);
p_person->Genus.Person->InsideRoom = wtn2;
}
// check turn
if (ROAD_bend(p_person->Genus.Person->pcom_move_arg >> 8, p_person->Genus.Person->pcom_move_arg & 0xff, p_person->Genus.Person->InsideRoom) < 0)
{
// left turn - do it late
dist += LEFT_TURN_DIST - RIGHT_TURN_DIST;
}
// do turn
if (dist < LEFT_TURN_DIST)
{
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_move_drive_down(p_person, p_person->Genus.Person->pcom_move_arg & 0xff, p_person->Genus.Person->InsideRoom);
}
#ifdef BIKE
else
{
PCOM_set_person_move_bike_down(p_person, p_person->Genus.Person->pcom_move_arg & 0xff, p_person->Genus.Person->InsideRoom);
}
#else
else ASSERT(0);
#endif
p_person->Genus.Person->InsideRoom = 0;
}
}
else
{
// ensure the next node is "none"
p_person->Genus.Person->InsideRoom = 0;
}
}
break;
default:
//
// Find a road to start driving down.
//
ROAD_find(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Z >> 8,
&n1,
&n2);
if (n1 && n2)
{
//
// Which side of the road are we on?
//
dist = ROAD_signed_dist(
n1,
n2,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Z >> 8);
if (dist < 0)
{
//
// We are on the wrong side of the road- go in the other direction.
//
SWAP(n1,n2);
}
if (p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
PCOM_set_person_move_drive_down(p_person, n1, n2);
}
#ifdef BIKE
else
{
PCOM_set_person_move_bike_down(p_person, n1, n2);
}
#else
else
{
ASSERT(0);
}
#endif
}
p_person->Genus.Person->InsideRoom = 0; // InsideRoom = next node to drive to
break;
}
}
//
// Processes a person moving between patrol points.
//
void PCOM_process_patrol(Thing *p_person)
{
SLONG waittime;
SLONG waypoint;
switch(p_person->Genus.Person->pcom_move_state)
{
default:
case PCOM_MOVE_STATE_STILL:
//
// Find a waypoint to get to.
//
waypoint = EWAY_find_nearest_waypoint(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
p_person->Genus.Person->pcom_colour,
p_person->Genus.Person->pcom_group);
if (waypoint == EWAY_NO_MATCH)
{
//
// Stay still for a while
//
PCOM_set_person_move_pause(p_person);
}
else
{
SLONG way_x;
SLONG way_y;
SLONG way_z;
//
// Too near to this waypoint?
//
EWAY_get_position(
waypoint,
&way_x,
&way_y,
&way_z);
SLONG dx = abs(way_x - (p_person->WorldPos.X >> 8));
SLONG dy = abs(way_y - (p_person->WorldPos.Y >> 8));
SLONG dz = abs(way_z - (p_person->WorldPos.Z >> 8));
SLONG dist = QDIST3(dx,dy,dz);
if (dist < 0x100)
{
//
// We have to put the current waypoint into the persons 'pcom_move_arg'
// because that is where PCOM_get_next_patrol_waypoint() expects it
// to be.
//
p_person->Genus.Person->pcom_move_arg = waypoint;
//
// We are really close to this waypoint, lets start going to
// the next one.
//
waypoint = PCOM_get_next_patrol_waypoint(p_person);
}
//
// Go towards this waypoint.
//
PCOM_set_person_move_mav_to_waypoint(
p_person,
waypoint,
(p_person->Genus.Person->pcom_bent & PCOM_BENT_DILIGENT) ? PCOM_MOVE_SPEED_RUN : PCOM_MOVE_SPEED_WALK);
}
break;
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
//
// Got to our waypoint yet?
//
if (PCOM_finished_nav(p_person))
{
//
// If this waypoint has a delay of 10 seconds, then make that mean that the person
// should stay here forever- i.e. go to PCOM_MOVE_STILL.
//
waypoint = p_person->Genus.Person->pcom_move_arg;
if (EWAY_get_delay(waypoint, 0) == 10 * 1000)
{
SLONG way_x;
SLONG way_y;
SLONG way_z;
//
// The position of the waypoint we are going to stay at.
//
EWAY_get_position(
waypoint,
&way_x,
&way_y,
&way_z);
p_person->Genus.Person->pcom_move = PCOM_MOVE_STILL;
p_person->Genus.Person->HomeX = way_x;
p_person->Genus.Person->HomeZ = way_z;
p_person->Genus.Person->HomeYaw = EWAY_get_angle(waypoint) >> 3;
PCOM_set_person_move_still(p_person);
}
else
{
//
// Wait at this waypoint before going onto
//
PCOM_set_person_move_pause(p_person);
//
// Turn to face the direction of the waypoint.
//
p_person->Draw.Tweened->Angle = EWAY_get_angle(p_person->Genus.Person->pcom_move_arg);
}
}
break;
case PCOM_MOVE_STATE_PAUSE:
//
// Finished waiting?
//
waittime = PCOM_get_duration(EWAY_get_delay(p_person->Genus.Person->pcom_move_arg, 0) / 100);
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
waittime += waittime;
}
if (p_person->Genus.Person->pcom_move_counter >= waittime)
{
//
// Move onto next waypoint.
//
waypoint = PCOM_get_next_patrol_waypoint(p_person);
if (waypoint == EWAY_NO_MATCH || waypoint == p_person->Genus.Person->pcom_move_arg)
{
PCOM_set_person_move_pause(p_person);
}
else
{
PCOM_set_person_move_mav_to_waypoint(
p_person,
waypoint,
(p_person->Genus.Person->pcom_bent & PCOM_BENT_DILIGENT) ? PCOM_MOVE_SPEED_RUN : PCOM_MOVE_SPEED_WALK);
}
}
else
{
//
// Turn to face the direction of the waypoint.
//
p_person->Draw.Tweened->Angle = EWAY_get_angle(p_person->Genus.Person->pcom_move_arg);
}
break;
//
// Default case is at the top of the switch statement!
//
}
}
SLONG should_person_regen(Thing *p_person)
{
SLONG dx,dz;
Thing *p_darci=NET_PERSON(0);
dx=abs((p_person->WorldPos.X-p_darci->WorldPos.X)>>8);
dz=abs((p_person->WorldPos.Z-p_darci->WorldPos.Z)>>8);
if(QDIST2(dx,dz)<(DRAW_DIST<<8))
return(0);
if(p_person->Genus.Person->InsideRoom>50)
return(1);
else
return(0);
}
extern ULONG timer_bored;
SLONG PCOM_do_regen(Thing *p_person)
{
SLONG wand_x;
SLONG wand_z;
SLONG nx,nz;
if(NET_PERSON(0)->Genus.Person->Ware || EWAY_stop_player_moving())
{
//
// Player is in a warehouse so why bother
//
return(0);
}
if (p_person->Genus.Person->Target)
{
Thing *p_target = TO_THING(p_person->Genus.Person->Target);
remove_from_gang_attack(p_person, p_target);
}
extern SLONG WAND_find_good_start_point(SLONG *mapx,SLONG *mapz);
if(WAND_find_good_start_point(&nx,&nz))
{
GameCoord new_position;
new_position.X = nx<<8;
new_position.Y = PAP_calc_height_at(nx,nz)<<8;
new_position.Z = nz<<8;
move_thing_on_map(p_person, &new_position);
p_person->Genus.Person->Flags&=~(FLAG_PERSON_KO | FLAG_PERSON_HELPLESS|FLAG_PERSON_WAREHOUSE|FLAG_PERSON_ARRESTED|FLAG_PERSON_ARRESTED|FLAG_PERSON_SEARCHED);
p_person->Genus.Person->Ware=0;
p_person->OnFace = 0;
if((signed)timer_bored>(BOREDOM_RATE*5000) && BOREDOM_RATE!=255)// && BOREDOM_RATE)
// if(0) //mdsoft
{
Thing *darci;
darci=NET_PERSON(0);
if(darci->Genus.Person->PersonType != PERSON_DARCI && darci->Genus.Person->PersonType != PERSON_ROPER)
{
//
//
// darci is thug
p_person->Genus.Person->pcom_ai = PCOM_AI_COP;
p_person->Genus.Person->pcom_bent = 0;
p_person->Genus.Person->PersonType=PERSON_COP;
p_person->Draw.Tweened->MeshID =4;
}
else
{
p_person->Genus.Person->pcom_ai = PCOM_AI_GANG;
p_person->Genus.Person->PersonType=PERSON_THUG_RASTA;
p_person->Genus.Person->pcom_bent = PCOM_BENT_FIGHT_BACK;
p_person->Draw.Tweened->MeshID =(Random()%3);
}
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = NULL;
p_person->Genus.Person->pcom_ai_other = NULL;
p_person->Genus.Person->pcom_move = PCOM_MOVE_WANDER;
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->InsideRoom=Random()&15;
p_person->Draw.Tweened->PersonID = 0;
p_person->Genus.Person->pcom_colour =0;
p_person->Genus.Person->pcom_group =0;
if(timer_bored&16)
p_person->Flags |= FLAGS_HAS_GUN;
else
p_person->Flags &= ~FLAGS_HAS_GUN;
p_person->Genus.Person->Health=200;
PCOM_set_person_ai_navtokill(p_person,NET_PERSON(0));
timer_bored=0;
// PCOM_set_person_ai_kill_person(p_person,NET_PERSON(0),0);
}
else
{
p_person->Flags &= ~FLAGS_HAS_GUN;
p_person->Genus.Person->pcom_ai = PCOM_AI_CIV;
p_person->Genus.Person->pcom_bent = 0;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = NULL;
p_person->Genus.Person->pcom_ai_other = NULL;
p_person->Genus.Person->pcom_move = PCOM_MOVE_WANDER;
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->InsideRoom=Random()&15;
p_person->Draw.Tweened->PersonID = 0;//6 + Random() % 4;
p_person->Draw.Tweened->MeshID =(Random()&1)+8;
p_person->Genus.Person->pcom_colour =Random()&3;
p_person->Genus.Person->PersonType=PERSON_CIV;
p_person->Genus.Person->Health=130;
p_person->Flags &= ~FLAGS_HAS_GUN;
WAND_get_next_place(
p_person,
&wand_x,
&wand_z);
//
// Go there.
//
PCOM_set_person_move_mav_to_xz(
p_person,
wand_x,
wand_z,
PCOM_MOVE_SPEED_WALK);
//
// Find a new place to wander to every five seconds... so we don't get stuck.
//
p_person->Genus.Person->pcom_ai_counter = 0;
}
return(1);
}
return(0);
}
//
// Processes a person moving wandering around
//
void PCOM_process_wander(Thing *p_person)
{
SLONG wand_x;
SLONG wand_z;
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
if (p_person->Genus.Person->PersonType == PERSON_THUG_RASTA ||
p_person->Genus.Person->PersonType == PERSON_COP)
{
//
// Fake wandering people shouldn't get too close to Darci if she is busy,
// but attack her if she _is_ busy.
//
if ((PTIME(p_person) & 0xf) == 0)
{
if (PCOM_should_fake_person_attack_darci(p_person))
{
PCOM_set_person_ai_navtokill(p_person, NET_PERSON(0));
return;
}
else
{
if (PCOM_get_dist_between(p_person, NET_PERSON(0)) < 0x100 * 15)
{
PCOM_set_person_ai_flee_person(p_person, NET_PERSON(0));
return;
}
}
}
}
}
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_GOTO_XZ:
if(p_person->Genus.Person->Flags2&FLAG2_PERSON_FAKE_WANDER)
if (p_person->Genus.Person->pcom_ai == PCOM_AI_CIV )
{
if ((p_person->Flags & FLAGS_IN_VIEW))
{
p_person->Genus.Person->InsideRoom=0;
}
else
{
p_person->Genus.Person->InsideRoom++; //for test puposes
if(should_person_regen(p_person)) //for test puposes
{
SLONG nx,nz;
p_person->Genus.Person->InsideRoom=240;
if(PCOM_do_regen(p_person))
return;
/*
extern SLONG WAND_find_good_start_point(SLONG *mapx,SLONG *mapz);
if(WAND_find_good_start_point(&nx,&nz))
{
GameCoord new_position;
new_position.X = nx<<8;
new_position.Y = PAP_calc_height_at(nx,nz)<<8;
new_position.Z = nz<<8;
move_thing_on_map(p_person, &new_position);
if(timer_bored>10000)
{
p_person->Genus.Person->pcom_ai = PCOM_AI_GANG;
p_person->Genus.Person->pcom_bent = PCOM_BENT_FIGHT_BACK;
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NONE;
p_person->Genus.Person->pcom_ai_arg = NULL;
p_person->Genus.Person->pcom_ai_other = NULL;
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_arg = 0;
p_person->Genus.Person->InsideRoom=Random()&15;
p_person->Draw.Tweened->PersonID = 0;//6 + Random() % 4;
p_person->Draw.Tweened->MeshID =0;//(Random()&1)+8;
p_person->Genus.Person->pcom_colour =Random()&3;
PCOM_set_person_ai_kill_person(p_person,NET_PERSON(0),0);
}
else
{
p_person->Genus.Person->InsideRoom=Random()&15;
p_person->Draw.Tweened->PersonID = 0;//6 + Random() % 4;
p_person->Draw.Tweened->MeshID =(Random()&1)+8;
p_person->Genus.Person->pcom_colour =Random()&3;
goto new_wander;
}
}
*/
}
}
}
//
// Got to where we are going yet?
//
if (!PCOM_finished_nav(p_person) && p_person->Genus.Person->pcom_ai_counter < PCOM_get_duration(50))
{
//
// Still on our way.
//
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
return;
}
if (p_person->Genus.Person->pcom_ai == PCOM_AI_ASSASIN)
{
PCOM_set_person_ai_normal(p_person);
return;
}
if (p_person->Genus.Person->pcom_ai == PCOM_AI_DRIVER ||
p_person->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
PCOM_set_person_ai_findcar(p_person, NULL);
return;
}
#ifdef BIKE
if (p_person->Genus.Person->pcom_ai == PCOM_AI_BIKER)
{
PCOM_set_person_ai_findbike(p_person);
return;
}
#endif
// FALLTHROUGH! To find a new place to wander to.
default:
case PCOM_MOVE_STATE_STILL:
//new_wander:;
//
// We do we wander to now?
//
WAND_get_next_place(
p_person,
&wand_x,
&wand_z);
//
// Go there.
//
PCOM_set_person_move_mav_to_xz(
p_person,
wand_x,
wand_z,
PCOM_MOVE_SPEED_WALK);
//
// Find a new place to wander to every five seconds... so we don't get stuck.
//
p_person->Genus.Person->pcom_ai_counter = 0;
break;
}
}
//
// The AI for combat.
//
void PCOM_process_killing(Thing *p_person)
{
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
SLONG quick_kick=0;
if (p_person->State == STATE_JUMPING)
{
return;
}
if (p_person->State == STATE_DANGLING)
{
if (p_person->SubState == SUB_STATE_DROP_DOWN)
{
return;
}
}
if ((PTIME(p_person) & 0x3) == 0)
{
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
if (p_person->Genus.Person->PersonType == PERSON_THUG_RASTA ||
p_person->Genus.Person->PersonType == PERSON_COP)
{
if (!PCOM_should_fake_person_attack_darci(p_person))
{
PCOM_set_person_ai_flee_person(p_person, NET_PERSON(0));
return;
}
}
}
}
//
// If our target is dead, then go home.
//
if (p_target->State == STATE_DEAD)
{
//
// We might be arresting this person...
//
if ((p_target->Genus.Person->Flags & FLAG_PERSON_ARRESTED) && p_target->SubState != SUB_STATE_DEAD_ARRESTED)
{
//
// In which case we must Wait till she is actually arrested!
//
}
else
{
//
// Do what you normally do.
//
PCOM_set_person_ai_normal(p_person);
return;
}
}
#ifdef BIKE
//
// Some people have ulterior motives for killing someone...
//
if (p_person->Genus.Person->Flags & FLAG_PERSON_KILL_WITH_A_PURPOSE)
{
//
// For a biker killing someone so they can use his bike.
//
if (p_person->Genus.Person->pcom_ai == PCOM_AI_BIKER)
{
if (p_target->Genus.Person->Flags & FLAG_PERSON_BIKING)
{
//
// We are trying to get our person off his bike.
//
}
else
{
p_person->Genus.Person->Flags &= ~FLAG_PERSON_KILL_WITH_A_PURPOSE;
//
// Don't kill em any more.
//
remove_from_gang_attack(p_person, p_target);
//
// Get on our targets bike!
//
PCOM_set_person_ai_findbike(p_person);
return;
}
}
}
#endif
if (PTIME(p_person) & 0x1)
{
SLONG too_far;
if (!is_person_ko(p_target))
{
//
// Make sure we stay close so someone who starts pegging it!
//
if (p_target->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PERSON)
{
too_far = 0x150;
}
else
{
too_far = 0x250;
}
//
// Too far from our target? Then renav.
//
if (PCOM_get_dist_between(p_person, p_target) > too_far ||
!can_a_see_b(p_person, p_target) || !there_is_a_los_things(p_person,p_target,LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG|LOS_FLAG_IGNORE_PRIMS|LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
{
if (p_person->State == STATE_CIRCLING)
{
remove_from_gang_attack(p_person,p_target);
}
//
// Go towards the player to try and beat him up.
//
PCOM_set_person_ai_navtokill(p_person, p_target);
return;
}
}
}
if (p_target->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER))
{
//
// If we have a gun then shoot the car...
//
if (PCOM_person_has_any_sort_of_gun_with_ammo(p_person))
{
//
// Navtokill is what shoots!!!
//
PCOM_set_person_ai_navtokill(p_person, p_target);
return;
}
else
{
//
// No point in having a fist fight with a car!
//
PCOM_set_person_ai_taunt(p_person, p_target);
return;
}
}
// if (((GAME_TURN+(THING_NUMBER(p_target)<<2)) & 0x3f) == 0)
if((PTIME(p_person)&0x3f)==0)
{
//
// Is our target ignoring us?
//
if (p_target->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
//
// Say something aggressive to him- to catch his attention.
//
// MFX_play_thing(THING_NUMBER(p_person),S_WHATRYOULOOKINAT,MFX_REPLACE,p_person);
//wh wh wh wh wh wh
#ifndef PSX
if (IsEnglish)
MFX_play_thing(THING_NUMBER(p_person),SOUND_Range(S_WTHUG1_ALERT_START,S_WTHUG1_ALERT_START+1),MFX_REPLACE,p_person);
#endif
PCOM_oscillate_tympanum(
PCOM_SOUND_LOOKINGATME,
p_person,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8);
}
}
//
// Make a detour to pickup a gun?
//
/*
#if PSX
if (((GAME_TURN + (THING_NUMBER(p_person) << 4)) & 0x7f) == 0)
#else
if (((GAME_TURN + (THING_NUMBER(p_person) << 5)) & 0xff) == 0)
#endif
*/
#if PSX
if ((PTIME(p_person)&0x7f)==0)
#else
if ((PTIME(p_person)&0xff)==0)
#endif
{
Thing *p_special = PCOM_is_there_an_item_i_should_get(p_person);
if (p_special)
{
PCOM_set_person_ai_getitem(
p_person,
p_special,
PCOM_MOVE_SPEED_RUN,
PCOM_EXCAR_NAVTOKILL,
p_person->Genus.Person->pcom_ai_arg);
return;
}
}
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
PCOM_set_person_move_circle(p_person, p_target);
//
// Wait for between 0.5 to 1.0 seconds between attacks. Increase
// or decrease this number to make people easier to kill.
//
p_person->Genus.Person->pcom_ai_counter = PCOM_get_random_duration(15, 20);
break;
case PCOM_MOVE_STATE_PAUSE:
case PCOM_MOVE_STATE_CIRCLE:
//
// All the AI code is done by fn_person_circle now.
//
break;
case PCOM_MOVE_STATE_ANIMATION:
case PCOM_MOVE_STATE_WAIT_CIRCLE:
case PCOM_MOVE_STATE_GRAPPLE:
break;
default:
ASSERT(0);
break;
}
}
//
// Processes a person running away from something.
// i.e. PCOM_AI_STATE_FLEE_PLACE
// PCOM_AI_STATE_FLEE_PERSON
//
void PCOM_process_fleeing(Thing *p_person)
{
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_SUPRISED:
//
// Finished looking dumb?
//
if (p_person->Genus.Person->pcom_ai_counter > PCOM_get_duration(10))
{
//
// Start running away.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LEGIT;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Get the person moving!
//
{
SLONG danger_x;
SLONG danger_z;
PCOM_get_flee_from_pos(
p_person,
&danger_x,
&danger_z);
PCOM_set_person_move_runaway(
p_person,
danger_x,
danger_z);
}
}
else
{
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
break;
case PCOM_AI_SUBSTATE_LEGIT:
//
// Let go of a balloon if you are carrying one.
//
#if !defined(PSX) && !defined(TARGET_DC)
if (p_person->Genus.Person->Balloon && p_person->Genus.Person->pcom_ai_counter > PCOM_get_duration(5))
{
BALLOON_release(p_person->Genus.Person->Balloon);
}
#endif
//
// If we have got to where we were legging it to, then leg-it again.
//
if (PCOM_finished_nav(p_person) || p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
SLONG danger_x;
SLONG danger_z;
PCOM_get_flee_from_pos(
p_person,
&danger_x,
&danger_z);
PCOM_set_person_move_runaway(
p_person,
danger_x,
danger_z);
}
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
// if ((GAME_TURN & 0xf) == 0)
if ((PTIME(p_person) & 0xf) == 0)
{
SLONG danger_x;
SLONG danger_z;
PCOM_get_flee_from_pos(
p_person,
&danger_x,
&danger_z);
//
// Are we far enough from what we are scared of?
//
SLONG dx = danger_x - (p_person->WorldPos.X >> 8);
SLONG dz = danger_z - (p_person->WorldPos.Z >> 8);
SLONG dist = abs(dx) + abs(dz);
SLONG want_dist = 0x100 * 15;
if (p_person->Genus.Person->pcom_ai_counter >= PCOM_get_duration(300))
{
want_dist = 0x100 * 3;
}
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
if (p_person->Genus.Person->PersonType == PERSON_THUG_RASTA ||
p_person->Genus.Person->PersonType == PERSON_COP)
{
want_dist = 0x100 * 20;
}
}
if (dist > want_dist)
{
//
// Nothing to be scared of any more- we can relax...
//
PCOM_set_person_move_still(p_person);
//
// ...and go back to doing what we were doing before.
//
PCOM_set_person_ai_normal(p_person);
}
}
break;
default:
ASSERT(0);
break;
}
}
//
// Processes a person investigating something.
//
void PCOM_process_investigating(Thing *p_person)
{
SLONG dist;
SLONG before;
SLONG after;
SLONG hide_x;
SLONG hide_z;
SLONG sound_x;
SLONG sound_z;
//
// The position of the sound we are investigating.
//
sound_x = (p_person->Genus.Person->pcom_ai_arg >> 8) & 0xff;
sound_z = (p_person->Genus.Person->pcom_ai_arg >> 0) & 0xff;
sound_x <<= 8;
sound_z <<= 8;
sound_x += 0x80;
sound_z += 0x80;
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_SUPRISED:
//
// Enough time being suprised?
//
if (p_person->Genus.Person->pcom_ai_counter > PCOM_get_duration(10))
{
//
// If the person can see where the sound came from then
// there is no point walking over there.
//
SLONG sound_y = PAP_calc_map_height_at(sound_x, sound_z) + 0x60;
if (there_is_a_los(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y + 0x6000 >> 8,
p_person->WorldPos.Z >> 8,
sound_x,
sound_y + 0x80,
sound_z,
LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
{
//
// Don't walk over.
//
PCOM_set_person_ai_normal(p_person);
}
else
{
//
// Start walking to where the sound came from.
//
PCOM_set_person_move_mav_to_xz(
p_person,
sound_x,
sound_z,
PCOM_MOVE_SPEED_WALK);
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_RESTRICTED)
{
//
// If you are restricted movement and you can't get to your
// target for certain then give up and go back to your normal
// routine.
//
if (!MAV_do_found_dest)
{
PCOM_set_person_ai_normal(p_person);
return;
}
}
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_WALKOVER;
}
}
else
{
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
break;
case PCOM_AI_SUBSTATE_WALKOVER:
//
// Are we where we want to be to investigate the sound?
//
dist = PCOM_person_dist_from(
p_person,
sound_x,
sound_z);
if (dist < PCOM_ARRIVE_DIST)
{
//
// Start looking around for signs of trouble.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LOOK;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
}
if (p_person->Genus.Person->pcom_move_state != PCOM_MOVE_STATE_GOTO_XZ)
{
PCOM_set_person_move_mav_to_xz(
p_person,
sound_x,
sound_z,
PCOM_MOVE_SPEED_WALK);
// PANEL_new_help_message("Important! Tell Mark that lavender is blue.");
}
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
break;
case PCOM_AI_SUBSTATE_LOOK:
before = p_person->Genus.Person->pcom_ai_counter;
after = p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if (before < PCOM_get_duration(10) && after >= PCOM_get_duration(10))
{
//
// Turn to the left.
//
p_person->Draw.Tweened->AngleTo -= 512;
p_person->Draw.Tweened->Angle -= 512;
p_person->Draw.Tweened->AngleTo &= 2047;
p_person->Draw.Tweened->Angle &= 2047;
}
if (before < PCOM_get_duration(30) && after >= PCOM_get_duration(30))
{
//
// Turn to the right.
//
p_person->Draw.Tweened->AngleTo += 1024;
p_person->Draw.Tweened->Angle += 1024;
p_person->Draw.Tweened->AngleTo &= 2047;
p_person->Draw.Tweened->Angle &= 2047;
}
if (after > PCOM_get_duration(50))
{
//
// Didn't find any shenanigans.
//
if (Random() & 0x1)
{
//
// Go back home.
//
PCOM_set_person_ai_homesick(p_person);
}
else
{
//
// Look for somewhere where somebody might be hiding.
//
if (PCOM_find_hiding_place(
p_person,
&hide_x,
&hide_z))
{
//
// Start walking to the hiding place.
//
PCOM_set_person_move_mav_to_xz(
p_person,
hide_x,
hide_z,
PCOM_MOVE_SPEED_WALK);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_WALKOVER;
hide_x >>= 8;
hide_z >>= 8;
p_person->Genus.Person->pcom_ai_arg = (hide_x << 8) | hide_z;
}
else
{
//
// Couldn't see anywhere where somebody might be hiding- go home.
//
PCOM_set_person_ai_homesick(p_person);
}
}
}
break;
default:
ASSERT(0);
break;
}
}
//
// The speed the person wants to follow the target at.
//
SLONG PCOM_follow_speed(Thing *p_person, Thing *p_target)
{
SLONG wantspeed;
if (p_target->Genus.Person->PlayerID)
{
switch(p_target->Genus.Person->Mode)
{
case PERSON_MODE_RUN: wantspeed = PERSON_SPEED_YOMP; break;
case PERSON_MODE_WALK: wantspeed = PERSON_SPEED_WALK; break;
case PERSON_MODE_SNEAK: wantspeed = PERSON_SPEED_SNEAK; break;
case PERSON_MODE_FIGHT: wantspeed = PERSON_SPEED_RUN; break;
case PERSON_MODE_SPRINT: wantspeed = PERSON_SPEED_RUN; break;
default:
ASSERT(0);
break;
}
if (p_target->SubState == SUB_STATE_CRAWLING ||
p_target->SubState == SUB_STATE_IDLE_CROUTCH ||
p_target->SubState == SUB_STATE_IDLE_CROUTCHING)
{
wantspeed = PERSON_SPEED_CRAWL;
}
}
else
{
wantspeed = p_target->Genus.Person->GotoSpeed;
if (wantspeed != PERSON_SPEED_RUN &&
wantspeed != PERSON_SPEED_WALK &&
wantspeed != PERSON_SPEED_SNEAK &&
wantspeed != PERSON_SPEED_YOMP &&
wantspeed != PERSON_SPEED_CRAWL)
{
wantspeed = PERSON_SPEED_RUN;
}
}
return wantspeed;
}
void PCOM_process_following(Thing *p_person)
{
SLONG dist;
SLONG wantspeed;
//
// Who are we following?
//
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
//
// If our target is in a vehicle and we are not in it...
//
if (p_target->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER))
{
if (p_person->Genus.Person->Flags & FLAG_PERSON_PASSENGER)
{
//
// We are in a car too... assume it is the right one!
//
ASSERT(p_person->Genus.Person->InCar == p_target->Genus.Person->InCar);
return;
}
else
{
//
// Get into the same car as who we are following.
//
PCOM_set_person_ai_hitch(p_person, TO_THING(p_target->Genus.Person->InCar));
return;
}
}
else
{
if (p_person->Genus.Person->Flags & FLAG_PERSON_PASSENGER)
{
//
// We are in a car but our target isn't. Get out of the car.
//
PCOM_set_person_ai_leavecar(p_person, PCOM_EXCAR_NORMAL, 0, 0);
return;
}
}
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PAUSE)
{
//
// Finished pausing?
//
// if ((GAME_TURN & 0x3) == 0)
if ((PTIME(p_person) & 0x3) == 0)
{
SLONG wantdist = 0xa0;
//
// If our target is moving we want to be really close!
//
if (p_target->SubState == SUB_STATE_RUNNING)
{
wantdist = 0x40;
}
if (PCOM_get_dist_between(
p_person,
p_target) > wantdist)
{
wantspeed = PCOM_follow_speed(p_person, p_target);
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
wantspeed);
return;
}
else
{
//
// Crouch if our target crouches.
//
if (p_target->SubState == SUB_STATE_CRAWLING ||
p_target->SubState == SUB_STATE_IDLE_CROUTCH ||
p_target->SubState == SUB_STATE_IDLE_CROUTCHING)
{
if (p_person->SubState == SUB_STATE_IDLE_CROUTCH ||
p_person->SubState == SUB_STATE_IDLE_CROUTCHING)
{
//
// We are croutching like our target already.
//
}
else
{
set_person_croutch(p_person);
}
}
else
if (p_person->SubState == SUB_STATE_IDLE_CROUTCH ||
p_person->SubState == SUB_STATE_IDLE_CROUTCHING)
{
//
// We are croutching for no reason.
//
set_person_idle_uncroutch(p_person);
}
else
{
//
// Pickup a weapon?
//
if (p_person->Genus.Person->pcom_ai != PCOM_AI_CIV)
{
#if PSX
// if (((GAME_TURN + (THING_NUMBER(p_person) << 4)) & 0x3f) == 0)
if ((PTIME(p_person)&0x3f)==0)
#else
//if (((GAME_TURN + (THING_NUMBER(p_person) << 5)) & 0x7f) == 0)
if ((PTIME(p_person)&0x7f)==0)
#endif
{
Thing *p_special = PCOM_is_there_an_item_i_should_get(p_person);
if (p_special)
{
PCOM_set_person_ai_getitem(
p_person,
p_special,
PCOM_MOVE_SPEED_RUN,
PCOM_EXCAR_NORMAL,
0);
return;
}
}
}
}
}
}
}
else
{
{
//
// Following people should run if they are too far from their target,
// but if they are close enough, they should copy their target's
// speed- i.e. walk or sneak. Only take (dx,dz) into account though...
//
SLONG dx = abs(p_target->WorldPos.X - p_person->WorldPos.X >> 8);
SLONG dz = abs(p_target->WorldPos.Z - p_person->WorldPos.Z >> 8);
dist = QDIST2(dx,dz);
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_GOTO_THING && (p_person->Genus.Person->pcom_move_substate == PCOM_MOVE_SUBSTATE_GOTO || p_person->Genus.Person->pcom_move_substate == PCOM_MOVE_SUBSTATE_LOSMAV))
{
if (dist > 0x180)
{
if (p_person->Genus.Person->GotoSpeed != PERSON_SPEED_RUN)
{
//
// Start running!
//
PCOM_set_person_move_mav_to_thing(p_person, p_target, PERSON_SPEED_RUN);
}
else
{
}
}
else
if (dist < 0xc0)
{
//
// Copy the targets movement.
//
wantspeed = PCOM_follow_speed(p_person, p_target);
if (p_person->Genus.Person->GotoSpeed != wantspeed)
{
//
// Get going at the new speed- except we are allowed to sprint
// if our target isn't so we can keep up!
//
if (p_person->Genus.Person->GotoSpeed == PERSON_SPEED_RUN)
{
if (wantspeed == PERSON_SPEED_WALK ||
wantspeed == PERSON_SPEED_SNEAK)
{
//
// This is a big change of speed!
//
PCOM_set_person_move_mav_to_thing(p_person, p_target, wantspeed);
}
}
else
{
PCOM_set_person_move_mav_to_thing(p_person, p_target, wantspeed);
}
}
}
//
// Extra boost if you're lagging behind!
//
if (p_person->Velocity < p_target->Velocity)
{
p_person->Velocity += 1;
}
}
}
//
// Don't stop moving if you're in the middle of doing some complicated thing.
//
if (p_person->State == STATE_GOTOING)
{
SLONG dx = abs(p_target->WorldPos.X - p_person->WorldPos.X >> 8);
SLONG dz = abs(p_target->WorldPos.Z - p_person->WorldPos.Z >> 8);
SLONG dist = QDIST2(dx,dz);
SLONG wantdist;
//
// If our target is moving we want to be really close!
//
if (p_target->SubState == SUB_STATE_RUNNING)
{
wantdist = 0x40;
}
else
{
wantdist = 0x80;
}
if (dist < wantdist)
{
//
// Pause for a while.
//
PCOM_set_person_move_pause(p_person);
if (p_target->SubState == SUB_STATE_CRAWLING ||
p_target->SubState == SUB_STATE_IDLE_CROUTCH ||
p_target->SubState == SUB_STATE_IDLE_CROUTCHING)
{
set_person_idle_croutch(p_person);
}
}
}
}
}
//
// Returns a place for the MIB to disappear and reappear to.
//
void PCOM_find_mib_appear_pos(
Thing *p_mib,
Thing *p_target,
SLONG *appear_x,
SLONG *appear_z)
{
}
#ifndef TARGET_DC
void draw_view_line(Thing *p_person,Thing *p_target)
{
#ifdef PSX
return;
#else
SLONG x1,y1,z1,x2,y2,z2;
SLONG dx,dy,dz;
SLONG len,step,count;
calc_sub_objects_position(p_person,p_person->Draw.Tweened->AnimTween,SUB_OBJECT_HEAD,&x1,&y1,&z1);
x1+=p_person->WorldPos.X>>8;
y1+=p_person->WorldPos.Y>>8;
z1+=p_person->WorldPos.Z>>8;
calc_sub_objects_position(p_target,p_target->Draw.Tweened->AnimTween,SUB_OBJECT_HEAD,&x2,&y2,&z2);
x2+=p_target->WorldPos.X>>8;
y2+=p_target->WorldPos.Y>>8;
z2+=p_target->WorldPos.Z>>8;
dx=x2-x1;
dy=y2-y1;
dz=z2-z1;
len=QDIST3(abs(dx),abs(dy),abs(dz));
#ifndef PSX
dx=(dx*20)/len;
dy=(dy*20)/len;
dz=(dz*20)/len;
count=(len/20)>>1;
#else
dx=(dx*40)/len;
dy=(dy*40)/len;
dz=(dz*40)/len;
count=(len/40)>>1;
#endif
for(step=0;step<count;step++)
{
//AENG_world_line(x1,y1,z1,2,0,x1+dx,y1+dy,z1+dz,2,0,TRUE);
AENG_world_line(x1,y1,z1,20,0xffffff,x1+dx,y1+dy,z1+dz,20,0xffffff,TRUE);
x1+=dx<<1;
y1+=dy<<1;
z1+=dz<<1;
}
#endif
}
#endif
void PCOM_process_navtokill(Thing *p_person)
{
SLONG dist;
SLONG hit_distance;
SLONG special;
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
if(p_target->State==STATE_DEAD && p_target->Genus.Person->PlayerID)
{
//
// the player is dead, he was my target!
//
PCOM_set_person_ai_investigate(p_person,p_target->WorldPos.X>>8,p_target->WorldPos.Z>>8);
return;
}
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
timer_bored=0;
if(p_person->State==STATE_JUMPING)
return;
if ((PTIME(p_person) & 0x7) == 0)
{
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
//
// If our target (i.e. Darci!) is doing something interesting,
// then don't attack her!
//
if (!PCOM_should_fake_person_attack_darci(p_person))
{
PCOM_set_person_ai_flee_person(p_person, NET_PERSON(0));
return;
}
}
}
//
// The distance we have to be from our target to start hitting her.
//
hit_distance = 240;
switch (p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_WAITING:
//
// Waiting for the player to get out of the cutscene...
//
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
if (!EWAY_stop_player_moving())
{
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
PCOM_MOVE_SPEED_RUN);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
}
else
if ((PTIME(p_person) & 0x3) == 0)
{
if ((Random() & 0x3) == 0)
{
//
// Another taunt!
//
set_face_thing(
p_person,
p_target);
PCOM_set_person_move_animation(p_person, ANIM_WANKER);
}
}
}
break;
case PCOM_AI_SUBSTATE_HUNTING_SLIDE:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Finished doing our sliding tackle.
//
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
PCOM_MOVE_SPEED_RUN);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
}
break;
case PCOM_AI_SUBSTATE_HUNTING:
if (p_target == NET_PERSON(0))
{
if (EWAY_stop_player_moving())
{
// if (((GAME_TURN + THING_NUMBER(p_person)) & 0x1f) == 8)
if (((PTIME(p_person)) & 0x1f) == 9)
{
//
// Wait for the player to stop being in the cutscene.
//
set_face_thing(
p_person,
p_target);
PCOM_set_person_move_animation(p_person, ANIM_WANKER);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_WAITING;
}
return;
}
}
if (p_person->State == STATE_IDLE ||
p_person->State == STATE_GUN ||
p_person->State == STATE_GOTOING)
{
//
// Don't navtokill outside your zone...
//
if (p_person->Genus.Person->pcom_zone)
{
if (!(p_person->Genus.Person->pcom_zone & PCOM_get_zone_for_position(p_target)))
{
//
// Our target is no longer in our zone...
//
if ((p_person->Genus.Person->pcom_zone & PCOM_get_zone_for_position(p_person->Genus.Person->HomeX,p_person->Genus.Person->HomeZ)))
{
//
// His Home is in the right zone
//
PCOM_set_person_ai_homesick(p_person);
return;
}
else
{
//
// This guys home isnt in his zone!, this is a level design error so clear his zone flag
//
p_person->Genus.Person->pcom_zone=0;
}
}
}
//
// Make a detour to pickup a gun...
//
#if PSX
// if (((GAME_TURN + (THING_NUMBER(p_person) << 4)) & 0x7f) == 0)
if (((PTIME(p_person)) & 0x7f) == 0)
#else
if (((PTIME(p_person)) & 0xff) == 0)
// if (((GAME_TURN + (THING_NUMBER(p_person) << 5)) & 0xff) == 0)
#endif
{
Thing *p_special = PCOM_is_there_an_item_i_should_get(p_person);
if (p_special)
{
PCOM_set_person_ai_getitem(
p_person,
p_special,
PCOM_MOVE_SPEED_RUN,
PCOM_EXCAR_NAVTOKILL,
p_person->Genus.Person->pcom_ai_arg);
return;
}
}
if (PCOM_person_has_any_sort_of_gun_with_ammo(p_person) && !is_person_ko(p_target))
{
SLONG check_look;
//
// I have a gun so only go into fight mode at the last second
//
hit_distance >>= 1;
//
// How often we check we can see enemy.
//
/*
if ((p_person->Genus.Person->pcom_bent & PCOM_BENT_KILL_ON_SIGHT))
{
check_look = PCOM_get_duration(2);
}
else
*/
{
check_look = PCOM_get_duration(5) - PCOM_get_duration100(GET_SKILL(p_person) << 1);
}
//
// Only check now and again to see if you can see enemy.
//
if (p_person->Genus.Person->pcom_ai_counter > check_look || p_person->Genus.Person->pcom_ai == PCOM_AI_SHOOT_DEAD)
{
if (p_target->Genus.Person->Mode == PERSON_MODE_FIGHT)// && !(p_person->Genus.Person->pcom_bent & PCOM_BENT_KILL_ON_SIGHT))
{
//
// Don't shoot the player if she is fighting someone (unless you are
// flagged as KILL_ON_SIGHT).
//
}
else
{
//
// If you are near enough and you can see your target, then take a pot-shot.
//
if (PCOM_get_dist_between(p_person, p_target) < 0x400 && can_a_see_b(p_person, p_target))
{
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_AIMING;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
break;
}
}
p_person->Genus.Person->pcom_ai_counter = 0;
}
}
//
// Near enough the player to attack?
//
dist = PCOM_get_dist_between(p_person, p_target);
//
// Fake killers, relieving boredom means there will only ever be one
//
if (p_person->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER)
{
if(dist>30<<8 || EWAY_stop_player_moving())
{
//
// I he gets too far from his target and not in view try a respawn
//
if (!(p_person->Flags & FLAGS_IN_VIEW))
{
p_person->Genus.Person->InsideRoom++; //for test puposes
p_person->Genus.Person->InsideRoom=240;
if(PCOM_do_regen(p_person))
return;
}
}
}
if (p_person->SubState == SUB_STATE_RUNNING &&
p_target->SubState == SUB_STATE_RUNNING)
{
if (p_person->Velocity >= 20 && dist < 0xc0)
{
if (p_person->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST)
{
//
// Fight test dummies don't perform sliding tackles.
//
}
else
{
//
// Fast enough and close enough. Do it less often to the player.
//
// if ((GAME_TURN & 0x7) == 0 || !p_target->Genus.Person->PlayerID)
if ((PTIME(p_person) & 0x7) == 0 || !p_target->Genus.Person->PlayerID)
{
//
// Must be able to see them to tackle them
//
if (can_a_see_b(p_person, p_target))
{
//
// Near enough to try a sliding tackle!
//
p_person->Velocity += 10;
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING_SLIDE;
PCOM_set_person_move_goto_thing_slide(p_person,p_target);
}
}
}
}
}
else
if (dist < hit_distance)
{
//
// Don't hit him if he is at a different level to me.
//
if (abs(p_person->WorldPos.Y - p_target->WorldPos.Y) < 0x7000)
{
SLONG x1;
SLONG y1;
SLONG z1;
SLONG x2;
SLONG y2;
SLONG z2;
//
// Start killing the target, only if there is a los between him and me.
//
x1 = p_person->WorldPos.X >> 8;
y1 = p_person->WorldPos.Y + 0x6000 >> 8;
z1 = p_person->WorldPos.Z >> 8;
x2 = p_target->WorldPos.X >> 8;
y2 = p_target->WorldPos.Y + 0x6000 >> 8;
z2 = p_target->WorldPos.Z >> 8;
if (there_is_a_los(
x1, y1, z1,
x2, y2, z2,
LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG |
LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
{
if ((p_target->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER)) && PCOM_person_has_any_sort_of_gun_with_ammo(p_person))
{
//
// Shoot people in cars if you have a gun...
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_AIMING;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
}
else
{
//
// If this person has a h2h weapon, he'll draw it now!
//
special = PCOM_person_has_any_sort_of_h2h(p_person);
if (p_person->Genus.Person->SpecialUse && TO_THING(p_person->Genus.Person->SpecialUse)->Genus.Special->SpecialType == special)
{
//
// He already has this weapon drawn.
//
special = NULL;
}
if (special)
{
//
// Draw a hand 2 hand combat weapon.
//
PCOM_set_person_move_draw_h2h(p_person,special);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_DRAW_H2H;
}
else
{
if (p_target->Genus.Person->Flags & FLAG_PERSON_DRIVING)
{
if (PCOM_person_has_any_sort_of_gun_with_ammo(p_person))
{
//
// Shoot people in cars if you have a gun...
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_AIMING;
p_person->Genus.Person->pcom_ai_counter = 0;
PCOM_set_person_move_still(p_person);
}
else
{
//
// No point having a fist fight with a car!
//
PCOM_set_person_ai_taunt(p_person, p_target);
}
}
else
{
PCOM_set_person_ai_kill_person(p_person, p_target);
}
}
}
}
}
}
}
break;
case PCOM_AI_SUBSTATE_AIMING:
if (p_target == NET_PERSON(0))
{
if (EWAY_stop_player_moving())
{
// if (((GAME_TURN + (THING_NUMBER(p_person) << 2)) & 0x1f) == 8)
if ((PTIME(p_person) & 0x1f) == 8)
{
//
// Wait for the player to stop being in the cutscene.
//
set_face_thing(
p_person,
p_target);
PCOM_set_person_move_animation(p_person, ANIM_WANKER);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_WAITING;
}
return;
}
}
if (PCOM_person_has_any_sort_of_gun(p_person))
{
if (!PCOM_person_has_gun_in_hand(p_person))
{
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Draw your gun.
//
PCOM_set_person_move_draw_gun(p_person);
}
p_person->Genus.Person->pcom_ai_counter = 0;
}
else
{
if (p_target->Genus.Person->PlayerID && EWAY_stop_player_moving())
{
//
// Don't shoot the player while there are stationary in a cutscene.
//
p_person->Genus.Person->pcom_ai_counter = 0;
}
//
// How quickly we shoot.
//
SLONG shoot_time;
shoot_time = PCOM_get_duration (get_rate_of_fire(p_person));
//
// shoot_time -= PCOM_get_duration100(GET_SKILL(p_person)<<2);
//
// I've made poeple shooting less accurate... so they can fire more often.
//
shoot_time -= shoot_time >> 2;
/*
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_KILL_ON_SIGHT)
{
//
// Always shoot if you are kill on sight.
//
}
else
*/
{
if (p_target->Genus.Person->Mode == PERSON_MODE_FIGHT)
{
//
// Don't shoot our target as often while he is in fight mode.
//
if (p_target->Genus.Person->Target == THING_NUMBER(p_person))
{
//
// This bloke is fighting me!
//
}
else
{
shoot_time <<= 1;
}
}
}
//
// If our target is running away from us!
//
if (p_target->Class == CLASS_PERSON && p_target->Genus.Person->Mode == PERSON_MODE_SPRINT)
{
//
// Stop people being able to sprint through the levels!
//
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
if (p_person->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD && p_target->Genus.Person->PlayerID==0)
{
shoot_time>>=2;
}
if(dist_to_target(p_person,p_target)< (10<<8) )
track_gun_sight(p_target,shoot_time-p_person->Genus.Person->pcom_ai_counter);
// ASSERT(dist_to_target(p_person,p_target)< (18<<8) );
#ifndef TARGET_DC
// (a) doesn't work and (b) doesn't look any good. So it's toast.
if(p_target->Genus.Person->PlayerID)
{
draw_view_line(p_person,p_target);
}
#endif
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_ANIMATION &&
p_person->Genus.Person->pcom_move_substate == PCOM_MOVE_SUBSTATE_SHOOT)
{
//
// Already shooting!
//
p_person->Genus.Person->pcom_ai_counter = 0;
}
else
{
// if(p_person->Genus.Person->pcom_ai == PCOM_AI_SHOOT_DEAD && !is_person_ko(p_target))
// shoot_time=0;
if (p_person->Genus.Person->pcom_ai_counter > shoot_time || p_person->Genus.Person->pcom_ai == PCOM_AI_SHOOT_DEAD)
{
//
// Time to shoot.
//
if (PCOM_get_dist_between(p_person, p_target) < 0x600 && can_a_see_b(p_person, p_target))
{
/*
//
// If you are being shot by a KILL_ON_SIGHT person, then you are
// going to die! Make the camera go to the person who is shooting.
//
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_KILL_ON_SIGHT)
{
if (GAME_cut_scene == 0)
{
if(p_person->Genus.Person->PlayerID)
{
FC_kill_player_cam(p_person);
}
}
}
*/
//
// Do we have any ammo left?
//
if (!PCOM_person_has_any_sort_of_gun_with_ammo(p_person))
{
//
// No ammo
//
//
// If you have no ammo then all this function does is play
// a click sound.
//
set_person_shoot(p_person,1);
//
// Put your gun away.
//
PCOM_set_person_move_gun_away(p_person);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NOMOREAMMO;
}
else
{
//
// Take a shot!
//
PCOM_set_person_move_shoot(p_person);
}
}
else
{
// CONSOLE_text("Too far away or can't see player.");
//
// Hunt down the player again so we can try to take another shot.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
PCOM_MOVE_SPEED_RUN);
}
p_person->Genus.Person->pcom_ai_counter = 0;
}
}
}
//
// Always face your target while aiming.
//
set_face_thing(p_person, p_target);
}
else
{
//
// may have had the gun kicked out of hand so go into hunting mode
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
PCOM_MOVE_SPEED_RUN);
}
break;
case PCOM_AI_SUBSTATE_NOMOREAMMO:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Finished putting our gun away- get hunting again!
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HUNTING;
PCOM_set_person_move_mav_to_thing(
p_person,
p_target,
PCOM_MOVE_SPEED_RUN);
}
break;
case PCOM_AI_SUBSTATE_DRAW_H2H:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Finished drawing our h2h weapon. Do we have to renav, or
// can we just start killing?
//
if (PCOM_get_dist_between(p_person, p_target) < 0x100 && can_a_see_b(p_person, p_target))
{
PCOM_set_person_ai_kill_person(p_person, p_target);
}
else
{
PCOM_set_person_ai_navtokill(p_person, p_target);
}
}
break;
default:
ASSERT(0);
break;
}
if (p_target->State == STATE_DEAD)
{
//
// Go back to do what you normally do.
//
PCOM_set_person_ai_normal(p_person);
}
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
void PCOM_process_findcar(Thing *p_person)
{
SLONG door;
Thing *p_vehicle = TO_THING(p_person->Genus.Person->pcom_ai_arg);
ASSERT(p_vehicle->Class == CLASS_VEHICLE);
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_GOTOCAR:
if (p_person->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER ||
p_person->Genus.Person->pcom_ai == PCOM_AI_DRIVER)
{
//
// These people don't want to get into a car driven by someone else!
//
if (p_vehicle->Genus.Vehicle->Driver)
{
PCOM_set_person_ai_findcar(p_person, NULL);
}
}
{
//
// Get into the car if nobody can see you and you've been near to the
// car for 20 gameturns.
//
if ((p_person->Flags & FLAGS_IN_VIEW) || PCOM_get_dist_between(p_person, p_vehicle) > 0x200)
{
p_person->Genus.Person->pcom_ai_counter = 0;
}
else
{
p_person->Genus.Person->pcom_ai_counter += 1;
}
extern SLONG in_right_place_for_car(Thing *p_person, Thing *p_vehicle, SLONG *door);
door = 0;
if (p_person->Genus.Person->pcom_ai_counter > 20 || in_right_place_for_car(p_person, p_vehicle, &door))
{
//
// We can get into a car! Lets do it.
//
ASSERT(door == 0 || door == 1);
PCOM_set_person_move_getincar(p_person, p_vehicle, FALSE, door);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GETINCAR;
p_person->Genus.Person->pcom_ai_counter = 0;
}
}
break;
case PCOM_AI_SUBSTATE_GETINCAR:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// We have got in the car... what now?
//
// if ( ((GAME_TURN & 0xf)==(THING_NUMBER(p_person)&0xf)) || PCOM_are_there_people_who_want_to_enter(p_vehicle))
//
// don't use ptime we want this to happen quick
//
#ifdef PSX
if ( ((GAME_TURN & 0x7)==(THING_NUMBER(p_person)&0x7)) || PCOM_are_there_people_who_want_to_enter(p_vehicle))
#else
if ( ((GAME_TURN & 0xf)==(THING_NUMBER(p_person)&0xf)) || PCOM_are_there_people_who_want_to_enter(p_vehicle))
#endif
// if ( ((PTIME(p_person) & 0xf)==0) || PCOM_are_there_people_who_want_to_enter(p_vehicle))
{
// every 16 game turns is false, except what if we arent processed on that game turn due to time slice, so ignore bottom 2 bits
//
// Wait a while...
//
}
else
{
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
}
}
else
{
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(40))
{
//
// We've spent a long time. Maybe there's a problem with getting into this car!
//
PCOM_set_person_ai_findcar(p_person, p_person->Genus.Person->pcom_ai_arg);
}
}
break;
default:
ASSERT(0);
break;
}
}
#ifdef BIKE
void PCOM_process_findbike(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
Thing *p_bike;
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_GOTOBIKE:
p_bike = TO_THING(p_person->Genus.Person->pcom_ai_arg);
//
// Near enough to the bike yet?
//
dx = abs(p_bike->WorldPos.X - p_person->WorldPos.X >> 8);
dz = abs(p_bike->WorldPos.Z - p_person->WorldPos.Z >> 8);
dist = QDIST2(dx,dz);
if (dist < 0x90)
{
//
// Get onto the bike.
//
set_person_mount_bike(p_person, p_bike);
//
// Do our normal thing.
//
p_person->Genus.Person->pcom_ai_state = PCOM_AI_STATE_NORMAL;
p_person->Genus.Person->pcom_ai_substate = 0;
p_person->Genus.Person->pcom_ai_counter = 0;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_NONE;
}
break;
default:
ASSERT(0);
break;
}
}
#endif
//
// Somebody who is talking.
//
void PCOM_process_talk(Thing *p_person)
{
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// The person stopped talking.
//
if (p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER)
{
//
// He was flagged as NO_RETURN_TO_NORMAL...
//
}
else
{
PCOM_set_person_ai_normal(p_person);
}
}
}
void PCOM_process_hands_up(Thing *p_person)
{
Thing *p_cop;
p_cop=TO_THING(p_person->Genus.Person->pcom_ai_arg);
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if(p_person->Genus.Person->pcom_ai_counter>PCOM_get_duration(20))
{
//
// after 20 seconds start looking to see if we are safe now.
//
if(p_cop->Genus.Person->Target!=THING_NUMBER(p_person) || (p_cop->State!=STATE_GUN && p_cop->SubState!=SUB_STATE_RUNNING))
{
//
// cop is now ignoring me
//
PCOM_set_person_ai_normal(p_person);
}
}
}
//
// Somebody who wants to get into a vehicle as a passenger.
//
void PCOM_process_hitch(Thing *p_person)
{
SLONG door;
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_GOTOCAR:
{
Thing *p_vehicle = TO_THING(p_person->Genus.Person->pcom_ai_arg);
ASSERT(p_vehicle->Class == CLASS_VEHICLE);
//
// Get into the car if nobody can see you and you've been near to the
// car for 20 gameturns.
//
if ((p_person->Flags & FLAGS_IN_VIEW) || PCOM_get_dist_between(p_person, p_vehicle) > 0x200)
{
p_person->Genus.Person->pcom_ai_counter = 0;
}
else
{
p_person->Genus.Person->pcom_ai_counter += 1;
}
extern SLONG in_right_place_for_car(Thing *p_person, Thing *p_vehicle, SLONG *door);
if (p_person->Genus.Person->pcom_ai_counter > 20 || in_right_place_for_car(p_person, p_vehicle, &door))
{
//
// We can get into a car! Lets do it.
//
PCOM_set_person_move_getincar(p_person, p_vehicle, TRUE, door);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_GETINCAR;
p_person->Genus.Person->pcom_ai_counter = 0;
}
}
break;
case PCOM_AI_SUBSTATE_GETINCAR:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// We have got in the car...
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_HITCHING;
}
break;
case PCOM_AI_SUBSTATE_HITCHING:
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_FOLLOW)
{
SLONG i_target = EWAY_get_person(p_person->Genus.Person->pcom_move_follow);
Thing *p_target = TO_THING(i_target);
ASSERT(p_target->Class == CLASS_PERSON);
if (!(p_target->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_PASSENGER)))
{
PCOM_set_person_ai_leavecar(p_person, PCOM_EXCAR_NORMAL, 0, 0);
return;
}
}
else
{
//
// What is the condition for exiting the vehicle?
//
ASSERT(0);
}
break;
default:
ASSERT(0);
break;
}
}
//
// Somebody who is knocked out.
//
void PCOM_process_knockedout(Thing *p_person)
{
if (!(p_person->Genus.Person->Flags & FLAG_PERSON_KO))
{
//
// The person has recovered.
//
PCOM_set_person_ai_normal(p_person);
}
}
void PCOM_process_taunt(Thing *p_person)
{
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
//
// Always face who you are taunting.
//
set_face_thing(
p_person,
p_target);
// if ((GAME_TURN & 0x7) == 0)
if ((PTIME(p_person) & 0x7) == 0)
{
if (!can_a_see_b(p_person, p_target))
{
//
// Don't taunt people you can't see!
//
PCOM_set_person_ai_normal(p_person);
return;
}
}
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
if (p_person->Genus.Person->pcom_zone && (PCOM_get_zone_for_position(p_person) & p_person->Genus.Person->pcom_zone))
{
//
// Is are target in our zone? If he is then kill him!
//
if (PCOM_get_zone_for_position(p_target) & p_person->Genus.Person->pcom_zone)
{
PCOM_set_person_ai_kill_person(p_person, p_target);
return;
}
}
else
{
//
// Shall we kill him?
//
if (Random() & 0x1)
{
PCOM_set_person_ai_kill_person(p_person, p_target);
return;
}
}
//
// Pause for a while.
//
PCOM_set_person_move_pause(p_person);
//
// This is how long we are going to pause for.
//
p_person->Genus.Person->pcom_ai_counter = PCOM_get_duration(Random() & 0xf);
break;
case PCOM_MOVE_STATE_PAUSE:
//
// Finished pausing?
//
if (p_person->Genus.Person->pcom_move_counter > p_person->Genus.Person->pcom_ai_counter)
{
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
//
// Lazy people dont taunt.
//
PCOM_set_person_move_still(p_person);
}
else
{
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLEE);
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLE_HELD);
// MFX_play_thing(THING_NUMBER(p_person),S_WANKER,MFX_REPLACE,p_person);
PCOM_set_person_move_animation(p_person, ANIM_WANKER);
}
}
break;
case PCOM_MOVE_STATE_ANIMATION:
if (p_person->Genus.Person->pcom_zone)
{
//
// Is are target in our zone? If he is then kill him!
//
if (PCOM_get_zone_for_position(p_target) & p_person->Genus.Person->pcom_zone)
{
PCOM_set_person_ai_kill_person(p_person, p_target);
return;
}
}
break;
default:
ASSERT(0);
break;
}
}
//
// Processes a cop trying to arrest someone!
//
void PCOM_process_arrest(Thing *p_person)
{
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
if (p_target->State == STATE_DEAD)
{
//
// No point arresting a dead person!
//
PCOM_set_person_ai_normal(p_person);
return;
}
//
// What if you are navigating to him!
//
/*
//
// Always face who you are arresting.
//
set_face_thing(
p_person,
p_target);
*/
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
/*
if(!is_person_ko(p_person))
if (!p_target->Genus.Person->PlayerID)
{
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLEE);
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLE_HELD);
//
// Make our target call us a wanker! (If they aren't a player!)
//
MFX_play_thing(THING_NUMBER(p_target),S_BLOODYPIGS,MFX_REPLACE,p_target);
PCOM_set_person_ai_taunt(p_target, p_person);
PCOM_oscillate_tympanum(
PCOM_SOUND_WANKER,
p_person,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8);
}
*/
//
// Wait for a while.
//
PCOM_set_person_move_pause(p_person);
break;
case PCOM_MOVE_STATE_PAUSE:
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(10))
{
//
// Start killing our target.
//
PCOM_set_person_ai_kill_person(
p_person,
p_target);
return;
}
break;
case PCOM_MOVE_STATE_GOTO_THING:
//
// Near enough yet?
//
if (PCOM_get_dist_between(p_person, p_target) < 0x200)
{
//
// Stand still.
//
PCOM_set_person_move_still(p_person);
}
break;
default:
ASSERT(0);
break;
}
}
//
// Processes someone going home.
//
void PCOM_process_homesick(Thing *p_person)
{
if (PCOM_finished_nav(p_person))
{
//
// Do what you normally do at home.
//
PCOM_set_person_ai_normal(p_person);
}
}
void PCOM_process_bdeactivate(Thing *p_person)
{
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_GOTOBOMB:
if (PCOM_finished_nav(p_person))
{
//
// Got to the bomb. Start deactivating it now.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_CUTWIRES;
p_person->Genus.Person->pcom_ai_counter = 0;
//
// Don't move while deactivating the bomb- its a tricky and intricate operation!
//
PCOM_set_person_move_still(p_person);
}
break;
case PCOM_AI_SUBSTATE_CUTWIRES:
//
// Make the person turn- (to show he is doing something)
//
p_person->Draw.Tweened->Angle += 32;
if (p_person->Genus.Person->pcom_ai_counter >= PCOM_get_duration(100))
{
//
// Deactivated the bomb. (Hurrah!)
//
Thing *p_bomb = TO_THING(p_person->Genus.Person->pcom_ai_arg);
p_bomb->SubState = SPECIAL_SUBSTATE_NONE;
//
// Do what you normally do now.
//
PCOM_set_person_ai_normal(p_person);
}
else
{
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
break;
default:
ASSERT(0);
break;
}
}
void PCOM_process_leavecar(Thing *p_person)
{
Thing *p_vehicle;
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_STILL:
//
// Finished getting out of the car.
//
switch(p_person->Genus.Person->pcom_ai_excar_state)
{
case PCOM_EXCAR_NORMAL:
PCOM_set_person_ai_normal(p_person);
break;
case PCOM_EXCAR_FLEE_PERSON:
PCOM_set_person_ai_flee_person(p_person, TO_THING(p_person->Genus.Person->pcom_ai_excar_arg));
break;
case PCOM_EXCAR_ARREST_PERSON:
PCOM_set_person_ai_arrest(p_person, TO_THING(p_person->Genus.Person->pcom_ai_excar_arg));
break;
default:
ASSERT(0);
break;
}
break;
case PCOM_MOVE_STATE_PARK_CAR:
case PCOM_MOVE_STATE_PARK_CAR_ON_ROAD:
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
if (p_vehicle->Velocity == 0)
{
//
// We can start getting out the car now.
//
PCOM_set_person_move_leavecar(p_person);
}
break;
case PCOM_MOVE_STATE_ANIMATION:
break;
default:
ASSERT(0);
break;
}
}
void PCOM_process_snipe(Thing *p_person)
{
#ifndef PSX
//
// Some friendly debug code.
//
if (p_person->Genus.Person->pcom_ai_arg == NULL)
{
//
// Nobody to kill!
//
#ifndef FINAL
//PANEL_new_text(p_person, 0, "Assassin (stand still) has no target");
#endif
p_person->Genus.Person->pcom_ai = PCOM_AI_NONE;
PCOM_set_person_ai_normal(p_person);
return;
}
#endif
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_LOOK:
//
// Can we see our target?
//
p_person->Genus.Person->Target = NULL;
if (!PCOM_person_has_any_sort_of_gun_with_ammo(p_person))
{
//
// Not much to do without ammo.
//
}
else
{
if (can_a_see_b(p_person, p_target))
{
//
// Take a shot.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_AIMING;
p_person->Genus.Person->pcom_ai_counter = 0;
}
else
{
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
p_person->Genus.Person->Target = NULL;
/*
//
// Snipers keep your gun out MD
//
if (p_person->Genus.Person->pcom_ai_counter > PCOM_get_duration(10))
{
//
// No need to have your gun out.
//
if (p_person->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
{
//
// Put your gun away.
//
PCOM_set_person_move_gun_away(p_person);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NOMOREAMMO;
}
}
*/
}
}
break;
case PCOM_AI_SUBSTATE_AIMING:
p_person->Genus.Person->Target = THING_NUMBER(p_target);
if (!person_has_gun_or_grenade_out(p_person))
{
//
// Draw your gun.
//
if (p_person->Genus.Person->pcom_move_state != PCOM_MOVE_STATE_ANIMATION)
{
PCOM_set_person_move_draw_gun(p_person);
}
}
else
{
if (PCOM_get_dist_between(p_person, p_target) < 0x600 && can_a_see_b(p_person, p_target))
{
//
// How quickly we shoot.
//
SLONG shoot_time;
shoot_time = PCOM_get_duration (get_rate_of_fire(p_person));
shoot_time -= PCOM_get_duration100(GET_SKILL(p_person)<<2);
if (p_person->Genus.Person->pcom_ai_counter > shoot_time || p_person->Genus.Person->pcom_ai == PCOM_AI_SHOOT_DEAD)
{
if (p_person->Genus.Person->Ammo == 0)
{
//
// If you have no ammo then all this function does is play
// a click sound.
//
set_person_shoot(p_person,1);
//
// Put your gun away.
//
PCOM_set_person_move_gun_away(p_person);
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_NOMOREAMMO;
}
else
{
//
// Take a shot!
//
p_person->Genus.Person->Target=THING_NUMBER(p_target);
PCOM_set_person_move_shoot(p_person);
p_person->Genus.Person->pcom_ai_counter = 0;
}
}
else
{
p_person->Genus.Person->pcom_ai_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
//
// Always face the target while sniping.
//
set_face_thing(p_person, p_target);
}
else
{
//
// Start looking again...
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LOOK;
}
}
break;
case PCOM_AI_SUBSTATE_NOMOREAMMO:
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Finished putting our gun away- get sniping again!
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LOOK;
p_person->Genus.Person->pcom_ai_counter = 0;
}
break;
default:
ASSERT(0);
break;
}
}
void PCOM_process_warm_hands(Thing *p_person)
{
SLONG i_fire;
Thing *p_fire;
switch(p_person->Genus.Person->pcom_ai_substate)
{
case PCOM_AI_SUBSTATE_GOTOFIRE:
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_PAUSE:
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(10))
{
//
// Look for a nearby fire.
//
i_fire = THING_find_nearest(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x300,
1 << CLASS_PYRO);
if (i_fire)
{
//
// Start going to this bit of fire.
//
p_person->Genus.Person->pcom_ai_arg = i_fire;
PCOM_set_person_move_mav_to_thing(p_person, TO_THING(i_fire), PCOM_MOVE_SPEED_WALK);
}
else
{
//
// Carry on waiting for some nice warm fire.
//
PCOM_set_person_move_pause(p_person);
}
}
break;
case PCOM_MOVE_STATE_GOTO_THING:
p_fire = TO_THING(p_person->Genus.Person->pcom_ai_arg);
if (PCOM_get_dist_between(p_person, p_fire) < 0xa0)
{
//
// Don't get too close! Start warming our hands about the fire.
//
p_person->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_WARMUP;
set_face_thing(p_person, p_fire);
PCOM_set_person_move_still(p_person);
}
break;
}
break;
case PCOM_AI_SUBSTATE_WARMUP:
p_fire = TO_THING(p_person->Genus.Person->pcom_ai_arg);
if (p_fire->Class != CLASS_PYRO)
{
//
// This fire must have gone out- better get looking for another one.
//
PCOM_set_person_ai_warm_hands(p_person);
}
else
{
//
// Every now and again play a warm-your-hands animation.
//
}
break;
default:
ASSERT(0);
break;
}
}
SLONG person_drawn_recently(Thing *p_person)
{
return p_person->Flags & FLAGS_IN_VIEW;
}
//
// Processes normal behaviour
//
void PCOM_teleport_home(Thing *p_person)
{
GameCoord pos;
pos.X=p_person->Genus.Person->HomeX<<8;
pos.Y=p_person->WorldPos.Y;
pos.Z=p_person->Genus.Person->HomeZ<<8;
move_thing_on_map(p_person,&pos);
p_person->Draw.Tweened->Angle = p_person->Genus.Person->HomeYaw << 3;
}
void PCOM_process_normal(Thing *p_person)
{
UWORD i_target;
Thing *p_target;
SLONG dist;
switch(p_person->Genus.Person->pcom_move)
{
case PCOM_MOVE_STILL:
case PCOM_MOVE_DANCE:
case PCOM_MOVE_HANDS_UP:
case PCOM_MOVE_TIED_UP:
if (p_person->State == STATE_MOVEING && (p_person->SubState == SUB_STATE_SIMPLE_ANIM || p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER))
{
//
// This person is busy sitting down or dancing!
//
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_STILL)
{
//
// Still people shouldn't be doing an animation... unless they
// are sitting down.
//
if (p_person->Draw.Tweened->CurrentAnim == ANIM_SIT_DOWN ||
p_person->Draw.Tweened->CurrentAnim == ANIM_SIT_IDLE ||
p_person->Draw.Tweened->CurrentAnim == ANIM_IDLE_SCRATCH2)
{
//
// Stay sitting down or wiping your brow.
//
}
else
{
if ((PTIME(p_person) & 0x3) == 0)
// if (((THING_NUMBER(p_person) + GAME_TURN) & 0x3) == 0)
{
//
// Wipe your brow...
//
PCOM_set_person_move_animation(p_person, ANIM_IDLE_SCRATCH2);
}
else
{
//
// Stand still without doing a silly animation.
//
PCOM_set_person_move_still(p_person);
}
}
}
}
else
{
//
// Still people constantly check their distance from home
//
dist = PCOM_get_dist_from_home(p_person);
if (dist > 256)
{
//
// Go back home before standing around.
//
PCOM_set_person_ai_homesick(p_person);
}
else
{
//
// Make sure they are facing in the right direction.
//
p_person->Draw.Tweened->Angle = p_person->Genus.Person->HomeYaw << 3;
if (dist > PCOM_ARRIVE_DIST)
{
if (!person_drawn_recently(p_person))
{
PCOM_teleport_home(p_person);
}
}
else
{
//
// This person is at home. Does he want to do a special animation?
//
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_DANCE ||
p_person->Genus.Person->pcom_move == PCOM_MOVE_HANDS_UP ||
p_person->Genus.Person->pcom_move == PCOM_MOVE_TIED_UP)
{
UWORD anim;
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_DANCE)
{
//
// Start dancing!
//
static UWORD dance_anim[4] =
{
ANIM_DANCE_BOOGIE,
ANIM_DANCE_WOOGIE,
ANIM_DANCE_HEADBANG,
ANIM_DANCE_BOOGIE
};
anim = dance_anim[THING_NUMBER(p_person) & 0x3];
}
else
{
//
// Tied up and hands up both do hands up...
//
anim = ANIM_HANDS_UP;
}
PCOM_set_person_move_animation(p_person, anim);
//
// This flag means that after the person has done the simple anim once, they
// won't go to STATE_IDLE but will carry on animating in SUBSTATE SUB_STATE_SIMPLE_ANIM_OVER
//
p_person->Genus.Person->Flags |= FLAG_PERSON_NO_RETURN_TO_NORMAL;
}
else
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_LAZY)
{
if ((p_person->SubState == SUB_STATE_SIMPLE_ANIM) ||
(p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER))
{
// already sitting down ...
break;
}
// if ((GAME_TURN & 0x3f) == 0)
if ((PTIME(p_person) & 0x3f) == 0)
{
//
// Look for a nearby bench or sofa thats not too far away.
//
#define PCOM_MAX_BENCH_WALK 0x200
SLONG mx;
SLONG mz;
SLONG mx1;
SLONG mz1;
SLONG mx2;
SLONG mz2;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG best_x;
SLONG best_y;
SLONG best_z;
SLONG best_yaw;
SLONG best_prim = NULL;
SLONG best_dist = PCOM_MAX_BENCH_WALK;
OB_Info *oi;
mx1 = (p_person->WorldPos.X >> 8) - PCOM_MAX_BENCH_WALK >> PAP_SHIFT_LO;
mz1 = (p_person->WorldPos.Z >> 8) - PCOM_MAX_BENCH_WALK >> PAP_SHIFT_LO;
mx2 = (p_person->WorldPos.X >> 8) + PCOM_MAX_BENCH_WALK >> PAP_SHIFT_LO;
mz2 = (p_person->WorldPos.Z >> 8) + PCOM_MAX_BENCH_WALK >> PAP_SHIFT_LO;
for (mx = mx1; mx <= mx2; mx++)
for (mz = mz1; mz <= mz2; mz++)
{
for (oi = OB_find(mx,mz); oi->prim; oi++)
{
if (oi->prim == PRIM_OBJ_PARK_BENCH ||
oi->prim == PRIM_OBJ_SOFA ||
oi->prim == PRIM_OBJ_ARMCHAIR)
{
dx = oi->x - (p_person->WorldPos.X >> 8);
dy = oi->y - (p_person->WorldPos.Y >> 8);
dz = oi->z - (p_person->WorldPos.Z >> 8);
dist = abs(dx) + abs(dz) + abs(dy + dy);
if (best_dist > dist)
{
best_prim = oi->prim;
best_dist = dist;
best_x = oi->x;
best_y = oi->y;
best_z = oi->z;
best_yaw = oi->yaw;
}
}
}
}
if (best_prim)
{
//
// This person want to sit on the prim! Teleport him to the right place.
//
if (PCOM_position_person_to_sit_on_prim(
p_person,
best_prim,
best_x,
best_y,
best_z,
best_yaw,
person_drawn_recently(p_person)))
{
//
// Sit him down.
//
PCOM_set_person_move_animation(p_person, ANIM_SIT_DOWN);
//
// This flag means that after the person has done the simple anim once, they
// won't go to STATE_IDLE but will carry on animating in SUBSTATE SUB_STATE_SIMPLE_ANIM_OVER
//
p_person->Genus.Person->Flags |= FLAG_PERSON_NO_RETURN_TO_NORMAL;
}
}
}
}
else
if (p_person->Genus.Person->pcom_ai == PCOM_AI_GUARD)
{
//
// Make guards draw their gun! (As long as they haven't got a pistol)
//
if (PCOM_person_has_any_sort_of_gun(p_person) && !(p_person->Flags & FLAGS_HAS_GUN))
{
if (!PCOM_person_has_gun_in_hand(p_person))
{
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_STILL)
{
//
// Draw your gun.
//
PCOM_set_person_move_draw_gun(p_person);
}
}
}
}
}
}
}
break;
case PCOM_MOVE_PATROL:
case PCOM_MOVE_PATROL_RAND:
PCOM_process_patrol(p_person);
break;
case PCOM_MOVE_WANDER:
PCOM_process_wander(p_person);
break;
case PCOM_MOVE_FOLLOW:
if (p_person->Genus.Person->pcom_ai_substate == PCOM_AI_SUBSTATE_CANTFIND)
{
if ((GAME_TURN & 0xf) == 0)
// if ((PTIME(p_person) & 0xf) == 0)
{
i_target = EWAY_get_person(p_person->Genus.Person->pcom_move_follow);
if (i_target)
{
if (can_a_see_b(p_person, TO_THING(i_target)))
{
PCOM_set_person_ai_follow(p_person, TO_THING(i_target));
}
}
}
else
{
PCOM_process_wander(p_person);
}
}
else
{
i_target = EWAY_get_person(p_person->Genus.Person->pcom_move_follow);
if (i_target)
{
PCOM_set_person_ai_follow(p_person, TO_THING(i_target));
}
}
break;
case PCOM_MOVE_WARM_HANDS:
if (PCOM_get_dist_from_home(p_person) > 0x200)
{
//
// Go back home before standing around- to make sure we find the
// correct barrel to warm our hands over.
//
PCOM_set_person_ai_homesick(p_person);
}
else
{
PCOM_set_person_ai_warm_hands(p_person);
}
break;
case PCOM_MOVE_FOLLOW_ON_SEE:
//
// If this person is near to who he is following, then change
// state to PCOM_MOVE_FOLLOW.
//
i_target = EWAY_get_person(p_person->Genus.Person->pcom_move_follow);
if (i_target)
{
if (PCOM_get_dist_between(p_person, TO_THING(i_target)) < 0x200)
{
if (can_a_see_b(p_person, TO_THING(i_target)))
{
//
// Start following this person.
//
p_person->Genus.Person->pcom_move = PCOM_MOVE_FOLLOW;
}
}
}
break;
default:
ASSERT(0);
break;
}
}
//
// Looks for an active bomb that the person can see.
//
UWORD PCOM_find_bomb(Thing *p_person)
{
SLONG i;
SLONG score;
SLONG best_thing;
SLONG best_score;
Thing *p_found;
PCOM_found_num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x300,
PCOM_found,
PCOM_MAX_FIND,
1 << CLASS_SPECIAL);
best_score = +INFINITY;
best_thing = NULL;
for (i = 0; i < PCOM_found_num ; i++)
{
p_found = TO_THING(PCOM_found[i]);
if (p_found->Genus.Special->SpecialType == SPECIAL_BOMB &&
p_found->SubState == SPECIAL_SUBSTATE_ACTIVATED)
{
if (can_a_see_b(p_person, p_found))
{
score = THING_dist_between(p_person, p_found);
if (score < best_score)
{
best_score = score;
best_thing = PCOM_found[i];
}
}
}
}
return best_thing;
}
//
// Does the default processing for a person.
//
void PCOM_process_default(Thing *p_person)
{
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
PCOM_process_normal(p_person);
break;
case PCOM_AI_STATE_INVESTIGATING:
PCOM_process_investigating(p_person);
break;
case PCOM_AI_STATE_SEARCHING:
break;
case PCOM_AI_STATE_KILLING:
PCOM_process_killing(p_person);
break;
case PCOM_AI_STATE_SLEEPING:
break;
case PCOM_AI_STATE_FLEE_PLACE:
case PCOM_AI_STATE_FLEE_PERSON:
PCOM_process_fleeing(p_person);
break;
case PCOM_AI_STATE_FOLLOWING:
PCOM_process_following(p_person);
break;
case PCOM_AI_STATE_NAVTOKILL:
PCOM_process_navtokill(p_person);
break;
case PCOM_AI_STATE_HOMESICK:
PCOM_process_homesick(p_person);
break;
case PCOM_AI_STATE_LOOKAROUND:
break;
case PCOM_AI_STATE_FINDCAR:
PCOM_process_findcar(p_person);
break;
case PCOM_AI_STATE_BDEACTIVATE:
PCOM_process_bdeactivate(p_person);
break;
case PCOM_AI_STATE_LEAVECAR:
PCOM_process_leavecar(p_person);
break;
case PCOM_AI_STATE_SNIPE:
PCOM_process_snipe(p_person);
break;
case PCOM_AI_STATE_WARM_HANDS:
PCOM_process_warm_hands(p_person);
break;
#ifdef BIKE
case PCOM_AI_STATE_FINDBIKE:
PCOM_process_findbike(p_person);
break;
#endif
case PCOM_AI_STATE_KNOCKEDOUT:
PCOM_process_knockedout(p_person);
break;
case PCOM_AI_STATE_TAUNT:
PCOM_process_taunt(p_person);
break;
case PCOM_AI_STATE_ARREST:
PCOM_process_arrest(p_person);
break;
case PCOM_AI_STATE_TALK:
PCOM_process_talk(p_person);
break;
case PCOM_AI_STATE_HITCH:
PCOM_process_hitch(p_person);
break;
case PCOM_AI_STATE_AIMLESS:
PCOM_process_wander(p_person);
break;
case PCOM_AI_STATE_HANDS_UP:
PCOM_process_hands_up(p_person);
break;
case PCOM_AI_STATE_GETITEM:
PCOM_process_getitem(p_person);
break;
default:
ASSERT(0);
break;
}
}
//
// Alerts all nearby MIB / Guards / Gangs to attack / fight test... including the person himself.
//
void PCOM_alert_nearby_mib_to_attack(Thing *p_person)
{
{
SLONG i;
SLONG num_found;
Thing *p_found;
//
// Alerts all nearby MIB to attack- including yourself!
//
num_found = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x500,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_PERSON);
for (i = 0; i < num_found; i++)
{
p_found = TO_THING(THING_array[i]);
if (p_found->Genus.Person->pcom_ai == PCOM_AI_MIB ||
p_found->Genus.Person->pcom_ai == PCOM_AI_GUARD ||
p_found->Genus.Person->pcom_ai == PCOM_AI_GANG ||
p_found->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST)
{
if (!(p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS))
{
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING)
{
PCOM_set_person_ai_navtokill(p_found, NET_PERSON(0));
}
}
}
}
}
}
//
// Returns who a bodyguard should be attacking...
//
Thing *PCOM_find_bodyguard_victim(Thing *p_bodyguard, Thing *p_client)
{
SLONG i;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG num_found;
SLONG best_score = INFINITY;
Thing *best_victim = NULL;
Thing *p_found;
num_found = THING_find_sphere(
p_bodyguard->WorldPos.X >> 8,
p_bodyguard->WorldPos.Y >> 8,
p_bodyguard->WorldPos.Z >> 8,
0x800,
THING_array,
THING_ARRAY_SIZE,
1 << CLASS_PERSON);
for (i = 0; i < num_found; i++)
{
p_found = TO_THING(THING_array[i]);
if (is_person_dead(p_found))
{
continue;
}
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL)
{
if (p_found->Genus.Person->pcom_ai_arg == THING_NUMBER(p_client) ||
p_found->Genus.Person->pcom_ai_arg == THING_NUMBER(p_bodyguard))
{
//
// This person is attacking me or my client.
//
dx = p_found->WorldPos.X - p_bodyguard->WorldPos.X;
dy = p_found->WorldPos.Y - p_bodyguard->WorldPos.Y;
dz = p_found->WorldPos.Z - p_bodyguard->WorldPos.Z;
dist = abs(dx) + abs(dz) + abs(dy << 1);
if (p_client->Genus.Person->Target == THING_array[i])
{
//
// If our client is already having a go at one of them be more
// likely to attack one of the other ones.
//
dist <<= 2;
}
if (is_person_ko(p_found))
{
//
// Knocked out people aren't much of a threat!
//
dist <<= 1;
}
if (dist < best_score)
{
best_score = dist;
best_victim = p_found;
}
}
}
}
return best_victim;
}
void PCOM_process_state_change(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG home_x;
SLONG home_z;
SLONG bomb;
Thing *p_target;
SLONG i_target;
//
// Nobody has their gun out by default...
//
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
if ((p_person->Flags & FLAGS_HAS_GUN) && (p_person->Genus.Person->Flags & FLAG_PERSON_GUN_OUT))
{
if (p_person->Genus.Person->pcom_move_state != PCOM_MOVE_STATE_ANIMATION ||
p_person->Genus.Person->pcom_move_substate != PCOM_MOVE_SUBSTATE_GUNAWAY)
{
PCOM_set_person_move_gun_away(p_person);
}
return;
}
}
if ((p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING) &&
p_person->Genus.Person->pcom_ai != PCOM_AI_DRIVER &&
p_person->Genus.Person->pcom_ai != PCOM_AI_COP_DRIVER &&
p_person->Genus.Person->pcom_ai_state != PCOM_AI_STATE_LEAVECAR)
{
//
// A non-driver doesn't want to be driving a car.
//
PCOM_set_person_ai_leavecar(p_person, PCOM_EXCAR_NORMAL, 0, 0);
}
switch(p_person->Genus.Person->pcom_ai)
{
case PCOM_AI_NONE:
break;
case PCOM_AI_CIV:
PCOM_process_default(p_person);
/*
if (((GAME_TURN + THING_NUMBER(p_person)) & 0xff) == 0)
{
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS)
{
//
// Civs remember nasty people.
//
if (p_person->Genus.Person->pcom_ai_memory && !EWAY_stop_player_moving())
{
Thing *p_nasty = TO_THING(p_person->Genus.Person->pcom_ai_memory);
if (PCOM_get_dist_between(
p_person,
p_nasty) < 0x120)
{
PCOM_set_person_ai_talk_to(
p_person,
p_nasty,
PCOM_AI_SUBSTATE_TALK_TELL,
FALSE);
if (p_nasty->Genus.Person->PlayerID && p_nasty->Genus.Person->PersonType == PERSON_DARCI)
{
PANEL_new_text(p_person, 4000, EWAY_get_fake_wander_message(EWAY_FAKE_MESSAGE_ANNOYED));
}
}
}
}
}
*/
break;
case PCOM_AI_GUARD:
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NAVTOKILL:
{
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_ai_arg);
if (PCOM_get_dist_between(p_person, p_target) > 20 * 0x100)
{
//
// Too far from our target... just give up!
//
PCOM_set_person_ai_normal(p_person);
return;
}
}
if (p_person->Genus.Person->pcom_zone)
{
//
// Just do normal processing for navtokill. The zone code will stop
// us going too far away from where we are meant to be.
//
PCOM_process_navtokill(p_person);
}
else
if (p_person->Genus.Person->pcom_move == PCOM_MOVE_WANDER)
{
//
// Wandering people don't check how far they are from home.
//
PCOM_process_navtokill(p_person);
}
else
{
//
// If the guard is too far from home, then return to guard whatever
// he's guarding.
//
home_x = p_person->Genus.Person->HomeX; //<< 8;
home_z = p_person->Genus.Person->HomeZ; //<< 8;
dist = PCOM_person_dist_from(
p_person,
home_x,
home_z);
if (dist > 16 * 0x100) // If more than sixteen mapsquares away
{
//
// Start going home.
//
PCOM_set_person_ai_homesick(p_person);
}
else
{
//
// Just do normal processing for navtokill.
//
PCOM_process_navtokill(p_person);
}
}
break;
default:
PCOM_process_default(p_person);
break;
}
// if ((GAME_TURN & 0x3) == 0)
if ((PTIME(p_person) & 0x3) == 0)
{
SLONG look = FALSE;
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK)
{
look = TRUE;
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING)
{
if (p_person->Genus.Person->pcom_ai_substate == PCOM_AI_SUBSTATE_SUPRISED)
{
look = (p_person->Genus.Person->pcom_ai_counter >= PCOM_get_duration(4));
}
else
{
look = TRUE;
}
}
if (look)
{
//
// Can you see the player?
//
p_target = PCOM_can_i_see_person_to_attack(p_person);
if (p_target)
{
//
// Tell nearby people to attack the player too!
//
PCOM_alert_nearby_mib_to_attack(p_person);
if(p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
// cant navigate to enemy so taunt
PCOM_set_person_ai_taunt(p_person, p_target);
}
// else //play wav anyway MikeD
{
#ifndef PSX
/*
if(((GAME_TURN+THING_NUMBER(p_person))&255)==0)
MFX_play_thing(THING_NUMBER(p_person),S_HEY_YOU,MFX_REPLACE,p_person);
*/
#endif
}
PCOM_oscillate_tympanum(
PCOM_SOUND_HEY,
p_person,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8);
//
// Put my health on screen in an available slot
//
//track_enemy(p_person);
}
}
}
break;
case PCOM_AI_ASSASIN:
case PCOM_AI_SHOOT_DEAD:
if (p_person->Genus.Person->pcom_ai_other == NULL)
{
#ifndef NDEBUG
CONSOLE_text("Assasin has no target");
#endif
}
else
{
if (p_person->Genus.Person->pcom_ai_other == NULL)
{
#ifndef NDEBUG
CONSOLE_text("Assasin waypoint has no person associated with it");
#endif
}
else
{
i_target = EWAY_get_person(p_person->Genus.Person->pcom_ai_other);
if (i_target)
{
p_target = TO_THING(i_target);
if (is_person_dead(p_target))
{
//
// Assasins change once they've killed their targets.
//
p_person->Genus.Person->pcom_ai = PCOM_AI_GANG;
p_person->Genus.Person->pcom_move = PCOM_MOVE_WANDER;
PCOM_set_person_ai_normal(p_person);
return;
}
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
switch(p_person->Genus.Person->pcom_move)
{
case PCOM_MOVE_STILL:
PCOM_set_person_ai_snipe(p_person, p_target);
break;
case PCOM_MOVE_PATROL:
case PCOM_MOVE_PATROL_RAND:
case PCOM_MOVE_WANDER:
#ifndef NDEBUG
CONSOLE_text("An assasin on patrol or wander acts like a sniper");
#endif
p_person->Genus.Person->pcom_move = PCOM_MOVE_STILL;
break;
case PCOM_MOVE_FOLLOW:
PCOM_set_person_ai_navtokill(p_person, p_target);
break;
}
break;
default:
PCOM_process_default(p_person);
break;
}
}
else
{
//
// This assasin has no target yet...
//
PCOM_process_default(p_person);
}
}
}
break;
case PCOM_AI_BOSS:
PCOM_process_default(p_person);
break;
case PCOM_AI_COP:
PCOM_process_default(p_person);
break;
case PCOM_AI_GANG:
PCOM_process_default(p_person);
{
SLONG look = FALSE;
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_INVESTIGATING)
{
if (p_person->Genus.Person->pcom_ai_substate == PCOM_AI_SUBSTATE_SUPRISED)
{
look = (p_person->Genus.Person->pcom_ai_counter >= PCOM_get_duration(4));
}
else
{
look = TRUE;
}
}
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK)
{
look = TRUE;
}
if (look)
{
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLEE);
ASSERT(p_person->SubState!=SUB_STATE_GRAPPLE_HELD);
if ((PTIME(p_person) & 0x7) == 0)
// if ((GAME_TURN & 0x7) == 0)
{
//
// Can I see somebody worth taunting?
//
p_target = PCOM_can_i_see_person_to_taunt(p_person);
if (p_target)
{
//
// Start taunting the person. If the person makes any sort of
// come on. Then the taunt AI will start killing the person.
//
PCOM_set_person_ai_taunt(p_person, p_target);
PCOM_oscillate_tympanum(
PCOM_SOUND_WANKER,
p_person,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8);
return;
}
}
}
}
break;
case PCOM_AI_DOORMAN:
PCOM_process_default(p_person);
break;
case PCOM_AI_BODYGUARD:
{
UWORD i_client = EWAY_get_person(p_person->Genus.Person->pcom_ai_other);
Thing *p_client = NULL;
if (i_client)
{
p_client = TO_THING(i_client);
}
p_person->Genus.Person->Flags2 &= ~FLAG2_PERSON_INVULNERABLE;
if (p_client && p_client->Genus.Person->PlayerID)
{
SLONG dx = abs(p_client->WorldPos.X - p_person->WorldPos.X);
SLONG dy = abs(p_client->WorldPos.Y - p_person->WorldPos.Y);
SLONG dz = abs(p_client->WorldPos.Z - p_person->WorldPos.Z);
SLONG dist = QDIST3(dx,dy,dz);
if (dist > 20 * 0x10000)
{
//
// More than twenty blocks from the player! Turn invulnerable.
//
p_person->Genus.Person->Flags2 |= FLAG2_PERSON_INVULNERABLE;
}
}
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
case PCOM_AI_STATE_FOLLOWING:
{
//
// Is our client under attack?
//
if (p_client)
{
Thing *p_target = PCOM_find_bodyguard_victim(p_person, p_client);
if (p_target)
{
//
// What's you upto mate!
//
// MFX_play_thing(THING_NUMBER(p_person),S_OIGUVNOR,MFX_REPLACE,p_person);
//
// Kill the person who is trying to kill our client.
//
PCOM_set_person_ai_navtokill(p_person, p_target);
}
}
}
//
// Fall-through to default processing.
//
default:
PCOM_process_default(p_person);
break;
}
}
break;
case PCOM_AI_COP_DRIVER:
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
/*
if ((GAME_TURN & 0x7) == 0)
{
p_target = PCOM_can_i_see_person_to_arrest(p_person);
if (p_target)
{
//
// Make the target wanted by the police.
//
p_target->Genus.Person->Flags |= FLAG_PERSON_FELON;
//
// Exit the car and once you've got out, arrest the person.
//
PCOM_set_person_ai_leavecar(
p_person,
PCOM_EXCAR_ARREST_PERSON,
0,
THING_NUMBER(p_target));
}
}
*/
}
//
// FALLTHROUGH to driving code
//
case PCOM_AI_DRIVER:
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
//
// Are we in are car?
//
if (!(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING))
{
//
// Find any old car and get into it.
//
PCOM_set_person_ai_findcar(p_person, NULL);
}
else
{
//
// Start driving around.
//
switch(p_person->Genus.Person->pcom_move)
{
case PCOM_MOVE_STILL:
PCOM_process_driving_still(p_person);
break;
case PCOM_MOVE_PATROL:
case PCOM_MOVE_PATROL_RAND:
PCOM_process_driving_patrol(p_person);
break;
case PCOM_MOVE_FOLLOW:
break;
case PCOM_MOVE_WANDER:
PCOM_process_driving_wander(p_person);
break;
default:
ASSERT(0);
break;
}
}
break;
default:
PCOM_process_default(p_person);
break;
}
break;
case PCOM_AI_BDISPOSER:
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
PCOM_process_normal(p_person);
//
// If he can see a bomb- then go over to it and deactivate it!
//
bomb = PCOM_find_bomb(p_person);
if (bomb)
{
PCOM_set_person_ai_bdeactivate(p_person, TO_THING(bomb));
}
break;
case PCOM_AI_STATE_FOLLOWING:
PCOM_process_following(p_person);
//
// If he can see a bomb- then go over to it and deactivate it!
//
bomb = PCOM_find_bomb(p_person);
if (bomb)
{
PCOM_set_person_ai_bdeactivate(p_person, TO_THING(bomb));
}
break;
default:
PCOM_process_default(p_person);
break;
}
break;
case PCOM_AI_BIKER:
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
#ifdef BIKE
//
// Are we on a bike?
//
if (!(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING))
{
//
// Find a bike and get onto it.
//
PCOM_set_person_ai_findbike(p_person);
}
else
#endif
{
//
// Start driving around.
//
switch(p_person->Genus.Person->pcom_move)
{
case PCOM_MOVE_STILL:
PCOM_process_driving_still(p_person);
break;
case PCOM_MOVE_PATROL:
case PCOM_MOVE_PATROL_RAND:
PCOM_process_driving_patrol(p_person);
break;
case PCOM_MOVE_FOLLOW:
break;
case PCOM_MOVE_WANDER:
PCOM_process_driving_wander(p_person);
break;
default:
ASSERT(0);
break;
}
}
break;
default:
PCOM_process_default(p_person);
break;
}
break;
case PCOM_AI_FIGHT_TEST:
if (p_person->Genus.Person->pcom_ai_other & PCOM_COMBAT_COMBO_KKK)
{
combo_display=2;
}
else
if (p_person->Genus.Person->pcom_ai_other & PCOM_COMBAT_COMBO_PPP)
{
combo_display=1;
}
PCOM_process_default(p_person);
if (!(p_person->Genus.Person->pcom_bent & PCOM_BENT_ROBOT))
{
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS)
{
if (PCOM_get_dist_between(p_person, NET_PERSON(0)) < 0x200)
{
PCOM_alert_nearby_mib_to_attack(p_person); // Not just MIBs!
}
}
}
break;
case PCOM_AI_BULLY:
// if(Keys[KB_B])
// FC_cam[0].focus = p_person;
PCOM_process_default(p_person);
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOWING ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS)
{
if ((PTIME(p_person) & 0x7) == 0)
// if ((GAME_TURN & 0x7) == 0)
{
//
// Can I see somebody worth bullying?
//
p_target = PCOM_can_i_see_person_to_bully(p_person);
if (p_target)
{
//
// Start killing the person.
//
PCOM_set_person_ai_kill_person(p_person, p_target);
return;
}
}
}
break;
case PCOM_AI_SUICIDE:
//
// The easiest AI! A random death.
//
p_person->Genus.Person->Health = 0;
set_person_dead(
p_person,
NULL,
PERSON_DEATH_TYPE_SHOT_PISTOL,//was combat
Random() & 0x1,
Random() % 3);
if (GAME_TURN < 32)
{
SLONG c0;
for(c0=0;c0<100;c0++)
{
if(p_person->StateFn)
p_person->StateFn(p_person);
}
}
// while(person_normal_animate(p_person)==0);
break;
case PCOM_AI_FLEE_PLAYER:
switch(p_person->Genus.Person->pcom_ai_state)
{
case PCOM_AI_STATE_NORMAL:
case PCOM_AI_STATE_HOMESICK:
//
// Is this person too near Darci?
//
if (PCOM_get_dist_between(p_person, NET_PERSON(0)) < 0x600)
{
PCOM_set_person_ai_flee_person(p_person, NET_PERSON(0));
}
//
// FALL-THROUGH TO DEFAULT PROCESSING!
//
default:
PCOM_process_default(p_person);
break;
}
break;
case PCOM_AI_KILL_COLOUR:
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
//
// Look for someone of the given colour to kill!
//
UWORD list;
SLONG dist;
SLONG best_dist = INFINITY;
Thing *best_target = NULL;
Thing *p_found;
list = thing_class_head[CLASS_PERSON];
SLONG hate_colour;
SLONG hate_example;
hate_example = EWAY_get_person(p_person->Genus.Person->pcom_ai_other);
if (hate_example)
{
Thing *p_example = TO_THING(hate_example);
ASSERT(p_example->Class == CLASS_PERSON);
hate_colour = p_example->Genus.Person->pcom_colour;
while(list)
{
p_found = TO_THING(list);
list = p_found->NextLink;
if (p_found->Genus.Person->pcom_colour == hate_colour && !is_person_dead(p_found) && !(p_found->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER))
{
if (p_person->Genus.Person->pcom_zone)
{
//
// Ignore people that aren't in your zone.
//
if (!(PCOM_get_zone_for_position(p_found->WorldPos.X >> 8, p_found->WorldPos.Z >> 8) & p_person->Genus.Person->pcom_zone))
{
continue;
}
}
//
// He hates this person!
//
dist = PCOM_get_dist_between(p_person, p_found);
if (best_dist > dist)
{
best_dist = dist;
best_target = p_found;
}
}
}
if (best_target)
{
PCOM_set_person_ai_kill_person(p_person, best_target);
}
/*
else
{
//
// Nothing more for this person to do!
//
if (p_person->Genus.Person->PersonType == PERSON_COP)
{
p_person->Genus.Person->pcom_ai = PCOM_AI_COP;
}
else
{
p_person->Genus.Person->pcom_ai = PCOM_AI_CIV;
p_person->Genus.Person->pcom_bent |= PCOM_BENT_FIGHT_BACK;
}
}
*/
}
}
PCOM_process_default(p_person);
break;
case PCOM_AI_MIB:
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
//
// Kills the player on sight.
//
if (can_a_see_b(p_person, NET_PERSON(0))&&!stealth_debug)
{
PCOM_alert_nearby_mib_to_attack(p_person);
}
}
PCOM_process_default(p_person);
break;
case PCOM_AI_BANE:
if (p_person->Genus.Person->pcom_ai_state != PCOM_AI_STATE_SUMMON)
{
PCOM_set_person_ai_summon(p_person);
}
PCOM_process_summon(p_person);
break;
case PCOM_AI_HYPOCHONDRIA:
//
// Easy peasy AI!
//
set_person_injured(p_person);
break;
default:
ASSERT(0);
break;
}
#if SANITY_PREVAILED
//
// MASTER OVERRIDE! If you are racist and see someone of the colour
// you hate...
//
if (p_person->Genus.Person->Flags & FLAG_PERSON_RACIST)
{
if (((THING_NUMBER(p_person) + GAME_TURN) & 0xf) == 0)
{
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FOLLOW)
{
SLONG i;
Thing *p_found;
//
// If you can see someone you hate...
//
PCOM_found_num = THING_find_sphere(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x600,
PCOM_found,
PCOM_MAX_FIND,
1 << CLASS_PERSON);
for (i = 0; i < PCOM_found_num; i++)
{
p_found = TO_THING(PCOM_found[i]);
if (p_found->Genus.Person->colour == p_person->Genus.Person->hate_colour)
{
//
// He hates this person!
//
if (can_a_see_b(p_person, p_found))
{
PCOM_set_person_ai_kill_person(p_person, p_found);
}
}
}
}
}
}
#endif
}
//
// For a person driving a car.. this function looks ahead of the car and
// returns what actions you should take to avoid any obsticles.
//
#define PCOM_RUNOVER_STOP (1 << 0)
#define PCOM_RUNOVER_BEEP_HORN (1 << 1)
#define PCOM_RUNOVER_SHOUT_OUT (1 << 2)
#define PCOM_RUNOVER_TURN_LEFT (1 << 3)
#define PCOM_RUNOVER_TURN_RIGHT (1 << 4)
#define PCOM_RUNOVER_SLOW_DOWN (1 << 5)
#define PCOM_RUNOVER_RUNAWAY (1 << 6) // Get our of the car and peg-it!
#define PCOM_RUNOVER_REVERSE (1 << 7)
Thing *PCOM_runover_scary_person;
// no messing here, -ve dangle means turning LEFT as most people would imagine it would
SLONG PCOM_find_runover_thing(Thing *p_person, SLONG dangle)
{
SLONG i;
SLONG dx;
SLONG dz;
SLONG px;
SLONG pz;
SLONG cx;
SLONG cz;
SLONG x1;
SLONG z1;
SLONG x2;
SLONG z2;
SLONG what;
SLONG dist;
SLONG cprod;
SLONG angle;
#define PCOM_RUNOVER_FIND 8
UWORD found[PCOM_RUNOVER_FIND];
SLONG num;
SLONG velocity;
Thing* p_vehicle;
Vehicle* veh;
Thing* p_found;
Vehicle* v_found;
ASSERT(p_person->Genus.Person->Flags & (FLAG_PERSON_DRIVING | FLAG_PERSON_BIKING));
p_vehicle = TO_THING(p_person->Genus.Person->InCar);
veh = p_vehicle->Genus.Vehicle;
//
// Find all the things in front of the vehicle.
//
num = VEH_find_runover_things(p_vehicle, found, PCOM_RUNOVER_FIND, dangle);
//
// The movement vector and speed of the vehicle.
//
switch(p_vehicle->Class)
{
case CLASS_VEHICLE:
angle = p_vehicle->Genus.Vehicle->Angle & 2047;
velocity = Root((veh->VelX >> 4) * (veh->VelX >> 4) + (veh->VelZ >> 4) * (veh->VelZ >> 4)) >> 4;
break;
case CLASS_BIKE:
angle = p_vehicle->Draw.Mesh->Angle & 2047;
velocity = 0;
break;
default:
ASSERT(0);
break;
}
dx = -SIN(angle) >> 8;
dz = -COS(angle) >> 8;
//
// get some info
//
SLONG wx = p_vehicle->WorldPos.X >> 8;
SLONG wz = p_vehicle->WorldPos.Z >> 8;
SLONG onroad = ROAD_is_road(wx >> 8, wz >> 8);
// find nearest road
SLONG rn1;
SLONG rn2;
if ((p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_DRIVE_DOWN) ||
(p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PARK_CAR_ON_ROAD))
{
rn1 = p_person->Genus.Person->pcom_move_arg & 0xFF;
rn2 = (p_person->Genus.Person->pcom_move_arg >> 8) & 0xFF;
}
else
{
ROAD_find(wx, wz, &rn1, &rn2);
}
// get side
SLONG rd = ROAD_signed_dist(rn1, rn2, wx, wz);
// find nearest node
SLONG nn;
SLONG nnd;
nn = ROAD_nearest_node(rn1, rn2, wx, wz, &nnd);
#if 0
SLONG col;
if (nnd < AT_JUNCTION) col = 0xFF0000;
else if (nnd < NEAR_JUNCTION) col = 0xFFFF00;
else col = 0x00FF00;
AENG_world_line(p_person->WorldPos.X >> 8, p_person->WorldPos.Y >> 8, p_person->WorldPos.Z >> 8, 16, col,
p_person->WorldPos.X >> 8, (p_person->WorldPos.Y >> 8) + 0x100, p_person->WorldPos.Z >> 8, 0, col,
TRUE);
#endif
// set action to none
what = 0;
// if we're near a junction, add objects
SLONG orig_num = num;
if (nnd < NEAR_JUNCTION)
{
SLONG jx,jz;
ROAD_node_pos(nn, &jx, &jz);
if ((jx - wx) * dx + (jz - wz) * dz > 0)
{
// approaching it
num += THING_find_sphere(jx, p_person->WorldPos.Y >> 8, jz, JN_RADIUS_IN, found + num, PCOM_RUNOVER_FIND - num, (1 << CLASS_PERSON) | (1 << CLASS_VEHICLE));
what = PCOM_RUNOVER_SLOW_DOWN;
}
}
// remove self from list
for (i = 0; i < num; i++)
{
if ((found[i] == THING_NUMBER(p_person)) || (found[i] == THING_NUMBER(p_vehicle)))
{
found[i] = found[--num];
}
}
// check objects in list
for (i = 0; i < num; i++)
{
p_found = TO_THING(found[i]);
#if 0
#define BLOCKED(C) AENG_world_line(p_person->WorldPos.X >> 8, p_person->WorldPos.Y >> 8, p_person->WorldPos.Z >> 8, 16, C, \
p_found->WorldPos.X >> 8, p_found->WorldPos.Y >> 8, p_found->WorldPos.Z >> 8, 16, C, TRUE);
#else
#define BLOCKED(C)
#endif
if ((p_found->Class == CLASS_PERSON) && (p_found->State == STATE_DYING || p_found->State == STATE_DEAD))
{
// Ignore dead or dying people
continue;
}
// if it's on a junction, check dot product
if (num >= orig_num)
{
SLONG vx = (p_found->WorldPos.X - p_person->WorldPos.X) >> 8;
SLONG vz = (p_found->WorldPos.Z - p_person->WorldPos.Z) >> 8;
if (vx * dx + vz * dz < 0) continue; // behind you!
}
BLOCKED(0x0000FF);
// if we're on the road ...
if (onroad)
{
// then ignore off-road things
if (!ROAD_is_road(p_found->WorldPos.X >> 16, p_found->WorldPos.Z >> 16)) continue;
// find which road the thing is on
SLONG trn1;
SLONG trn2;
ROAD_find(p_found->WorldPos.X >> 8, p_found->WorldPos.Z >> 8, &trn1, &trn2);
// find nearest node
SLONG tnn;
SLONG tnnd;
tnn = ROAD_nearest_node(trn1, trn2, p_found->WorldPos.X >> 8, p_found->WorldPos.Z >> 8, &tnnd);
//
// handle junctions
//
//#if 0
if ((nnd < AT_JUNCTION) && (p_found->Class == CLASS_VEHICLE))
{
// *on* the junction
if ((tnnd < AT_JUNCTION) && (tnn == nn) && (ROAD_node_degree(nn) > 2))
{
// another car is on the junction
if (p_vehicle < p_found)
{
// reverse back to make room
BLOCKED(0x888888);
return PCOM_RUNOVER_REVERSE;
}
}
// ignore other cars when we're *on* the junction
continue;
}
//#endif
if ((nnd < NEAR_JUNCTION) && (p_found->Class == CLASS_VEHICLE) &&
(tnn ==nn) && (ROAD_node_degree(nn) > 2))
{
// near junction, looking at a car on the same junction, not a bend
if (tnnd < AT_JUNCTION)
{
// stop if approaching a busy junction
BLOCKED(0x888888);
return PCOM_RUNOVER_STOP;
}
else if (tnnd < NEAR_JUNCTION)
{
// stop if both approaching and other car is nearer
if (tnnd < nnd)
{
BLOCKED(0x888888);
return PCOM_RUNOVER_STOP;
}
}
}
if (nnd > AT_JUNCTION)// && (abs(dangle) < 32))
{
// look at the side of the road we're both on
// (only take this into account away from junctions, and when we aren't turning)
if (((rn1 == trn1) && (rn2 == trn2)) ||
((rn1 == trn2) && (rn2 == trn1)))
{
SLONG trd = ROAD_signed_dist(rn1, rn2, p_found->WorldPos.X >> 8, p_found->WorldPos.Z >> 8);
if (abs(trd - rd) > 0xC0) continue;
}
}
}
switch(p_found->Class)
{
case CLASS_PERSON:
if (p_found->OnFace) break; // ignore people on cars
if ((veh->Type != VEH_TYPE_VAN) && (veh->Type != VEH_TYPE_AMBULANCE) && (veh->Type != VEH_TYPE_WILDCATVAN))
{
// can't hijack vans or ambulances
if ((p_found->Genus.Person->Flags & FLAG_PERSON_GUN_OUT) ||
(p_found->Genus.Person->SpecialUse))
{
// person has a gun out
SLONG angle = calc_angle(dx,dz);
SLONG dangle = p_found->Draw.Tweened->Angle - angle;
if (abs(dangle) < 256)
{
// pointing it in our direction
if (veh->Flags & FLAG_VEH_SHOT_AT)
{
// and shooting it!
if (Random() & 0x08)
{
// scared!
PCOM_runover_scary_person = p_found;
BLOCKED(0x888888);
return PCOM_RUNOVER_STOP | PCOM_RUNOVER_RUNAWAY;
}
else
{
// not scared
veh->Flags &= ~FLAG_VEH_SHOT_AT;
}
}
}
}
}
if (ROAD_is_zebra(
p_found->WorldPos.X >> 16,
p_found->WorldPos.Z >> 16))
{
// Always stop for people on zebra crossings...
BLOCKED(0x888888);
return PCOM_RUNOVER_STOP;
}
else
{
BLOCKED(0x888888);
switch(((GAME_TURN) + THING_NUMBER(p_vehicle)) & 0x7f)
{
case 0: return PCOM_RUNOVER_STOP | PCOM_RUNOVER_BEEP_HORN;
case 25: return PCOM_RUNOVER_STOP | PCOM_RUNOVER_SHOUT_OUT;
default: return PCOM_RUNOVER_STOP;
}
}
break;
case CLASS_VEHICLE:
{
v_found = p_found->Genus.Vehicle;
SLONG vel = Root((v_found->VelX >> 4) * (v_found->VelX >> 4) + (v_found->VelZ >> 4) * (v_found->VelZ >> 4)) >> 4;
//
// Do we stop for a car in front of us or do we try and drive around?
//
SLONG avoid = FALSE;
// avoid parked (driverless) cars and dead cars
if (!v_found->Driver) avoid = TRUE;
if ((p_found->State == STATE_DYING) || (p_found->State == STATE_DEAD)) avoid = TRUE;
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_DILIGENT)
{
//
// Diligent people are in a hurry!
//
avoid = TRUE;
}
if (avoid)
{
if (vel < (velocity >> 2))
{
#if 0
//
// This car is parked or going much slower than us! Try and avoid it.
//
px = p_found->WorldPos.X - p_vehicle->WorldPos.X >> 8;
pz = p_found->WorldPos.Z - p_vehicle->WorldPos.Z >> 8;
cprod = px*dz - pz*dx;
if (cprod < 0)
{
what |= PCOM_RUNOVER_TURN_LEFT;
}
else
{
what |= PCOM_RUNOVER_TURN_RIGHT;
}
#endif
// no, just stop
BLOCKED(0x888888);
return PCOM_RUNOVER_STOP;
}
else //if (vel < velocity)
{
BLOCKED(0xFF0000);
return PCOM_RUNOVER_STOP;
}
}
else
{
// if (vel < velocity)
{
BLOCKED(0x00FF00);
return PCOM_RUNOVER_STOP;
}
}
}
break;
default:
ASSERT(0);
break;
}
}
return what;
}
void PCOM_process_movement(Thing *p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG what;
SLONG dest_x;
SLONG dest_z;
SLONG goal_x;
SLONG goal_z;
SLONG ladder;
SLONG wangle;
SLONG dangle;
SLONG wspeed;
SLONG dspeed;
SLONG dlane;
SLONG renav = FALSE;
Thing *p_vehicle;
Thing *p_target;
Thing *p_bike;
#ifdef BIKE
BIKE_Control bc;
#endif
SLONG steer;
SLONG accel;
//
// Low-level movement.
//
if(p_person->State==STATE_DYING||p_person->State==STATE_DEAD)
return;
//
// High-level movement states.
//
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_PLAYER:
break;
case PCOM_MOVE_STATE_STILL:
if (p_person->SubState==SUB_STATE_GRAPPLE_HELD)
{
p_person->Genus.Person->pcom_move_state=PCOM_MOVE_STATE_GRAPPLE;
}
break;
case PCOM_MOVE_STATE_GOTO_THING_SLIDE:
//
// Finished sliding?
//
if (p_person->State == STATE_IDLE ||
p_person->State == STATE_GUN && p_person->SubState == SUB_STATE_AIM_GUN)
{
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
}
else
{
//
// Make sure we always slide towards our target.
//
ASSERT(p_person->Genus.Person->pcom_move_arg);
turn_towards_thing(p_person, TO_THING(p_person->Genus.Person->pcom_move_arg));
}
break;
case PCOM_MOVE_STATE_GOTO_XZ:
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
case PCOM_MOVE_STATE_GOTO_THING:
if (p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
break;
}
switch(p_person->Genus.Person->pcom_move_substate)
{
case PCOM_MOVE_SUBSTATE_GOTO:
//
// Arrived at our sub-goal?
//
PCOM_get_mav_action_pos(
p_person,
&goal_x,
&goal_z);
#ifndef PSX
#ifndef TARGET_DC
if (ControlFlag&&allow_debug_keys)
{
AENG_world_line(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
16,
0x00ffff00,
goal_x,
p_person->WorldPos.Y >> 8,
goal_z,
0,
0x000000ff,
TRUE);
}
#endif
#endif
/*
goal_x &= 0xffffff00;
goal_z &= 0xffffff00;
goal_x |= 0x80;
goal_z |= 0x80;
*/
dist = PCOM_person_dist_from(
p_person,
goal_x,
goal_z);
if (dist < PCOM_ARRIVE_DIST)
{
if (p_person->Genus.Person->pcom_move_ma.action == MAV_ACTION_GOTO)
{
//
// Nothing more to do for this subgoal. Initialise a renavigation.
//
renav = TRUE;
}
else
{
//
// We've arrived but we have to do another action. Make sure we are
// pointing in the correct direction.
//
p_person->Draw.Tweened->AngleTo =
p_person->Draw.Tweened->Angle =
PCOM_get_angle_for_dir(p_person->Genus.Person->pcom_move_ma.dir);
//
// Initialise the action.
//
switch(p_person->Genus.Person->pcom_move_ma.action)
{
case MAV_ACTION_JUMP:
case MAV_ACTION_JUMPPULL:
case MAV_ACTION_JUMPPULL2:
set_person_running_jump(p_person);
break;
case MAV_ACTION_PULLUP:
set_person_running_jump(p_person);
break;
case MAV_ACTION_CLIMB_OVER:
set_person_running_jump(p_person);
break;
case MAV_ACTION_FALL_OFF:
set_person_walking(p_person);
break;
case MAV_ACTION_LADDER_UP:
//
// Look for a nearby ladder.
//
ladder = find_nearby_ladder_colvect(p_person);
if (ladder)
{
set_person_climb_ladder(p_person, ladder);
}
else
{
ASSERT(0);
}
break;
default:
ASSERT(0);
break;
}
//
// Process the action.
//
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ACTION;
}
}
else
{
if (p_person->State == STATE_DANGLING &&
p_person->SubState == SUB_STATE_DANGLING)
{
//
// Ended up falling and dangling off of somewhere.
//
set_person_pulling_up(p_person);
}
else
if (p_person->Genus.Person->SlideOdd >= 50)
{
if (p_person->Genus.Person->pcom_ai == PCOM_AI_CIV &&
p_person->Genus.Person->pcom_move == PCOM_MOVE_WANDER &&
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL)
{
//
// Wandering civs don't jump!
//
}
else
{
//
// We've slid along something odd for 50 consecutive gameturns.
// EMERGENCY! Take evasive action.
//
set_person_running_jump(p_person);
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_ACTION;
p_person->Genus.Person->SlideOdd = 0;
}
}
else
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(20))
{
//
// We had better renav! We might be in trouble.
//
if ((p_person->State == STATE_GOTOING) ||
(p_person->State == STATE_GUN && p_person->SubState == SUB_STATE_AIM_GUN) ||
(p_person->State == STATE_IDLE))
{
renav = TRUE;
}
else
{
//
// Don't renav in the middle of a complicated manouvre (like climbing a ladder or jumping)
//
}
}
}
break;
case PCOM_MOVE_SUBSTATE_ACTION:
switch(p_person->State)
{
case STATE_MOVEING:
if (p_person->SubState == SUB_STATE_RUNNING)
{
//
// Running after completing a jump.
//
renav = TRUE;
}
break;
case STATE_IDLE:
//
// Stopped doing anything- it must be time for a renavigation!
//
renav = TRUE;
break;
case STATE_LANDING:
case STATE_JUMPING:
case STATE_FIGHTING:
case STATE_FALLING:
case STATE_USE_SCENERY:
case STATE_DOWN:
case STATE_HIT:
case STATE_CHANGE_LOCATION:
case STATE_DYING:
case STATE_DEAD:
break;
case STATE_DANGLING:
if (p_person->SubState == SUB_STATE_DANGLING)
{
switch(p_person->Genus.Person->pcom_move_ma.action)
{
case MAV_ACTION_JUMPPULL:
case MAV_ACTION_JUMPPULL2:
case MAV_ACTION_PULLUP:
set_person_pulling_up(p_person);
break;
default:
set_person_drop_down(p_person, PERSON_DROP_DOWN_OFF_FACE);
break;
}
}
else
if (p_person->SubState == SUB_STATE_DANGLING_CABLE)
{
//
// Should never be on a cable!
//
set_person_drop_down(p_person, PERSON_DROP_DOWN_OFF_FACE);
}
break;
case STATE_CLIMB_LADDER:
//
// If you've finished getting on the ladder,
// then start climbing up it.
//
if (p_person->SubState == SUB_STATE_ON_LADDER)
{
p_person->SubState = SUB_STATE_CLIMB_UP_LADDER;
}
break;
case STATE_HIT_RECOIL:
break;
case STATE_CLIMBING:
if (p_person->SubState == SUB_STATE_STOPPING || p_person->SubState == SUB_STATE_CLIMB_AROUND_WALL)
{
if (p_person->Genus.Person->pcom_move_ma.action == MAV_ACTION_CLIMB_OVER)
{
//
// Climb over.
//
p_person->SubState = SUB_STATE_CLIMB_UP_WALL;
}
else
{
//
// Shouldn't be on a fence.
//
set_person_drop_down(p_person, 0);
}
}
break;
case STATE_GUN:
if (p_person->SubState == SUB_STATE_AIM_GUN)
{
//
// Stopped doing anything- it must be time for a renavigation!
//
renav = TRUE;
}
break;
case STATE_SHOOT:
case STATE_DRIVING:
case STATE_NAVIGATING:
case STATE_WAIT:
case STATE_FIGHT:
case STATE_STAND_UP:
case STATE_MAVIGATING:
case STATE_GRAPPLING:
break;
case STATE_GOTOING:
break;
default:
ASSERT(0);
break;
}
break;
case PCOM_MOVE_SUBSTATE_LOSMAV:
{
ASSERT(p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_GOTO_THING);
Thing *p_target = TO_THING(p_person->Genus.Person->pcom_move_arg);
if (!PCOM_should_i_try_to_los_mav_to_person(p_person, p_target))
{
//
// We should try proper mavigation!
//
renav = TRUE;
}
else
{
//
// Update where this person want to be going to.
//
p_person->Genus.Person->GotoX = p_target->WorldPos.X >> 8;
p_person->Genus.Person->GotoZ = p_target->WorldPos.Z >> 8;
}
if (p_person->State == STATE_IDLE)
{
//
// Something happened to this bloke! Get him moving again.
//
renav = TRUE;
}
}
break;
default:
ASSERT(0);
break;
}
if (renav)
{
if (p_person->SubState == SUB_STATE_PULL_UP ||
p_person->SubState == SUB_STATE_CLIMB_OFF_LADDER_TOP)
{
//
// Don't renav while doing this...
//
}
else
{
//
// Time for a renavigation.
//
PCOM_renav(p_person);
}
}
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
break;
case PCOM_MOVE_STATE_PAUSE:
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
break;
case PCOM_MOVE_STATE_WAIT_CIRCLE:
if ((p_person->State == STATE_IDLE && p_person->SubState != SUB_STATE_IDLE_CROUTCH_ARREST) ||
(p_person->StateFn == NULL))
{
//
// The animation is over.
//
set_person_recircle(p_person);
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_CIRCLE;
}
else
if(p_person->State == STATE_FIGHTING && (p_person->SubState == SUB_STATE_GRAPPLE_HOLD || p_person->SubState == SUB_STATE_GRAPPLE_HELD))
{
//
// The animation is over.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GRAPPLE;
}
break;
case PCOM_MOVE_STATE_ANIMATION:
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if ((p_person->State == STATE_IDLE && p_person->SubState != SUB_STATE_IDLE_CROUTCH_ARREST) ||
(p_person->State == STATE_GUN && p_person->SubState == SUB_STATE_AIM_GUN) ||
(p_person->State == STATE_MOVEING && p_person->SubState == SUB_STATE_INSIDE_VEHICLE) ||
(p_person->State == STATE_MOVEING && p_person->SubState == SUB_STATE_SIMPLE_ANIM_OVER && p_person->Genus.Person->pcom_move != PCOM_MOVE_DANCE && p_person->Genus.Person->pcom_move != PCOM_MOVE_HANDS_UP && p_person->Genus.Person->pcom_move != PCOM_MOVE_TIED_UP) ||
(p_person->StateFn == NULL))
{
//
// The animation is over.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_STILL;
}
else
if(p_person->State == STATE_FIGHTING && (p_person->SubState == SUB_STATE_GRAPPLE_HOLD || p_person->SubState == SUB_STATE_GRAPPLE_HELD))
{
//
// The animation is over.
//
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GRAPPLE;
}
break;
case PCOM_MOVE_STATE_GRAPPLE:
if (p_person->SubState == SUB_STATE_GRAPPLE_HOLD)
{
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if (p_person->Genus.Person->pcom_move_counter++ > p_person->Genus.Person->pcom_ai_counter)
{
if (p_person->Genus.Person->pcom_ai == PCOM_AI_COP ||
p_person->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
//
// Cops are Ninjas! They throw you to the ground and
// then arrest you.
//
p_person->Genus.Person->Flags |= FLAG_PERSON_REQUEST_PUNCH;
}
else
{
p_person->Genus.Person->Flags |= FLAG_PERSON_REQUEST_KICK;
}
p_person->Genus.Person->pcom_move_counter = 0;
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_ANIMATION;
}
}
if (p_person->SubState == SUB_STATE_GRAPPLE_HELD)
{
// if((GAME_TURN+THING_NUMBER(p_person))&1)
if((PTIME(p_person))&1)
{
p_person->Genus.Person->Flags|=FLAG_PERSON_REQUEST_BLOCK;
}
}
if (p_person->State == STATE_IDLE)
{
set_person_recircle(p_person); //, TO_THING(p_person->Genus.Person->pcom_move_arg));
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_CIRCLE;
p_person->Genus.Person->pcom_move_arg = p_person->Genus.Person->Target;
p_person->Genus.Person->pcom_move_counter = 0;
}
break;
case PCOM_MOVE_STATE_CIRCLE:
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if (p_person->State == STATE_IDLE || (p_person->State == STATE_GUN && p_person->SubState == SUB_STATE_AIM_GUN))
{
//
// This person has probably been punched and has just recovered.
//
set_person_recircle(p_person); //, TO_THING(p_person->Genus.Person->pcom_move_arg));
}
else
if((p_person->SubState == SUB_STATE_GRAPPLE_HELD))
{
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GRAPPLE;
}
else
if((p_person->SubState == SUB_STATE_GRAPPLE_HELD))
{
p_person->Genus.Person->pcom_move_state = PCOM_MOVE_STATE_GRAPPLE;
}
break;
case PCOM_MOVE_STATE_PARK_CAR:
ParkCar(p_person);
break;
case PCOM_MOVE_STATE_DRIVETO:
case PCOM_MOVE_STATE_DRIVE_DOWN:
case PCOM_MOVE_STATE_PARK_CAR_ON_ROAD:
DriveCar(p_person);
break;
#ifdef BIKE
case PCOM_MOVE_STATE_PARK_BIKE:
ParkBike(p_person);
break;
case PCOM_MOVE_STATE_BIKETO:
case PCOM_MOVE_STATE_BIKE_DOWN:
DriveBike(p_person);
break;
#endif
default:
ASSERT(0);
break;
}
}
void PCOM_process_person(Thing *p_person)
{
//
// Do movement AI and low-level state stuff.
//
if (p_person->StateFn)
{
p_person->StateFn(p_person);
}
if (p_person->Genus.Person->PlayerID)
{
//
// Keep track of how long the player has been idle.
//
if (p_person->State == STATE_IDLE)
{
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(30))
{
p_person->Genus.Person->pcom_move_counter = 0;
UWORD pnear;
//
// Is Darci near someone dancing?
//
remove_thing_from_map(p_person);
pnear = THING_find_nearest(
p_person->WorldPos.X >> 8,
p_person->WorldPos.Y >> 8,
p_person->WorldPos.Z >> 8,
0x200,
1 << CLASS_PERSON);
add_thing_to_map(p_person);
if (pnear)
{
Thing *p_near;
//
// Is this person dancing?
//
p_near = TO_THING(pnear);
ASSERT(p_near->Class == CLASS_PERSON);
if (p_near->State == STATE_MOVEING && (p_near->SubState == SUB_STATE_SIMPLE_ANIM || p_near->SubState == SUB_STATE_SIMPLE_ANIM_OVER) && (p_near->Draw.Tweened->CurrentAnim == ANIM_DANCE_BOOGIE || p_near->Draw.Tweened->CurrentAnim == ANIM_DANCE_WOOGIE || p_near->Draw.Tweened->CurrentAnim == ANIM_DANCE_HEADBANG))
{
//
// This person is dancing... dance with him!
//
set_face_thing(p_person, p_near);
set_person_do_a_simple_anim(p_person, p_near->Draw.Tweened->CurrentAnim);
p_person->Genus.Person->Flags |= FLAG_PERSON_NO_RETURN_TO_NORMAL;
p_person->Genus.Person->Action = ACTION_SIT_BENCH;
}
}
}
}
else
{
p_person->Genus.Person->pcom_move_counter = 0;
}
//
// Players don't need to do the rest of this stuff.
//
return;
}
PCOM_process_movement(p_person);
if (p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
//
// Nothing this person can do.
//
return;
}
if (p_person->State == STATE_DEAD ||
p_person->State == STATE_DYING)
{
//
// No AI after brain death. But maybe this person should be
// resurrected. Like Jesus.
//
if (p_person->Genus.Person->pcom_ai == PCOM_AI_CIV &&
p_person->Genus.Person->pcom_move == PCOM_MOVE_WANDER)
{
//
// Wandering civillians come back to life when you can't see them!
//
if (!(p_person->Flags & FLAGS_IN_VIEW))
{
p_person->Genus.Person->pcom_ai_counter += 1;
if (p_person->Genus.Person->pcom_ai_counter > 200)
{
//
// Bring this person back to life. Put him at home.
//
GameCoord newpos;
newpos.X = (p_person->Genus.Person->HomeX << 16) + 0x8000;
newpos.Z = (p_person->Genus.Person->HomeZ << 16) + 0x8000;
newpos.Y = PAP_calc_map_height_at(newpos.X >> 8, newpos.Z >> 8);
extern SLONG plant_feet(Thing *p_person); // in collide.cpp
plant_feet(p_person);
//
// Give him back his health.
//
p_person->Genus.Person->Health = health[p_person->Genus.Person->PersonType];
//
// Make him start doing what he normally does.
//
p_person->Flags &= ~FLAGS_BURNING;
p_person->Genus.Person->BurnIndex = 0;
PCOM_set_person_ai_normal(p_person);
}
}
}
}
else
{
//
// Is it time to change what we are doing?
//
PCOM_process_state_change(p_person);
}
#ifdef NOT_USED
if (PCOM_person_doing_nothing_important(p_person))
{
if (p_person->Genus.Person->pcom_lookat_what == PCOM_LOOKAT_NOTHING)
{
// if (((GAME_TURN + THING_NUMBER(p_person)) & 0x1f) == 0)
{
// if (Random() & 0x4)
{
//
// Look around for something interesting. The Player will do!
//
p_person->Genus.Person->pcom_lookat_what = PCOM_LOOKAT_THING;
p_person->Genus.Person->pcom_lookat_counter = 128 + (Random() & 0x7f);
p_person->Genus.Person->pcom_lookat_index = THING_NUMBER(NET_PERSON(0));
}
}
}
else
{
if (p_person->Genus.Person->pcom_lookat_counter == 0)
{
p_person->Genus.Person->pcom_lookat_what = PCOM_LOOKAT_NOTHING;
p_person->Genus.Person->pcom_lookat_index = 0;
}
else
{
p_person->Genus.Person->pcom_lookat_counter -= 1;
}
}
}
else
{
p_person->Genus.Person->pcom_lookat_what = PCOM_LOOKAT_NOTHING;
p_person->Genus.Person->pcom_lookat_counter = 0;
p_person->Genus.Person->pcom_lookat_index = 0;
}
#endif
}
struct Noise
{
UWORD Type;
UWORD Person;
SWORD X,Y,Z;
};
#define MAX_NOISE 4
SWORD noise_count=0;
struct Noise noises[MAX_NOISE+1];
void init_noises(void)
{
noise_count=0;
}
void process_noises(void)
{
SLONG c0;
for(c0=0;c0<noise_count;c0++)
{
PCOM_oscillate_tympanum(
noises[c0].Type,
(noises[c0].Person) ? (TO_THING(noises[c0].Person)) : NULL,
noises[c0].X,
noises[c0].Y,
noises[c0].Z,0);
}
noise_count=0;
}
void PCOM_oscillate_tympanum(
SLONG type,
Thing *p_person, // The person who caused the sound.
SLONG sound_x, // The position of the sound.
SLONG sound_y,
SLONG sound_z,
UBYTE store_it)
{
SLONG i;
SLONG found_upto;
SLONG radius;
Thing *p_found;
if (stealth_debug&&(p_person==NET_PERSON(0))) return;
if(store_it)
{
struct Noise *p_noise;
if(noise_count>=MAX_NOISE)
{
ASSERT(0);
return;
}
p_noise=&noises[noise_count];
p_noise->Type=type;
p_noise->Person = p_person ? (THING_NUMBER(p_person)) : 0;
p_noise->X=(SWORD)sound_x;
p_noise->Y=(SWORD)sound_y;
p_noise->Z=(SWORD)sound_z;
noise_count++;
return;
}
//
// The volume of each type of sound.
//
switch(type)
{
case PCOM_SOUND_FOOTSTEP: radius = 0x280; break;
case PCOM_SOUND_UNUSUAL: radius = 0x600; break;
case PCOM_SOUND_HEY: radius = 0x600; break;
case PCOM_SOUND_ALARM: radius = 0x800; break;
case PCOM_SOUND_FIGHT: radius = 0x900; break;
case PCOM_SOUND_GUNSHOT: radius = 0xa00; break;
case PCOM_SOUND_DROP: radius = 0x200; break;
case PCOM_SOUND_DROP_MED: radius = 0x400; break;
case PCOM_SOUND_DROP_BIG: radius = 0x600; break;
case PCOM_SOUND_VAN: radius = 0x180; break;
case PCOM_SOUND_BANG: radius = 0x700; break;
case PCOM_SOUND_MINE: radius = 0x300; break;
case PCOM_SOUND_LOOKINGATME: radius = 0x400; break;
case PCOM_SOUND_WANKER: radius = 0x400; break;
case PCOM_SOUND_DRAW_GUN: radius = 0x600; break;
case PCOM_SOUND_GRENADE_HIT: radius = 0x300; break;
case PCOM_SOUND_GRENADE_FLY: radius = 0x300; break;
default:
ASSERT(0);
break;
}
//
// Look for people to be effected by this sound.
//
found_upto = THING_find_sphere(
sound_x,
sound_y,
sound_z,
radius,
THING_array,
THING_ARRAY_SIZE,
THING_FIND_PEOPLE);
if (type == PCOM_SOUND_DRAW_GUN && p_person)
{
//
// This isn't a sound- it is a visual thing so we must take out
// all people who can't see the person who is drawing the gun.
//
for (i = 0; i < found_upto; i++)
{
p_found = TO_THING(THING_array[i]);
if (!can_a_see_b(p_found, p_person))
{
THING_array[i] = THING_array[found_upto - 1];
i -= 1;
found_upto -= 1;
}
}
}
for (i = 0; i < found_upto; i++)
{
p_found = TO_THING(THING_array[i]);
if (p_found == p_person)
{
//
// Don't disturb yourself!
//
continue;
}
if (p_person && p_person->Class == CLASS_PERSON)
{
if (p_person->Genus.Person->Ware != p_found->Genus.Person->Ware)
{
//
// Ignore sounds in a warehouse you're not in; if you're in
// a warehouse, ignore sounds outside.
//
continue;
}
}
if (p_found->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
//
// Can't do anything even if he is scared.
//
continue;
}
if (p_found->State == STATE_DEAD ||
p_found->State == STATE_DYING)
{
//
// Dead people ignore their tympanum.
//
continue;
}
if (p_found->Genus.Person->PlayerID)
{
//
// Don't do anything to players.
//
continue;
}
if (p_found->Genus.Person->pcom_bent & PCOM_BENT_ROBOT)
{
//
// Robotic people ignore sounds.
//
continue;
}
if (p_found->Genus.Person->pcom_zone)
{
//
// Ignore sounds that aren't in your zone.
//
if (!(PCOM_get_zone_for_position(sound_x, sound_z) & p_found->Genus.Person->pcom_zone))
{
continue;
}
}
switch(p_found->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_GOTO_XZ:
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
case PCOM_MOVE_STATE_GOTO_THING:
if (p_found->Genus.Person->pcom_move_substate == PCOM_MOVE_SUBSTATE_ACTION)
{
//
// In the middle of doing a complicated moving manouvre.
//
continue;
}
}
if (type == PCOM_SOUND_VAN)
{
//
// Only civilians are scared of cars...
//
if (p_found->Genus.Person->Flags & (FLAG_PERSON_DRIVING|FLAG_PERSON_BIKING))
{
//
// but not civs driving.
//
}
else
{
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_CIV)
{
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PLACE &&
p_found->Genus.Person->pcom_ai_state == PCOM_AI_SUBSTATE_SUPRISED)
{
//
// Don't scare them again or they'll never run away.
//
}
else
{
if (ROAD_is_zebra(
p_found->WorldPos.X >> 16,
p_found->WorldPos.Z >> 16))
{
//
// Civs on zebra crossings have a sense of security.
//
}
else
{
PCOM_set_person_ai_flee_place(
p_found,
sound_x,
sound_z);
p_found->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LEGIT; //MD27oct
}
}
}
}
}
else
if (type == PCOM_SOUND_GRENADE_FLY ||
type == PCOM_SOUND_GRENADE_HIT)
{
//
// Ignore this unless you can see the grenade.
//
if (!can_i_see_place(
p_found,
sound_x,
sound_y,
sound_z))
{
if (type == PCOM_SOUND_GRENADE_HIT)
{
//
// Some people will investigate this sound...
//
if (p_found->Genus.Person->pcom_ai == PCOM_AI_GANG ||
p_found->Genus.Person->pcom_ai == PCOM_AI_COP)
{
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS)
{
PCOM_set_person_ai_investigate(
p_found,
sound_x,
sound_z);
}
}
}
}
else
{
if (/* This grenade is going to land near me... */ 1)
{
PCOM_set_person_ai_flee_place(
p_found,
sound_x,
sound_z);
}
}
}
else
{
switch(p_found->Genus.Person->pcom_ai)
{
case PCOM_AI_FIGHT_TEST:
case PCOM_AI_NONE:
break;
case PCOM_AI_CIV:
//
// Scared of gun-shots, explosions and fighting.
//
if (type == PCOM_SOUND_FIGHT && (p_found->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK))
{
//
// Fight back civs aren't scared of fighting!
//
}
else
if (type == PCOM_SOUND_GUNSHOT ||
type == PCOM_SOUND_BANG ||
type == PCOM_SOUND_MINE ||
type == PCOM_SOUND_LOOKINGATME ||
type == PCOM_SOUND_DRAW_GUN)
{
if (p_person)
{
PCOM_set_person_ai_flee_person(
p_found,
p_person);
}
else
{
PCOM_set_person_ai_flee_place(
p_found,
sound_x,
sound_z);
}
if(!VIOLENCE)
{
p_found->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LEGIT; //MD27oct
}
}
break;
case PCOM_AI_GUARD:
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK)
{
//
// Go an investigate the sound.
//
PCOM_set_person_ai_investigate(
p_found,
sound_x,
sound_z);
SOUND_Curious(p_found);
}
break;
case PCOM_AI_ASSASIN:
break;
case PCOM_AI_GANG:
//
// Thugs ain't scared of anything! But they are interested by things...
//
case PCOM_AI_COP:
//
// Ignore sounds made by Darci
//
if (p_person && p_person->Genus.Person->PersonType == PERSON_DARCI)
{
//
// Cops ignore sounds made by Darci?
//
if (type == PCOM_SOUND_FOOTSTEP)
{
//
// They ignore Darci's footsteps!
//
continue;
}
}
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_WARM_HANDS)
{
PCOM_set_person_ai_investigate(
p_found,
sound_x,
sound_z);
}
break;
case PCOM_AI_DOORMAN:
case PCOM_AI_BODYGUARD:
case PCOM_AI_DRIVER:
case PCOM_AI_BDISPOSER:
case PCOM_AI_BIKER:
case PCOM_AI_BOSS:
case PCOM_AI_BULLY:
case PCOM_AI_COP_DRIVER:
case PCOM_AI_SUICIDE:
case PCOM_AI_FLEE_PLAYER:
case PCOM_AI_KILL_COLOUR:
case PCOM_AI_BANE:
case PCOM_AI_SHOOT_DEAD:
break;
case PCOM_AI_MIB:
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NORMAL ||
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_HOMESICK)
{
if (p_person && p_person->Genus.Person->PlayerID)
{
PCOM_alert_nearby_mib_to_attack(p_person);
}
}
break;
default:
ASSERT(0);
break;
}
}
}
}
void PCOM_youre_being_grappled(
Thing *p_victim,
Thing *p_attacker)
{
}
SLONG on_same_side(Thing *p_victim,Thing *p_attacker)
{
if(p_victim->Genus.Person->PersonType==PERSON_ROPER||p_victim->Genus.Person->PersonType==PERSON_DARCI||p_victim->Genus.Person->PersonType==PERSON_COP)
{
if(p_attacker->Genus.Person->PersonType==PERSON_ROPER||p_attacker->Genus.Person->PersonType==PERSON_DARCI||p_attacker->Genus.Person->PersonType==PERSON_COP)
{
return(1);
}
}
return(0);
}
#if DARCI_HITS_COPS
//
// Returns TRUE if the player hit the cop on purpose.
//
SLONG PCOM_player_hit_cop_on_purpose(Thing *p_cop, Thing *p_darci)
{
if (p_darci->Genus.Person->Flags & FLAG_PERSON_FELON)
{
//
// Darci is a known villain.
//
return TRUE;
}
//
// Is there somebody fighting Darci nearby?
//
Thing *p_attacker;
p_attacker = is_person_under_attack(p_darci);
if (p_attacker)
{
//
// Somebody is out to get Darci... it was probably an accident!
//
if (p_attacker->Genus.Person->pcom_ai == PCOM_AI_COP ||
p_attacker->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
//
// Hold on! She is already fighting a cop! She must have hit
// me on purpose.
//
return TRUE;
}
else
{
return FALSE;
}
}
//
// Am I fighting anyone?
//
if (p_cop->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING ||
p_cop->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL)
{
//
// I am busy hitting somebody- darci is probably trying to help me!
//
return FALSE;
}
return TRUE;
}
#endif
//
// you have been attacked
//
extern void set_person_fight_idle(Thing *p_person);
void PCOM_attack_happened(
Thing *p_victim,
Thing *p_attacker)
{
if (p_victim->Genus.Person->PlayerID)
{
return;
}
if (p_attacker==NET_PERSON(0) && stealth_debug) return;
if (p_victim->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
//
// Can't do anything.
//
return;
}
extern SLONG people_allowed_to_hit_each_other(Thing *p_victim,Thing *p_agressor);
if(!people_allowed_to_hit_each_other(p_victim,p_attacker))
{
//
//dont retaliate if you cant hurt them
//
return;
}
//
// I am truly a great coder
// I am just having a day off, OK?
//
if (p_victim->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)
goto fight;
if (p_victim->Genus.Person->pcom_bent & PCOM_BENT_ROBOT)
return;
if(p_victim->SubState==SUB_STATE_GRAPPLE_HOLD||p_victim->SubState==SUB_STATE_GRAPPLE_ATTACK)
{
//
// take hit while grappleing, hmmmmmm
//
//
// better let go of person we are grappelling
//
set_person_fight_idle(TO_THING(p_victim->Genus.Person->Target));
// return;
}
if(p_victim->SubState==SUB_STATE_GRAPPLE_HELD)
{
//
// don't really have any sensible options here
//
return;
}
switch(p_victim->Genus.Person->pcom_ai)
{
case PCOM_AI_CIV:
goto flee;
break;
case PCOM_AI_COP:
case PCOM_AI_COP_DRIVER:
/*
if (p_attacker->Genus.Person->pcom_ai == PCOM_AI_COP ||
p_attacker->Genus.Person->pcom_ai == PCOM_AI_COP_DRIVER)
{
//
// A cop hitting another cop? It must have been
// an accident.
//
return;
}
*/
#if DARCI_HITS_COPS
if (p_attacker->Genus.Person->PlayerID)
{
//
// A cop has been hit by the player... was this accidental?
//
if (PCOM_player_hit_cop_on_purpose(p_victim, p_attacker))
{
//
// Has she hit me on purpose recently?
//
if (p_victim->Genus.Person->UnderAttack == 0)
{
//
// She hasn't recently hit me!
//
p_victim->Genus.Person->UnderAttack = 0xffff;
return;
}
}
else
{
//
// Ignore all accidental hits.
//
return;
}
}
#endif
// FALL-THROUGH
case PCOM_AI_GANG:
case PCOM_AI_GUARD:
case PCOM_AI_ASSASIN:
goto fight;
break;
case PCOM_AI_BODYGUARD:
//
// Ignore hits from who you are meant to be protecting.
//
if (THING_NUMBER(p_attacker) != EWAY_get_person(p_victim->Genus.Person->pcom_ai_other))
{
goto fight;
}
break;
}
return;
fight:
//
// If you are already fighting your attacker...
//
if (p_victim->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL ||
p_victim->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING)
{
if (p_victim->Genus.Person->pcom_ai_arg == THING_NUMBER(p_attacker))
{
return;
}
}
//
// Don't retaliate against someone in your own gang.
//
if ((p_victim ->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
(p_attacker->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
(p_victim ->Genus.Person->pcom_colour == p_attacker->Genus.Person->pcom_colour))
{
//
// Ignore the hit (it was a mistake!)
//
return;
}
//
// retaliate
//
PCOM_set_person_ai_kill_person(p_victim,p_attacker);
return;
flee:
PCOM_set_person_ai_flee_person(p_victim,p_attacker);
if(!VIOLENCE)
p_victim->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LEGIT; //MD27oct
return;
}
void PCOM_attack_happened_but_missed(Thing *p_victim,Thing *p_attacker)
{
if (p_victim->Genus.Person->PlayerID)
{
return;
}
if (p_attacker==NET_PERSON(0) && stealth_debug) return;
if (p_victim->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
//
// Can't do anything.
//
return;
}
if(on_same_side(p_victim,p_attacker))
return;
//
// I am truly a great coder
// I am just having a day off, OK?
//
if (p_victim->Genus.Person->pcom_bent & PCOM_BENT_ROBOT)
return;
if(!people_allowed_to_hit_each_other(p_victim,p_attacker))
return;
if (p_victim->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK)
goto fight;
switch(p_victim->Genus.Person->pcom_ai)
{
case PCOM_AI_CIV:
goto flee;
break;
case PCOM_AI_COP:
case PCOM_AI_COP_DRIVER:
#if DARCI_HITS_COPS
/*
if (p_attacker->Genus.Person->pcom_ai == PCOM_AI_COP)
{
//
// A cop hitting another cop? It must have been
// an accident.
//
return;
}
*/
if (p_attacker->Genus.Person->PlayerID)
{
//
// A cop has been hit by the player... was this accidental?
//
if (PCOM_player_hit_cop_on_purpose(p_victim, p_attacker))
{
//
// Has she hit me on purpose recently?
//
if (p_victim->Genus.Person->UnderAttack == 0)
{
//
// She hasn't recently hit me!
//
p_victim->Genus.Person->UnderAttack = 0xffff;
}
}
else
{
//
// Ignore all accidental hits.
//
return;
}
}
#endif
// FALL-THROUGH
case PCOM_AI_GANG:
case PCOM_AI_GUARD:
case PCOM_AI_ASSASIN:
goto fight;
break;
case PCOM_AI_BODYGUARD:
//
// Ignore hits from who you are meant to be protecting.
//
if (THING_NUMBER(p_attacker) != EWAY_get_person(p_victim->Genus.Person->pcom_ai_other))
{
goto fight;
}
break;
}
return;
fight:
//
// If you are already fighting your attacker...
//
if (p_victim->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL ||
p_victim->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING)
{
if (p_victim->Genus.Person->pcom_ai_arg == THING_NUMBER(p_attacker))
{
return;
}
}
//
// Don't retaliate against someone in your own gang.
//
if ((p_victim ->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
(p_attacker->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
(p_victim ->Genus.Person->pcom_colour == p_attacker->Genus.Person->pcom_colour))
{
//
// Ignore the hit (it was a mistake!)
//
return;
}
//
// retaliate
//
PCOM_set_person_ai_kill_person(p_victim,p_attacker);
return;
flee:
PCOM_set_person_ai_flee_person(p_victim,p_attacker);
if(!VIOLENCE)
p_victim->Genus.Person->pcom_ai_substate = PCOM_AI_SUBSTATE_LEGIT; //MD27oct
return;
}
SLONG PCOM_jumping_navigating_person_continue_moving(Thing *p_person)
{
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_GOTO_XZ ||
p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_GOTO_WAYPOINT ||
p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_GOTO_THING)
{
//
// Unless your doing a difficult jump that you'll really have to go for...
//
if (p_person->Genus.Person->pcom_move_ma.action != MAV_ACTION_JUMPPULL2)
{
SLONG goal_x;
SLONG goal_z;
PCOM_get_mav_action_pos(
p_person,
&goal_x,
&goal_z);
SLONG dx = goal_x - (p_person->WorldPos.X >> 8);
SLONG dz = goal_z - (p_person->WorldPos.Z >> 8);
SLONG dist = abs(dx) + abs(dz);
if (dist < 0x100)
{
//
// Stop moving or you'll overshoot.
//
return FALSE;
}
}
}
return TRUE;
}
void PCOM_knockdown_happened(Thing *p_person)
{
//
// This function doesn't do anything to the person. It just changes
// state of the 'brain' to wait for recovery.
//
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL ||
p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_CIRCLE ||
p_person->State == STATE_CIRCLING)
{
//
// if you do this to people who are attacking you, then when they get up they just wander off, rather than getting back into the fight
//
}
else
{
PCOM_set_person_ai_knocked_out(p_person);
}
}
#ifndef PSX
CBYTE PCOM_debug_string[256];
#endif
CBYTE *PCOM_person_state_debug(Thing *p_person)
{
#ifndef PSX
SLONG i;
CBYTE bent[256];
if (p_person->Genus.Person->PlayerID)
{
sprintf(
PCOM_debug_string,
"Player %d\n"
"Pos (0x%x,0x%x) height 0x%x\n"
"Warehouse %d\n",
p_person->Genus.Person->PlayerID,
p_person->WorldPos.X >> 8,
p_person->WorldPos.Z >> 8,
p_person->WorldPos.Y >> 8,
p_person->Genus.Person->Ware);
return PCOM_debug_string;
}
//
// A string describing the person's characteristics.
//
bent[0] = '\000';
for (i = 0; i < PCOM_BENT_NUMBER; i++)
{
if (p_person->Genus.Person->pcom_bent & (1 << i))
{
strcat(bent, PCOM_bent_name[i]);
}
}
if (p_person->Genus.Person->Flags & FLAG_PERSON_HELPLESS)
{
strcat(bent, "Helpless ");
}
sprintf(
PCOM_debug_string,
"%s%s%s,ptype %d,mesh %d personid %d \nState %s : %s\nMove %s : %s\nPerson 0x%p(%d) action %d anim %d Y %d st %d subs %d Agr %d",
bent,
PCOM_ai_name[p_person->Genus.Person->pcom_ai],
(p_person->Genus.Person->Ware) ? " ware" : "",
p_person->Genus.Person->PersonType,
p_person->Draw.Tweened->MeshID,
p_person->Draw.Tweened->PersonID,
PCOM_ai_state_name [p_person->Genus.Person->pcom_ai_state],
PCOM_ai_substate_name[p_person->Genus.Person->pcom_ai_substate],
PCOM_move_name [p_person->Genus.Person->pcom_move],
PCOM_move_state_name [p_person->Genus.Person->pcom_move_state],
p_person,THING_NUMBER(p_person),p_person->Genus.Person->Action,p_person->Draw.Tweened->CurrentAnim,
p_person->WorldPos.Y>>8,
p_person->State,
p_person->SubState,
p_person->Genus.Person->Agression);
return PCOM_debug_string;
#else
return (CBYTE*)0;
#endif
}
SLONG PCOM_cop_aiming_at_you(Thing *p_person,Thing *p_cop)
{
if (p_cop == NET_PERSON(0) && stealth_debug)
{
return 0;
}
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_ROBOT)
{
return 0;
}
if (p_person->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD)
{
//
// Bodyguards ignore being aimed at by the person they are guarding.
//
if (THING_NUMBER(p_cop) == EWAY_get_person(p_person->Genus.Person->pcom_ai_other))
{
return 0;
}
}
if(is_person_guilty(p_person))
{
if(p_person->State==STATE_DYING||p_person->State==STATE_DEAD)
return(0);
//
// don't put hands up because you are guilty and need to do something else
//
if (p_person->Genus.Person->pcom_ai_state != PCOM_AI_STATE_NAVTOKILL && p_person->Genus.Person->pcom_ai_state != PCOM_AI_STATE_FLEE_PERSON)
{
PCOM_set_person_ai_navtokill(p_person, p_cop);
return(1);
}
else
{
return(0);
}
/*
if (PCOM_person_has_any_sort_of_gun(p_person))
{
//
// you have a gun so kill the cop
//
PCOM_set_person_ai_navtokill_shoot(p_person, p_cop);
return(1);
}
else
if (!(p_person->Genus.Person->pcom_bent & PCOM_BENT_FIGHT_BACK) && p_person->Genus.Person->pcom_ai != PCOM_AI_ASSASIN)
{
//
// no gun so run away
//
PCOM_set_person_ai_flee_person(p_person, p_cop);
return(1);
}
*/
}
if(p_person->Genus.Person->PersonType==PERSON_ROPER||p_person->Genus.Person->PersonType==PERSON_DARCI||p_person->Genus.Person->PersonType==PERSON_COP)
{
//
// cops darci and roper don't put hands up
//
return(0);
}
/*
if(p_person->Genus.Person->PersonType==PERSON_ROPER||p_person->Genus.Person->PersonType==PERSON_DARCI||p_person->Genus.Person->PersonType==PERSON_COP||p_person->Genus.Person->PersonType==PERSON_THUG_GREY || p_person->Genus.Person->PersonType==PERSON_THUG_RASTA|| p_person->Genus.Person->PersonType==PERSON_THUG_RED)
{
//
// Thugs don't hands up
//
return(0);
}
*/
if(PCOM_person_doing_nothing_important(p_person))//||(VIOLENCE==0&&p_person->Genus.Person->PersonType==PERSON_CIV)
{
PCOM_set_person_ai_hands_up(p_person,p_cop);
return(1);
}
return(0);
}
void PCOM_make_people_talk_to_eachother(
Thing *p_person_a,
Thing *p_person_b,
UBYTE is_a_asking_a_question,
UBYTE stay_looking_at_eachother,
UBYTE make_the_person_talked_at_listen)
{
SLONG substate;
if (is_a_asking_a_question)
{
substate = PCOM_AI_SUBSTATE_TALK_ASK;
}
else
{
substate = PCOM_AI_SUBSTATE_TALK_TELL;
}
PCOM_set_person_ai_talk_to(p_person_a, p_person_b, substate, stay_looking_at_eachother);
p_person_a->Genus.Person->Flags |= FLAG_PERSON_NON_INT_M | FLAG_PERSON_NON_INT_C;
if (make_the_person_talked_at_listen)
{
PCOM_set_person_ai_talk_to(p_person_b, p_person_a, PCOM_AI_SUBSTATE_TALK_LISTEN, stay_looking_at_eachother);
p_person_b->Genus.Person->Flags |= FLAG_PERSON_NON_INT_M | FLAG_PERSON_NON_INT_C;
}
}
void PCOM_stop_people_talking_to_eachother(
Thing *p_person_a,
Thing *p_person_b)
{
p_person_a->Genus.Person->Flags &= ~FLAG_PERSON_NO_RETURN_TO_NORMAL;
p_person_b->Genus.Person->Flags &= ~FLAG_PERSON_NO_RETURN_TO_NORMAL;
if (p_person_a->Genus.Person->pcom_ai_state == PCOM_AI_STATE_TALK) {PCOM_set_person_ai_normal(p_person_a);}
if (p_person_b->Genus.Person->pcom_ai_state == PCOM_AI_STATE_TALK) {PCOM_set_person_ai_normal(p_person_b);}
}
SLONG PCOM_person_a_hates_b(Thing *p_person_a, Thing *p_person_b)
{
ASSERT(p_person_a->Class == CLASS_PERSON);
ASSERT(p_person_b->Class == CLASS_PERSON);
if (p_person_a == p_person_b)
{
//
// Nobody hates themselves.
//
return FALSE;
}
//
// People in the same gang like eachother.
//
if (p_person_a->Genus.Person->pcom_bent & p_person_b->Genus.Person->pcom_bent & PCOM_BENT_GANG)
{
if (p_person_a->Genus.Person->pcom_colour ==
p_person_b->Genus.Person->pcom_colour)
{
return FALSE;
}
}
if (p_person_a->Genus.Person->PlayerID)
{
//
// Players like their bodyguards.
//
if (p_person_b->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD && EWAY_get_person(p_person_b->Genus.Person->pcom_ai_other) == THING_NUMBER(p_person_a))
{
return FALSE;
}
//
// Players like other players.
//
if (p_person_b->Genus.Person->PersonType == PERSON_DARCI ||
p_person_b->Genus.Person->PersonType == PERSON_ROPER)
{
return FALSE;
}
//
// Players like people who are following them.
//
if (p_person_b->Genus.Person->pcom_move == PCOM_MOVE_FOLLOW && EWAY_get_person(p_person_b->Genus.Person->pcom_move_follow) == THING_NUMBER(p_person_a))
{
return FALSE;
}
//
// Players hate everybody else...
//
return TRUE;
}
if (p_person_a->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL ||
p_person_a->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING ||
p_person_a->Genus.Person->pcom_ai_state == PCOM_AI_STATE_TAUNT ||
p_person_a->Genus.Person->pcom_ai_state == PCOM_AI_STATE_ARREST)
{
//
// These people don't like the person they are dealing with.
//
if (p_person_a->Genus.Person->pcom_ai_arg == THING_NUMBER(p_person_b))
{
return TRUE;
}
}
return FALSE;
}
THING_INDEX PCOM_person_wants_to_kill(Thing *p_person)
{
if (p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL ||
p_person->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING)
{
return p_person->Genus.Person->pcom_ai_arg;
}
return NULL;
}
// ParkCar
//
// handler for PCOM_MOVE_STATE_PARK_CAR
void ParkCar(Thing* p_person)
{
SLONG wangle;
SLONG dangle;
//
// If you're going to do some driving- then you have to be in a car!
//
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
Thing* p_vehicle = TO_THING(p_person->Genus.Person->InCar);
//
// What direction do we want the car to face?
//
p_vehicle->Genus.Vehicle->IsAnalog = 0;
p_vehicle->Genus.Vehicle->Steering = 0;
if (p_person->Genus.Person->pcom_move_arg)
{
wangle = EWAY_get_angle(p_person->Genus.Person->pcom_move_arg);
dangle = wangle - p_vehicle->Genus.Vehicle->Angle;
if (dangle < -1024) {dangle += 2048;}
if (dangle > +1024) {dangle -= 2048;}
if (dangle < -8) {p_vehicle->Genus.Vehicle->Steering = -1;}
if (dangle > +8) {p_vehicle->Genus.Vehicle->Steering = +1;}
}
//
// Deccelerate.
//
if (WITHIN(p_vehicle->Velocity, -10, +10))
{
p_vehicle->Genus.Vehicle->DControl = 0;
p_vehicle->Velocity = 0;
// p_vehicle->Genus.Vehicle->Acceleration = 0;
}
else
if (p_vehicle->Velocity > 0)
{
p_vehicle->Genus.Vehicle->DControl = VEH_DECEL;
}
else
{
p_vehicle->Genus.Vehicle->DControl = VEH_ACCEL;
}
}
// DriveCar
//
// AI for driving a car - states PCOM_MOVE_STATE_DRIVE_DOWN, PCOM_MOVE_STATE_PARK_CAR_ON_ROAD and PCOM_MOVE_STATE_DRIVETO
void DriveCar(Thing* p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG dest_x;
SLONG dest_z;
SLONG wangle;
SLONG dangle;
SLONG dlane;
SLONG dspeed;
SLONG wspeed;
SLONG what;
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_DRIVING);
Thing* p_vehicle = TO_THING(p_person->Genus.Person->InCar);
ASSERT(p_vehicle);
#ifndef PSX
#ifndef TARGET_DC
#ifndef NDEBUG
extern Thing* SelectedThing;
if (LeftButton && (SelectedThing == p_vehicle))
{
_asm int 3;
LeftButton = 0;
}
#endif
#endif
#endif
if (p_person->Genus.Person->pcom_move_state != PCOM_MOVE_STATE_PARK_CAR_ON_ROAD)
{
//
// If the vehicle collided last time it moved, then we had better do something.
//
if (p_vehicle->Flags & FLAGS_COLLIDED)
{
switch(p_person->Genus.Person->pcom_move_substate)
{
case PCOM_MOVE_SUBSTATE_GOTO:
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_3PTURN;
p_person->Genus.Person->pcom_move_counter = 0;
break;
case PCOM_MOVE_SUBSTATE_3PTURN:
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
p_person->Genus.Person->pcom_move_counter = 0;
break;
default:
ASSERT(0);
break;
}
}
}
//
// Where are we going?
//
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
//
// If we are driving down a road...
//
if ((p_person->Genus.Person->pcom_move_state != PCOM_MOVE_STATE_DRIVETO) &&
(p_person->Genus.Person->pcom_move_substate != PCOM_MOVE_SUBSTATE_3PTURN))
{
//
// How far are we from the middle of the road?
//
dist = ROAD_signed_dist(
p_person->Genus.Person->pcom_move_arg >> 8,
p_person->Genus.Person->pcom_move_arg & 0xff,
p_vehicle->WorldPos.X >> 8,
p_vehicle->WorldPos.Z >> 8);
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PARK_CAR_ON_ROAD)
{
dlane = 0x300 - dist;
}
else
{
dlane = 0x180 - dist;
}
if (abs(dlane) > 0x80 || p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PARK_CAR_ON_ROAD)
{
//
// We are quite for from our lane. We should aim for the
// middle of our lane.
//
SLONG rx1;
SLONG rz1;
SLONG rx2;
SLONG rz2;
SLONG rdest_x;
SLONG rdest_z;
ROAD_node_pos(
p_person->Genus.Person->pcom_move_arg >> 8,
&rx1,
&rz1);
ROAD_node_pos(
p_person->Genus.Person->pcom_move_arg & 0xff,
&rx2,
&rz2);
nearest_point_on_line(
rx1, rz1,
rx2, rz2,
p_vehicle->WorldPos.X >> 8,
p_vehicle->WorldPos.Z >> 8,
&rdest_x,
&rdest_z);
SLONG drx = SIGN(rx2 - rx1) << 8;
SLONG drz = SIGN(rz2 - rz1) << 8;
rdest_x += drx;
rdest_z += drz;
rdest_x += drx;
rdest_z += drz;
rdest_x -= drz;
rdest_z += drx;
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PARK_CAR_ON_ROAD)
{
rdest_x -= drz;
rdest_z += drx;
rdest_x -= drz;
rdest_z += drx;
}
dest_x = rdest_x;
dest_z = rdest_z;
}
}
//
// What direction do we want the car to face?
//
dx = dest_x - (p_vehicle->WorldPos.X >> 8);
dz = dest_z - (p_vehicle->WorldPos.Z >> 8);
dangle = (p_vehicle->Genus.Vehicle->Angle - (calc_angle(dx,dz) + 1024)) & 2047;
if (dangle >= 1024) dangle -= 2048;
//
// What speed do we want to be going at?
//
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_PARK_CAR_ON_ROAD)
{
if (abs(dangle) < 100 && abs(dlane) < 0x80)
{
wspeed = 0;
}
else
{
wspeed = VEH_SPEED_LIMIT >> 1;
}
}
else
{
switch(p_person->Genus.Person->pcom_move_substate)
{
case PCOM_MOVE_SUBSTATE_GOTO:
if (abs(dangle) > 100)
{
wspeed = VEH_SPEED_LIMIT - ((abs(dangle) - 100) >> 1);
if (wspeed < 250)
{
wspeed = 250;
}
}
else
{
wspeed = VEH_SPEED_LIMIT;
}
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_DILIGENT)
{
wspeed += wspeed;
}
break;
case PCOM_MOVE_SUBSTATE_3PTURN:
//
// Always uturn for a little while at least.
//
if (p_person->Genus.Person->pcom_move_counter < PCOM_get_duration(15))
{
}
else
{
if (abs(dangle) < 500)
{
//
// We can start driving normally.
//
p_person->Genus.Person->pcom_move_substate = PCOM_MOVE_SUBSTATE_GOTO;
}
}
wspeed = -VEH_REVERSE_SPEED;
dangle = -dangle;
break;
default:
ASSERT(0);
break;
}
}
//
// Are we going to crash into anyone?
//
what = PCOM_find_runover_thing(p_person, dangle);
if (what & PCOM_RUNOVER_STOP) {if (wspeed > 0) {wspeed = 0;}}
// if (what & PCOM_RUNOVER_BEEP_HORN) {MFX_play_thing(THING_NUMBER(p_person), S_BEEP, MFX_REPLACE, p_person);}
// if (what & PCOM_RUNOVER_SHOUT_OUT) {MFX_play_thing(THING_NUMBER(p_person), S_GETOUTTHEWAY, MFX_REPLACE, p_person);}
if (what & (PCOM_RUNOVER_BEEP_HORN|PCOM_RUNOVER_SHOUT_OUT)) {MFX_play_thing(THING_NUMBER(p_person), SOUND_Range(S_CAR_HORN_START,S_CAR_HORN_END), MFX_REPLACE, p_person);}
if (what & PCOM_RUNOVER_SLOW_DOWN) {if (wspeed > 0) {wspeed >>= 1;}}
if (what & PCOM_RUNOVER_REVERSE) {wspeed = -(wspeed >> 2); dangle = 0;}
if (what & PCOM_RUNOVER_TURN_LEFT) {p_person->Genus.Person->pcom_move_flag |= PCOM_MOVE_FLAG_AVOID_LEFT; p_person->Genus.Person->pcom_move_counter = 0;}
if (what & PCOM_RUNOVER_TURN_RIGHT) {p_person->Genus.Person->pcom_move_flag |= PCOM_MOVE_FLAG_AVOID_RIGHT; p_person->Genus.Person->pcom_move_counter = 0;}
if (what & PCOM_RUNOVER_RUNAWAY)
{
//
// The movement bit is updating the high-level ai- sentience
// through complexity.
//
PCOM_set_person_ai_flee_person(p_person, PCOM_runover_scary_person);
return;
}
//
// Turn towards our destination.
//
p_vehicle->Genus.Vehicle->IsAnalog = 0;
p_vehicle->Genus.Vehicle->Steering = 0;
if (dangle > +8) {p_vehicle->Genus.Vehicle->Steering = +1;}
if (dangle < -8) {p_vehicle->Genus.Vehicle->Steering = -1;}
//
// Accelerate... decellerate?
//
p_vehicle->Genus.Vehicle->DControl = 0;
dspeed = p_vehicle->Velocity - wspeed;
if (dspeed < -10) {p_vehicle->Genus.Vehicle->DControl = VEH_ACCEL;}
if (dspeed > +10) {p_vehicle->Genus.Vehicle->DControl = VEH_DECEL;}
// shift up if gay delinquent person
if (p_person->Genus.Person->pcom_bent & PCOM_BENT_DILIGENT)
{
// p_vehicle->Genus.Vehicle->DControl |= VEH_FASTER;
}
//
// Avoid people.
//
if (p_person->Genus.Person->pcom_move_flag & PCOM_MOVE_FLAG_AVOID_LEFT) {p_vehicle->Genus.Vehicle->Steering = -1;}
if (p_person->Genus.Person->pcom_move_flag & PCOM_MOVE_FLAG_AVOID_RIGHT) {p_vehicle->Genus.Vehicle->Steering = +1;}
if (p_person->Genus.Person->pcom_move_flag & (PCOM_MOVE_FLAG_AVOID_LEFT | PCOM_MOVE_FLAG_AVOID_RIGHT))
{
SLONG avoid_time;
if (p_vehicle->Velocity > 700)
{
avoid_time = PCOM_get_duration(1);
}
else
{
avoid_time = PCOM_get_duration(2);
}
if (p_person->Genus.Person->pcom_move_counter > avoid_time)
{
p_person->Genus.Person->pcom_move_flag &= ~(PCOM_MOVE_FLAG_AVOID_LEFT | PCOM_MOVE_FLAG_AVOID_RIGHT);
}
}
/*
AENG_world_line_infinite(
p_vehicle->WorldPos.X >> 8,
p_vehicle->WorldPos.Y >> 8,
p_vehicle->WorldPos.Z >> 8,
32,
0xffffff,
dest_x,
0,
dest_z,
0,
0x000000,
TRUE);
*/
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
#ifdef BIKE
// ParkBike
//
// AI for parking a bike
void ParkBike(Thing* p_person)
{
SLONG wangle;
SLONG dangle;
BIKE_Control bc;
SLONG steer;
SLONG accel;
//
// Make sure we're on a bike.
//
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING);
Thing* p_bike = TO_THING(p_person->Genus.Person->InCar);
bc = BIKE_control_get(p_bike);
steer = bc.steer;
accel = bc.accel;
//
// What direction do we want the bike to face?
//
if (p_person->Genus.Person->pcom_move_arg)
{
wangle = EWAY_get_angle(p_person->Genus.Person->pcom_move_arg);
dangle = wangle - p_bike->Genus.Vehicle->Angle;
if (dangle < -1024) {dangle += 2048;}
if (dangle > +1024) {dangle -= 2048;}
if (dangle < -8) {steer += -10;}
if (dangle > +8) {steer += +10;}
}
//
// Deccelerate.
//
if (BIKE_get_speed(p_bike) > 0)
{
accel = -20;
}
else
{
accel = -0;
}
SATURATE(steer, -127, +127);
SATURATE(accel, -127, +127);
bc.accel = accel;
bc.steer = steer;
BIKE_control_set(p_bike, bc);
}
// DriveBike
//
// AI for driving a bike
void DriveBike(Thing* p_person)
{
SLONG dx;
SLONG dz;
SLONG dist;
SLONG what;
SLONG dest_x;
SLONG dest_z;
SLONG wangle;
SLONG dangle;
SLONG wspeed;
SLONG dspeed;
SLONG dlane;
BIKE_Control bc;
SLONG steer;
SLONG accel;
//
// Make sure we are on a bike
//
ASSERT(p_person->Genus.Person->Flags & FLAG_PERSON_BIKING);
if (p_person->SubState != SUB_STATE_RIDING_BIKE)
{
//
// We are getting onto or off the bike.
//
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
return;
}
Thing* p_bike = TO_THING(p_person->Genus.Person->InCar);
//
// Where are we going?
//
PCOM_get_person_dest(
p_person,
&dest_x,
&dest_z);
//
// If we are biking down a road...
//
if (p_person->Genus.Person->pcom_move_state == PCOM_MOVE_STATE_BIKE_DOWN)
{
//
// How far are we from the middle of the road?
//
dist = ROAD_signed_dist(
p_person->Genus.Person->pcom_move_arg >> 8,
p_person->Genus.Person->pcom_move_arg & 0xff,
p_bike->WorldPos.X >> 8,
p_bike->WorldPos.Z >> 8);
dlane = 0x100 - dist;
if (abs(dlane) > (0x80 + (rand() & 0x7f)))
{
//
// We are quite for from our lane. We should aim for the
// middle of our lane.
//
SLONG rx1;
SLONG rz1;
SLONG rx2;
SLONG rz2;
ROAD_node_pos(
p_person->Genus.Person->pcom_move_arg >> 8,
&rx1,
&rz1);
ROAD_node_pos(
p_person->Genus.Person->pcom_move_arg & 0xff,
&rx2,
&rz2);
#ifndef PSX
#ifndef TARGET_DC
if (ControlFlag&&allow_debug_keys)
{
AENG_world_line_infinite(
rx1, 0, rz1,
32,
0x008800,
rx2, 0, rz2,
0,
0x004400,
FALSE);
}
#endif
#endif // PSX
nearest_point_on_line(
rx1, rz1,
rx2, rz2,
p_bike->WorldPos.X >> 8,
p_bike->WorldPos.Z >> 8,
&dest_x,
&dest_z);
SLONG drx = SIGN(rx2 - rx1) << 8;
SLONG drz = SIGN(rz2 - rz1) << 8;
dest_x += drz + drx;
dest_z -= drx - drz;
}
}
//
// What direction do we want the bike to face?
//
dx = dest_x - (p_bike->WorldPos.X >> 8);
dz = dest_z - (p_bike->WorldPos.Z >> 8);
wangle = calc_angle(dx,dz);
wangle += 1024;
wangle &= 2047;
dangle = wangle - p_bike->Draw.Mesh->Angle;
if (dangle < -1024) {dangle += 2048;}
if (dangle > +1024) {dangle -= 2048;}
//
// What speed do we want to be going at?
//
if (abs(dangle) > 300)
{
wspeed = 600 - abs((dangle - 300) >> 1);
if (wspeed < 150)
{
wspeed = 150;
}
}
else
{
wspeed = 600;
}
//
// Are we going to crash into anyone?
//
what = PCOM_find_runover_thing(p_person, -dangle);
if (what & PCOM_RUNOVER_STOP) {if (wspeed > 0) {wspeed = 0;}}
if (what & PCOM_RUNOVER_BEEP_HORN) {MFX_play_thing(THING_NUMBER(p_person), S_BEEP,MFX_REPLACE, p_person);}
#ifndef PSX
if (what & PCOM_RUNOVER_SHOUT_OUT) {MFX_play_thing(THING_NUMBER(p_person), S_GETOUTTHEWAY,MFX_REPLACE, p_person);}
#endif
if (what & PCOM_RUNOVER_SLOW_DOWN) {if (wspeed > 0) {wspeed >>= 1;}}
if (what & PCOM_RUNOVER_TURN_LEFT) {p_person->Genus.Person->pcom_move_flag |= PCOM_MOVE_FLAG_AVOID_LEFT; p_person->Genus.Person->pcom_move_counter = 0;}
if (what & PCOM_RUNOVER_TURN_RIGHT) {p_person->Genus.Person->pcom_move_flag |= PCOM_MOVE_FLAG_AVOID_RIGHT; p_person->Genus.Person->pcom_move_counter = 0;}
if (what & PCOM_RUNOVER_RUNAWAY)
{
//
// The movement bit is updating the high-level ai- sentience
// through complexity.
//
PCOM_set_person_ai_flee_person(p_person, PCOM_runover_scary_person);
return;
}
//
// Turn towards our destination.
//
bc = BIKE_control_get(p_bike);
steer = bc.steer;
if (dangle < -8) {steer += -10;}
if (dangle > +8) {steer += +10;}
//
// Accelerate... decellerate?
//
dspeed = wspeed - BIKE_get_speed(p_bike);
accel = bc.accel;
if (dspeed < -10) {accel += -10;}
if (dspeed > +10) {accel += +10;}
//
// Avoid people.
//
if (p_person->Genus.Person->pcom_move_flag & PCOM_MOVE_FLAG_AVOID_LEFT) {steer += +18;}
if (p_person->Genus.Person->pcom_move_flag & PCOM_MOVE_FLAG_AVOID_RIGHT) {steer += -18;}
if (p_person->Genus.Person->pcom_move_flag & (PCOM_MOVE_FLAG_AVOID_LEFT | PCOM_MOVE_FLAG_AVOID_RIGHT))
{
if (p_person->Genus.Person->pcom_move_counter > PCOM_get_duration(1))
{
p_person->Genus.Person->pcom_move_flag &= ~(PCOM_MOVE_FLAG_AVOID_LEFT | PCOM_MOVE_FLAG_AVOID_RIGHT);
}
}
SATURATE(steer, -127, +127);
SATURATE(accel, -127, +127);
bc.accel = accel;
bc.steer = steer;
BIKE_control_set(p_bike, bc);
#ifndef PSX
#ifndef TARGET_DC
if (ControlFlag&&allow_debug_keys)
{
AENG_world_line_infinite(
p_bike->WorldPos.X >> 8,
p_bike->WorldPos.Y >> 8,
p_bike->WorldPos.Z >> 8,
32,
0xffffff,
dest_x,
0,
dest_z,
0,
0x000000,
TRUE);
}
#endif
#endif // PSX
p_person->Genus.Person->pcom_move_counter += PCOM_TICKS_PER_TURN * TICK_RATIO >> TICK_SHIFT;
}
#endif
SLONG PCOM_if_i_wanted_to_jump_how_fast_should_i_do_it(Thing *p_person)
{
if (!p_person->Genus.Person->PlayerID)
{
switch(p_person->Genus.Person->pcom_move_state)
{
case PCOM_MOVE_STATE_GOTO_XZ:
case PCOM_MOVE_STATE_GOTO_WAYPOINT:
case PCOM_MOVE_STATE_GOTO_THING:
switch(p_person->Genus.Person->pcom_move_ma.action)
{
case MAV_ACTION_JUMP:
case MAV_ACTION_PULLUP:
case MAV_ACTION_CLIMB_OVER:
return 24;
}
}
}
return 40;
}
void PCOM_make_driver_run_away(Thing *p_driver, Thing *p_scary)
{
if (p_driver->Genus.Person->pcom_ai_state == PCOM_AI_STATE_LEAVECAR ||
p_driver->Genus.Person->pcom_ai_state == PCOM_AI_STATE_FLEE_PERSON)
{
return;
}
if (!(p_driver->Genus.Person->Flags & FLAG_PERSON_DRIVING))
{
//
// Not driving a car!
//
PCOM_set_person_ai_flee_person(p_driver, p_scary);
}
else
{
PCOM_set_person_ai_leavecar(
p_driver,
PCOM_EXCAR_FLEE_PERSON,
0,
THING_NUMBER(p_scary));
}
}