1 /* Patrick 4/7/97 ---------------------------------------------------
2 Source file for predator AI
3 ---------------------------------------------------------------------*/
4 #include "3dc.h"
5 #include "inline.h"
6 #include "module.h"
7 #include "stratdef.h"
8 #include "gamedef.h"
9 #include "comp_shp.h"
10 #include "dynblock.h"
11 #include "dynamics.h"
12 #include "pfarlocs.h"
13 #include "pheromon.h"
14 #include "bh_types.h"
15 #include "pvisible.h"
16 #include "bh_far.h"
17 #include "bh_debri.h"
18 #include "bh_pred.h"
19 #include "bh_paq.h"
20 #include "bh_queen.h"
21 #include "bh_marin.h"
22 #include "bh_alien.h"
23 #include "lighting.h"
24 #include "bh_weap.h"
25 #include "weapons.h"
26 #include "psnd.h"
27 #include "equipmnt.h"
28 #include "los.h"
29 #include "ai_sight.h"
30 #include "targeting.h"
31 #include "dxlog.h"
32 #include "showcmds.h"
33 #include "huddefs.h"
34 #include "pldghost.h"
35 #include "bh_gener.h"
36 #include "bh_corpse.h"
37 #include "bh_dummy.h"
38 #include "bh_agun.h"
39 #include "scream.h"
40 #include "game_statistics.h"
41 
42 #define UseLocalAssert Yes
43 #include "ourasert.h"
44 #include "extents.h"
45 
46 #define ALL_NEW_AVOIDANCE_PRED  1
47 #define PREDATOR_HIT_DELTAS     1
48 
49 /* external global variables used in this file */
50 extern int ModuleArraySize;
51 extern char *ModuleCurrVisArray;
52 extern int NormalFrameTime;
53 extern SECTION_DATA* LOS_HModel_Section;        /* Section of HModel hit */
54 extern void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer);
55 extern void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data);
56 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
57 extern int GlobalFrameCounter;
58 extern int RouteFinder_CallsThisFrame;
59 extern int ShowPredoStats;
60 extern unsigned char Null_Name[8];
61 extern DEATH_DATA Predator_Special_SelfDestruct_Death;
62 
63 static DAMAGE_PROFILE Pred_Weapon_Damage;
64 
65 extern void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output);
66 extern STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor);
67 extern STRATEGYBLOCK* CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player);
68 extern DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir);
69 
70 /* prototypes for this file */
71 static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule);
72 
73 static PRED_RETURN_CONDITION Execute_PFS_Wander(STRATEGYBLOCK *sbPtr);
74 static PRED_RETURN_CONDITION Execute_PFS_Hunt(STRATEGYBLOCK *sbPtr);
75 static PRED_RETURN_CONDITION Execute_PFS_Retreat(STRATEGYBLOCK *sbPtr);
76 static PRED_RETURN_CONDITION Execute_PFS_Avoidance(STRATEGYBLOCK *sbPtr);
77 static PRED_RETURN_CONDITION Execute_PFS_Pathfinder(STRATEGYBLOCK *sbPtr);
78 static PRED_RETURN_CONDITION Execute_PFS_Return(STRATEGYBLOCK *sbPtr);
79 static PRED_RETURN_CONDITION Execute_PFS_Engage(STRATEGYBLOCK *sbPtr);
80 
81 #if 0
82 static PRED_RETURN_CONDITION Execute_PNS_Approach(STRATEGYBLOCK *sbPtr);
83 static PRED_RETURN_CONDITION Execute_PNS_StandGround(STRATEGYBLOCK *sbPtr);
84 static PRED_RETURN_CONDITION Execute_PNS_NewDischargePistol(STRATEGYBLOCK *sbPtr);
85 static PRED_RETURN_CONDITION Predator_ThreatAnalysis(STRATEGYBLOCK *sbPtr);
86 static void CreateNPCPredatorPlasBolt(VECTORCH *startingPosition, VECTORCH *targetDirection);
87 static void CreateNPCPredatorDisc(VECTORCH *startingPosition, VECTORCH *targetDirection);
88 #endif
89 static PRED_RETURN_CONDITION Execute_PNS_Avoidance(STRATEGYBLOCK *sbPtr);
90 static PRED_RETURN_CONDITION Execute_PNS_Wander(STRATEGYBLOCK *sbPtr);
91 static PRED_RETURN_CONDITION Execute_PNS_Hunt(STRATEGYBLOCK *sbPtr);
92 static PRED_RETURN_CONDITION Execute_PNS_Retreat(STRATEGYBLOCK *sbPtr);
93 static PRED_RETURN_CONDITION Execute_PNS_EngageWithPistol(STRATEGYBLOCK *sbPtr);
94 static PRED_RETURN_CONDITION Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr);
95 static PRED_RETURN_CONDITION Execute_PNS_EngageWithPlasmaCaster(STRATEGYBLOCK *sbPtr);
96 static PRED_RETURN_CONDITION Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr);
97 static PRED_RETURN_CONDITION Execute_PNS_EngageWithWristblade(STRATEGYBLOCK *sbPtr);
98 static PRED_RETURN_CONDITION Execute_PNS_AttackWithWristblade(STRATEGYBLOCK *sbPtr);
99 static PRED_RETURN_CONDITION Execute_PNS_SwapWeapon(STRATEGYBLOCK *sbPtr);
100 static PRED_RETURN_CONDITION Execute_PNS_EngageWithStaff(STRATEGYBLOCK *sbPtr);
101 static PRED_RETURN_CONDITION Execute_PNS_AttackWithStaff(STRATEGYBLOCK *sbPtr);
102 static PRED_RETURN_CONDITION Execute_PNS_Pathfinder(STRATEGYBLOCK *sbPtr);
103 static PRED_RETURN_CONDITION Execute_PNS_Return(STRATEGYBLOCK *sbPtr);
104 static PRED_RETURN_CONDITION Execute_PNS_Recover(STRATEGYBLOCK *sbPtr);
105 static PRED_RETURN_CONDITION Execute_PNS_Taunting(STRATEGYBLOCK *sbPtr);
106 static PRED_RETURN_CONDITION Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr);
107 static PRED_RETURN_CONDITION Execute_PNS_AttackBrutallyWithPlasmaCaster(STRATEGYBLOCK *sbPtr);
108 
109 static PRED_RETURN_CONDITION Execute_PNS_SelfDestruct(STRATEGYBLOCK *sbPtr);
110 
111 static void Execute_Dying(STRATEGYBLOCK *sbPtr);
112 
113 static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening);
114 static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr);
115 static int PredatorShouldAttackPlayer(STRATEGYBLOCK *sbPtr);
116 
117 static void InitPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus);
118 static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus);
119 static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus);
120 static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus,DYNAMICSBLOCK *dynPtr);
121 
122 static int PredatorCanSeeTarget(STRATEGYBLOCK *sbPtr);
123 static int PredatorCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target);
124 static int PredatorIsAwareOfTarget(STRATEGYBLOCK *sbPtr);
125 
126 void Predator_Enter_Swapping_State(STRATEGYBLOCK *sbPtr);
127 void Predator_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr);
128 void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr);
129 void Predator_Enter_Engaged_State(STRATEGYBLOCK *sbPtr);
130 void Predator_Enter_Withdrawal_State(STRATEGYBLOCK *sbPtr);
131 void Predator_Enter_Recover_State(STRATEGYBLOCK *sbPtr);
132 void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr);
133 void Predator_Enter_Hunt_State(STRATEGYBLOCK *sbPtr);
134 void Predator_Enter_Return_State(STRATEGYBLOCK *sbPtr);
135 void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr);
136 void Predator_Enter_Taunt_State(STRATEGYBLOCK *sbPtr);
137 
138 void Predator_SwitchState(STRATEGYBLOCK *sbPtr,PRED_RETURN_CONDITION state_result);
139 STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *me);
140 int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr);
141 void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr);
142 void DoPredatorHitSound(STRATEGYBLOCK *sbPtr);
143 void DoPredatorAcidSound(STRATEGYBLOCK *sbPtr);
144 void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr);
145 void DoPredatorTauntSound(STRATEGYBLOCK *sbPtr);
146 void DoPredatorDeathSound(STRATEGYBLOCK *sbPtr);
147 void DoPredatorAISwipeSound(STRATEGYBLOCK *sbPtr);
148 
149 void CreatePredoBot(VECTORCH *position, int weapon);
150 void Predator_Enter_SelfDestruct_State(STRATEGYBLOCK *sbPtr);
151 /* Patrick 21/8/97 --------------------------------------------------
152 Predator personalisation parameters:
153 format: health,speed,defenceHealth,useShoulderCannon,
154 timebetweenRangedAttacks,maxShotsPerRangedAttack,
155 timeBetweenEachShot,closeAttackDamage,chanceOfCloaking(1-8)
156 ---------------------------------------------------------------------*/
157 static PREDATOR_PERSONALPARAMETERS predatorCV[] =
158 {
159         {800,8000,200,1,(2*ONE_FIXED),3,(ONE_FIXED),25,200,2},
160         {1000,7000,500,0,(ONE_FIXED),1,(ONE_FIXED>>1),20,400,4},
161         {600,10000,10,1,(4*ONE_FIXED),2,(ONE_FIXED>>1),50,300,8},
162         {600,8000,200,0,(2*ONE_FIXED),2,(ONE_FIXED),25,500,2},
163         {1000,9000,100,1,(ONE_FIXED),1,(ONE_FIXED>>1),35,400,6},
164 };
165 
166 PREDATOR_WEAPON_DATA NPC_Predator_Weapons[] = {
167         {
168                 PNPCW_Pistol,                                           /* ID */
169                 Execute_PNS_DischargePistol,         /* Fire Func. */
170                 Execute_PNS_EngageWithPistol,           /* Engage Func. */
171                 "hnpcpredator",                                         /* Riffname */
172                 "pred + pistol",                                        /* HierarchyName */
173                 "pistol",                                                       /* GunName */
174                 "R shoulder",                                           /* ElevationName */
175                 "predator",                                                     /* HitLocationTableName */
176                 1000,                                                                      /* MinRange (Don't fire when closer) */
177                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
178                 20000,                                                          /* MaxRange (Don't fire if further) */
179                 //65536>>3,                                                     /* Firing Rate */
180                 65536,                                                          /* Firing Rate */
181                 8,                                                                      /* VolleySize */
182                 65536>>1,                                                       /* SwappingTime */
183                 1,                                                                      /* UseElevation */
184         },
185         {
186                 PNPCW_Wristblade,                                       /* ID */
187                 Execute_PNS_AttackWithWristblade,       /* Fire Func. */
188                 Execute_PNS_EngageWithWristblade,       /* Engage Func. */
189                 "hnpcpredator",                                         /* Riffname */
190                 "pred with wristblade",                         /* HierarchyName */
191                 NULL,                                                           /* GunName */
192                 "R shoulder",                                           /* ElevationName */
193                 "predator",                                                     /* HitLocationTableName */
194                 0,                                                                      /* MinRange (Don't fire when closer) */
195                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
196                 PRED_CLOSE_ATTACK_RANGE,                        /* MaxRange (Don't fire if further) */
197                 65536<<1,                                                       /* Firing Rate */
198                 1,                                                                      /* VolleySize */
199                 65536>>1,                                                       /* SwappingTime */
200                 1,                                                                      /* UseElevation */
201         },
202         {
203                 PNPCW_PlasmaCaster,                             /* ID */
204                 Execute_PNS_AttackWithPlasmaCaster,     /* Fire Func. */
205                 Execute_PNS_EngageWithPlasmaCaster,     /* Engage Func. */
206                 "hnpcpredator",                                         /* Riffname */
207                 "pred with Plasma Caster",                      /* HierarchyName */
208                 "Plasma caster",                                        /* GunName */
209                 "Plasma caster",                                        /* ElevationName */
210                 "predator",                                                     /* HitLocationTableName */
211                 0,                                                                      /* MinRange (Don't fire when closer) */
212                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
213                 -1,                                                                     /* MaxRange (Don't fire if further) */
214                 65536,                                                          /* Firing Rate */
215                 1,                                                                      /* VolleySize */
216                 65536,                                                          /* SwappingTime */
217                 1,                                                                      /* UseElevation */
218         },
219         {
220                 PNPCW_Staff,                                            /* ID */
221                 Execute_PNS_AttackWithStaff,            /* Fire Func. */
222                 Execute_PNS_EngageWithStaff,            /* Engage Func. */
223                 "hnpcpredator",                                         /* Riffname */
224                 "pred with staff",                                      /* HierarchyName */
225                 NULL,                                                           /* GunName */
226                 "R shoulder",                                           /* ElevationName */
227                 "predator",                                                     /* HitLocationTableName */
228                 0,                                                                      /* MinRange (Don't fire when closer) */
229                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
230                 PRED_CLOSE_ATTACK_RANGE,                        /* MaxRange (Don't fire if further) */
231                 65536<<1,                                                       /* Firing Rate */
232                 1,                                                                      /* VolleySize */
233                 65536>>1,                                                       /* SwappingTime */
234                 0,                                                                      /* UseElevation */
235         },
236         {
237                 PNPCW_Medicomp,                                         /* ID */
238                 Execute_PNS_DischargePistol,            /* Fire Func. */
239                 Execute_PNS_EngageWithPistol,           /* Engage Func. */
240                 "hnpcpredator",                                         /* Riffname */
241                 "medicomp",                                                     /* HierarchyName */
242                 "P caster box",                                         /* GunName */
243                 "R shoulder",                                           /* ElevationName */
244                 "predator",                                                     /* HitLocationTableName */
245                 0,                                                                      /* MinRange (Don't fire when closer) */
246                 0,                                                                      /* ForceFireRange (Fire if closer) */
247                 0,                                                                      /* MaxRange (Don't fire if further) */
248                 65536>>3,                                                       /* Firing Rate */
249                 8,                                                                      /* VolleySize */
250                 65536>>1,                                                       /* SwappingTime */
251                 1,                                                                      /* UseElevation */
252         },
253         {
254                 PNPCW_Speargun,                                         /* ID */
255                 Execute_PNS_DischargeSpeargun,          /* Fire Func. */
256                 Execute_PNS_EngageWithPistol,           /* Engage Func. */
257                 "hnpcpredator",                                         /* Riffname */
258                 "Speargun",                                                     /* HierarchyName */
259                 "staff gun root",                                       /* GunName */
260                 "R shoulder",                                           /* ElevationName */
261                 "predator",                                                     /* HitLocationTableName */
262                 0,                                                                      /* MinRange (Don't fire when closer) */
263                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
264                 -1,                                                                     /* MaxRange (Don't fire if further) */
265                 65536>>2,                                                       /* Firing Rate */
266                 1,                                                                      /* VolleySize */
267                 65536>>1,                                                       /* SwappingTime */
268                 1,                                                                      /* UseElevation */
269         },
270         {
271                 PNPCW_SeriousPlasmaCaster,                              /* ID */
272                 Execute_PNS_AttackBrutallyWithPlasmaCaster,     /* Fire Func. */
273                 Execute_PNS_EngageWithPlasmaCaster,     /* Engage Func. */
274                 "hnpcpredator",                                         /* Riffname */
275                 "pred with Plasma Caster",                      /* HierarchyName */
276                 "Plasma caster",                                        /* GunName */
277                 "Plasma caster",                                        /* ElevationName */
278                 "predator",                                                     /* HitLocationTableName */
279                 0,                                                                      /* MinRange (Don't fire when closer) */
280                 PRED_CLOSE_ATTACK_RANGE,                        /* ForceFireRange (Fire if closer) */
281                 -1,                                                                     /* MaxRange (Don't fire if further) */
282                 65536>>2,                                                       /* Firing Rate */
283                 1,                                                                      /* VolleySize */
284                 65536,                                                          /* SwappingTime */
285                 1,                                                                      /* UseElevation */
286         },
287         {
288                 PNPCW_End,
289                 NULL,
290                 NULL,
291                 NULL,
292                 NULL,
293                 NULL,
294                 NULL,
295                 NULL,
296                 0,
297                 0,
298                 0,
299                 0,
300                 0,
301                 0,
302                 0,
303         },
304 };
305 
GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id)306 PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id) {
307 
308         int a;
309 
310         a=0;
311         while (NPC_Predator_Weapons[a].id!=PNPCW_End) {
312                 if (NPC_Predator_Weapons[a].id==this_id) {
313                         return(&NPC_Predator_Weapons[a]);
314                 }
315                 a++;
316         }
317 
318         return(NULL);
319 
320 }
321 
GetPredatorAttackDamageType(STRATEGYBLOCK * sbPtr,int flagnum)322 static enum AMMO_ID GetPredatorAttackDamageType(STRATEGYBLOCK *sbPtr,int flagnum) {
323 
324         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
325 
326         LOCALASSERT(sbPtr);
327         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
328         LOCALASSERT(predatorStatusPointer);
329 
330         if (predatorStatusPointer->current_attack==NULL) {
331                 return(AMMO_NONE);
332         }
333 
334         /* No different types of predators! */
335         return(predatorStatusPointer->current_attack->flag_damage[flagnum]);
336 
337 }
338 
PredatorNearDamageShell(STRATEGYBLOCK * sbPtr)339 static void PredatorNearDamageShell(STRATEGYBLOCK *sbPtr)
340 {
341         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
342         DYNAMICSBLOCK *dynPtr;
343         int workingflags,flagnum,a;
344         int dist,dodamage;
345 
346         LOCALASSERT(sbPtr);
347         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
348         dynPtr = sbPtr->DynPtr;
349         LOCALASSERT(predatorStatusPointer);
350         LOCALASSERT(dynPtr);
351 
352         /* Damage shell! */
353         workingflags=predatorStatusPointer->HModelController.keyframe_flags>>1;
354         flagnum=0;
355 
356         dist = VectorDistance(&(dynPtr->Position),&(predatorStatusPointer->Target->DynPtr->Position));
357         if (dist<PRED_CLOSE_ATTACK_RANGE) {
358                 dodamage=1;
359         } else if ((predatorStatusPointer->Selected_Weapon->id==PNPCW_Staff)&&(dist<PRED_STAFF_ATTACK_RANGE)) {
360                 dodamage=1;
361         } else {
362                 dodamage=0;
363         }
364 
365         for (a=0; a<NUM_ATTACKFLAGS; a++) {
366 
367                 if (workingflags&1) {
368 
369                 /* Do the alien attack sound */
370 
371                     #if 0
372         	        	unsigned int rand=FastRandom();
373                         switch (rand % 4)
374                         {
375                                 case 0:
376                                 {
377                                 Sound_Play(SID_SWIPE,"dp",&dynPtr->Position,(rand&255)-128);
378                                 break;
379                         }
380                         case 1:
381                         {
382                                 Sound_Play(SID_SWIPE2,"dp",&dynPtr->Position,(rand&255)-128);
383                                 break;
384                         }
385                         case 2:
386                         {
387                                 Sound_Play(SID_SWIPE3,"dp",&dynPtr->Position,(rand&255)-128);
388                                 break;
389                         }
390                                 case 3:
391                         {
392                                 Sound_Play(SID_SWIPE4,"dp",&dynPtr->Position,(rand&255)-128);
393                                 break;
394                         }
395                                 default:
396                                 {
397                                         break;
398                                 }
399                         }
400 					#else
401 					DoPredatorAISwipeSound(sbPtr);
402 					#endif
403                         /* Oops, check range first. */
404                         if (dodamage) {
405 
406                                 if (predatorStatusPointer->Target->SBdptr) {
407                                         VECTORCH rel_pos,attack_dir;
408 
409                                         rel_pos.vx=predatorStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
410                                         rel_pos.vy=predatorStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
411                                         rel_pos.vz=predatorStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
412 
413                                         GetDirectionOfAttack(predatorStatusPointer->Target,&rel_pos,&attack_dir);
414 
415                                         if (predatorStatusPointer->Target->SBdptr->HModelControlBlock) {
416                                                 HtoHDamageToHModel(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED, sbPtr, &attack_dir);
417                                         } else {
418                                                 CauseDamageToObject(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
419                                         }
420                                 } else {
421                                         VECTORCH rel_pos,attack_dir;
422 
423                                         rel_pos.vx=predatorStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
424                                         rel_pos.vy=predatorStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
425                                         rel_pos.vz=predatorStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
426 
427                                         GetDirectionOfAttack(predatorStatusPointer->Target,&rel_pos,&attack_dir);
428 
429                                         CauseDamageToObject(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
430                                 }
431                         }
432                 }
433                 /* Prepare next flag. */
434                 workingflags>>=1;
435                 flagnum++;
436         }
437 
438 }
439 
StartWristbladeAttackSequence(STRATEGYBLOCK * sbPtr)440 static void StartWristbladeAttackSequence(STRATEGYBLOCK *sbPtr) {
441 
442         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
443         ATTACK_DATA *thisAttack;
444 
445         LOCALASSERT(sbPtr);
446         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
447         LOCALASSERT(predatorStatusPointer);
448 
449         thisAttack=GetWristbladeAttackSequence(&predatorStatusPointer->HModelController,0,
450                 predatorStatusPointer->IAmCrouched);
451 
452         GLOBALASSERT(thisAttack);
453 
454         SetPredatorAnimationSequence(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence,
455                 thisAttack->Sequence_Length,thisAttack->TweeningTime);
456 
457         predatorStatusPointer->current_attack=thisAttack;
458 
459 }
460 
StartPredStaffAttackSequence(STRATEGYBLOCK * sbPtr)461 static void StartPredStaffAttackSequence(STRATEGYBLOCK *sbPtr) {
462 
463         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
464         ATTACK_DATA *thisAttack;
465 
466         LOCALASSERT(sbPtr);
467         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
468         LOCALASSERT(predatorStatusPointer);
469 
470         thisAttack=GetPredStaffAttackSequence(&predatorStatusPointer->HModelController,0,
471                 predatorStatusPointer->IAmCrouched);
472 
473         GLOBALASSERT(thisAttack);
474 
475         SetPredatorAnimationSequence(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence,
476                 thisAttack->Sequence_Length,thisAttack->TweeningTime);
477 
478         predatorStatusPointer->current_attack=thisAttack;
479 
480 }
481 
482 /* ChrisF 11/6/98 - Bot functions. */
483 
CastPredoBot(int weapon)484 void CastPredoBot(int weapon) {
485 
486         #define BOTRANGE 2000
487 
488         VECTORCH position;
489 
490         if (AvP.Network!=I_No_Network) {
491                 NewOnScreenMessage("NO PREDOBOTS IN MULTIPLAYER MODE");
492                 return;
493         }
494 
495         position=Player->ObStrategyBlock->DynPtr->Position;
496         position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
497         position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
498         position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
499 
500         CreatePredoBot(&position, weapon);
501 
502 }
503 
CreatePredoBot(VECTORCH * position,int weapon)504 void CreatePredoBot(VECTORCH *position, int weapon)
505 {
506 
507         STRATEGYBLOCK* sbPtr;
508 
509         /* create and initialise a strategy block */
510         sbPtr = CreateActiveStrategyBlock();
511         if(!sbPtr) {
512                 NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
513                 return; /* failure */
514         }
515         InitialiseSBValues(sbPtr);
516 
517         sbPtr->I_SBtype = I_BehaviourPredator;
518 
519         AssignNewSBName(sbPtr);
520 
521         /* create, initialise and attach a dynamics block */
522         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
523         if(sbPtr->DynPtr)
524         {
525                 EULER zeroEuler = {0,0,0};
526                 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
527         dynPtr->PrevPosition = dynPtr->Position = *position;
528                 dynPtr->OrientEuler = zeroEuler;
529                 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
530                 TransposeMatrixCH(&dynPtr->OrientMat);
531 
532                 /* zero linear velocity in dynamics block */
533                 dynPtr->LinVelocity.vx = 0;
534                 dynPtr->LinVelocity.vy = 0;
535                 dynPtr->LinVelocity.vz = 0;
536         }
537         else
538         {
539                 /* allocation failure */
540                 RemoveBehaviourStrategy(sbPtr);
541                 NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
542                 return;
543         }
544 
545         sbPtr->shapeIndex = 0;
546 
547         sbPtr->maintainVisibility = 1;
548         sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
549 
550         /* Initialise predator's stats */
551         {
552                 NPC_DATA *NpcData;
553 
554 
555                 NpcData=GetThisNpcData(I_NPC_Predator);
556                 LOCALASSERT(NpcData);
557                 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
558                 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
559                 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
560         }
561 
562         /* create, initialise and attach a predator data block */
563         sbPtr->SBdataptr = (void *)AllocateMem(sizeof(PREDATOR_STATUS_BLOCK));
564         if(sbPtr->SBdataptr)
565         {
566                 SECTION *root_section;
567                 PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr;
568 
569 				memset(predatorStatus,0,sizeof(*predatorStatus));
570 
571                 predatorStatus->personalNumber = 0;
572                 if(predatorStatus->personalNumber<0)
573                 {
574                         predatorStatus->personalNumber=0;
575                         LOCALASSERT(1==0);
576                 }
577                 if(predatorStatus->personalNumber>PRED_MAXIDENTITY)
578                 {
579                         predatorStatus->personalNumber=PRED_MAXIDENTITY;
580                         LOCALASSERT(1==0);
581                 }
582 
583                 NPC_InitMovementData(&(predatorStatus->moveData));
584                 NPC_InitWanderData(&(predatorStatus->wanderData));
585                         predatorStatus->health = predatorCV[predatorStatus->personalNumber].startingHealth;
586                 sbPtr->integrity = predatorStatus->health;
587                 predatorStatus->behaviourState = PBS_Wandering;
588                 predatorStatus->stateTimer = PRED_FAR_MOVE_TIME;
589                 predatorStatus->internalState=0;
590                 predatorStatus->weaponTarget.vx = predatorStatus->weaponTarget.vy = predatorStatus->weaponTarget.vz = 0;
591                 predatorStatus->volleySize = 0;
592                 predatorStatus->IAmCrouched = 0;
593                 predatorStatus->nearSpeed = predatorCV[predatorStatus->personalNumber].speed;
594                 predatorStatus->GibbFactor=0;
595                 predatorStatus->current_attack=NULL;
596 
597                 predatorStatus->incidentFlag=0;
598                 predatorStatus->incidentTimer=0;
599                 predatorStatus->patience=PRED_PATIENCE_TIME;
600                 predatorStatus->enableSwap=0;
601                 predatorStatus->enableTaunt=0;
602                 predatorStatus->Explode=0;
603 
604                 switch( weapon )
605                 {
606                 case 0:
607                 default:
608                         predatorStatus->PrimaryWeapon=PNPCW_Wristblade;
609                         break;
610 
611                 case 1:
612                         predatorStatus->PrimaryWeapon=PNPCW_PlasmaCaster;
613                         break;
614                 }
615 
616                 predatorStatus->SecondaryWeapon=PNPCW_Staff;
617                 predatorStatus->ChangeToWeapon=PNPCW_End;
618                 predatorStatus->Selected_Weapon=GetThisNPCPredatorWeapon(predatorStatus->PrimaryWeapon);
619 
620                 predatorStatus->obstruction.environment=0;
621                 predatorStatus->obstruction.destructableObject=0;
622                 predatorStatus->obstruction.otherCharacter=0;
623                 predatorStatus->obstruction.anySingleObstruction=0;
624 
625                 Initialise_AvoidanceManager(sbPtr,&predatorStatus->avoidanceManager);
626                 InitWaypointManager(&predatorStatus->waypointManager);
627 
628                 predatorStatus->Target=NULL; //Player->ObStrategyBlock;
629                 COPY_NAME(predatorStatus->Target_SBname,Null_Name);
630 
631                 predatorStatus->soundHandle = SOUND_NOACTIVEINDEX;
632 
633                 predatorStatus->Pred_Laser_On=0;
634 
635                 predatorStatus->missionmodule=NULL;
636                 predatorStatus->fearmodule=NULL;
637                 predatorStatus->path=-1;
638                 predatorStatus->stepnumber=-1;
639 
640                 //a generated predator won't have a death target
641                 {
642                         int i;
643                         for(i=0;i<SB_NAME_LENGTH;i++) predatorStatus->death_target_ID[i] =0;
644                         predatorStatus->death_target_request=0;
645                         predatorStatus->death_target_sbptr=0;
646                 }
647 
648 
649                 root_section=GetNamedHierarchyFromLibrary(predatorStatus->Selected_Weapon->Riffname,predatorStatus->Selected_Weapon->HierarchyName);
650                 if (!root_section) {
651                         RemoveBehaviourStrategy(sbPtr);
652                         NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL");
653                         return;
654                 }
655                 Create_HModel(&predatorStatus->HModelController,root_section);
656                 InitHModelSequence(&predatorStatus->HModelController,0,0,ONE_FIXED);
657 
658                 if (predatorStatus->Selected_Weapon->UseElevation) {
659                         DELTA_CONTROLLER *delta;
660                         delta=Add_Delta_Sequence(&predatorStatus->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0);
661                         GLOBALASSERT(delta);
662                         delta->timer=32767;
663                 }
664 
665                 predatorStatus->My_Gun_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->GunName);
666                 predatorStatus->My_Elevation_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->ElevationName);
667 
668                 #if PREDATOR_HIT_DELTAS
669                 if (HModelSequence_Exists(&predatorStatus->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) {
670                         DELTA_CONTROLLER *delta;
671                         delta=Add_Delta_Sequence(&predatorStatus->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1);
672                         GLOBALASSERT(delta);
673                         delta->Playing=0;
674                 }
675                 #endif
676 
677                 ProveHModel_Far(&predatorStatus->HModelController,sbPtr);
678 
679                 InitPredatorCloak(predatorStatus);
680 
681                 if(!(sbPtr->containingModule))
682                 {
683                         /* no containing module can be found... abort*/
684                         RemoveBehaviourStrategy(sbPtr);
685                         NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE");
686                         return;
687                 }
688                 LOCALASSERT(sbPtr->containingModule);
689 
690                 MakePredatorNear(sbPtr);
691 
692                 NewOnScreenMessage("PREDOBOT CREATED");
693 
694         }
695         else
696         {
697                 /* allocation failure */
698                 RemoveBehaviourStrategy(sbPtr);
699                 NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE");
700                 return;
701         }
702 }
703 
704 /* Patrick 4/7/97 --------------------------------------------------
705 Basic NPC functions for predator:
706 Initialiser, visibility management,behaviour shell, and damage functions
707 ---------------------------------------------------------------------*/
InitPredatorBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)708 void InitPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
709 {
710         TOOLS_DATA_PREDATOR *toolsData;
711         int i;
712 
713         LOCALASSERT(sbPtr);
714         LOCALASSERT(bhdata);
715         toolsData = (TOOLS_DATA_PREDATOR *)bhdata;
716 
717         /* check we're not in a net game */
718         if(AvP.Network != I_No_Network)
719         {
720                 RemoveBehaviourStrategy(sbPtr);
721                 return;
722         }
723 
724         /* make the assumption that the loader has initialised the strategy
725         block sensibly...
726         so just set the shapeIndex from the tools data & copy the name id*/
727         sbPtr->shapeIndex = toolsData->shapeIndex;
728         for(i=0;i<SB_NAME_LENGTH;i++) sbPtr->SBname[i] = toolsData->nameID[i];
729 
730         /* create, initialise and attach a dynamics block */
731         sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
732         if(sbPtr->DynPtr)
733         {
734                 EULER zeroEuler = {0,0,0};
735                 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
736         dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
737                 dynPtr->OrientEuler = zeroEuler;
738                 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
739                 TransposeMatrixCH(&dynPtr->OrientMat);
740 
741                 /* zero linear velocity in dynamics block */
742                 dynPtr->LinVelocity.vx = 0;
743                 dynPtr->LinVelocity.vy = 0;
744                 dynPtr->LinVelocity.vz = 0;
745         }
746         else
747         {
748                 /* allocation failure */
749                 RemoveBehaviourStrategy(sbPtr);
750                 return;
751         }
752 
753         /* Initialise predator's stats */
754         {
755                 NPC_DATA *NpcData;
756 
757 
758                 NpcData=GetThisNpcData(I_NPC_Predator);
759                 LOCALASSERT(NpcData);
760                 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
761                 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
762                 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
763         }
764 
765         /* create, initialise and attach a predator data block */
766         sbPtr->SBdataptr = (void *)AllocateMem(sizeof(PREDATOR_STATUS_BLOCK));
767         if(sbPtr->SBdataptr)
768         {
769                 SECTION *root_section;
770                 PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr;
771 
772                 predatorStatus->personalNumber = toolsData->predator_number;
773                 if(predatorStatus->personalNumber<0)
774                 {
775                         predatorStatus->personalNumber=0;
776                         LOCALASSERT(1==0);
777                 }
778                 if(predatorStatus->personalNumber>PRED_MAXIDENTITY)
779                 {
780                         predatorStatus->personalNumber=PRED_MAXIDENTITY;
781                         LOCALASSERT(1==0);
782                 }
783 
784                 NPC_InitMovementData(&(predatorStatus->moveData));
785                 NPC_InitWanderData(&(predatorStatus->wanderData));
786         predatorStatus->health = predatorCV[predatorStatus->personalNumber].startingHealth;
787                 sbPtr->integrity = predatorStatus->health;
788                 predatorStatus->behaviourState = PBS_Wandering;
789                 predatorStatus->stateTimer = PRED_FAR_MOVE_TIME;
790                 predatorStatus->internalState=0;
791                 predatorStatus->weaponTarget.vx = predatorStatus->weaponTarget.vy = predatorStatus->weaponTarget.vz = 0;
792                 predatorStatus->volleySize = 0;
793                 predatorStatus->IAmCrouched = 0;
794                 predatorStatus->nearSpeed = predatorCV[predatorStatus->personalNumber].speed;
795                 predatorStatus->GibbFactor=0;
796                 predatorStatus->current_attack=NULL;
797 
798                 predatorStatus->incidentFlag=0;
799                 predatorStatus->incidentTimer=0;
800                 predatorStatus->patience=PRED_PATIENCE_TIME;
801                 predatorStatus->enableSwap=0;
802                 predatorStatus->enableTaunt=0;
803                 predatorStatus->Explode=0;
804 
805                 #if 0
806                 predatorStatus->PrimaryWeapon=PNPCW_Pistol;
807                 predatorStatus->SecondaryWeapon=PNPCW_Wristblade;
808                 #else
809                 predatorStatus->PrimaryWeapon=toolsData->primary;
810                 predatorStatus->SecondaryWeapon=toolsData->secondary;
811                 #endif
812                 predatorStatus->ChangeToWeapon=PNPCW_End;
813                 predatorStatus->Selected_Weapon=GetThisNPCPredatorWeapon(predatorStatus->PrimaryWeapon);
814 
815                 predatorStatus->obstruction.environment=0;
816                 predatorStatus->obstruction.destructableObject=0;
817                 predatorStatus->obstruction.otherCharacter=0;
818                 predatorStatus->obstruction.anySingleObstruction=0;
819 
820                 Initialise_AvoidanceManager(sbPtr,&predatorStatus->avoidanceManager);
821                 InitWaypointManager(&predatorStatus->waypointManager);
822 
823                 predatorStatus->Target=NULL; //Player->ObStrategyBlock;
824                 COPY_NAME(predatorStatus->Target_SBname,Null_Name);
825 
826                 predatorStatus->soundHandle = SOUND_NOACTIVEINDEX;
827 
828                 predatorStatus->Pred_Laser_On=0;
829 
830                 predatorStatus->missionmodule=NULL;
831                 predatorStatus->fearmodule=NULL;
832                 predatorStatus->path=toolsData->path;
833                 predatorStatus->stepnumber=toolsData->stepnumber;
834                 if ((predatorStatus->path!=-1)&&(predatorStatus->stepnumber!=-1)) {
835                         predatorStatus->behaviourState = PBS_Pathfinding;
836                 }
837 
838                 for(i=0;i<SB_NAME_LENGTH;i++) predatorStatus->death_target_ID[i] = toolsData->death_target_ID[i];
839                 predatorStatus->death_target_request=toolsData->death_target_request;
840                 predatorStatus->death_target_sbptr=0;
841 
842 
843                 root_section=GetNamedHierarchyFromLibrary(predatorStatus->Selected_Weapon->Riffname,predatorStatus->Selected_Weapon->HierarchyName);
844                 GLOBALASSERT(root_section);
845                 Create_HModel(&predatorStatus->HModelController,root_section);
846                 InitHModelSequence(&predatorStatus->HModelController,0,0,ONE_FIXED);
847 
848                 if (predatorStatus->Selected_Weapon->UseElevation) {
849                         DELTA_CONTROLLER *delta;
850                         delta=Add_Delta_Sequence(&predatorStatus->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0);
851                         GLOBALASSERT(delta);
852                         delta->timer=32767;
853                 }
854 
855                 predatorStatus->My_Gun_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->GunName);
856                 predatorStatus->My_Elevation_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->ElevationName);
857 
858                 #if PREDATOR_HIT_DELTAS
859                 if (HModelSequence_Exists(&predatorStatus->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) {
860                         DELTA_CONTROLLER *delta;
861                         delta=Add_Delta_Sequence(&predatorStatus->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1);
862                         GLOBALASSERT(delta);
863                         delta->Playing=0;
864                 }
865                 #endif
866 
867                 ProveHModel_Far(&predatorStatus->HModelController,sbPtr);
868 
869                 InitPredatorCloak(predatorStatus);
870         }
871         else
872         {
873                 /* allocation failure */
874                 RemoveBehaviourStrategy(sbPtr);
875                 return;
876         }
877 }
878 
InitDormantPredatorBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)879 void InitDormantPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
880 {
881         DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv;
882         GLOBALASSERT(sbPtr);
883         pred_bhv=(DORMANT_PREDATOR_STATUS_BLOCK*)AllocateMem(sizeof(DORMANT_PREDATOR_STATUS_BLOCK));
884 
885         pred_bhv->bhvr_type=I_BehaviourDormantPredator;
886         pred_bhv->toolsData=bhdata;
887 
888         sbPtr->SBdataptr=(void*) pred_bhv;
889 
890 }
891 
ActivateDormantPredator(STRATEGYBLOCK * sbPtr)892 void ActivateDormantPredator(STRATEGYBLOCK* sbPtr)
893 {
894         DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv;
895         void* toolsData;
896 
897         GLOBALASSERT(sbPtr);
898         GLOBALASSERT(sbPtr->SBdataptr);
899         pred_bhv = (DORMANT_PREDATOR_STATUS_BLOCK*)sbPtr->SBdataptr;
900         toolsData=pred_bhv->toolsData;
901 
902         //convert this strategyblock to a predator
903         DeallocateMem(pred_bhv);
904         InitialiseSBValues(sbPtr);
905         sbPtr->I_SBtype = I_BehaviourPredator;
906         EnableBehaviourType(sbPtr,I_BehaviourPredator ,toolsData );
907 
908         //find strategyblock of death target
909         {
910                 PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr;
911                 predatorStatus->death_target_sbptr = FindSBWithName(predatorStatus->death_target_ID);
912         }
913 
914         sbPtr->maintainVisibility = 1;
915         sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
916 
917 
918 }
919 
920 
SetPredatorElevation(STRATEGYBLOCK * sbPtr)921 void SetPredatorElevation(STRATEGYBLOCK *sbPtr) {
922 
923         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
924         int offsetx,offsety,offsetz,offseta,angle1;
925         DELTA_CONTROLLER *elevation_controller;
926         VECTORCH gunpos;
927 
928         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
929 
930         if (predatorStatusPointer->Selected_Weapon->UseElevation==0) {
931                 /* Non elevating weapon. */
932                 return;
933         }
934 
935         /* Get gun position? */
936 
937         if (predatorStatusPointer->My_Elevation_Section) {
938                 gunpos=predatorStatusPointer->My_Elevation_Section->World_Offset;
939         } else {
940                 GetTargetingPointOfObject_Far(sbPtr,&gunpos);
941         }
942 
943         /* Aim at weaponTarget. */
944 
945         offsetx=(predatorStatusPointer->weaponTarget.vx)-(gunpos.vx);
946         offsety=(predatorStatusPointer->weaponTarget.vz)-(gunpos.vz);
947         offseta=-((predatorStatusPointer->weaponTarget.vy)-(gunpos.vy));
948 
949         while( (offsetx>(ONE_FIXED>>2))
950                 ||(offsety>(ONE_FIXED>>2))
951                 ||(offseta>(ONE_FIXED>>2))
952                 ||(offsetx<-(ONE_FIXED>>2))
953                 ||(offsety<-(ONE_FIXED>>2))
954                 ||(offseta<-(ONE_FIXED>>2))) {
955 
956                 offsetx>>=1;
957                 offsety>>=1;
958                 offseta>>=1;
959 
960         }
961 
962         offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
963         angle1=ArcTan(offseta,offsetz);
964 
965         if (angle1>=3072) angle1-=4096;
966         if (angle1>=2048) angle1=angle1-3072;
967         if (angle1>1024) angle1=2048-angle1;
968 
969         GLOBALASSERT(angle1>=-1024);
970         GLOBALASSERT(angle1<=1024);
971 
972         elevation_controller=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
973         GLOBALASSERT(elevation_controller);
974         {
975                 int fake_timer;
976 
977                 fake_timer=1024-angle1;
978                 fake_timer<<=5;
979                 if (fake_timer==65536) fake_timer=65535;
980 
981                 GLOBALASSERT(fake_timer>=0);
982                 GLOBALASSERT(fake_timer<65536);
983 
984                 elevation_controller->timer=fake_timer;
985 
986         }
987 
988 }
989 
CentrePredatorElevation(STRATEGYBLOCK * sbPtr)990 void CentrePredatorElevation(STRATEGYBLOCK *sbPtr) {
991 
992         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
993         DELTA_CONTROLLER *elevation_controller;
994 
995         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
996 
997         if (predatorStatusPointer->Selected_Weapon->UseElevation==0) {
998                 /* Non elevating weapon. */
999                 return;
1000         }
1001 
1002         elevation_controller=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
1003 		if (elevation_controller) {
1004 	    	/* You can't be too careful with swap weapon stuff...? */
1005 	        elevation_controller->timer=32767;
1006 		}
1007 
1008 }
1009 
PredatorBehaviour(STRATEGYBLOCK * sbPtr)1010 void PredatorBehaviour(STRATEGYBLOCK *sbPtr)
1011 {
1012         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1013         int predatorIsNear;
1014         char *descriptor;
1015         PRED_RETURN_CONDITION state_result;
1016 
1017         LOCALASSERT(sbPtr);
1018         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
1019     LOCALASSERT(predatorStatusPointer);
1020 
1021         /* test if we've got a containing module: if we haven't, do nothing.
1022         This is important as the object could have been marked for deletion by the visibility
1023         management system...*/
1024         if(!sbPtr->containingModule)
1025         {
1026                 DestroyAnyStrategyBlock(sbPtr); /* just to make sure */
1027                 return;
1028         }
1029 
1030         if(sbPtr->SBdptr)
1031         {
1032                 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
1033                 predatorIsNear=1;
1034         } else {
1035                 predatorIsNear=0;
1036         }
1037 
1038         if (ShowSlack) {
1039                 int synthSpeed,setSpeed,slack;
1040                 VECTORCH offset;
1041                 extern int SlackTotal;
1042                 extern int SlackSize;
1043 
1044                 offset.vx=(sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx);
1045                 offset.vy=(sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy);
1046                 offset.vz=(sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz);
1047 
1048                 synthSpeed=Magnitude(&offset);
1049                 synthSpeed=DIV_FIXED(synthSpeed,NormalFrameTime);
1050                 setSpeed=Magnitude(&sbPtr->DynPtr->LinVelocity);
1051 
1052                 if (setSpeed) {
1053                         slack=(ONE_FIXED-(DIV_FIXED(synthSpeed,setSpeed)));
1054                         SlackTotal+=slack;
1055                         SlackSize++;
1056                 }
1057                 #if 0
1058                 PrintDebuggingText("MaxSpeed = %d, SynthSpeed = %d, SetSpeed = %d, Slack %d\n",alienStatusPointer->MaxSpeed,synthSpeed,setSpeed,slack);
1059                 #endif
1060         }
1061 
1062         InitWaypointSystem(0);
1063         predatorStatusPointer->Pred_Laser_On=0;
1064 
1065         if (Validate_Target(predatorStatusPointer->Target,predatorStatusPointer->Target_SBname)==0) {
1066                 predatorStatusPointer->Target=NULL;
1067         }
1068 
1069 		/* Consider changing target? */
1070 		if (predatorStatusPointer->behaviourState==PBS_Engaging) {
1071 			if (predatorStatusPointer->incidentFlag) {
1072 				if ((FastRandom()&65535)<32767) {
1073 					predatorStatusPointer->Target=NULL;
1074 				}
1075 			}
1076 		}
1077 
1078         if (predatorStatusPointer->Target==NULL) {
1079         	if ((predatorIsNear)||(predatorStatusPointer->incidentFlag)) {
1080                 /* Get new target. */
1081                 predatorStatusPointer->Target=Predator_GetNewTarget(sbPtr);
1082 
1083                 if (predatorStatusPointer->Target) {
1084                         #if 0
1085                         textprint("Predator gets new target.\n");
1086                         #endif
1087                         COPY_NAME(predatorStatusPointer->Target_SBname,predatorStatusPointer->Target->SBname);
1088 
1089                 } else {
1090                         #if 0
1091                                 PrintDebuggingText("Predator found no target!\n");
1092                         #endif
1093                 }
1094 			}
1095         }
1096 
1097         /* first of all, look after our cloaking device */
1098         DoPredatorCloak(predatorStatusPointer,sbPtr->DynPtr);
1099 
1100         /* Unset incident flag. */
1101         predatorStatusPointer->incidentFlag=0;
1102 
1103         predatorStatusPointer->incidentTimer-=NormalFrameTime;
1104 
1105         if (predatorStatusPointer->incidentTimer<0) {
1106                 predatorStatusPointer->incidentFlag=1;
1107                 predatorStatusPointer->incidentTimer=32767+(FastRandom()&65535);
1108         }
1109 
1110         if (predatorStatusPointer->GibbFactor) {
1111                 /* If you're gibbed, you're dead. */
1112                 sbPtr->SBDamageBlock.Health = 0;
1113         }
1114 
1115         if (sbPtr->SBDamageBlock.IsOnFire) {
1116 
1117                 CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL);
1118 
1119                 if (sbPtr->I_SBtype==I_BehaviourNetCorpse) {
1120                         /* Gettin' out of here... */
1121                         return;
1122                 }
1123 
1124                 if (predatorStatusPointer->incidentFlag) {
1125                         if ((FastRandom()&65535)<32767) {
1126                                 sbPtr->SBDamageBlock.IsOnFire=0;
1127                         }
1128                 }
1129 
1130         }
1131 
1132         if (predatorStatusPointer->behaviourState!=PBS_Dying) {
1133                 HModel_Regen(&predatorStatusPointer->HModelController,PRED_REGEN_TIME);
1134         }
1135 
1136         /* now execute behaviour state */
1137         switch(predatorStatusPointer->behaviourState)
1138         {
1139                 case (PBS_Wandering):
1140                 {
1141                         descriptor="Wandering";
1142                         if (predatorIsNear) {
1143                                 state_result=Execute_PNS_Wander(sbPtr);
1144                                 CentrePredatorElevation(sbPtr);
1145                         } else {
1146                                 state_result=Execute_PFS_Wander(sbPtr);
1147                         }
1148                         break;
1149                 }
1150                 case (PBS_Hunting):
1151                 {
1152                         descriptor="Hunting";
1153                         if (predatorIsNear) {
1154                                 state_result=Execute_PNS_Hunt(sbPtr);
1155                                 CentrePredatorElevation(sbPtr);
1156                         } else {
1157                                 state_result=Execute_PFS_Hunt(sbPtr);
1158                         }
1159                         break;
1160                 }
1161                 case (PBS_Avoidance):
1162                 {
1163                         switch (predatorStatusPointer->avoidanceManager.substate) {
1164                                 default:
1165                                 case AvSS_FreeMovement:
1166                                         descriptor="Avoidance Level 0";
1167                                         break;
1168                                 case AvSS_FirstAvoidance:
1169                                         descriptor="Avoidance Level 1";
1170                                         break;
1171                                 case AvSS_SecondAvoidance:
1172                                         descriptor="Avoidance Level 2";
1173                                         break;
1174                                 case AvSS_ThirdAvoidance:
1175                                         descriptor="Avoidance Level 3";
1176                                         break;
1177                         }
1178                         if (predatorIsNear) {
1179                                 state_result=Execute_PNS_Avoidance(sbPtr);
1180                                 CentrePredatorElevation(sbPtr);
1181                         } else {
1182                                 state_result=Execute_PFS_Avoidance(sbPtr);
1183                         }
1184                         break;
1185                 }
1186                 case (PBS_Dying):
1187                 {
1188                         descriptor="Dying";
1189                         if (predatorIsNear) {
1190                                 Execute_Dying(sbPtr);
1191                         } else {
1192                                 Execute_Dying(sbPtr);
1193                         }
1194                         state_result=PRC_No_Change;
1195                         break;
1196                 }
1197                 case (PBS_Withdrawing):
1198                 {
1199                         descriptor="Withdrawing";
1200                         if (predatorIsNear) {
1201                                 state_result=Execute_PNS_Retreat(sbPtr);
1202                                 CentrePredatorElevation(sbPtr);
1203                         } else {
1204                                 state_result=Execute_PFS_Retreat(sbPtr);
1205                         }
1206                         break;
1207                 }
1208                 case (PBS_Recovering):
1209                 {
1210                         descriptor="Recovering";
1211                         if (predatorIsNear) {
1212                                 state_result=Execute_PNS_Recover(sbPtr);
1213                                 CentrePredatorElevation(sbPtr);
1214                         } else {
1215                                 state_result=Execute_PNS_Recover(sbPtr);
1216                         }
1217                         break;
1218                 }
1219                 case (PBS_SwapWeapon):
1220                 {
1221                         descriptor="Swapping";
1222                         if (predatorIsNear) {
1223                                 state_result=Execute_PNS_SwapWeapon(sbPtr);
1224                                 CentrePredatorElevation(sbPtr);
1225                         } else {
1226                                 /* Oooh! */
1227                                 state_result=Execute_PNS_SwapWeapon(sbPtr);
1228                                 ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
1229                         }
1230                         break;
1231                 }
1232                 case (PBS_Engaging):
1233                 {
1234                         descriptor="Engaging";
1235                         if (predatorIsNear) {
1236                                 state_result=(*predatorStatusPointer->Selected_Weapon->WeaponEngageFunction)(sbPtr);
1237                         } else {
1238                                 state_result=Execute_PFS_Engage(sbPtr);
1239                         }
1240                         break;
1241                 }
1242                 case (PBS_Attacking):
1243                 {
1244                         descriptor="Attacking";
1245                         if (predatorIsNear) {
1246                                 state_result=(*predatorStatusPointer->Selected_Weapon->WeaponFireFunction)(sbPtr);
1247                                 SetPredatorElevation(sbPtr);
1248                         } else {
1249                                 state_result=Execute_PFS_Engage(sbPtr);
1250                         }
1251                         break;
1252                 }
1253                 case (PBS_Returning):
1254                 {
1255                         descriptor="Returning";
1256                         if (predatorIsNear) {
1257                                 state_result=Execute_PNS_Return(sbPtr);
1258                                 CentrePredatorElevation(sbPtr);
1259                         } else {
1260                                 state_result=Execute_PFS_Return(sbPtr);
1261                         }
1262                         break;
1263                 }
1264                 case (PBS_Pathfinding):
1265                 {
1266                         descriptor="Pathfinding";
1267                         if (predatorIsNear) {
1268                                 state_result=Execute_PNS_Pathfinder(sbPtr);
1269                                 CentrePredatorElevation(sbPtr);
1270                         } else {
1271                                 state_result=Execute_PFS_Pathfinder(sbPtr);
1272                         }
1273                         break;
1274                 }
1275                 case (PBS_Taunting):
1276                 {
1277                         descriptor="Taunting";
1278                         if (predatorIsNear) {
1279                                 state_result=Execute_PNS_Taunting(sbPtr);
1280                                 CentrePredatorElevation(sbPtr);
1281                         } else {
1282                                 state_result=Execute_PNS_Taunting(sbPtr);
1283                         }
1284                         break;
1285                 }
1286                 case (PBS_SelfDestruct):
1287                 {
1288                         descriptor="Self Destructing";
1289                         if (predatorIsNear) {
1290                                 state_result=Execute_PNS_SelfDestruct(sbPtr);
1291                                 /* No elevation should be present. */
1292                         } else {
1293                                 state_result=Execute_PNS_SelfDestruct(sbPtr);
1294                         }
1295                         break;
1296                 }
1297                 default:
1298                 {
1299                         LOCALASSERT(1==0);
1300                         break;
1301                 }
1302         }
1303 
1304         if (ShowPredoStats) {
1305                 switch (predatorStatusPointer->CloakStatus) {
1306                         case PCLOAK_Off:
1307                                 PrintDebuggingText("DeCloaked ");
1308                                 break;
1309                         case PCLOAK_On:
1310                                 PrintDebuggingText("Cloaked ");
1311                                 break;
1312                         case PCLOAK_Activating:
1313                                 PrintDebuggingText("Cloaking (%d) ",predatorStatusPointer->CloakTimer);
1314                                 break;
1315                         case PCLOAK_Deactivating:
1316                                 PrintDebuggingText("DeCloaking (%d) ",predatorStatusPointer->CloakTimer);
1317                                 break;
1318                         default:
1319                                 GLOBALASSERT(0);
1320                                 break;
1321                 }
1322                 PrintDebuggingText("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name,
1323                         (sbPtr->SBDamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->SBDamageBlock.Armour>>ONE_FIXED_SHIFT));
1324         }
1325 
1326         Predator_SwitchState(sbPtr,state_result);
1327 
1328         if (!predatorIsNear) {
1329 
1330                 /* check here to see if predator is in a proximity door - if so, trigger it to open. */
1331                 {
1332                         MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
1333 
1334                         if(doorType == MDT_ProxDoor)
1335                                 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->alienTrigger = 1;
1336                 }
1337 
1338                 /* lastly, do a containment test: to make sure that we are inside a module. */
1339                 #if UseLocalAssert
1340                 {
1341                         VECTORCH localCoords;
1342                         MODULE *thisModule = sbPtr->containingModule;
1343 
1344                         LOCALASSERT(thisModule);
1345 
1346                         localCoords = sbPtr->DynPtr->Position;
1347                         localCoords.vx -= thisModule->m_world.vx;
1348                         localCoords.vy -= thisModule->m_world.vy;
1349                         localCoords.vz -= thisModule->m_world.vz;
1350 
1351                         if(PointIsInModule(thisModule, &localCoords)==0)
1352                         {
1353                                 textprint("FAR PREDATOR MODULE CONTAINMENT FAILURE \n");
1354                                 LOCALASSERT(1==0);
1355                         }
1356                 }
1357                 #endif
1358         }
1359 
1360         /* if we have actually died, we need to remove the strategyblock... so do this here */
1361         if((predatorStatusPointer->behaviourState == PBS_Dying)&&
1362            (predatorStatusPointer->stateTimer <= 0)) {
1363                 DestroyAnyStrategyBlock(sbPtr);
1364         }
1365 
1366         #if 0
1367         /* Now, right at the end, fix animation speed. */
1368         if ((predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Standard)
1369                 ||(predatorStatusPointer->HModelController.Sub_Sequence==PCSS_Standard)) {
1370 
1371                 int speed,animfactor;
1372                 /* ...compute speed factor... */
1373                 speed=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity);
1374                 if (speed==0) {
1375                         animfactor=ONE_FIXED;
1376                 } else {
1377                         animfactor=DIV_FIXED(625,speed); // Was 512!  Difference to correct for rounding down...
1378                 }
1379                 GLOBALASSERT(animfactor>0);
1380                 if (ShowPredoStats) {
1381                         PrintDebuggingText("Anim Factor %d, Tweening %d\n",animfactor,predatorStatusPointer->HModelController.Tweening);
1382                 }
1383                 if (predatorStatusPointer->HModelController.Tweening==0) {
1384                         HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor);
1385                 }
1386         }
1387         #endif
1388 
1389         /* Update delta playing flag. */
1390         {
1391                 DELTA_CONTROLLER *hitdelta;
1392 
1393                 hitdelta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
1394 
1395                 if (hitdelta) {
1396                         if (DeltaAnimation_IsFinished(hitdelta)) {
1397                                 hitdelta->Playing=0;
1398                         }
1399                 }
1400         }
1401 
1402 	if (predatorStatusPointer->Explode) {
1403 		StartPredatorSelfDestructExplosion(sbPtr);
1404 	}
1405 }
1406 
PredatorHandleMovingAnimation(STRATEGYBLOCK * sbPtr)1407 void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr)
1408 {
1409         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1410         VECTORCH offset;
1411         int speed,animfactor,walking;
1412 
1413         LOCALASSERT(sbPtr);
1414         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
1415     LOCALASSERT(predatorStatusPointer);
1416 
1417         offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx;
1418         offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
1419         offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz;
1420 
1421         /* ...compute speed factor... */
1422         speed=Magnitude(&offset);
1423         if ((speed<(MUL_FIXED(NormalFrameTime,50)))
1424                 &&(predatorStatusPointer->HModelController.Tweening==0)) {
1425                 /* Not moving much, are we?  Be stationary! */
1426                if (ShowPredoStats)
1427                {
1428                         PrintDebuggingText("Forced stationary animation!\n");
1429                }
1430                if(predatorStatusPointer->IAmCrouched)
1431                {
1432                         if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorCrouch)
1433                                 ||(predatorStatusPointer->HModelController.Sub_Sequence!=PCrSS_Standard))
1434                         {
1435                                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,-1,(ONE_FIXED>>3));
1436                         }
1437                 }
1438                 else
1439                 {
1440                         if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorStand)
1441                                 ||(predatorStatusPointer->HModelController.Sub_Sequence!=PSSS_Standard))
1442                         {
1443                                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,-1,(ONE_FIXED>>3));
1444                                  // Alex: this is a bit of a fudge
1445                                 (predatorStatusPointer->avoidanceManager.avoidanceDirection).vx = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vx;
1446                                 (predatorStatusPointer->avoidanceManager.avoidanceDirection).vz = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vz;
1447                         }
1448                 }
1449                 return;
1450         }
1451         speed=DIV_FIXED(speed,NormalFrameTime);
1452 
1453         if (speed==0) {
1454                 animfactor=ONE_FIXED;
1455         } else {
1456                 animfactor=DIV_FIXED(625,speed); // Was 512!  Difference to correct for rounding down...
1457         }
1458         GLOBALASSERT(animfactor>0);
1459         if (ShowPredoStats) {
1460                 PrintDebuggingText("Anim Factor %d, Tweening %d, Speed %d\n",animfactor,predatorStatusPointer->HModelController.Tweening,speed);
1461         }
1462 
1463         walking=0;
1464 
1465         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,HMSQT_PredatorRun,PRSS_Walk)) {
1466                 /* Are we currently walking? */
1467                 if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun)
1468                         &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Walk)) {
1469                         if (speed<PRED_WALKING_SPEED_MAX) {
1470                                 walking=1;
1471                         } else {
1472                                 walking=0;
1473                         }
1474                 } else {
1475                         if (speed<PRED_WALKING_SPEED_MIN) {
1476                                 walking=1;
1477                         } else {
1478                                 walking=0;
1479                         }
1480                 }
1481         }
1482 
1483         /* Start animation? */
1484         if (predatorStatusPointer->HModelController.Tweening==0) {
1485 
1486                 /* If still tweening, probably best to leave it alone... */
1487 
1488                 if (PredatorShouldBeCrawling(sbPtr)) {
1489 
1490                         predatorStatusPointer->IAmCrouched=1;
1491 
1492                         /* Only one possible sequence here. */
1493                         if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorCrawl)
1494                                 ||(predatorStatusPointer->HModelController.Sub_Sequence!=PCSS_Standard)) {
1495                                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1496                         }
1497 
1498                 } else if (walking==0) {
1499 
1500                         predatorStatusPointer->IAmCrouched=0;
1501 
1502                         /* Are we doing the right anim? */
1503                         if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorRun)
1504                                 ||(predatorStatusPointer->HModelController.Sub_Sequence!=PRSS_Standard)) {
1505 
1506                                 /* If we're currently walking, tween over. */
1507                                 if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun)
1508                                         &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Walk)) {
1509                                         InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun,
1510                                                 PRSS_Standard,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1);
1511                                 } else {
1512                                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1513                                 }
1514                         }
1515 
1516                 } else {
1517 
1518                         predatorStatusPointer->IAmCrouched=0;
1519 
1520                         /* Are we doing the right anim? */
1521                         if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorRun)
1522                                 ||(predatorStatusPointer->HModelController.Sub_Sequence!=PRSS_Walk)) {
1523                                 /* If we're currently running, tween over. */
1524                                 if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun)
1525                                         &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Standard)) {
1526                                         InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun,
1527                                                 PRSS_Walk,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1);
1528                                 } else {
1529                                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Walk,ONE_FIXED,(ONE_FIXED>>3));
1530                                 }
1531                         }
1532 
1533                 }
1534 
1535         }
1536 
1537         if (predatorStatusPointer->HModelController.Tweening==0) {
1538                 HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor);
1539         }
1540 
1541 }
1542 
MakePredatorNear(STRATEGYBLOCK * sbPtr)1543 void MakePredatorNear(STRATEGYBLOCK *sbPtr)
1544 {
1545         extern MODULEMAPBLOCK AlienDefaultMap;
1546         MODULE tempModule;
1547         DISPLAYBLOCK *dPtr;
1548         DYNAMICSBLOCK *dynPtr;
1549         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1550 
1551         LOCALASSERT(sbPtr);
1552         dynPtr = sbPtr->DynPtr;
1553         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
1554     LOCALASSERT(predatorStatusPointer);
1555     LOCALASSERT(dynPtr);
1556         LOCALASSERT(sbPtr->SBdptr == NULL);
1557 
1558         AlienDefaultMap.MapShape = sbPtr->shapeIndex;
1559         tempModule.m_mapptr = &AlienDefaultMap;
1560         tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
1561         tempModule.m_numlights = 0;
1562         tempModule.m_lightarray = (struct lightblock *)0;
1563         tempModule.m_extraitemdata = (struct extraitemdata *)0;
1564         tempModule.m_dptr = NULL;
1565         AllocateModuleObject(&tempModule);
1566         dPtr = tempModule.m_dptr;
1567         if(dPtr==NULL) return; /* cannot allocate displayblock, so leave far */
1568 
1569         sbPtr->SBdptr = dPtr;
1570         dPtr->ObStrategyBlock = sbPtr;
1571         dPtr->ObMyModule = NULL;
1572 
1573         /* need to initialise positional information in the new display block */
1574         dPtr->ObWorld = dynPtr->Position;
1575         dPtr->ObEuler = dynPtr->OrientEuler;
1576         dPtr->ObMat = dynPtr->OrientMat;
1577 
1578         /* status block init */
1579         predatorStatusPointer->weaponTarget.vx = predatorStatusPointer->weaponTarget.vy = predatorStatusPointer->weaponTarget.vz = 0;
1580         predatorStatusPointer->volleySize = 0;
1581         InitPredatorCloak(predatorStatusPointer);
1582 
1583         /* regenerate health (before deciding whether to attack or defend) */
1584         if(predatorStatusPointer->health < predatorCV[predatorStatusPointer->personalNumber].startingHealth)
1585         {
1586                 predatorStatusPointer->health += predatorCV[predatorStatusPointer->personalNumber].regenerationUnit;
1587 
1588                 if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].startingHealth)
1589                         predatorStatusPointer->health = predatorCV[predatorStatusPointer->personalNumber].startingHealth;
1590         }
1591 
1592         /* zero linear velocity in dynamics block */
1593         sbPtr->DynPtr->LinVelocity.vx = 0;
1594         sbPtr->DynPtr->LinVelocity.vy = 0;
1595         sbPtr->DynPtr->LinVelocity.vz = 0;
1596 
1597         /* initialise state and sequence... */
1598 
1599         dPtr->HModelControlBlock=&predatorStatusPointer->HModelController;
1600 
1601         CentrePredatorElevation(sbPtr);
1602 
1603         ProveHModel(dPtr->HModelControlBlock,dPtr);
1604 
1605         /* LOCALASSERT(predatorStatusPointer->nearBehaviourState != PNS_Dying); */
1606         if(PredatorShouldBeCrawling(sbPtr)) predatorStatusPointer->IAmCrouched = 1;
1607         else predatorStatusPointer->IAmCrouched = 0;
1608 
1609         /*Copy extents from the collision extents in extents.c*/
1610         dPtr->ObMinX=-CollisionExtents[CE_PREDATOR].CollisionRadius;
1611         dPtr->ObMaxX=CollisionExtents[CE_PREDATOR].CollisionRadius;
1612         dPtr->ObMinZ=-CollisionExtents[CE_PREDATOR].CollisionRadius;
1613         dPtr->ObMaxZ=CollisionExtents[CE_PREDATOR].CollisionRadius;
1614         dPtr->ObMinY=CollisionExtents[CE_PREDATOR].CrouchingTop;
1615         dPtr->ObMaxY=CollisionExtents[CE_PREDATOR].Bottom;
1616         dPtr->ObRadius = 1000;
1617         InitWaypointManager(&predatorStatusPointer->waypointManager);
1618 
1619         if (predatorStatusPointer->behaviourState==PBS_Recovering) {
1620                 if(predatorStatusPointer->IAmCrouched) {
1621                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1622                 } else {
1623                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1624                 }
1625         } else if ((predatorStatusPointer->behaviourState!=PBS_SwapWeapon)
1626         	&&(predatorStatusPointer->behaviourState!=PBS_SelfDestruct)) {
1627                 if(predatorStatusPointer->IAmCrouched) {
1628                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1629                 } else {
1630                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
1631                 }
1632         }
1633 
1634 }
1635 
MakePredatorFar(STRATEGYBLOCK * sbPtr)1636 void MakePredatorFar(STRATEGYBLOCK *sbPtr)
1637 {
1638         /* get the predator's status block */
1639         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1640         int i;
1641 
1642         LOCALASSERT(sbPtr);
1643         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
1644         LOCALASSERT(predatorStatusPointer);
1645         LOCALASSERT(sbPtr->SBdptr != NULL);
1646 
1647         /* get rid of the displayblock */
1648         i = DestroyActiveObject(sbPtr->SBdptr);
1649         LOCALASSERT(i==0);
1650         sbPtr->SBdptr = NULL;
1651 
1652         /* zero linear velocity in dynamics block */
1653         sbPtr->DynPtr->LinVelocity.vx = 0;
1654         sbPtr->DynPtr->LinVelocity.vy = 0;
1655         sbPtr->DynPtr->LinVelocity.vz = 0;
1656 
1657         /* status block init */
1658         if ((predatorStatusPointer->behaviourState!=PBS_SwapWeapon)
1659         	&&(predatorStatusPointer->behaviourState!=PBS_SelfDestruct)) {
1660                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
1661         }
1662         InitPredatorCloak(predatorStatusPointer);
1663 
1664         /* initialise state and sequence... */
1665         if(predatorStatusPointer->behaviourState == PBS_Dying)
1666         {
1667                 DestroyAnyStrategyBlock(sbPtr);
1668                 return;
1669         }
1670 
1671         #if 0
1672         if(PredatorShouldAttackPlayer(sbPtr))
1673         {
1674                 predatorStatusPointer->behaviourState = PBS_Hunting;
1675         }
1676         else
1677         {
1678                 predatorStatusPointer->behaviourState = PBS_Withdrawing;
1679         }
1680         #endif
1681 }
1682 
PredatorIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,SECTION_DATA * Section,VECTORCH * incoming)1683 void PredatorIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming)
1684 {
1685 
1686         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1687 
1688         LOCALASSERT(sbPtr);
1689         LOCALASSERT(sbPtr->DynPtr);
1690         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
1691         LOCALASSERT(predatorStatusPointer);
1692 
1693         /* if we're dying, do nothing */
1694         if(predatorStatusPointer->behaviourState==PBS_Dying)
1695         {
1696                 /* PFS should be dying, too */
1697                 return;
1698         }
1699 
1700         if(!(sbPtr->SBdptr))
1701         {
1702                 DestroyAnyStrategyBlock(sbPtr);
1703                 return;
1704         }
1705 
1706         /* Might want to get a new target? */
1707 
1708         predatorStatusPointer->Target=NULL;
1709 
1710         if (predatorStatusPointer->behaviourState!=PBS_SelfDestruct) {
1711                 NPC_DATA *NpcData;
1712                 /* we are far enough away, so return to approach? */
1713 
1714                 NpcData=GetThisNpcData(I_NPC_Predator);
1715 
1716                 if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-3)))
1717                         &&(sbPtr->SBDamageBlock.Health>0)) {
1718                         /* 12.5% health? */
1719                         Predator_Enter_SelfDestruct_State(sbPtr);
1720                         return;
1721                 }
1722         }
1723 
1724 		#if 0
1725 		{
1726 			int tkd;
1727 			VECTORCH origin,blast;
1728 			/* Make a blood splat? */
1729 			tkd=TotalKineticDamage(damage);
1730 			tkd=MUL_FIXED(tkd,multiple);
1731 
1732 			if (tkd) {
1733 				if (Section) {
1734 					origin=Section->World_Offset;
1735 				} else {
1736 					GetTargetingPointOfObject_Far(sbPtr,&origin);
1737 				}
1738 				if (incoming) {
1739 					blast=origin;
1740 					blast.vx+=incoming->vx;
1741 					blast.vy+=incoming->vy;
1742 					blast.vz+=incoming->vz;
1743 				} else {
1744 					blast=origin;
1745 				}
1746 				MakeBloodExplosion(&origin, 100, &blast, (tkd>>2), PARTICLE_PREDATOR_BLOOD);
1747 			}
1748 		}
1749 		#endif
1750 
1751 		/* Do we really want to die? */
1752         if(sbPtr->SBDamageBlock.Health <= 0) {
1753 	        if (predatorStatusPointer->behaviourState!=PBS_SelfDestruct) {
1754 				if (damage->Id==AMMO_ALIEN_TAIL) {
1755 					/* Actually, don't die just yet... */
1756 	                NPC_DATA *NpcData;
1757 
1758 	                NpcData=GetThisNpcData(I_NPC_Predator);
1759 
1760 	                sbPtr->SBDamageBlock.Health=(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-3));
1761 					/* 12.5% health. */
1762 					Predator_Enter_SelfDestruct_State(sbPtr);
1763 					return;
1764 				}
1765 			}
1766 		}
1767 
1768         if(sbPtr->SBDamageBlock.Health <= 0)
1769         {
1770                 /* KILL PREDATOR! */
1771                 int deathtype=0;
1772 
1773 				if (AvP.PlayerType!=I_Predator) {
1774 					CurrentGameStats_CreatureKilled(sbPtr,Section);
1775 				}
1776 
1777                 /*notify death target ,if predator has one*/
1778                 if(predatorStatusPointer->death_target_sbptr)
1779                 {
1780                         RequestState(predatorStatusPointer->death_target_sbptr,predatorStatusPointer->death_target_request, 0);
1781                 }
1782 
1783                 #if 0
1784                 /* switch to dying-suicide state? */
1785                 predatorStatusPointer->behaviourState = PBS_Dying;
1786                 predatorStatusPointer->stateTimer = PRED_DIETIME;
1787                 /* No longer need with corpses, and allows us to reference behaviourState later. */
1788                 #endif
1789 
1790                 /* Set deathtype */
1791 
1792                 {
1793                         int tkd;
1794 
1795                         tkd=TotalKineticDamage(damage);
1796                         deathtype=0;
1797 
1798                         if (damage->ExplosivePower==1) {
1799                                 if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
1800                                         /* Okay, you can... splat now. */
1801                                         predatorStatusPointer->GibbFactor=-(ONE_FIXED>>1);
1802                                         deathtype=2;
1803                                 }
1804                         } else if ((tkd<40)&&((multiple>>16)>1)) {
1805                                 int newmult;
1806 
1807                                 newmult=DIV_FIXED(multiple,NormalFrameTime);
1808                                 if (MUL_FIXED(tkd,newmult)>(500)) {
1809                                         predatorStatusPointer->GibbFactor=-(ONE_FIXED>>2);
1810                                         deathtype=2;
1811                                 }
1812                         }
1813 
1814                         if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) {
1815                                 /* Basically SADARS only. */
1816                                 predatorStatusPointer->GibbFactor=-(ONE_FIXED);
1817                                 deathtype=3;
1818                         }
1819                 }
1820 
1821                 if (damage->ForceBoom) {
1822                         deathtype+=damage->ForceBoom;
1823                 }
1824 
1825                 {
1826                         SECTION_DATA *chest;
1827 
1828                         chest=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"chest");
1829 
1830                         if (chest==NULL) {
1831                                 /* I'm impressed. */
1832                                 deathtype+=2;
1833                         } else if ((chest->flags&section_data_notreal)
1834                                 &&(chest->flags&section_data_terminate_here)) {
1835                                 /* That's gotta hurt. */
1836                                 deathtype++;
1837                         }
1838                 }
1839 
1840 				/* Gibb noise? */
1841 				if (predatorStatusPointer->GibbFactor>0) {
1842 					/* This probably never happens... */
1843 				} else {
1844 					SECTION_DATA *head;
1845 					/* make a sound... if you have a head. */
1846 					head=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"head");
1847 
1848 					/* Is it still attached? */
1849 					if (head) {
1850 						if (head->flags&section_data_notreal) {
1851 							head=NULL;
1852 						}
1853 					}
1854 
1855 					if ((predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX)&&(head)) {
1856 						DoPredatorDeathSound(sbPtr);
1857 					}
1858 				}
1859 
1860                 {
1861                         DEATH_DATA *this_death;
1862                         HIT_FACING facing;
1863                         SECTION *root;
1864                         int burning;
1865                         int wounds;
1866 
1867                         root=GetNamedHierarchyFromLibrary("hnpcpredator","Template");
1868 
1869                         facing.Front=0;
1870                         facing.Back=0;
1871                         facing.Left=0;
1872                         facing.Right=0;
1873 
1874                         if (incoming) {
1875                                 if (incoming->vz>0) {
1876                                         facing.Back=1;
1877                                 } else {
1878                                         facing.Front=1;
1879                                 }
1880                                 if (incoming->vx>0) {
1881                                         facing.Right=1;
1882                                 } else {
1883                                         facing.Left=1;
1884                                 }
1885                         }
1886 
1887                         if ((damage->Impact==0)
1888                                 &&(damage->Cutting==0)
1889                                 &&(damage->Penetrative==0)
1890                                 &&(damage->Fire>0)
1891                                 &&(damage->Electrical==0)
1892                                 &&(damage->Acid==0)
1893                                 ) {
1894                                 burning=1;
1895                         } else {
1896                                 burning=0;
1897                         }
1898 
1899                         if (Section) {
1900                                 wounds=(Section->flags&section_flags_wounding);
1901                         } else {
1902                                 wounds=0;
1903                         }
1904 
1905                         //if (predatorStatusPointer->behaviourState==PBS_SelfDestruct) {
1906                         //      this_death=&Predator_Special_SelfDestruct_Death;
1907                         //} else {
1908                                 this_death=GetPredatorDeathSequence(&predatorStatusPointer->HModelController,root,wounds,
1909                                         wounds,deathtype,&facing,burning,predatorStatusPointer->IAmCrouched,0);
1910                         //}
1911 
1912                         GLOBALASSERT(this_death);
1913 
1914                         Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
1915                         Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
1916 
1917                         Convert_Predator_To_Corpse(sbPtr,this_death);
1918 
1919                         return;
1920                 }
1921         } else {
1922                 /* If not dead, play a hit delta. */
1923                 DELTA_CONTROLLER *hitdelta;
1924                 int frontback;
1925 
1926 				if ((damage->Impact==0)
1927 					&&(damage->Cutting==0)
1928 					&&(damage->Penetrative==0)
1929 					&&(damage->Fire==0)
1930 					&&(damage->Electrical==0)
1931 					&&(damage->Acid>0)
1932 					) {
1933 					DoPredatorAcidSound(sbPtr);
1934 				} else {
1935 					DoPredatorHitSound(sbPtr);
1936 				}
1937 
1938                 hitdelta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
1939 
1940                 if (incoming) {
1941                         if (incoming->vz>=0) {
1942                                 frontback=0;
1943                         } else {
1944                                 frontback=1;
1945                         }
1946                 } else {
1947                         /* Default to front. */
1948                         frontback=1;
1949                 }
1950 
1951                 if (hitdelta) {
1952                         /* A hierarchy with hit deltas! */
1953                         if (hitdelta->Playing==0) {
1954 
1955                                 int CrouchSubSequence;
1956                                 int StandSubSequence;
1957 
1958                                 if (Section==NULL) {
1959                                         if (frontback==0) {
1960                                                 CrouchSubSequence=PCrSS_HitChestBack;
1961                                                 StandSubSequence=PSSS_HitChestBack;
1962                                         } else {
1963                                                 CrouchSubSequence=PCrSS_HitChestFront;
1964                                                 StandSubSequence=PSSS_HitChestFront;
1965                                         }
1966                                 } else if (Section->sempai->flags&section_flag_head) {
1967                                         if (frontback==0) {
1968                                                 CrouchSubSequence=PCrSS_HitHeadBack;
1969                                                 StandSubSequence=PSSS_HitHeadBack;
1970                                         } else {
1971                                                 CrouchSubSequence=PCrSS_HitHeadFront;
1972                                                 StandSubSequence=PSSS_HitHeadFront;
1973                                         }
1974                                 } else if ((Section->sempai->flags&section_flag_left_arm)
1975                                         ||(Section->sempai->flags&section_flag_left_hand)) {
1976                                         if (frontback==0) {
1977                                                 CrouchSubSequence=PCrSS_HitRightArm;
1978                                                 StandSubSequence=PSSS_HitRightArm;
1979                                         } else {
1980                                                 CrouchSubSequence=PCrSS_HitLeftArm;
1981                                                 StandSubSequence=PSSS_HitLeftArm;
1982                                         }
1983                                 } else if ((Section->sempai->flags&section_flag_right_arm)
1984                                         ||(Section->sempai->flags&section_flag_right_hand)) {
1985                                         if (frontback==0) {
1986                                                 CrouchSubSequence=PCrSS_HitLeftArm;
1987                                                 StandSubSequence=PSSS_HitLeftArm;
1988                                         } else {
1989                                                 CrouchSubSequence=PCrSS_HitRightArm;
1990                                                 StandSubSequence=PSSS_HitRightArm;
1991                                         }
1992                                 } else if ((Section->sempai->flags&section_flag_left_leg)
1993                                         ||(Section->sempai->flags&section_flag_left_foot)) {
1994                                         if (frontback==0) {
1995                                                 CrouchSubSequence=PCrSS_HitRightLeg;
1996                                                 StandSubSequence=PSSS_HitRightLeg;
1997                                         } else {
1998                                                 CrouchSubSequence=PCrSS_HitLeftLeg;
1999                                                 StandSubSequence=PSSS_HitLeftLeg;
2000                                         }
2001                                 } else if ((Section->sempai->flags&section_flag_right_leg)
2002                                         ||(Section->sempai->flags&section_flag_right_foot)) {
2003                                         if (frontback==0) {
2004                                                 CrouchSubSequence=PCrSS_HitLeftLeg;
2005                                                 StandSubSequence=PSSS_HitLeftLeg;
2006                                         } else {
2007                                                 CrouchSubSequence=PCrSS_HitRightLeg;
2008                                                 StandSubSequence=PSSS_HitRightLeg;
2009                                         }
2010                                 } else {
2011                                         /* Chest or misc. hit. */
2012                                         if (frontback==0) {
2013                                                 CrouchSubSequence=PCrSS_HitChestBack;
2014                                                 StandSubSequence=PSSS_HitChestBack;
2015                                         } else {
2016                                                 CrouchSubSequence=PCrSS_HitChestFront;
2017                                                 StandSubSequence=PSSS_HitChestFront;
2018                                         }
2019                                 }
2020 
2021 
2022                                 if(predatorStatusPointer->IAmCrouched) {
2023                                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorCrouch,CrouchSubSequence)) {
2024                                                 Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorCrouch,CrouchSubSequence,-1);
2025                                         }
2026                                 } else {
2027                                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,StandSubSequence)) {
2028                                                 Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorStand,StandSubSequence,-1);
2029                                         }
2030                                 }
2031                                 hitdelta->Playing=1;
2032                                 /* Not looped. */
2033                         }
2034                 }
2035 
2036                 /* Break out of recover. */
2037                 if (predatorStatusPointer->behaviourState==PBS_Recovering) {
2038                         Predator_Enter_Swapping_State(sbPtr);
2039                 }
2040 
2041         }
2042 }
2043 
2044 /* Patrick 4/7/97 --------------------------------------------------
2045   The various far state behaviour execution functions for predator...
2046 
2047   1. Wandering is the initial far state, to which the predator never
2048   returns: after becoming visible for the first time, it will use only
2049   hunt and retreat
2050   2. Hunting is used if the predator feels confident enough to engage
2051   the player.
2052   3. Retreating is used if the predator is not confident
2053 ---------------------------------------------------------------------*/
Execute_PFS_Wander(STRATEGYBLOCK * sbPtr)2054 static PRED_RETURN_CONDITION Execute_PFS_Wander(STRATEGYBLOCK *sbPtr)
2055 {
2056         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2057         AIMODULE *targetModule = 0;
2058 
2059         LOCALASSERT(sbPtr);
2060         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2061         LOCALASSERT(predatorStatusPointer);
2062 
2063         /* Decrement the Far state timer */
2064         predatorStatusPointer->stateTimer -= NormalFrameTime;
2065         /* check if far state timer has timed-out. If so, it is time
2066         to do something. Otherwise just return. */
2067         if(predatorStatusPointer->stateTimer > 0) {
2068                 return(PRC_No_Change);
2069         }
2070 
2071         /* check for state changes */
2072         if(PredatorIsAwareOfTarget(sbPtr))
2073         {
2074                 /* we should be hunting */
2075                 return(PRC_Request_Engage);
2076         }
2077 
2078         /* Preds NEVER camp.  I mean, get tired of wandering. */
2079 
2080         /* timer has timed-out in roving mode */
2081         targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL,0);
2082 
2083         /* if there is no target module, it means that the pred is trapped in an
2084         unlinked module. In this case, reset the timer and return. */
2085         if(!targetModule)
2086         {
2087                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2088                 return(PRC_No_Change);
2089         }
2090         /* Examine target, and decide what to do */
2091         GLOBALASSERT(AIModuleIsPhysical(targetModule));
2092         ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
2093         /* reset timer */
2094         predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2095         return(PRC_No_Change);
2096 }
2097 
Execute_PFS_Hunt(STRATEGYBLOCK * sbPtr)2098 static PRED_RETURN_CONDITION Execute_PFS_Hunt(STRATEGYBLOCK *sbPtr)
2099 {
2100         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2101         AIMODULE *targetModule = 0;
2102 
2103         LOCALASSERT(sbPtr);
2104         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2105         LOCALASSERT(predatorStatusPointer);
2106 
2107         /* Decrement the Far state timer */
2108         predatorStatusPointer->stateTimer -= NormalFrameTime;
2109         /* check if far state timer has timed-out. If so, it is time
2110         to do something. Otherwise just return. */
2111         if(predatorStatusPointer->stateTimer > 0) {
2112                 return(PRC_No_Change);
2113         }
2114 
2115         if ((!PredatorIsAwareOfTarget(sbPtr))
2116                 ||(predatorStatusPointer->Target!=Player->ObStrategyBlock))
2117         {
2118                 /* I have a bad feeling about this. */
2119                 return(PRC_Request_Wander);
2120         }
2121 
2122         /* timer has timed-out in hunting mode: */
2123         targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0);
2124 
2125         /* if there is no target module, it means that the pred is trapped in an
2126         unlinked module. In this case, reset the timer and return. */
2127         if(!targetModule)
2128         {
2129                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2130                 return(PRC_No_Change);
2131         }
2132 
2133         /* NB don't need to check for state changes... will regen health on makenear */
2134 
2135         /* Examine target, and decide what to do */
2136         GLOBALASSERT(AIModuleIsPhysical(targetModule));
2137         ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
2138         /* reset timer */
2139         predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2140         return(PRC_No_Change);
2141 }
2142 
Execute_PFS_Engage(STRATEGYBLOCK * sbPtr)2143 static PRED_RETURN_CONDITION Execute_PFS_Engage(STRATEGYBLOCK *sbPtr)
2144 {
2145         /* If we're far, we should be hunting, surely? */
2146 
2147         return(PRC_Request_Hunt);
2148 
2149 }
2150 
Execute_PFS_Retreat(STRATEGYBLOCK * sbPtr)2151 static PRED_RETURN_CONDITION Execute_PFS_Retreat(STRATEGYBLOCK *sbPtr)
2152 {
2153         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2154         AIMODULE *targetModule = 0;
2155         AIMODULE *old_fearmodule;
2156 
2157         LOCALASSERT(sbPtr);
2158         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2159         LOCALASSERT(predatorStatusPointer);
2160 
2161         old_fearmodule=predatorStatusPointer->fearmodule;
2162 
2163         /* Decrement the state timer */
2164         predatorStatusPointer->stateTimer -= NormalFrameTime;
2165 
2166         if(!(PredatorIsAwareOfTarget(sbPtr))) {
2167                 /* What am I running from? */
2168                 return(PRC_Request_Recover);
2169         }
2170 
2171         /* check for state changes: randomly decide to switch to recover... */
2172 
2173         if (predatorStatusPointer->incidentFlag) {
2174                 if (!(PredatorCanSeeTarget(sbPtr))) {
2175                         return(PRC_Request_Recover);
2176                 }
2177         }
2178 
2179         if(predatorStatusPointer->stateTimer > 0) {
2180                 return(PRC_No_Change);
2181         }
2182 
2183         /* timer has timed-out in retreat mode: */
2184 
2185         /* Yeah, from where _am_ I running? */
2186         if(PredatorIsAwareOfTarget(sbPtr)) {
2187                 predatorStatusPointer->fearmodule=predatorStatusPointer->Target->containingModule->m_aimodule;
2188         } else if (predatorStatusPointer->fearmodule==NULL) {
2189                 predatorStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule;
2190         }
2191 
2192         if ((predatorStatusPointer->missionmodule==NULL)||(predatorStatusPointer->fearmodule!=old_fearmodule)) {
2193 
2194                 /* Recompute mission module. */
2195                 if (predatorStatusPointer->fearmodule) {
2196                         predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5);
2197                 } else {
2198                         predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,Player->ObStrategyBlock->containingModule->m_aimodule,5);
2199                 }
2200 
2201         }
2202 
2203         if (predatorStatusPointer->missionmodule==NULL) {
2204                 /* Hey, it'll drop through. */
2205                 return(PRC_Request_Recover);
2206         }
2207 
2208         targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0);
2209 
2210         if(!targetModule)
2211         {
2212                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2213                 return(PRC_Request_Recover);
2214         }
2215 
2216         /* Examine target, and decide what to do */
2217         GLOBALASSERT(AIModuleIsPhysical(targetModule));
2218         ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
2219         /* reset timer */
2220         predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2221         return(PRC_No_Change);
2222 }
2223 
Execute_PFS_Avoidance(STRATEGYBLOCK * sbPtr)2224 static PRED_RETURN_CONDITION Execute_PFS_Avoidance(STRATEGYBLOCK *sbPtr) {
2225 
2226         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2227 
2228         LOCALASSERT(sbPtr);
2229         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2230     LOCALASSERT(predatorStatusPointer);
2231 
2232         /* High on the list of Things Not To Be Doing. */
2233 
2234         #if ALL_NEW_AVOIDANCE_PRED
2235         Initialise_AvoidanceManager(sbPtr,&predatorStatusPointer->avoidanceManager);
2236         #endif
2237 
2238         switch (predatorStatusPointer->lastState) {
2239                 case PBS_Recovering:
2240                         return(PRC_Request_Recover);
2241                         break;
2242                 case PBS_Hunting:
2243                         return(PRC_Request_Hunt);
2244                         break;
2245                 case PBS_Engaging:
2246                         /* Go directly to approach.  Do not pass GO.  Do not collect 200 zorkmids. */
2247                         return(PRC_Request_Engage);
2248                         break;
2249                 default:
2250                         return(PRC_Request_Wander);
2251                         break;
2252         }
2253         /* Still here? */
2254         return(PRC_Request_Wander);
2255 
2256 }
2257 
ProcessFarPredatorTargetAIModule(STRATEGYBLOCK * sbPtr,AIMODULE * targetModule)2258 static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
2259 {
2260         NPC_TARGETMODULESTATUS targetStatus;
2261         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2262 
2263         LOCALASSERT(sbPtr);
2264         LOCALASSERT(targetModule);
2265         LOCALASSERT(sbPtr->I_SBtype == I_BehaviourPredator);
2266         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2267         LOCALASSERT(predatorStatusPointer);
2268 
2269         targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0);
2270         switch(targetStatus)
2271         {
2272                 case(NPCTM_NoEntryPoint):
2273                 {
2274                         /* do nothing: can't get in. reset lastVisitedModule to avoid getting
2275                         stuck in a conceptual dead end (?)*/
2276                         FarNpc_FlipAround(sbPtr);
2277                         break;
2278                 }
2279                 case(NPCTM_NormalRoom):
2280                 {
2281                         /* locate to target     */
2282                         LocateFarNPCInAIModule(sbPtr, targetModule);
2283                         break;
2284                 }
2285                 case(NPCTM_AirDuct):
2286                 {
2287                         LocateFarNPCInAIModule(sbPtr, targetModule);
2288                         break;
2289                 }
2290                 case(NPCTM_LiftTeleport):
2291                 {
2292                         /* do nothing - predators can't go into lifts   */
2293                         FarNpc_FlipAround(sbPtr);
2294                         break;
2295                 }
2296                 case(NPCTM_ProxDoorOpen):
2297                 {
2298                         /* locate to target: don't need to move thro'quick, as door is constantly retriggered   */
2299                         LocateFarNPCInAIModule(sbPtr, targetModule);
2300                         break;
2301                 }
2302                 case(NPCTM_ProxDoorNotOpen):
2303                 {
2304                         /* trigger the door, and set timer to quick so we can catch the door when it's open */
2305                         MODULE *renderModule;
2306                         renderModule=*(targetModule->m_module_ptrs);
2307                         /* trigger the door, and set timer to quick so we can catch the door when it's open */
2308                         ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1;
2309                         break;
2310                 }
2311                 case(NPCTM_LiftDoorOpen):
2312                 {
2313                         /* do nothing - can't use lifts */
2314                         FarNpc_FlipAround(sbPtr);
2315                         break;
2316                 }
2317                 case(NPCTM_LiftDoorNotOpen):
2318                 {
2319                         /*  do nothing - can't open lift doors */
2320                         FarNpc_FlipAround(sbPtr);
2321                         break;
2322                 }
2323                 case(NPCTM_SecurityDoorOpen):
2324                 {
2325                         /* locate to target, and move thro' quick as we can't retrigger */
2326                         LocateFarNPCInAIModule(sbPtr, targetModule);
2327                         break;
2328                 }
2329                 case(NPCTM_SecurityDoorNotOpen):
2330                 {
2331                         MODULE *renderModule;
2332                         renderModule=*(targetModule->m_module_ptrs);
2333                         /* do some door opening stuff here. Door should stay open for long enough
2334                         for us to catch it open next time */
2335                         RequestState((renderModule->m_sbptr),1,0);
2336                         break;
2337                 }
2338                 default:
2339                 {
2340                         LOCALASSERT(1==0);
2341                         break;
2342                 }
2343         }
2344 }
2345 
Execute_PNS_DischargePistol(STRATEGYBLOCK * sbPtr)2346 static PRED_RETURN_CONDITION Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr)
2347 {
2348         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2349         VECTORCH orientationDirn,relPos,relPos2;
2350         int correctlyOrientated,range;
2351 
2352         LOCALASSERT(sbPtr);
2353         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2354         LOCALASSERT(predatorStatusPointer);
2355 
2356         /* zero linear velocity in dynamics block */
2357         LOCALASSERT(sbPtr->DynPtr);
2358         sbPtr->DynPtr->LinVelocity.vx = 0;
2359         sbPtr->DynPtr->LinVelocity.vy = 0;
2360         sbPtr->DynPtr->LinVelocity.vz = 0;
2361 
2362         if (predatorStatusPointer->Target==NULL) {
2363                 /* Bomb out. */
2364                 return(PRC_Request_Wander);
2365         }
2366 
2367         /* Always turn to face... */
2368         GLOBALASSERT(predatorStatusPointer->Target);
2369         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
2370 
2371         /* Fix weapon target! */
2372         {
2373                 predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
2374                         200);
2375                 predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
2376                         200);
2377                 predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
2378                         200);
2379         }
2380 		/* Aim up a little? */
2381 		range=VectorDistance((&predatorStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position));
2382 
2383 		if (range>3000) {
2384 			predatorStatusPointer->weaponTarget.vy-=(range/6);
2385 		} else {
2386 			/* I'm afraid it just won't work. */
2387 			return(PRC_Request_Swap);
2388 		}
2389         /* Out of range? */
2390         if(range > predatorStatusPointer->Selected_Weapon->MaxRange)
2391         {
2392 				/* Return to approach... */
2393                 return(PRC_Request_Engage);
2394         }
2395 
2396         /* orientate to firing point first */
2397         if (predatorStatusPointer->My_Elevation_Section) {
2398                 /* Assume range large w.r.t. half shoulder width... */
2399                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
2400                 orientationDirn.vy = 0;
2401                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
2402         } else {
2403                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
2404                 orientationDirn.vy = 0;
2405                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
2406         }
2407         /* Target shift? */
2408         correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
2409 
2410         /* Decloaking? */
2411         if (predatorStatusPointer->CloakStatus==PCLOAK_On) {
2412                 PredatorCloakOff(predatorStatusPointer);
2413         }
2414 
2415         /* If still tweening, pause. */
2416         if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
2417                 return(PRC_No_Change);
2418         }
2419 
2420         if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate) {
2421 
2422                 predatorStatusPointer->HModelController.Playing=0;
2423 
2424                 /* Only terminate if you haven't fired yet... */
2425                 if(!PredatorCanSeeTarget(sbPtr))
2426                 {
2427                         #if 1
2428                         /* ... and remove the gunflash */
2429                         #endif
2430 
2431                         return(PRC_Request_Engage);
2432                 }
2433 
2434                 /* we are not correctly orientated to the target: this could happen because we have
2435                 just entered this state, or the target has moved during firing*/
2436                 if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off))
2437                 {
2438                         #if 1
2439                         /* stop visual and audio cues: technically, we're not firing at this moment */
2440                         #endif
2441                         return(PRC_No_Change);
2442                 }
2443 
2444                 /* If you are correctly oriented, you can now fire! */
2445 
2446                 predatorStatusPointer->HModelController.Playing=1;
2447                 predatorStatusPointer->HModelController.sequence_timer=0;
2448 
2449                 relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
2450                 relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
2451                 relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
2452 
2453                 relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx);
2454                 relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy);
2455                 relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz);
2456 
2457                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
2458 
2459                 #if 1
2460                 /* look after the gun flash */
2461                 #endif
2462 
2463                 /* look after the sound */
2464                 Sound_Play(SID_PRED_PISTOL,"d",&(sbPtr->DynPtr->Position));
2465 
2466                 /* Now fire a bolt. */
2467 
2468                 {
2469                         SECTION_DATA *muzzle;
2470 
2471                         muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
2472 
2473                         CreatePPPlasmaBoltKernel(&muzzle->World_Offset, &muzzle->SecMat,0);
2474                         predatorStatusPointer->volleySize++;
2475                 }
2476 
2477                 if (predatorStatusPointer->volleySize>3) {
2478                         predatorStatusPointer->enableSwap=1;
2479                 }
2480         }
2481 
2482         predatorStatusPointer->stateTimer -= NormalFrameTime;
2483 
2484         /* You must have fired already. */
2485 
2486         if(predatorStatusPointer->stateTimer > 0)       {
2487                 return(PRC_No_Change);
2488         }
2489 
2490         if(range < predatorStatusPointer->Selected_Weapon->MinRange)
2491         {
2492                 /* renew firing, as we are still too close to approach */
2493                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2494                 predatorStatusPointer->volleySize = 0;
2495                 return(PRC_No_Change);
2496         }
2497         else
2498         {
2499                 NPC_DATA *NpcData;
2500                 /* we are far enough away, so return to approach? */
2501 
2502                 NpcData=GetThisNpcData(I_NPC_Predator);
2503 
2504                 if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
2505                         &&(sbPtr->SBDamageBlock.Health>0)) {
2506                         /* 50% health? */
2507                         if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) {
2508                                 return(PRC_Request_Withdraw);
2509                         } else {
2510                                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2511                                 return(PRC_No_Change);
2512                         }
2513                 }
2514 
2515                 if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) {
2516                         if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) {
2517                                 /* Change weapon! */
2518                                 return(PRC_Request_Swap);
2519                         } else {
2520                                 return(PRC_Request_Engage);
2521                         }
2522                 } else {
2523                         /* And another! */
2524                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2525                         return(PRC_No_Change);
2526                 }
2527         }
2528         return(PRC_No_Change);
2529 }
2530 
Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK * sbPtr)2531 static PRED_RETURN_CONDITION Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr)
2532 {
2533         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2534         VECTORCH orientationDirn,relPos,relPos2;
2535         int correctlyOrientated,range,onTarget;
2536 
2537         LOCALASSERT(sbPtr);
2538         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2539         LOCALASSERT(predatorStatusPointer);
2540 
2541         /* zero linear velocity in dynamics block */
2542         LOCALASSERT(sbPtr->DynPtr);
2543         sbPtr->DynPtr->LinVelocity.vx = 0;
2544         sbPtr->DynPtr->LinVelocity.vy = 0;
2545         sbPtr->DynPtr->LinVelocity.vz = 0;
2546 
2547         if (predatorStatusPointer->Target==NULL) {
2548                 /* Bomb out. */
2549                 return(PRC_Request_Wander);
2550         }
2551 
2552         if (predatorStatusPointer->internalState==0) {
2553                 if (predatorStatusPointer->HModelController.Tweening==Controller_NoTweening) {
2554                         predatorStatusPointer->HModelController.Playing=0;
2555                 }
2556         }
2557 
2558         /* Always turn to face... */
2559         GLOBALASSERT(predatorStatusPointer->Target);
2560         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
2561 
2562         /* orientate to firing point first */
2563         if (predatorStatusPointer->My_Elevation_Section) {
2564                 /* Assume range large w.r.t. half shoulder width... */
2565                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
2566                 orientationDirn.vy = 0;
2567                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
2568         } else {
2569                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
2570                 orientationDirn.vy = 0;
2571                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
2572         }
2573         /* Target shift? */
2574         correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
2575 
2576         /* Decloaking? */
2577         if (predatorStatusPointer->CloakStatus==PCLOAK_On) {
2578                 PredatorCloakOff(predatorStatusPointer);
2579         }
2580 
2581         /* Project three dots? */
2582         onTarget=DoPredatorLaserTargeting(sbPtr);
2583 
2584 		if (predatorStatusPointer->Target->I_SBtype==I_BehaviourAutoGun) {
2585 	        predatorStatusPointer->stateTimer -= (NormalFrameTime<<2);
2586 		} else {
2587 	        predatorStatusPointer->stateTimer -= NormalFrameTime;
2588 		}
2589 
2590         /* Only terminate if you haven't fired yet... */
2591         if(!PredatorCanSeeTarget(sbPtr))
2592         {
2593                 #if 1
2594                 /* ... and remove the gunflash */
2595                 #endif
2596 
2597                 return(PRC_Request_Engage);
2598         }
2599 
2600         if (predatorStatusPointer->internalState==1) {
2601                 /* Using stateTimer, thanks! */
2602         } else if(predatorStatusPointer->stateTimer > 0)        {
2603                 return(PRC_No_Change);
2604         }
2605 
2606         /* State timed out - try to fire! */
2607 
2608         /* we are not correctly orientated to the target: this could happen because we have
2609         just entered this state, or the target has moved during firing*/
2610         if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off))
2611         {
2612                 #if 1
2613                 /* stop visual and audio cues: technically, we're not firing at this moment */
2614                 #endif
2615                 return(PRC_No_Change);
2616         }
2617 
2618         if (correctlyOrientated&&(predatorStatusPointer->internalState!=2)) {
2619                 if (predatorStatusPointer->internalState!=1) {
2620                         predatorStatusPointer->internalState=1;
2621                         /* Pausing. */
2622 	                    predatorStatusPointer->stateTimer=(ONE_FIXED);
2623                 }
2624         }
2625 
2626         range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
2627 
2628         if ((predatorStatusPointer->internalState==1)&&(predatorStatusPointer->stateTimer<=0)) {
2629                 if (onTarget) {
2630 
2631                         /* If you are correctly oriented, you can now fire!  Or taunt instead? */
2632 
2633                         if (((FastRandom()&65535)<32767)&&(predatorStatusPointer->enableTaunt)
2634                         	&&(predatorStatusPointer->Target->I_SBtype!=I_BehaviourAutoGun)) {
2635                                 /* Suprise! */
2636                                 return(PRC_Request_Taunt);
2637                         }
2638                         /* Fire at least once! */
2639                         predatorStatusPointer->enableTaunt=1;
2640 
2641                         predatorStatusPointer->HModelController.Playing=1;
2642                         predatorStatusPointer->HModelController.Looped=0;
2643                         predatorStatusPointer->HModelController.sequence_timer=0;
2644                         predatorStatusPointer->internalState=2;
2645 
2646                         relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
2647                         relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
2648                         relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
2649 
2650                         relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx);
2651                         relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy);
2652                         relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz);
2653 
2654                         #if 1
2655                         /* look after the gun flash */
2656                         #endif
2657 
2658                         /* look after the sound */
2659                         Sound_Play(SID_PRED_LAUNCHER,"d",&(sbPtr->DynPtr->Position));
2660 
2661                         /* Now fire a bolt. */
2662 
2663                         {
2664                                 SECTION_DATA *muzzle;
2665 
2666                                 muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
2667 
2668                                 InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat,0,&TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty],65536);
2669                                 predatorStatusPointer->volleySize++;
2670                         }
2671                         predatorStatusPointer->stateTimer=(ONE_FIXED);
2672                         predatorStatusPointer->enableSwap=1;
2673                         return(SRC_No_Change);
2674                 } else {
2675                         /* You think you're correctly orientated - but you're still not hitting. */
2676                         if (predatorStatusPointer->stateTimer<=0) {
2677                                 /* Oh, just give up. */
2678                                 predatorStatusPointer->HModelController.Playing=1;
2679                                 predatorStatusPointer->HModelController.Looped=0;
2680                                 predatorStatusPointer->HModelController.sequence_timer=0;
2681                                 predatorStatusPointer->internalState=2;
2682                         }
2683                 }
2684         }
2685 
2686         if (predatorStatusPointer->internalState==2) {
2687 
2688                 /* After shot. */
2689 
2690                 if (predatorStatusPointer->HModelController.sequence_timer<(ONE_FIXED-1)) {
2691                         /* Still playing. */
2692                         return(PRC_No_Change);
2693                 }
2694 
2695                 if(range < predatorStatusPointer->Selected_Weapon->MinRange)
2696                 {
2697                         /* renew firing, as we are still too close to approach */
2698                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2699                         predatorStatusPointer->volleySize = 0;
2700                         predatorStatusPointer->internalState=0;
2701                         return(PRC_No_Change);
2702                 }
2703                 else
2704                 {
2705                         NPC_DATA *NpcData;
2706                         /* we are far enough away, so return to approach? */
2707 
2708                         NpcData=GetThisNpcData(I_NPC_Predator);
2709 
2710                         if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
2711                                 &&(sbPtr->SBDamageBlock.Health>0)) {
2712                                 /* 50% health? */
2713                                 if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) {
2714                                         return(PRC_Request_Withdraw);
2715                                 } else {
2716                                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2717                                         predatorStatusPointer->internalState=0;
2718                                         return(PRC_No_Change);
2719                                 }
2720                         }
2721 
2722                         if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) {
2723                                 if ((range<PRED_CLOSE_ATTACK_RANGE)||((FastRandom()&65535)>52000)) {
2724                                         /* Change weapon! */
2725                                         return(PRC_Request_Swap);
2726                                 } else {
2727                                         return(PRC_Request_Engage);
2728                                 }
2729                         } else {
2730                                 /* And another! */
2731                                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
2732                                 predatorStatusPointer->internalState=0;
2733                                 return(PRC_No_Change);
2734                         }
2735                 }
2736 
2737         }
2738 
2739         return(PRC_No_Change);
2740 }
2741 
Execute_PNS_Avoidance(STRATEGYBLOCK * sbPtr)2742 static PRED_RETURN_CONDITION Execute_PNS_Avoidance(STRATEGYBLOCK *sbPtr)
2743 {
2744         int terminateState = 0;
2745         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2746 
2747         LOCALASSERT(sbPtr);
2748         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2749         LOCALASSERT(predatorStatusPointer);
2750 
2751         /* first check for a close attack... */
2752         if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE)
2753         {
2754                 return(PRC_Request_Attack);
2755         }
2756 
2757         /* New avoidance kernel. */
2758 
2759         NPCSetVelocity(sbPtr, &(predatorStatusPointer->avoidanceManager.avoidanceDirection), (predatorStatusPointer->nearSpeed));
2760         /* Velocity CANNOT be zero, unless deliberately so! */
2761         {
2762                 AVOIDANCE_RETURN_CONDITION rc;
2763 
2764                 rc=AllNewAvoidanceKernel(sbPtr,&predatorStatusPointer->avoidanceManager);
2765 
2766                 if (rc!=AvRC_Avoidance) {
2767                         terminateState=1;
2768                 }
2769         }
2770 
2771         PredatorHandleMovingAnimation(sbPtr);
2772 
2773         if(terminateState)
2774         {
2775                 /* Better exit. */
2776                 switch (predatorStatusPointer->lastState) {
2777                         case PBS_Avoidance:
2778                         default:
2779                                 /* switch to approach */
2780                                 if(PredatorShouldAttackPlayer(sbPtr))
2781                                 {
2782                                         /* go to approach */
2783                                         NPC_InitMovementData(&(predatorStatusPointer->moveData));
2784                                         return(PRC_Request_Engage);
2785                                 }
2786                                 else
2787                                 {
2788                                         /* go to retreat */
2789                                         NPC_InitMovementData(&(predatorStatusPointer->moveData));
2790                                         return(PRC_Request_Withdraw);
2791                                 }
2792                                 break;
2793                         case PBS_Wandering:
2794                                 return(PRC_Request_Wander);
2795                                 break;
2796                         case PBS_Hunting:
2797                                 return(PRC_Request_Hunt);
2798                                 break;
2799                         case PBS_Withdrawing:
2800                                 return(PRC_Request_Withdraw);
2801                                 break;
2802                         case PBS_Engaging:
2803                         case PBS_Attacking:
2804                                 return(PRC_Request_Engage);
2805                                 break;
2806                         case PBS_Returning:
2807                                 return(PRC_Request_Return);
2808                                 break;
2809                         case PBS_Pathfinding:
2810                                 return(PRC_Request_Pathfind);
2811                                 break;
2812                 }
2813         }
2814         return(PRC_No_Change);
2815 }
2816 
2817 #if 0
2818 static PRED_RETURN_CONDITION Execute_PNS_Approach(STRATEGYBLOCK *sbPtr)
2819 {
2820         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2821         VECTORCH velocityDirection = {0,0,0};
2822         VECTORCH targetPosition;
2823         int targetIsAirduct = 0;
2824 
2825         LOCALASSERT(sbPtr);
2826         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2827         LOCALASSERT(predatorStatusPointer);
2828 
2829         LOCALASSERT(sbPtr->DynPtr);
2830 
2831         GLOBALASSERT(0);
2832         /* Function unused! */
2833 
2834         /* Make some noise if not cloaked */
2835         if (predatorStatusPointer->CloakStatus == PCLOAK_Off)
2836         {
2837 			#if 0
2838           unsigned int random=FastRandom() & 127;
2839           switch (random)
2840           {
2841             case 0:
2842             {
2843               Sound_Play(SID_PRED_SNARL,"d",&sbPtr->DynPtr->Position);
2844                 break;
2845             }
2846             case 1:
2847             {
2848               Sound_Play(SID_PRED_SCREAM1,"d",&sbPtr->DynPtr->Position);
2849               break;
2850             }
2851             case 2:
2852             {
2853               Sound_Play(SID_PRED_LOUDROAR,"d",&sbPtr->DynPtr->Position);
2854               break;
2855             }
2856                         case 3:
2857             {
2858               Sound_Play(SID_PRED_SHORTROAR,"d",&sbPtr->DynPtr->Position);
2859               break;
2860                   }
2861       default:
2862       {
2863         break;
2864       }
2865         }
2866 			#else
2867 			DoPredatorRandomSound(sbPtr);
2868 			#endif
2869         }
2870 
2871         PredatorHandleMovingAnimation(sbPtr);
2872 
2873         /* check for state changes...*/
2874 
2875         /* now check if we want to close-attack */
2876         if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE)
2877         {
2878                 return(PRC_Request_Attack);
2879         }
2880 
2881         /* now check if we should stand ground */
2882         if(!(PredatorShouldAttackPlayer(sbPtr)))
2883         {
2884                 return(PRC_Request_Withdraw);
2885         }
2886 
2887 
2888         /* decrement the state timer if it is > 0. When this timer expires, predator
2889            will fire at player when it can next see him (or her) */
2890         if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime;
2891         if(predatorStatusPointer->stateTimer <= 0)
2892         {
2893                 /* if we can see the player, switch to fire */
2894                 if(NPCCanSeeTarget(sbPtr,Player->ObStrategyBlock, PRED_NEAR_VIEW_WIDTH))
2895                 {
2896                         return(PRC_Request_Attack);
2897                 }
2898                 else
2899                 {
2900                         /* reset the timer if we couldn't fire */
2901                         predatorStatusPointer->stateTimer = predatorCV[predatorStatusPointer->personalNumber].timeBetweenRangedAttacks;
2902                 }
2903 
2904         }
2905 
2906         /* get and set approach velocity */
2907         NPCGetMovementTarget(sbPtr, Player->ObStrategyBlock, &targetPosition, &targetIsAirduct,0);
2908         NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager);
2909         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
2910 
2911         /* test here for impeding collisions, and not being able to reach target... */
2912         {
2913                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
2914                         /* Go to all new avoidance. */
2915                         return(PRC_Request_Avoidance);
2916                 }
2917         }
2918         return(PRC_No_Change);
2919 }
2920 #endif
2921 
Execute_PNS_EngageWithPistol(STRATEGYBLOCK * sbPtr)2922 static PRED_RETURN_CONDITION Execute_PNS_EngageWithPistol(STRATEGYBLOCK *sbPtr)
2923 {
2924         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
2925         VECTORCH velocityDirection = {0,0,0};
2926         VECTORCH targetPosition;
2927         int targetIsAirduct = 0;
2928         int range;
2929 
2930         LOCALASSERT(sbPtr);
2931         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
2932         LOCALASSERT(predatorStatusPointer);
2933 
2934         PredatorHandleMovingAnimation(sbPtr);
2935 
2936         /* now check for state changes... firstly, if we can no longer attack the target, go
2937         to wander */
2938         if(!(PredatorIsAwareOfTarget(sbPtr)))
2939         {
2940                 return(PRC_Request_Hunt);
2941                 /* Drop out null targets. */
2942         } else {
2943 
2944                 /* We have a target that we are aware of. */
2945 
2946                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
2947 
2948                 /* Wanna Cloak? */
2949                 if (predatorStatusPointer->CloakStatus==PCLOAK_Off) {
2950                         PredatorCloakOn(predatorStatusPointer);
2951                 }
2952 
2953                 /* if we are close... go directly to firing */
2954                 if(range < PRED_CLOSE_ATTACK_RANGE)
2955                 {
2956                         /* switch directly to firing, at this distance */
2957 
2958                         return(PRC_Request_Attack);
2959                 }
2960 
2961                 /* if our state timer has run out in approach state, see if we can fire*/
2962                 if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime;
2963                 if(predatorStatusPointer->stateTimer <= 0)
2964                 {
2965                         /* it is time to fire, if we can see the target  */
2966                         if(PredatorCanSeeTarget(sbPtr))
2967                         {
2968                                 /* we are going to fire then */
2969 
2970                                 return(PRC_Request_Attack);
2971                         }
2972                         else
2973                         {
2974                                 /* renew approach state */
2975                                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
2976                                 /* Whatever. */
2977                         }
2978                 }
2979         }
2980 
2981         /* See which way we want to go. */
2982         {
2983 
2984                 AIMODULE *targetModule;
2985                 MODULE *tcm;
2986                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
2987 
2988                 GLOBALASSERT(predatorStatusPointer->Target!=NULL);
2989 
2990                 if (predatorStatusPointer->Target->containingModule) {
2991                         tcm=predatorStatusPointer->Target->containingModule;
2992                 } else {
2993                         tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
2994                 }
2995 
2996                 if (tcm) {
2997                         targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
2998                 } else {
2999                         targetModule=NULL;
3000                 }
3001 
3002                 if (targetModule==sbPtr->containingModule->m_aimodule) {
3003                         /* Try going for it, we still can't see them. */
3004                         NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
3005                         NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager);
3006                 } else if (!targetModule) {
3007                         /* Must be inaccessible. */
3008                         if (ShowPredoStats) {
3009                                 if (predatorStatusPointer->Target->containingModule) {
3010                                         PrintDebuggingText("I can see you, but I can't get there!\n");
3011                                 } else {
3012                                         PrintDebuggingText("Hey, you've got no Containing Module!\n");
3013                                 }
3014                         }
3015                         return(PRC_No_Change);
3016                 } else {
3017 
3018                         thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
3019                         if (!thisEp) {
3020                                 LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
3021                                         (*(targetModule->m_module_ptrs))->name,
3022                                         sbPtr->containingModule->name));
3023                                 GLOBALASSERT(thisEp);
3024                         }
3025                         /* If that fired, there's a farped adjacency. */
3026 
3027                         predatorStatusPointer->wanderData.worldPosition=thisEp->position;
3028                         predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
3029                         predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
3030                         predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
3031 
3032                         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
3033                 }
3034 
3035         }
3036 
3037         /* Should have a velocity set now. */
3038 
3039         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
3040 
3041         /* test here for impeding collisions, and not being able to reach target... */
3042         #if ALL_NEW_AVOIDANCE_PRED
3043         {
3044                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
3045                         /* Go to all new avoidance. */
3046                         return(PRC_Request_Avoidance);
3047                 }
3048         }
3049         #else
3050         {
3051                 STRATEGYBLOCK *destructableObject = NULL;
3052 
3053                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
3054                 if(predatorStatusPointer->obstruction.environment)
3055                 {
3056                         /* go to avoidance */
3057                         return(PRC_Request_Avoidance);
3058                 }
3059                 if(predatorStatusPointer->obstruction.destructableObject)
3060                 {
3061                         LOCALASSERT(destructableObject);
3062                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3063                 }
3064         }
3065 
3066         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection))
3067         {
3068 
3069                 predatorStatusPointer->obstruction.environment=1;
3070                 predatorStatusPointer->obstruction.destructableObject=0;
3071                 predatorStatusPointer->obstruction.otherCharacter=0;
3072                 predatorStatusPointer->obstruction.anySingleObstruction=0;
3073 
3074                 return(PRC_Request_Avoidance);
3075         }
3076         #endif
3077         return(PRC_No_Change);
3078 }
3079 
Execute_PNS_EngageWithPlasmaCaster(STRATEGYBLOCK * sbPtr)3080 static PRED_RETURN_CONDITION Execute_PNS_EngageWithPlasmaCaster(STRATEGYBLOCK *sbPtr)
3081 {
3082         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3083         VECTORCH velocityDirection = {0,0,0};
3084         VECTORCH targetPosition;
3085         int targetIsAirduct = 0;
3086         int range;
3087 
3088         /* For the moment, the same as the pistol. */
3089 
3090         LOCALASSERT(sbPtr);
3091         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3092         LOCALASSERT(predatorStatusPointer);
3093 
3094         PredatorHandleMovingAnimation(sbPtr);
3095 
3096         predatorStatusPointer->patience-=NormalFrameTime;
3097         /* Have we become impatient? */
3098         if (predatorStatusPointer->patience<=0) {
3099                 return(PRC_Request_Swap);
3100         }
3101 
3102         /* now check for state changes... firstly, if we can no longer attack the target, go
3103         to wander */
3104         if(!(PredatorIsAwareOfTarget(sbPtr)))
3105         {
3106                 return(PRC_Request_Hunt);
3107                 /* Drop out null targets. */
3108         } else {
3109 
3110                 /* We have a target that we are aware of. */
3111 
3112                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
3113 
3114                 /* if we are close... go directly to firing */
3115                 if(range < PRED_CLOSE_ATTACK_RANGE)
3116                 {
3117                         /* switch directly to firing, at this distance */
3118 
3119                         return(PRC_Request_Attack);
3120                 } else {
3121 
3122                         /* Wanna Cloak? */
3123                         if (predatorStatusPointer->CloakStatus==PCLOAK_Off) {
3124                                 PredatorCloakOn(predatorStatusPointer);
3125                         }
3126 
3127                 }
3128 
3129                 /* if our state timer has run out in approach state, see if we can fire*/
3130                 if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime;
3131                 if(predatorStatusPointer->stateTimer <= 0)
3132                 {
3133                         /* it is time to fire, if we can see the target  */
3134                         if(PredatorCanSeeTarget(sbPtr))
3135                         {
3136                                 /* we are going to fire then */
3137 
3138                                 return(PRC_Request_Attack);
3139                         }
3140                         else
3141                         {
3142                                 /* renew approach state */
3143                                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
3144                                 /* Whatever. */
3145                         }
3146                 }
3147         }
3148 
3149         /* See which way we want to go. */
3150         {
3151 
3152                 AIMODULE *targetModule;
3153                 MODULE *tcm;
3154                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
3155 
3156                 GLOBALASSERT(predatorStatusPointer->Target!=NULL);
3157 
3158                 if (predatorStatusPointer->Target->containingModule) {
3159                         tcm=predatorStatusPointer->Target->containingModule;
3160                 } else {
3161                         tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
3162                 }
3163 
3164                 if (tcm) {
3165                         targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
3166                 } else {
3167                         targetModule=NULL;
3168                 }
3169 
3170                 if (targetModule==sbPtr->containingModule->m_aimodule) {
3171                         /* Try going for it, we still can't see them. */
3172                         NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
3173                         NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager);
3174                 } else if (!targetModule) {
3175                         /* Must be inaccessible. */
3176                         if (ShowPredoStats) {
3177                                 if (predatorStatusPointer->Target->containingModule) {
3178                                         PrintDebuggingText("I can see you, but I can't get there!\n");
3179                                 } else {
3180                                         PrintDebuggingText("Hey, you've got no Containing Module!\n");
3181                                 }
3182                         }
3183                         return(PRC_No_Change);
3184                 } else {
3185 
3186                         thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
3187                         if (!thisEp) {
3188                                 LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
3189                                         (*(targetModule->m_module_ptrs))->name,
3190                                         sbPtr->containingModule->name));
3191                                 GLOBALASSERT(thisEp);
3192                         }
3193                         /* If that fired, there's a farped adjacency. */
3194 
3195                         predatorStatusPointer->wanderData.worldPosition=thisEp->position;
3196                         predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
3197                         predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
3198                         predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
3199 
3200                         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
3201                 }
3202 
3203         }
3204 
3205         /* Should have a velocity set now. */
3206 
3207         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
3208 
3209         /* test here for impeding collisions, and not being able to reach target... */
3210         #if ALL_NEW_AVOIDANCE_PRED
3211         {
3212                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
3213                         /* Go to all new avoidance. */
3214                         return(PRC_Request_Avoidance);
3215                 }
3216         }
3217         #else
3218         {
3219                 STRATEGYBLOCK *destructableObject = NULL;
3220 
3221                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
3222                 if(predatorStatusPointer->obstruction.environment)
3223                 {
3224                         /* go to avoidance */
3225                         return(PRC_Request_Avoidance);
3226                 }
3227                 if(predatorStatusPointer->obstruction.destructableObject)
3228                 {
3229                         LOCALASSERT(destructableObject);
3230                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3231                 }
3232         }
3233 
3234         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection))
3235         {
3236 
3237                 predatorStatusPointer->obstruction.environment=1;
3238                 predatorStatusPointer->obstruction.destructableObject=0;
3239                 predatorStatusPointer->obstruction.otherCharacter=0;
3240                 predatorStatusPointer->obstruction.anySingleObstruction=0;
3241 
3242                 return(PRC_Request_Avoidance);
3243         }
3244         #endif
3245         return(PRC_No_Change);
3246 }
3247 
Execute_PNS_EngageWithWristblade(STRATEGYBLOCK * sbPtr)3248 static PRED_RETURN_CONDITION Execute_PNS_EngageWithWristblade(STRATEGYBLOCK *sbPtr)
3249 {
3250         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3251         VECTORCH velocityDirection = {0,0,0};
3252         VECTORCH targetPosition;
3253         int targetIsAirduct = 0;
3254         int range;
3255 
3256         LOCALASSERT(sbPtr);
3257         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3258         LOCALASSERT(predatorStatusPointer);
3259 
3260         PredatorHandleMovingAnimation(sbPtr);
3261 
3262         predatorStatusPointer->patience-=NormalFrameTime;
3263         /* Have we become impatient? */
3264         if (predatorStatusPointer->patience<=0) {
3265                 return(PRC_Request_Swap);
3266         }
3267 
3268         /* now check for state changes... firstly, if we can no longer attack the target, go
3269         to wander */
3270         if(!(PredatorIsAwareOfTarget(sbPtr)))
3271         {
3272                 return(PRC_Request_Hunt);
3273                 /* Drop out null targets. */
3274         } else {
3275 
3276                 /* We have a target that we are aware of. */
3277 
3278                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
3279 
3280                 /* Wanna Cloak? */
3281                 if (range<5000) {
3282                         /* Decloak when close. */
3283                         PredatorCloakOff(predatorStatusPointer);
3284                 } else if (predatorStatusPointer->CloakStatus==PCLOAK_Off) {
3285                         PredatorCloakOn(predatorStatusPointer);
3286                 }
3287 
3288                 /* if we are close... go directly to firing */
3289                 if(range < PRED_CLOSE_ATTACK_RANGE)
3290                 {
3291                         /* switch directly to firing, at this distance */
3292 
3293                         return(PRC_Request_Attack);
3294                 }
3295 
3296                 /* if our state timer has run out in approach state, see if we can fire*/
3297                 if(predatorStatusPointer->stateTimer > 0) {
3298                         predatorStatusPointer->stateTimer -= NormalFrameTime;
3299                 }
3300 
3301                 if(predatorStatusPointer->stateTimer <= 0)
3302                 {
3303                         /* A moment of decision... */
3304                         /* Might want to withdraw. */
3305                         if(!PredatorCanSeeTarget(sbPtr))
3306                         {
3307                                 /* Lost sight of him! */
3308 
3309                                 return(PRC_Request_Hunt);
3310                         }
3311                         else
3312                         {
3313                                 /* renew approach state */
3314                                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
3315                                 /* Whatever. */
3316                         }
3317                 }
3318         }
3319 
3320         /* See which way we want to go. */
3321         {
3322 
3323                 AIMODULE *targetModule;
3324                 MODULE *tcm;
3325                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
3326 
3327                 GLOBALASSERT(predatorStatusPointer->Target!=NULL);
3328 
3329                 if (predatorStatusPointer->Target->containingModule) {
3330                         tcm=predatorStatusPointer->Target->containingModule;
3331                 } else {
3332                         tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
3333                 }
3334 
3335                 if (tcm) {
3336                         targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
3337                 } else {
3338                         targetModule=NULL;
3339                 }
3340 
3341                 if (targetModule==sbPtr->containingModule->m_aimodule) {
3342                         /* Try going for it, we still can't see them. */
3343                         NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
3344                         NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager);
3345                 } else if (!targetModule) {
3346                         /* Must be inaccessible. */
3347                         if (ShowPredoStats) {
3348                                 if (predatorStatusPointer->Target->containingModule) {
3349                                         PrintDebuggingText("I can see you, but I can't get there!\n");
3350                                 } else {
3351                                         PrintDebuggingText("Hey, you've got no Containing Module!\n");
3352                                 }
3353                         }
3354                         return(PRC_No_Change);
3355                 } else {
3356 
3357                         thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
3358                         if (!thisEp) {
3359                                 LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
3360                                         (*(targetModule->m_module_ptrs))->name,
3361                                         sbPtr->containingModule->name));
3362                                 GLOBALASSERT(thisEp);
3363                         }
3364                         /* If that fired, there's a farped adjacency. */
3365 
3366                         predatorStatusPointer->wanderData.worldPosition=thisEp->position;
3367                         predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
3368                         predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
3369                         predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
3370 
3371                         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
3372                 }
3373 
3374         }
3375 
3376         /* Should have a velocity set now. */
3377 
3378         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
3379 
3380         /* test here for impeding collisions, and not being able to reach target... */
3381         #if ALL_NEW_AVOIDANCE_PRED
3382         {
3383                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
3384                         /* Go to all new avoidance. */
3385                         return(PRC_Request_Avoidance);
3386                 }
3387         }
3388         #else
3389         {
3390                 STRATEGYBLOCK *destructableObject = NULL;
3391 
3392                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
3393                 if(predatorStatusPointer->obstruction.environment)
3394                 {
3395                         /* go to avoidance */
3396                         return(PRC_Request_Avoidance);
3397                 }
3398                 if(predatorStatusPointer->obstruction.destructableObject)
3399                 {
3400                         LOCALASSERT(destructableObject);
3401                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3402                 }
3403         }
3404 
3405         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection))
3406         {
3407 
3408                 predatorStatusPointer->obstruction.environment=1;
3409                 predatorStatusPointer->obstruction.destructableObject=0;
3410                 predatorStatusPointer->obstruction.otherCharacter=0;
3411                 predatorStatusPointer->obstruction.anySingleObstruction=0;
3412 
3413                 predatorStatusPointer->patience-=ONE_FIXED;
3414 
3415                 return(PRC_Request_Avoidance);
3416         }
3417         #endif
3418         return(PRC_No_Change);
3419 }
3420 
Execute_PNS_AttackWithWristblade(STRATEGYBLOCK * sbPtr)3421 static PRED_RETURN_CONDITION Execute_PNS_AttackWithWristblade(STRATEGYBLOCK *sbPtr)
3422 {
3423         VECTORCH orientationDirn;
3424         int i;
3425         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3426         DYNAMICSBLOCK *dynPtr;
3427 
3428         LOCALASSERT(sbPtr);
3429         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3430         LOCALASSERT(predatorStatusPointer);
3431         LOCALASSERT (sbPtr->DynPtr);
3432 
3433         /* zero linear velocity in dynamics block */
3434         LOCALASSERT(sbPtr->DynPtr);
3435         sbPtr->DynPtr->LinVelocity.vx = 0;
3436         sbPtr->DynPtr->LinVelocity.vy = 0;
3437         sbPtr->DynPtr->LinVelocity.vz = 0;
3438 
3439         dynPtr = sbPtr->DynPtr;
3440 
3441         if (predatorStatusPointer->Target==NULL) {
3442                 /* Bomb out. */
3443                 return(PRC_Request_Wander);
3444         }
3445 
3446         /* De-cloak. */
3447         if(predatorStatusPointer->CloakStatus==PCLOAK_On)
3448         {
3449                 PredatorCloakOff(predatorStatusPointer);
3450         }
3451 
3452         GLOBALASSERT(predatorStatusPointer->Target);
3453         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
3454 
3455         /* check for state changes: */
3456         if(VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)) > PRED_CLOSE_ATTACK_RANGE)
3457         {
3458                 if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) {
3459                         /* Change weapon! */
3460                         return(PRC_Request_Swap);
3461                 } else {
3462                         /* switch back to engage. */
3463                         GLOBALASSERT(predatorStatusPointer->Target);
3464                         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
3465                         return(PRC_Request_Engage);
3466                 }
3467         }
3468 
3469         /* Orientate towards player, just to make sure we're facing */
3470         orientationDirn.vx = predatorStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
3471         orientationDirn.vy = 0;
3472         orientationDirn.vz = predatorStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
3473         i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
3474 
3475         /* Decrement the near state timer */
3476         predatorStatusPointer->stateTimer -= NormalFrameTime;
3477 
3478         PredatorNearDamageShell(sbPtr);
3479 
3480         if (predatorStatusPointer->HModelController.keyframe_flags&1) {
3481 
3482                 predatorStatusPointer->enableSwap=1;
3483                 StartWristbladeAttackSequence(sbPtr);
3484                 predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
3485                 /* Shrug. */
3486         }
3487         return(PRC_No_Change);
3488 
3489 }
3490 
3491 #if 0
3492 static PRED_RETURN_CONDITION Execute_PNS_StandGround(STRATEGYBLOCK *sbPtr)
3493 {
3494         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3495 
3496         LOCALASSERT(sbPtr);
3497         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3498         LOCALASSERT(predatorStatusPointer);
3499 
3500         /* basically just stand there and fire... */
3501 
3502         /* zero linear velocity in dynamics block */
3503         LOCALASSERT(sbPtr->DynPtr);
3504         sbPtr->DynPtr->LinVelocity.vx = 0;
3505         sbPtr->DynPtr->LinVelocity.vy = 0;
3506         sbPtr->DynPtr->LinVelocity.vz = 0;
3507 
3508         /* check if we want to close-attack */
3509         if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE)
3510         {
3511                 return(PRC_Request_Attack);
3512         }
3513 
3514         /* decrement the state timer if it is > 0. When this timer expires, predator
3515            will fire at player when it can next see him (or her) */
3516         if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime;
3517         if(predatorStatusPointer->stateTimer <= 0)
3518         {
3519                 /* if we can see the player, switch to fire */
3520                 if(NPCCanSeeTarget(sbPtr,Player->ObStrategyBlock, PRED_NEAR_VIEW_WIDTH))
3521                 {
3522                         return(PRC_Request_Attack);
3523                 }
3524                 else
3525                 {
3526                         /* reset the timer if we couldn't fire */
3527                         predatorStatusPointer->stateTimer = predatorCV[predatorStatusPointer->personalNumber].timeBetweenRangedAttacks;
3528                 }
3529         }
3530         return(PRC_No_Change);
3531 }
3532 #endif
3533 
Execute_PNS_SwapWeapon(STRATEGYBLOCK * sbPtr)3534 static PRED_RETURN_CONDITION Execute_PNS_SwapWeapon(STRATEGYBLOCK *sbPtr) {
3535 
3536         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3537 
3538         LOCALASSERT(sbPtr);
3539         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3540         LOCALASSERT(predatorStatusPointer);
3541 
3542         /* zero linear velocity in dynamics block */
3543         LOCALASSERT(sbPtr->DynPtr);
3544         sbPtr->DynPtr->LinVelocity.vx = 0;
3545         sbPtr->DynPtr->LinVelocity.vy = 0;
3546         sbPtr->DynPtr->LinVelocity.vz = 0;
3547 
3548         if (predatorStatusPointer->ChangeToWeapon==PNPCW_End) {
3549                 /* Rubbish! */
3550                 return(PRC_Request_Hunt);
3551         }
3552 
3553 		Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3554 			"Predator Swap Weapon Start");
3555 
3556         if (predatorStatusPointer->stateTimer==0) {
3557                 /* Haven't started yet. */
3558                 if (predatorStatusPointer->ChangeToWeapon==predatorStatusPointer->Selected_Weapon->id) {
3559                         /* Stop wasting my time! */
3560                         return(PRC_Request_Hunt);
3561                 }
3562 
3563                 if (ShowPredoStats) {
3564                         PrintDebuggingText("Part one ");
3565                 }
3566 
3567                 /* Decloak. */
3568                 if (predatorStatusPointer->CloakStatus!=PCLOAK_Off) {
3569                         /* Sorry, I want to see this. */
3570                         return(PRC_No_Change);
3571                 }
3572 
3573                 /* Right.  Is there a 'deselect' anim? */
3574                 if (predatorStatusPointer->IAmCrouched) {
3575                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,
3576                                 (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) {
3577                                 /* It's there! */
3578                                 if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) {
3579                                         /* Valid swap time, too. */
3580                                         InitHModelTweening_Backwards(&predatorStatusPointer->HModelController,
3581                                                 (ONE_FIXED>>2),(int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon,
3582                                                 predatorStatusPointer->Selected_Weapon->SwappingTime,0);
3583                                         predatorStatusPointer->HModelController.Looped=0;
3584                                         predatorStatusPointer->stateTimer=1; /* Swapping Out. */
3585                                         return(PRC_No_Change);
3586                                 }
3587                         }
3588                 } else {
3589                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,
3590                                 (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon)) {
3591                                 /* It's there! */
3592                                 if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) {
3593                                         /* Valid swap time, too. */
3594                                         InitHModelTweening_Backwards(&predatorStatusPointer->HModelController,
3595                                                 (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon,
3596                                                 predatorStatusPointer->Selected_Weapon->SwappingTime,0);
3597                                         predatorStatusPointer->HModelController.Looped=0;
3598                                         predatorStatusPointer->stateTimer=1; /* Swapping Out. */
3599                                         return(PRC_No_Change);
3600                                 }
3601                         }
3602                 }
3603                 /* If you're still here, there must be no swapping out sequence. */
3604                 predatorStatusPointer->stateTimer=2;
3605                 /* Ah well, go directly to the middle. */
3606                 return(PRC_No_Change);
3607         } else if (predatorStatusPointer->stateTimer==1) {
3608                 /* You are in the process of swapping out. */
3609 
3610                 if (ShowPredoStats) {
3611                         PrintDebuggingText("Part two ");
3612                 }
3613 
3614                 if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) {
3615                         /* Right, you've finished! */
3616                         predatorStatusPointer->stateTimer=2;
3617                         return(PRC_No_Change);
3618                 } else {
3619                         GLOBALASSERT(predatorStatusPointer->HModelController.Looped==0);
3620                         return(PRC_No_Change);
3621                 }
3622         } else if (predatorStatusPointer->stateTimer==2) {
3623                 /* In the middle! */
3624                 PREDATOR_WEAPON_DATA *targetWeapon;
3625                 SECTION *root_section;
3626 
3627                 if (ShowPredoStats) {
3628                         PrintDebuggingText("Part three ");
3629                 }
3630 
3631                 targetWeapon=GetThisNPCPredatorWeapon(predatorStatusPointer->ChangeToWeapon);
3632                 if (!targetWeapon) {
3633                         /* We're screwed.  Stay with the old one! */
3634                         predatorStatusPointer->ChangeToWeapon=PNPCW_End;
3635                         return(PRC_Request_Hunt);
3636                 }
3637                 predatorStatusPointer->Selected_Weapon=targetWeapon;
3638                 root_section=GetNamedHierarchyFromLibrary(predatorStatusPointer->Selected_Weapon->Riffname,predatorStatusPointer->Selected_Weapon->HierarchyName);
3639                 GLOBALASSERT(root_section);
3640 
3641                 /* Strip out HitDelta for now, if any... */
3642                 {
3643                         DELTA_CONTROLLER *delta;
3644                         delta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
3645                         if (delta) {
3646                                 Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
3647                         }
3648                 }
3649 
3650                 /* Strip off elevation too. */
3651                 {
3652                         DELTA_CONTROLLER *delta;
3653                         delta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
3654                         if (delta) {
3655                                 Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
3656                         }
3657                 }
3658 
3659 				Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3660 					"Predator Swap Weapon Two");
3661 
3662 				/* In the interests of getting the new sections right... */
3663                 predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorStand;
3664 				predatorStatusPointer->HModelController.Sub_Sequence=(int)PSSS_Get_Weapon;
3665 
3666                 Transmogrify_HModels(sbPtr,&predatorStatusPointer->HModelController,root_section,0,1,0);
3667 
3668                 #if PREDATOR_HIT_DELTAS
3669                 if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) {
3670                         /* This ritual in case _one_ of the hierarchies doesn't have hitdeltas. */
3671                         DELTA_CONTROLLER *delta;
3672                         delta=Add_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1);
3673                         GLOBALASSERT(delta);
3674                         delta->Playing=0;
3675                 }
3676                 #endif
3677 
3678                 /* Replace elevation. */
3679                 if (predatorStatusPointer->Selected_Weapon->UseElevation) {
3680 					if (Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation")==NULL) {
3681                         DELTA_CONTROLLER *delta;
3682                         delta=Add_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0);
3683                         GLOBALASSERT(delta);
3684                     	delta->timer=32767;
3685                     }
3686                 } else {
3687 					/* Better make sure it's gone... */
3688                     Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
3689                 }
3690 
3691 				Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3692 					"Predator Swap Weapon Two A");
3693 
3694 				DeInitialise_HModel(&predatorStatusPointer->HModelController);
3695                 ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
3696 
3697 				Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3698 					"Predator Swap Weapon Three");
3699 
3700                 predatorStatusPointer->My_Gun_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->GunName);
3701                 predatorStatusPointer->My_Elevation_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName);
3702 
3703                 /* Now go for the Get_Weapon sequence. */
3704                 if (predatorStatusPointer->IAmCrouched) {
3705                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,
3706                                 (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) {
3707                                 /* It's there! */
3708                                 if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) {
3709                                         /* Valid swap time, too. */
3710                                         predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorCrouch;
3711                                         predatorStatusPointer->HModelController.Sub_Sequence=(int)PCrSS_Get_Weapon;
3712                                         predatorStatusPointer->HModelController.Seconds_For_Sequence=predatorStatusPointer->Selected_Weapon->SwappingTime;
3713                                         /* That to get the new sections right. */
3714                                         InitHModelTweening(&predatorStatusPointer->HModelController,
3715                                                 (ONE_FIXED>>2),(int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon,
3716                                                 predatorStatusPointer->Selected_Weapon->SwappingTime,0);
3717                                         predatorStatusPointer->HModelController.Looped=0;
3718                                         predatorStatusPointer->stateTimer=3; /* Swapping In. */
3719 
3720 										Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3721 											"Predator Swap Weapon Three A");
3722 
3723 						                ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
3724 
3725 										Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3726 											"Predator Swap Weapon Four");
3727 
3728                                         return(PRC_No_Change);
3729                                 }
3730                         }
3731                 } else {
3732                         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,
3733                                 (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon)) {
3734                                 /* It's there! */
3735                                 if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) {
3736                                         /* Valid swap time, too. */
3737                                         predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorStand;
3738                                         predatorStatusPointer->HModelController.Sub_Sequence=(int)PSSS_Get_Weapon;
3739                                         predatorStatusPointer->HModelController.Seconds_For_Sequence=predatorStatusPointer->Selected_Weapon->SwappingTime;
3740                                         /* That to get the new sections right. */
3741                                         InitHModelTweening(&predatorStatusPointer->HModelController,
3742                                                 (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon,
3743                                                 predatorStatusPointer->Selected_Weapon->SwappingTime,0);
3744                                         predatorStatusPointer->HModelController.Looped=0;
3745                                         predatorStatusPointer->stateTimer=3; /* Swapping In. */
3746 
3747 										Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3748 											"Predator Swap Weapon Four A");
3749 
3750 						                ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
3751 
3752 										Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3753 											"Predator Swap Weapon Five");
3754 
3755                                         return(PRC_No_Change);
3756                                 }
3757                         }
3758                 }
3759 
3760                 /* If you're still here, there must be no swapping in sequence. */
3761                 predatorStatusPointer->stateTimer=4;
3762                 /* Ah well, go directly to the end. */
3763 
3764 				Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController,
3765 					"Predator Swap Weapon Six");
3766 
3767                 return(PRC_No_Change);
3768 
3769         } else if (predatorStatusPointer->stateTimer==3) {
3770                 /* You are in the process of swapping in. */
3771 
3772                 if (ShowPredoStats) {
3773                         PrintDebuggingText("Part four ");
3774                 }
3775 
3776                 if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) {
3777                         /* Right, you've finished! */
3778                         predatorStatusPointer->stateTimer=4;
3779                         return(PRC_No_Change);
3780                 } else {
3781                         GLOBALASSERT(predatorStatusPointer->HModelController.Looped==0);
3782                         return(PRC_No_Change);
3783                 }
3784         } else if (predatorStatusPointer->stateTimer==4) {
3785                 /* All (valid) conclusions arrive here. */
3786 
3787                 if (ShowPredoStats) {
3788                         PrintDebuggingText("Part five ");
3789                 }
3790 
3791                 predatorStatusPointer->ChangeToWeapon=PNPCW_End;
3792                 if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Medicomp) {
3793                         return(PRC_Request_Recover);
3794                 } else {
3795                         return(PRC_Request_Attack);
3796                 }
3797         }
3798 
3799         if (ShowPredoStats) {
3800                 PrintDebuggingText("No Part %d ",predatorStatusPointer->stateTimer);
3801         }
3802 
3803         return(PRC_No_Change);
3804 
3805 }
3806 
Execute_PNS_Wander(STRATEGYBLOCK * sbPtr)3807 static PRED_RETURN_CONDITION Execute_PNS_Wander(STRATEGYBLOCK *sbPtr)
3808 {
3809         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3810         DYNAMICSBLOCK *dynPtr;
3811         VECTORCH velocityDirection = {0,0,0};
3812 
3813         LOCALASSERT(sbPtr);
3814         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3815         dynPtr = sbPtr->DynPtr;
3816         LOCALASSERT(predatorStatusPointer);
3817         LOCALASSERT(dynPtr);
3818 
3819         PredatorHandleMovingAnimation(sbPtr);
3820 
3821         /* should we change to approach state? */
3822         if (PredatorIsAwareOfTarget(sbPtr))
3823         {
3824                 /* doesn't require a sequence change */
3825                 return(PRC_Request_Engage);
3826         }
3827 
3828         /* Are we using bimble rules? */
3829 
3830         if (predatorStatusPointer->wanderData.currentModule==NPC_BIMBLINGINMODULE) {
3831 
3832                 int range;
3833 
3834                 /* Range to target... */
3835 
3836                 range=VectorDistance((&predatorStatusPointer->wanderData.worldPosition),(&sbPtr->DynPtr->Position));
3837 
3838                 if (range<2000) {
3839 
3840                         /* Reset system, try again. */
3841                         predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
3842 
3843                 }
3844 
3845         }
3846         else
3847         {
3848                 /* wander target aquisition: if no target, or moved module */
3849                 LOCALASSERT(sbPtr->containingModule);
3850                 if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
3851                 {
3852                         NPC_InitMovementData(&(predatorStatusPointer->moveData));
3853                         NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0);
3854                 }
3855                 else if(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)
3856                 {
3857                         NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0);
3858                 }
3859 
3860                 /* if we still haven't got one, bimble about in this one for a bit. */
3861                 if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
3862                 {
3863                         NPC_GetBimbleTarget(sbPtr,&predatorStatusPointer->wanderData.worldPosition);
3864                         predatorStatusPointer->wanderData.currentModule=NPC_BIMBLINGINMODULE;
3865                 }
3866 
3867         }
3868 
3869         /* ok: should have a current target at this stage... */
3870         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
3871         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
3872 
3873         /* test here for impeding collisions, and not being able to reach target... */
3874         if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager))
3875         {
3876                         /* Go to all new avoidance. */
3877             return(PRC_Request_Avoidance);
3878         }
3879 
3880         return(PRC_No_Change);
3881 }
3882 
Execute_PNS_Hunt(STRATEGYBLOCK * sbPtr)3883 static PRED_RETURN_CONDITION Execute_PNS_Hunt(STRATEGYBLOCK *sbPtr)
3884 {
3885         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
3886         DYNAMICSBLOCK *dynPtr;
3887         VECTORCH velocityDirection = {0,0,0};
3888 
3889         /* Your mission: to advance into the players module, even if near. */
3890 
3891         LOCALASSERT(sbPtr);
3892         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
3893         dynPtr = sbPtr->DynPtr;
3894         LOCALASSERT(predatorStatusPointer);
3895         LOCALASSERT(dynPtr);
3896 
3897         PredatorHandleMovingAnimation(sbPtr);
3898 
3899         /* should we change to approach state? */
3900         if(PredatorCanSeeTarget(sbPtr))
3901         {
3902                 return(PRC_Request_Engage);
3903         } else if(!(PredatorIsAwareOfTarget(sbPtr))) {
3904                 /* I have a bad feeling about this, too. */
3905                 //return(PRC_No_Change);
3906 				/* Might just be in a non-vis module now... */
3907         }
3908 
3909         {
3910                 AIMODULE *targetModule;
3911                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
3912 
3913                 targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0);
3914 
3915                 if (targetModule) {
3916                         if (ShowPredoStats) {
3917                                 PrintDebuggingText("Target Module %s.\n",(*(targetModule->m_module_ptrs))->name);
3918                         }
3919                 } else {
3920                         if (ShowPredoStats) {
3921                                 PrintDebuggingText("Target Module NULL.\n");
3922                         }
3923                 }
3924 
3925                 if (targetModule==sbPtr->containingModule->m_aimodule) {
3926                         /* Hey, it'll drop through. */
3927 						if (predatorStatusPointer->Target==NULL) {
3928 	                        return(PRC_Request_Wander);
3929 						} else {
3930 	                        return(PRC_Request_Engage);
3931 						}
3932                 }
3933 
3934                 if (!targetModule) {
3935                         #if 1
3936                         /* Must be sealed off. */
3937                         return(PRC_Request_Recover);
3938                         #else
3939                         extern MODULE *playerPherModule;
3940 
3941                         LOGDXFMT(("Jules's bug: predator is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name));
3942                         GLOBALASSERT(targetModule);
3943                         #endif
3944                 }
3945 
3946                 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
3947                 if (!thisEp) {
3948                         LOGDXFMT(("This assert is a busted adjacency!"));
3949                         GLOBALASSERT(thisEp);
3950                 }
3951                 /* If that fired, there's a farped adjacency. */
3952 
3953                 predatorStatusPointer->wanderData.worldPosition=thisEp->position;
3954                 predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
3955                 predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
3956                 predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
3957 
3958         }
3959 
3960         /* ok: should have a current target at this stage... */
3961         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
3962         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
3963 
3964         /* test here for impeding collisions, and not being able to reach target... */
3965         #if ALL_NEW_AVOIDANCE_PRED
3966         {
3967                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
3968                         /* Go to all new avoidance. */
3969                         return(PRC_Request_Avoidance);
3970                 }
3971         }
3972         #else
3973         {
3974                 STRATEGYBLOCK *destructableObject = NULL;
3975 
3976                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
3977                 if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter))
3978                 {
3979                         return(PRC_Request_Avoidance);
3980                 }
3981                 if(predatorStatusPointer->obstruction.destructableObject)
3982                 {
3983                         LOCALASSERT(destructableObject);
3984                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3985                 }
3986         }
3987 
3988         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection))
3989         {
3990                 /* go to avoidance */
3991                 /* no sequence change required */
3992 
3993                 predatorStatusPointer->obstruction.environment=1;
3994                 predatorStatusPointer->obstruction.destructableObject=0;
3995                 predatorStatusPointer->obstruction.otherCharacter=0;
3996                 predatorStatusPointer->obstruction.anySingleObstruction=0;
3997 
3998                 return(PRC_Request_Avoidance);
3999         }
4000         #endif
4001         return(PRC_No_Change);
4002 }
4003 
Execute_PNS_Retreat(STRATEGYBLOCK * sbPtr)4004 static PRED_RETURN_CONDITION Execute_PNS_Retreat(STRATEGYBLOCK *sbPtr)
4005 {
4006         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4007         DYNAMICSBLOCK *dynPtr;
4008         VECTORCH velocityDirection = {0,0,0};
4009         AIMODULE *old_fearmodule;
4010 
4011         /* Your mission: to advance out of trouble, even if near. */
4012 
4013         LOCALASSERT(sbPtr);
4014         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4015         dynPtr = sbPtr->DynPtr;
4016         LOCALASSERT(predatorStatusPointer);
4017         LOCALASSERT(dynPtr);
4018 
4019         PredatorHandleMovingAnimation(sbPtr);
4020 
4021         old_fearmodule=predatorStatusPointer->fearmodule;
4022 
4023         if(!(PredatorIsAwareOfTarget(sbPtr))) {
4024                 /* What am I running from? */
4025                 return(PRC_Request_Recover);
4026         }
4027 
4028         #if 0
4029         if (predatorStatusPointer->incidentFlag) {
4030                 /* Need a better test here. */
4031                 if (!(PredatorCanSeeTarget(sbPtr))) {
4032                         return(PRC_Request_Recover);
4033                 }
4034         }
4035         #endif
4036 
4037         /* Yeah, from where _am_ I running? */
4038         if(PredatorIsAwareOfTarget(sbPtr)) {
4039                 predatorStatusPointer->fearmodule=predatorStatusPointer->Target->containingModule->m_aimodule;
4040         } else if (predatorStatusPointer->fearmodule==NULL) {
4041                 predatorStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule;
4042         }
4043 
4044         if ((predatorStatusPointer->missionmodule==NULL)||(predatorStatusPointer->fearmodule!=old_fearmodule)) {
4045 
4046                 /* Recompute mission module. */
4047                 if (predatorStatusPointer->fearmodule) {
4048                         predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5);
4049                 } else {
4050                         predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,Player->ObStrategyBlock->containingModule->m_aimodule,5);
4051                 }
4052 
4053         }
4054 
4055         {
4056                 AIMODULE *targetModule;
4057                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
4058 
4059                 if (predatorStatusPointer->missionmodule==NULL) {
4060                         /* Hey, it'll drop through. */
4061                         return(PRC_Request_Recover);
4062                 }
4063 
4064                 if (ShowPredoStats) {
4065                         PrintDebuggingText("Target Module %s.\n",(*(predatorStatusPointer->missionmodule->m_module_ptrs))->name);
4066                 }
4067 
4068                 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0);
4069 
4070                 if (targetModule) {
4071                         if (ShowPredoStats) {
4072                                 PrintDebuggingText("Next Module is %s.\n",(*(targetModule->m_module_ptrs))->name);
4073                         }
4074                 } else {
4075                         if (ShowPredoStats) {
4076                                 PrintDebuggingText("Next Module is NULL!\n");
4077                         }
4078                 }
4079 
4080                 if ((targetModule==sbPtr->containingModule->m_aimodule)
4081                         || (targetModule==NULL)) {
4082                         /* Hey, it'll drop through. */
4083                         return(PRC_Request_Recover);
4084                 }
4085 
4086                 GLOBALASSERT(targetModule);
4087 
4088                 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
4089                 if (!thisEp) {
4090                         LOGDXFMT(("This assert is a busted adjacency!"));
4091                         GLOBALASSERT(thisEp);
4092                 }
4093                 /* If that fired, there's a farped adjacency. */
4094 
4095                 predatorStatusPointer->wanderData.worldPosition=thisEp->position;
4096                 predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
4097                 predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
4098                 predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
4099 
4100         }
4101 
4102         /* ok: should have a current target at this stage... */
4103         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
4104         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
4105 
4106         /* test here for impeding collisions, and not being able to reach target... */
4107         #if ALL_NEW_AVOIDANCE_PRED
4108         {
4109                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
4110                         /* Go to all new avoidance. */
4111                         return(PRC_Request_Avoidance);
4112                 }
4113         }
4114         #else
4115         {
4116                 STRATEGYBLOCK *destructableObject = NULL;
4117 
4118                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
4119                 if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter))
4120                 {
4121                         return(PRC_Request_Avoidance);
4122                 }
4123                 if(predatorStatusPointer->obstruction.destructableObject)
4124                 {
4125                         LOCALASSERT(destructableObject);
4126                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
4127                 }
4128         }
4129 
4130         #if 1
4131         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection))
4132         {
4133                 /* go to avoidance */
4134                 /* no sequence change required */
4135 
4136                 predatorStatusPointer->obstruction.environment=1;
4137                 predatorStatusPointer->obstruction.destructableObject=0;
4138                 predatorStatusPointer->obstruction.otherCharacter=0;
4139                 predatorStatusPointer->obstruction.anySingleObstruction=0;
4140 
4141                 return(PRC_Request_Avoidance);
4142         }
4143         #endif
4144         #endif
4145         return(PRC_No_Change);
4146 }
4147 
Execute_Dying(STRATEGYBLOCK * sbPtr)4148 static void Execute_Dying(STRATEGYBLOCK *sbPtr)
4149 {
4150         PREDATOR_STATUS_BLOCK *predStatusPointer;
4151 
4152         LOCALASSERT(sbPtr);
4153         LOCALASSERT(sbPtr->DynPtr);
4154         predStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4155         LOCALASSERT(predStatusPointer);
4156 
4157         /* make sure we're not cloaked... if activating, ignore until fully on */
4158         if(predStatusPointer->CloakStatus==PCLOAK_On)
4159         {
4160                 PredatorCloakOff(predStatusPointer);
4161                 Sound_Play(SID_VISION_ON,"d",&sbPtr->DynPtr->Position);
4162         }
4163 
4164         sbPtr->DynPtr->LinImpulse.vx = 0;
4165         sbPtr->DynPtr->LinImpulse.vy = 0;
4166         sbPtr->DynPtr->LinImpulse.vz = 0;
4167 
4168         predStatusPointer->stateTimer -= NormalFrameTime;
4169 }
4170 
4171 #if 0
4172 /* Patrick 4/7/97 --------------------------------------------------
4173 Behaviour support functions
4174 ---------------------------------------------------------------------*/
4175 #define PRED_PLASMASPEED 30000
4176 #define PRED_DISCSPEED 30000
4177 static void CreateNPCPredatorPlasBolt(VECTORCH *startingPosition, VECTORCH *targetDirection)
4178 {
4179         DISPLAYBLOCK *dPtr;
4180         DYNAMICSBLOCK *dynPtr;
4181 
4182         /* make displayblock with correct shape, etc */
4183         dPtr = MakeObject(I_BehaviourPredatorEnergyBolt,startingPosition);
4184         if(!dPtr) return;
4185         LOCALASSERT(dPtr->ObStrategyBlock);
4186 
4187         /* add lighting effect */
4188         AddLightingEffectToObject(dPtr,LFX_ROCKETJET);
4189 
4190         /* setup dynamics block */
4191         dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
4192         if(!dynPtr)
4193         {
4194                 RemoveBehaviourStrategy(dPtr->ObStrategyBlock);
4195                 return;
4196         }
4197 
4198         dPtr->ObStrategyBlock->DynPtr = dynPtr;
4199 
4200         /* give projectile a maximum lifetime */
4201         dPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK));
4202         if(!dPtr->ObStrategyBlock->SBdataptr)
4203         {
4204                 RemoveBehaviourStrategy(dPtr->ObStrategyBlock);
4205                 return;
4206         }
4207 
4208         ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
4209         ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->damage = TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty];
4210         ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->blast_radius = 2000;
4211         /* align projectile to launcher */
4212         dynPtr->Position = *startingPosition;
4213         dynPtr->PrevPosition=dynPtr->Position;
4214         MakeMatrixFromDirection(targetDirection, &(dynPtr->OrientMat));
4215         dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */
4216 
4217         /* set velocity */
4218     dynPtr->LinVelocity.vx = MUL_FIXED(targetDirection->vx,PRED_PLASMASPEED);
4219     dynPtr->LinVelocity.vy = MUL_FIXED(targetDirection->vy,PRED_PLASMASPEED);
4220     dynPtr->LinVelocity.vz = MUL_FIXED(targetDirection->vz,PRED_PLASMASPEED);
4221 }
4222 
4223 static void CreateNPCPredatorDisc(VECTORCH *startingPosition, VECTORCH *targetDirection)
4224 {
4225         DISPLAYBLOCK *dPtr;
4226         DYNAMICSBLOCK *dynPtr;
4227 
4228         /* make displayblock with correct shape, etc */
4229         dPtr = MakeObject(I_BehaviourNPCPredatorDisc,startingPosition);
4230         if(!dPtr) return;
4231         LOCALASSERT(dPtr->ObStrategyBlock);
4232 
4233         /* add lighting effect */
4234         dPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
4235 
4236         /* setup dynamics block */
4237         dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
4238         if(!dynPtr)
4239         {
4240                 RemoveBehaviourStrategy(dPtr->ObStrategyBlock);
4241                 return;
4242         }
4243 
4244         dPtr->ObStrategyBlock->DynPtr = dynPtr;
4245 
4246         /* give projectile a maximum lifetime */
4247         dPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK));
4248         if(!dPtr->ObStrategyBlock->SBdataptr)
4249         {
4250                 RemoveBehaviourStrategy(dPtr->ObStrategyBlock);
4251                 return;
4252         }
4253 
4254         ((ONE_SHOT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
4255         /* align projectile to launcher */
4256         dynPtr->Position = *startingPosition;
4257         MakeMatrixFromDirection(targetDirection, &(dynPtr->OrientMat));
4258         dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */
4259 
4260         /* set velocity */
4261     dynPtr->LinVelocity.vx = MUL_FIXED(targetDirection->vx,PRED_DISCSPEED);
4262     dynPtr->LinVelocity.vy = MUL_FIXED(targetDirection->vy,PRED_DISCSPEED);
4263     dynPtr->LinVelocity.vz = MUL_FIXED(targetDirection->vz,PRED_DISCSPEED);
4264 }
4265 #endif
4266 
SetPredatorAnimationSequence(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES type,int subtype,int length,int tweening)4267 static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening)
4268 {
4269 
4270         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4271 
4272         LOCALASSERT(sbPtr);
4273         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4274         LOCALASSERT(predatorStatusPointer);
4275 
4276         GLOBALASSERT(length!=0);
4277 
4278         if (tweening<=0) {
4279                 InitHModelSequence(&predatorStatusPointer->HModelController,(int)type,subtype,length);
4280         } else {
4281                 InitHModelTweening(&predatorStatusPointer->HModelController, tweening, (int)type,subtype,length, 1);
4282         }
4283 }
4284 
PredatorShouldAttackPlayer(STRATEGYBLOCK * sbPtr)4285 static int PredatorShouldAttackPlayer(STRATEGYBLOCK *sbPtr)
4286 {
4287         PREDATOR_STATUS_BLOCK *predStatusPointer;
4288 
4289         LOCALASSERT(sbPtr);
4290         LOCALASSERT(sbPtr->DynPtr);
4291         predStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4292         LOCALASSERT(predStatusPointer);
4293 
4294         if(predStatusPointer->health > predatorCV[predStatusPointer->personalNumber].defenceHealth)
4295                 return 1;
4296         else
4297                 return 0;
4298 }
4299 
PredatorShouldBeCrawling(STRATEGYBLOCK * sbPtr)4300 static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr)
4301 {
4302         if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) return 1;
4303         return 0;
4304 }
4305 
4306 /* Patrick 21/8/97 ----------------------------------------------------
4307 Predator cloak interface functions...
4308 -----------------------------------------------------------------------*/
InitPredatorCloak(PREDATOR_STATUS_BLOCK * predStatus)4309 static void InitPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus)
4310 {
4311         predStatus->CloakStatus = PCLOAK_Off;
4312         predStatus->CloakingEffectiveness = 0;
4313         predStatus->CloakTimer = 0;
4314 }
4315 
PredatorCloakOn(PREDATOR_STATUS_BLOCK * predStatus)4316 static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus)
4317 {
4318         LOCALASSERT(predStatus);
4319 
4320         #if 0
4321         /* Temp! */
4322         return;
4323         #else
4324         if (predStatus->CloakStatus==PCLOAK_On) {
4325                 return;
4326         } else if (predStatus->CloakStatus==PCLOAK_Deactivating) {
4327                 /* Don't reset timer. */
4328                 predStatus->CloakStatus = PCLOAK_Activating;
4329                 return;
4330         } else if (predStatus->CloakStatus==PCLOAK_Activating) {
4331                 /* Okay, okay! */
4332                 return;
4333         } else {
4334                 /* Cloak ust be Off. */
4335                 predStatus->CloakStatus = PCLOAK_Activating;
4336                 predStatus->CloakTimer = ONE_FIXED-1;
4337         }
4338         #endif
4339 }
4340 
PredatorCloakOff(PREDATOR_STATUS_BLOCK * predStatus)4341 static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus)
4342 {
4343         LOCALASSERT(predStatus);
4344 
4345         if (predStatus->CloakStatus==PCLOAK_Off) {
4346                 return;
4347         } else if (predStatus->CloakStatus==PCLOAK_Activating) {
4348                 /* Don't reset timer. */
4349                 predStatus->CloakStatus = PCLOAK_Deactivating;
4350                 return;
4351         } else if (predStatus->CloakStatus==PCLOAK_Deactivating) {
4352                 /* Okay, okay! */
4353                 return;
4354         } else {
4355                 /* Cloak must be On. */
4356                 predStatus->CloakStatus = PCLOAK_Deactivating;
4357                 predStatus->CloakTimer = 0; /* Was predStatus->PredShimmer. */
4358         }
4359 }
4360 
4361 
DoPredatorCloak(PREDATOR_STATUS_BLOCK * predStatus,DYNAMICSBLOCK * dynPtr)4362 static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus,DYNAMICSBLOCK *dynPtr)
4363 {
4364         LOCALASSERT(predStatus);
4365         switch(predStatus->CloakStatus)
4366         {
4367                 case(PCLOAK_Off):
4368                 {
4369                         /* do nothing */
4370                         break;
4371                 }
4372                 case(PCLOAK_Activating):
4373                 {
4374                         predStatus->CloakTimer -= (NormalFrameTime);
4375                         if(predStatus->CloakTimer<=0)
4376                         {
4377                                 predStatus->CloakTimer=0;
4378                                 predStatus->CloakStatus=PCLOAK_On;
4379                         }
4380                         break;
4381                 }
4382                 case(PCLOAK_On):
4383                 {
4384                         break;
4385                 }
4386                 case(PCLOAK_Deactivating):
4387                 {
4388                         predStatus->CloakTimer += (NormalFrameTime);
4389                         if(predStatus->CloakTimer>=(ONE_FIXED))
4390                         {
4391                                 predStatus->CloakTimer=0;
4392                                 predStatus->CloakStatus=PCLOAK_Off;
4393                         }
4394                         break;
4395                 }
4396                 default:
4397                 {
4398                         LOCALASSERT(1==0);
4399                         break;
4400                 }
4401         }
4402 
4403 	/* KJL - cloaking effectiveness */
4404 	if(predStatus->CloakStatus!=PCLOAK_Off)
4405 	{
4406 		int maxPossibleEffectiveness;
4407 		VECTORCH velocity;
4408 
4409 		velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx;
4410 		velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy;
4411 		velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz;
4412 
4413 		maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*4,NormalFrameTime);
4414 
4415 		if (maxPossibleEffectiveness<0) maxPossibleEffectiveness = 0;
4416 
4417 		predStatus->CloakingEffectiveness += NormalFrameTime;
4418 		if (predStatus->CloakingEffectiveness>maxPossibleEffectiveness)
4419 		{
4420 			predStatus->CloakingEffectiveness = maxPossibleEffectiveness;
4421 		}
4422 	}
4423 	else
4424 	{
4425 		predStatus->CloakingEffectiveness -= NormalFrameTime;
4426 		if (predStatus->CloakingEffectiveness<0)
4427 		{
4428 			predStatus->CloakingEffectiveness=0;
4429 		}
4430 	}
4431 //	PrintDebuggingText("cloaking effectiveness %d\n",predStatus->CloakingEffectiveness);
4432 
4433 }
4434 
NPCPredatorIsCloaked(STRATEGYBLOCK * sbPtr)4435 int NPCPredatorIsCloaked(STRATEGYBLOCK *sbPtr) {
4436 
4437         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4438 
4439         LOCALASSERT(sbPtr);
4440         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4441         LOCALASSERT(predatorStatusPointer);
4442 
4443         /* For external calls. */
4444 
4445         switch(predatorStatusPointer->CloakStatus)
4446         {
4447                 case(PCLOAK_Off):
4448                 case(PCLOAK_Activating):
4449                 case(PCLOAK_Deactivating):
4450                 {
4451                         return(0);
4452                         break;
4453                 }
4454                 case(PCLOAK_On):
4455                 {
4456                         return(1);
4457                         break;
4458                 }
4459                 default:
4460                 {
4461                         LOCALASSERT(1==0);
4462                         break;
4463                 }
4464         }
4465 
4466         return(0);
4467 }
4468 
PredatorCanSeeTarget(STRATEGYBLOCK * sbPtr)4469 static int PredatorCanSeeTarget(STRATEGYBLOCK *sbPtr)
4470 {
4471         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4472         int targetIsCloaked;
4473 
4474         LOCALASSERT(sbPtr);
4475         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4476         LOCALASSERT(predatorStatusPointer);
4477 
4478         if (predatorStatusPointer->Target==NULL) {
4479                 /* You can't see nothin. */
4480                 return(0);
4481         }
4482 
4483         /* Predators see... well, anything. */
4484 
4485         targetIsCloaked=0;
4486 
4487         if (predatorStatusPointer->Target==Player->ObStrategyBlock) {
4488                 /* test for player hiding? */
4489 
4490         } else {
4491                 /* Test for NPC aliens hiding? */
4492         }
4493 
4494         if(!(NPCCanSeeTarget(sbPtr,predatorStatusPointer->Target, 1000000))) {
4495                 return(0);
4496         }
4497 
4498         if (targetIsCloaked) {
4499                 return(0);
4500         }
4501 
4502         return(1);
4503 }
4504 
PredatorCanSeeObject(STRATEGYBLOCK * sbPtr,STRATEGYBLOCK * target)4505 static int PredatorCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target)
4506 {
4507         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4508         int targetIsCloaked;
4509 
4510         LOCALASSERT(sbPtr);
4511         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4512         LOCALASSERT(predatorStatusPointer);
4513 
4514         if (target==NULL) {
4515                 /* You can't see nothin. */
4516                 return(0);
4517         }
4518 
4519         /* Predators see... well, anything. */
4520 
4521         targetIsCloaked=0;
4522 
4523         if (target==Player->ObStrategyBlock) {
4524                 /* test for player hiding? */
4525 
4526         } else {
4527                 /* Test for NPC aliens hiding? */
4528         }
4529 
4530         if(!(NPCCanSeeTarget(sbPtr,target, 1000000))) {
4531                 return(0);
4532         }
4533 
4534         if (targetIsCloaked) {
4535                 return(0);
4536         }
4537 
4538         return(1);
4539 }
4540 
PredatorIsAwareOfTarget(STRATEGYBLOCK * sbPtr)4541 static int PredatorIsAwareOfTarget(STRATEGYBLOCK *sbPtr)
4542 {
4543         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4544 
4545         LOCALASSERT(sbPtr);
4546         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4547         LOCALASSERT(predatorStatusPointer);
4548 
4549         if (predatorStatusPointer->Target==NULL) {
4550                 /* You can't see nothin. */
4551                 return(0);
4552         }
4553 
4554         /* Okay, let's cut to the chase. */
4555 
4556 		/* Slightly more restrictive now... */
4557 		if ((IsModuleVisibleFromModule(sbPtr->containingModule,
4558 			predatorStatusPointer->Target->containingModule))) {
4559 			return(1);
4560 		} else {
4561 			return(0);
4562 		}
4563 
4564         return(1);
4565 }
4566 
Predator_Enter_Wander_State(STRATEGYBLOCK * sbPtr)4567 void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr) {
4568 
4569         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4570 
4571         LOCALASSERT(sbPtr);
4572         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4573         LOCALASSERT(predatorStatusPointer);
4574 
4575         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4576         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4577         InitWaypointManager(&predatorStatusPointer->waypointManager);
4578         predatorStatusPointer->volleySize = 0;
4579         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4580         predatorStatusPointer->behaviourState = PBS_Wandering;
4581         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4582         predatorStatusPointer->Pred_Laser_On=0;
4583 
4584         #if 0
4585         if(predatorStatusPointer->IAmCrouched) {
4586                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4587         } else {
4588                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4589         }
4590         #endif
4591 
4592 }
4593 
Predator_Enter_Hunt_State(STRATEGYBLOCK * sbPtr)4594 void Predator_Enter_Hunt_State(STRATEGYBLOCK *sbPtr) {
4595 
4596         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4597 
4598         LOCALASSERT(sbPtr);
4599         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4600         LOCALASSERT(predatorStatusPointer);
4601 
4602         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4603         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4604         InitWaypointManager(&predatorStatusPointer->waypointManager);
4605         predatorStatusPointer->volleySize = 0;
4606         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4607         predatorStatusPointer->behaviourState = PBS_Hunting;
4608         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4609         predatorStatusPointer->Pred_Laser_On=0;
4610 
4611         #if 0
4612         if(predatorStatusPointer->IAmCrouched) {
4613                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4614         } else {
4615                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4616         }
4617         #endif
4618 
4619 }
4620 
Predator_Enter_Recover_State(STRATEGYBLOCK * sbPtr)4621 void Predator_Enter_Recover_State(STRATEGYBLOCK *sbPtr) {
4622 
4623         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4624 
4625         LOCALASSERT(sbPtr);
4626         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4627         LOCALASSERT(predatorStatusPointer);
4628 
4629         if (predatorStatusPointer->Selected_Weapon->id!=PNPCW_Medicomp) {
4630                 /* Change to it. */
4631                 predatorStatusPointer->ChangeToWeapon=PNPCW_Medicomp;
4632                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
4633                 NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4634                 InitWaypointManager(&predatorStatusPointer->waypointManager);
4635                 predatorStatusPointer->volleySize = 0;
4636                 predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4637                 predatorStatusPointer->behaviourState = PBS_SwapWeapon;
4638                 predatorStatusPointer->stateTimer = 0; /* Just starting. */
4639                 predatorStatusPointer->Pred_Laser_On=0;
4640 
4641                 /* Deal with sequence in a bit. */
4642                 PredatorCloakOff(predatorStatusPointer);
4643                 return;
4644         }
4645 
4646         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4647         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4648         InitWaypointManager(&predatorStatusPointer->waypointManager);
4649         predatorStatusPointer->volleySize = 0;
4650         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4651         predatorStatusPointer->behaviourState = PBS_Recovering;
4652         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4653         predatorStatusPointer->Pred_Laser_On=0;
4654 
4655         if(predatorStatusPointer->IAmCrouched) {
4656                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Attack_Primary,ONE_FIXED,(ONE_FIXED>>3));
4657         } else {
4658                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Attack_Primary,ONE_FIXED,(ONE_FIXED>>3));
4659         }
4660 
4661 }
4662 
Predator_Enter_Withdrawal_State(STRATEGYBLOCK * sbPtr)4663 void Predator_Enter_Withdrawal_State(STRATEGYBLOCK *sbPtr) {
4664 
4665         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4666 
4667         LOCALASSERT(sbPtr);
4668         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4669         LOCALASSERT(predatorStatusPointer);
4670 
4671         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4672         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4673         InitWaypointManager(&predatorStatusPointer->waypointManager);
4674         predatorStatusPointer->volleySize = 0;
4675         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4676         predatorStatusPointer->behaviourState = PBS_Withdrawing;
4677         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4678         predatorStatusPointer->Pred_Laser_On=0;
4679 
4680         /* Force re-evaluation of priorities. */
4681         predatorStatusPointer->missionmodule=NULL;
4682         predatorStatusPointer->fearmodule=NULL;
4683 
4684         #if 0
4685         if(predatorStatusPointer->IAmCrouched) {
4686                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4687         } else {
4688                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4689         }
4690         #endif
4691 
4692 }
4693 
Predator_Enter_Engaged_State(STRATEGYBLOCK * sbPtr)4694 void Predator_Enter_Engaged_State(STRATEGYBLOCK *sbPtr) {
4695 
4696         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4697 
4698         LOCALASSERT(sbPtr);
4699         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4700         LOCALASSERT(predatorStatusPointer);
4701 
4702         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4703         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4704         InitWaypointManager(&predatorStatusPointer->waypointManager);
4705         predatorStatusPointer->volleySize = 0;
4706         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4707         predatorStatusPointer->behaviourState = PBS_Engaging;
4708         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4709         predatorStatusPointer->Pred_Laser_On=0;
4710 
4711         #if 0
4712         if(predatorStatusPointer->IAmCrouched) {
4713                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4714         } else {
4715                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4716         }
4717         #endif
4718 
4719 }
4720 
Predator_Enter_Attacking_State(STRATEGYBLOCK * sbPtr)4721 void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr) {
4722 
4723         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4724 
4725         LOCALASSERT(sbPtr);
4726         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4727         LOCALASSERT(predatorStatusPointer);
4728 
4729         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4730         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4731         InitWaypointManager(&predatorStatusPointer->waypointManager);
4732         predatorStatusPointer->volleySize = 0;
4733         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4734         predatorStatusPointer->behaviourState = PBS_Attacking;
4735         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
4736         predatorStatusPointer->Pred_Laser_On=0;
4737         predatorStatusPointer->internalState=0;
4738         /* Become patient again. */
4739         predatorStatusPointer->patience=PRED_PATIENCE_TIME;
4740 
4741         if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Wristblade) {
4742                 StartWristbladeAttackSequence(sbPtr);
4743         } else if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Staff) {
4744                 StartPredStaffAttackSequence(sbPtr);
4745         } else {
4746                 if(predatorStatusPointer->IAmCrouched) {
4747                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Attack_Primary,-1,(ONE_FIXED>>3));
4748                 } else {
4749                         SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Attack_Primary,-1,(ONE_FIXED>>3));
4750                 }
4751         }
4752 }
4753 
Predator_Enter_Avoidance_State(STRATEGYBLOCK * sbPtr)4754 void Predator_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) {
4755 
4756         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4757 
4758         LOCALASSERT(sbPtr);
4759         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4760         LOCALASSERT(predatorStatusPointer);
4761 
4762         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4763         NPCGetAvoidanceDirection(sbPtr, &(predatorStatusPointer->moveData.avoidanceDirn),&predatorStatusPointer->obstruction);
4764         InitWaypointManager(&predatorStatusPointer->waypointManager);
4765         predatorStatusPointer->volleySize = 0;
4766         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4767         predatorStatusPointer->behaviourState = PBS_Avoidance;
4768         predatorStatusPointer->stateTimer = NPC_AVOIDTIME;
4769         predatorStatusPointer->Pred_Laser_On=0;
4770 
4771         /* zero linear velocity in dynamics block */
4772         sbPtr->DynPtr->LinVelocity.vx = 0;
4773         sbPtr->DynPtr->LinVelocity.vy = 0;
4774         sbPtr->DynPtr->LinVelocity.vz = 0;
4775 
4776         #if 0
4777         if(predatorStatusPointer->IAmCrouched) {
4778                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4779         } else {
4780                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4781         }
4782         #endif
4783 
4784 }
4785 
Predator_Enter_Swapping_State(STRATEGYBLOCK * sbPtr)4786 void Predator_Enter_Swapping_State(STRATEGYBLOCK *sbPtr) {
4787 
4788         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4789 
4790         LOCALASSERT(sbPtr);
4791         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4792         LOCALASSERT(predatorStatusPointer);
4793 
4794         /* What are we swapping to? */
4795         if (predatorStatusPointer->ChangeToWeapon==PNPCW_End) {
4796                 /* Use default. */
4797                 if (predatorStatusPointer->Selected_Weapon->id==predatorStatusPointer->PrimaryWeapon) {
4798                         /* Using primary - change to secondary. */
4799                         predatorStatusPointer->ChangeToWeapon=predatorStatusPointer->SecondaryWeapon;
4800                 } else {
4801                         /* Using secondary or other - change to primary. */
4802                         predatorStatusPointer->ChangeToWeapon=predatorStatusPointer->PrimaryWeapon;
4803                 }
4804         }
4805 
4806         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4807         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4808         InitWaypointManager(&predatorStatusPointer->waypointManager);
4809         predatorStatusPointer->volleySize = 0;
4810         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4811         predatorStatusPointer->behaviourState = PBS_SwapWeapon;
4812         predatorStatusPointer->stateTimer = 0; /* Just starting. */
4813         predatorStatusPointer->Pred_Laser_On=0;
4814         predatorStatusPointer->patience=PRED_PATIENCE_TIME;
4815 
4816         predatorStatusPointer->enableSwap=0;
4817 
4818         /* Deal with sequence in a bit. */
4819         PredatorCloakOff(predatorStatusPointer);
4820 }
4821 
Predator_Enter_Return_State(STRATEGYBLOCK * sbPtr)4822 void Predator_Enter_Return_State(STRATEGYBLOCK *sbPtr) {
4823 
4824         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4825 
4826         LOCALASSERT(sbPtr);
4827         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4828         LOCALASSERT(predatorStatusPointer);
4829 
4830         GLOBALASSERT(predatorStatusPointer->path!=-1);
4831         GLOBALASSERT(predatorStatusPointer->stepnumber!=-1);
4832 
4833         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4834         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4835         InitWaypointManager(&predatorStatusPointer->waypointManager);
4836         predatorStatusPointer->volleySize = 0;
4837         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4838         predatorStatusPointer->behaviourState = PBS_Returning;
4839         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4840         predatorStatusPointer->Pred_Laser_On=0;
4841 
4842         #if 0
4843         if(predatorStatusPointer->IAmCrouched) {
4844                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4845         } else {
4846                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4847         }
4848         #endif
4849 
4850 }
4851 
Predator_Enter_Pathfinder_State(STRATEGYBLOCK * sbPtr)4852 void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) {
4853 
4854         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4855 
4856         LOCALASSERT(sbPtr);
4857         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4858         LOCALASSERT(predatorStatusPointer);
4859 
4860         GLOBALASSERT(predatorStatusPointer->path!=-1);
4861         GLOBALASSERT(predatorStatusPointer->stepnumber!=-1);
4862 
4863         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4864         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4865         InitWaypointManager(&predatorStatusPointer->waypointManager);
4866         predatorStatusPointer->volleySize = 0;
4867         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4868         predatorStatusPointer->behaviourState = PBS_Pathfinding;
4869         predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
4870         predatorStatusPointer->Pred_Laser_On=0;
4871 
4872         #if 0
4873         if(predatorStatusPointer->IAmCrouched) {
4874                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4875         } else {
4876                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
4877         }
4878         #endif
4879 
4880 }
4881 
Predator_Enter_Taunt_State(STRATEGYBLOCK * sbPtr)4882 void Predator_Enter_Taunt_State(STRATEGYBLOCK *sbPtr) {
4883 
4884         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4885 
4886         LOCALASSERT(sbPtr);
4887         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4888         LOCALASSERT(predatorStatusPointer);
4889 
4890         if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Taunt_One)) {
4891 
4892                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
4893                 NPCGetAvoidanceDirection(sbPtr, &(predatorStatusPointer->moveData.avoidanceDirn),&predatorStatusPointer->obstruction);
4894                 InitWaypointManager(&predatorStatusPointer->waypointManager);
4895                 predatorStatusPointer->volleySize = 0;
4896                 predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4897                 predatorStatusPointer->behaviourState = PBS_Taunting;
4898                 predatorStatusPointer->stateTimer = NPC_AVOIDTIME;
4899                 predatorStatusPointer->Pred_Laser_On=0;
4900                 /* Become patient again. */
4901                 predatorStatusPointer->patience=PRED_PATIENCE_TIME;
4902                 predatorStatusPointer->enableTaunt=0;
4903 
4904                 SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Taunt_One,-1,(ONE_FIXED>>3));
4905                 predatorStatusPointer->HModelController.LoopAfterTweening=0;
4906 
4907 				#if 0
4908                 Sound_Play(SID_PRED_NEWROAR,"d",&sbPtr->DynPtr->Position);
4909 				#else
4910 				DoPredatorTauntSound(sbPtr);
4911 				#endif
4912 
4913         } else {
4914                 /* Yuck. */
4915                 Predator_Enter_Engaged_State(sbPtr);
4916         }
4917 
4918 }
4919 
Predator_Enter_SelfDestruct_State(STRATEGYBLOCK * sbPtr)4920 void Predator_Enter_SelfDestruct_State(STRATEGYBLOCK *sbPtr) {
4921 
4922         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4923         SECTION *root;
4924 
4925         LOCALASSERT(sbPtr);
4926         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4927         LOCALASSERT(predatorStatusPointer);
4928 
4929         /* Switch to template. */
4930         root=GetNamedHierarchyFromLibrary("hnpcpredator","Template");
4931         GLOBALASSERT(root);
4932         RemoveAllDeltas(&predatorStatusPointer->HModelController);
4933         /* Set 'new' sequence. */
4934         predatorStatusPointer->HModelController.Sequence_Type=HMSQT_PredatorCrouch;
4935         predatorStatusPointer->HModelController.Sub_Sequence=PCrSS_Det_Prog;
4936         Transmogrify_HModels(sbPtr,&predatorStatusPointer->HModelController,root, 1, 0,0);
4937         ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
4938 
4939         InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),
4940                 HMSQT_PredatorCrouch,PCrSS_Det_Prog,-1,0);
4941 
4942         /* Init stats. */
4943         NPC_InitMovementData(&(predatorStatusPointer->moveData));
4944         NPC_InitWanderData(&(predatorStatusPointer->wanderData));
4945         InitWaypointManager(&predatorStatusPointer->waypointManager);
4946         predatorStatusPointer->volleySize = 0;
4947         predatorStatusPointer->lastState=predatorStatusPointer->behaviourState;
4948         predatorStatusPointer->behaviourState = PBS_SelfDestruct;
4949         predatorStatusPointer->stateTimer = 0;
4950         predatorStatusPointer->Pred_Laser_On=0;
4951         predatorStatusPointer->internalState=0; /* Not yet primed. */
4952         predatorStatusPointer->IAmCrouched = 1;
4953 
4954 }
4955 
Predator_SwitchState(STRATEGYBLOCK * sbPtr,PRED_RETURN_CONDITION state_result)4956 void Predator_SwitchState(STRATEGYBLOCK *sbPtr,PRED_RETURN_CONDITION state_result) {
4957 
4958         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
4959 
4960         LOCALASSERT(sbPtr);
4961         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
4962         LOCALASSERT(predatorStatusPointer);
4963 
4964         switch (state_result) {
4965                 case (PRC_No_Change):
4966                 {
4967                         /* No action. */
4968                         break;
4969                 }
4970                 case (PRC_Request_Engage):
4971                 {
4972                         Predator_Enter_Engaged_State(sbPtr);
4973                         break;
4974                 }
4975                 case (PRC_Request_Attack):
4976                 {
4977                         Predator_Enter_Attacking_State(sbPtr);
4978                         break;
4979                 }
4980                 case (PRC_Request_Wander):
4981                 {
4982                         if ((predatorStatusPointer->path!=-1)&&
4983                                 (predatorStatusPointer->stepnumber!=-1)) {
4984                                 /* Pathfinding mission. */
4985                                 if ((predatorStatusPointer->behaviourState==PBS_Returning)
4986                                         ||(predatorStatusPointer->behaviourState==PBS_Pathfinding)) {
4987                                         /* A real order. */
4988                                         Predator_Enter_Wander_State(sbPtr);
4989                                 } else {
4990                                         /* Pathfind instead. */
4991                                         Predator_Enter_Pathfinder_State(sbPtr);
4992                                 }
4993                         } else {
4994                                 Predator_Enter_Wander_State(sbPtr);
4995                         }
4996                         break;
4997                 }
4998                 case (PRC_Request_Avoidance):
4999                 {
5000                         Predator_Enter_Avoidance_State(sbPtr);
5001                         break;
5002                 }
5003                 case (PRC_Request_Hunt):
5004                 {
5005                         Predator_Enter_Hunt_State(sbPtr);
5006                         break;
5007                 }
5008                 case (PRC_Request_Withdraw):
5009                 {
5010                         Predator_Enter_Withdrawal_State(sbPtr);
5011                         break;
5012                 }
5013                 case (PRC_Request_Recover):
5014                 {
5015                         Predator_Enter_Recover_State(sbPtr);
5016                         break;
5017                 }
5018                 case (PRC_Request_Swap):
5019                 {
5020                         Predator_Enter_Swapping_State(sbPtr);
5021                         break;
5022                 }
5023                 case (PRC_Request_Pathfind):
5024                 {
5025                         Predator_Enter_Pathfinder_State(sbPtr);
5026                         break;
5027                 }
5028                 case (PRC_Request_Return):
5029                 {
5030                         Predator_Enter_Return_State(sbPtr);
5031                         break;
5032                 }
5033                 case (PRC_Request_Taunt):
5034                 {
5035                         Predator_Enter_Taunt_State(sbPtr);
5036                         break;
5037                 }
5038                 default:
5039                 {
5040                         /* No action? */
5041                         break;
5042                 }
5043 
5044 }
5045 
5046 }
5047 
Predator_TargetFilter(STRATEGYBLOCK * candidate)5048 int Predator_TargetFilter(STRATEGYBLOCK *candidate) {
5049 
5050         switch (candidate->I_SBtype) {
5051                 case I_BehaviourMarinePlayer:
5052                 case I_BehaviourAlienPlayer:
5053                 case I_BehaviourPredatorPlayer:
5054                         {
5055                                 if (Observer) {
5056                                         return(0);
5057                                 }
5058 
5059                                 switch(AvP.PlayerType)
5060                                 {
5061                                         case I_Alien:
5062                                         case I_Marine:
5063                                                 return(1);
5064                                                 break;
5065                                         case I_Predator:
5066                                                 /* Just this once. */
5067                                                 return(0);
5068                                                 break;
5069                                         default:
5070                                                 GLOBALASSERT(0);
5071                                                 return(0);
5072                                                 break;
5073                                 }
5074                                 break;
5075                         }
5076                 case I_BehaviourDummy:
5077                         {
5078                                 DUMMY_STATUS_BLOCK *dummyStatusPointer;
5079                                 dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr);
5080                             LOCALASSERT(dummyStatusPointer);
5081                                 switch (dummyStatusPointer->PlayerType) {
5082                                         case I_Marine:
5083                                         case I_Alien:
5084                                                 return(1);
5085                                                 break;
5086                                         case I_Predator:
5087                                                 return(0);
5088                                                 break;
5089                                         default:
5090                                                 GLOBALASSERT(0);
5091                                                 return(0);
5092                                                 break;
5093                                 }
5094                                 break;
5095                         }
5096                 case I_BehaviourAlien:
5097                         {
5098                                 ALIEN_STATUS_BLOCK *alienStatusPointer;
5099                                 LOCALASSERT(candidate);
5100                                 LOCALASSERT(candidate->DynPtr);
5101 
5102                                 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr);
5103 
5104                                 if (NPC_IsDead(candidate)) {
5105                                         return(0);
5106                                 } else {
5107                                         return(1);
5108                                 }
5109                                 break;
5110                         }
5111 				case I_BehaviourAutoGun:
5112                     if (NPC_IsDead(candidate)) {
5113                             return(0);
5114                     } else {
5115                             AUTOGUN_STATUS_BLOCK *autogunStatusPointer;
5116                             autogunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(candidate->SBdataptr);
5117                             LOCALASSERT(autogunStatusPointer);
5118 
5119 							if (autogunStatusPointer->behaviourState==I_inactive) {
5120 	                            return(0);
5121 							} else {
5122 	                            return(1);
5123 							}
5124                     }
5125 					break;
5126                 case I_BehaviourQueenAlien:
5127                 case I_BehaviourFaceHugger:
5128                 case I_BehaviourMarine:
5129                 case I_BehaviourXenoborg:
5130                 case I_BehaviourSeal:
5131                 case I_BehaviourPredatorAlien:
5132                         /* Valid. */
5133                         return(1);
5134                         break;
5135                 case I_BehaviourPredator:
5136                         #if ANARCHY
5137                         return(1);
5138                         #else
5139                         return(0);
5140                         #endif
5141                         break;
5142                 case I_BehaviourNetGhost:
5143                         {
5144                                 NETGHOSTDATABLOCK *dataptr;
5145                                 dataptr=candidate->SBdataptr;
5146                                 switch (dataptr->type) {
5147                                         case I_BehaviourMarinePlayer:
5148                                         case I_BehaviourAlienPlayer:
5149                                         case I_BehaviourPredatorPlayer:
5150                                                 //return(1);
5151                                                 return(0);
5152                                                 break;
5153                                         default:
5154                                                 return(0);
5155                                                 break;
5156                                 }
5157                         }
5158                         break;
5159                 default:
5160                         return(0);
5161                         break;
5162         }
5163 
5164 }
5165 
5166 
Predator_GetNewTarget(STRATEGYBLOCK * sbPtr)5167 STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *sbPtr) {
5168 
5169         #if 0
5170         /* Here's the simple one, for testing purposes. */
5171         return(Player->ObStrategyBlock);
5172         #else
5173 
5174         int neardist, newblip;
5175         STRATEGYBLOCK *nearest;
5176 
5177         int a;
5178         STRATEGYBLOCK *candidate;
5179         MODULE *dmod;
5180         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5181         int dist;
5182         VECTORCH offset;
5183 
5184         LOCALASSERT(sbPtr);
5185         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5186         LOCALASSERT(predatorStatusPointer);
5187 
5188         dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule);
5189 
5190         LOCALASSERT(dmod);
5191 
5192         nearest=NULL;
5193         neardist=ONE_FIXED;
5194         newblip=0;
5195 
5196         for (a=0; a<NumActiveStBlocks; a++) {
5197                 candidate=ActiveStBlockList[a];
5198                 if (candidate!=sbPtr) {
5199                         if (candidate->DynPtr) {
5200                                 /* Arc reject. */
5201                                 MATRIXCH WtoL;
5202 
5203                                 offset.vx=sbPtr->DynPtr->Position.vx-candidate->DynPtr->Position.vx;
5204                                 offset.vy=sbPtr->DynPtr->Position.vy-candidate->DynPtr->Position.vy;
5205                                 offset.vz=sbPtr->DynPtr->Position.vz-candidate->DynPtr->Position.vz;
5206 
5207                                 WtoL=sbPtr->DynPtr->OrientMat;
5208                                 TransposeMatrixCH(&WtoL);
5209                                 RotateVector(&offset,&WtoL);
5210 
5211                                 if (offset.vz<=0) {
5212 
5213                                         if (Predator_TargetFilter(candidate)) {
5214 
5215                                                 dist=Approximate3dMagnitude(&offset);
5216 
5217                                                 if (dist<neardist) {
5218                                                         /* Check visibility? */
5219                                                         if (candidate->SBdptr) {
5220                                                                 /* Near case. */
5221                                                                 if (!NPC_IsDead(candidate)) {
5222                                                                         if ((PredatorCanSeeObject(sbPtr,candidate))) {
5223                                                                                 nearest=candidate;
5224                                                                                 neardist=dist;
5225                                                                         }
5226                                                                 }
5227                                                         } else {
5228                                                                 if (!NPC_IsDead(candidate)) {
5229                                                                         if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
5230                                                                                 nearest=candidate;
5231                                                                                 neardist=dist;
5232                                                                         }
5233                                                                 }
5234                                                         }
5235                                                 }
5236                                         }
5237                                 }
5238                         }
5239                 }
5240         }
5241 
5242         return(nearest);
5243         #endif
5244 
5245 }
5246 
DoPredatorLaserTargeting(STRATEGYBLOCK * sbPtr)5247 int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr) {
5248 
5249         int i,hits;
5250         MATRIXCH matrix;
5251         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5252         SECTION_DATA *plasma_muzzle;
5253         VECTORCH offset[3] =
5254         {
5255                 {0,-50,0},
5256                 {43,25,0},
5257                 {-43,25,0},
5258         };
5259         STRATEGYBLOCK *laserhits[3];
5260         STRATEGYBLOCK *consensus;
5261         VECTORCH z_vec;
5262 
5263         LOCALASSERT(sbPtr);
5264         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5265         LOCALASSERT(predatorStatusPointer);
5266 
5267         predatorStatusPointer->Pred_Laser_On=0;
5268         /* Reset it at the end! */
5269 
5270         plasma_muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
5271         if (plasma_muzzle==NULL) {
5272                 return(0);
5273         }
5274 
5275         matrix = plasma_muzzle->SecMat;
5276 
5277         z_vec.vx=matrix.mat31;
5278         z_vec.vy=matrix.mat32;
5279         z_vec.vz=matrix.mat33;
5280 
5281         TransposeMatrixCH(&matrix);
5282 
5283         predatorStatusPointer->Pred_Laser_Sight.LightSource=plasma_muzzle->World_Offset;
5284         predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer=0;
5285 
5286         i=2;
5287         hits=0;
5288 
5289         do {
5290                 VECTORCH position = offset[i];
5291 
5292                 RotateVector(&position,&matrix);
5293                 position.vx += plasma_muzzle->World_Offset.vx;
5294                 position.vy += plasma_muzzle->World_Offset.vy;
5295                 position.vz += plasma_muzzle->World_Offset.vz;
5296                 FindPolygonInLineOfSight(&z_vec, &position, 0,sbPtr->SBdptr);
5297 
5298                 predatorStatusPointer->Pred_Laser_Sight.Normal[i] = LOS_ObjectNormal;
5299                 predatorStatusPointer->Pred_Laser_Sight.Position[i] = LOS_Point;
5300 
5301                 if (LOS_ObjectHitPtr==Player) {
5302                         predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer=1;
5303                 }
5304 
5305                 if (LOS_ObjectHitPtr) {
5306                         laserhits[i]=LOS_ObjectHitPtr->ObStrategyBlock;
5307                 } else {
5308                         laserhits[i]=NULL;
5309                 }
5310 
5311                 if (laserhits[i]) {
5312                         hits++;
5313                 }
5314         } while(i--);
5315 
5316         /* Now, what have we hit? */
5317 
5318         consensus=NULL;
5319 
5320         switch (hits) {
5321                 case 0:
5322                 default:
5323                         consensus=NULL;
5324                         break;
5325                 case 1:
5326                         i=2;
5327                         do {
5328                                 if (laserhits[i]!=NULL) {
5329                                         consensus=laserhits[i];
5330                                 }
5331                         } while (i--);
5332                         break;
5333                 case 2:
5334                         i=2;
5335                         do {
5336                                 if (laserhits[i]!=NULL) {
5337                                         if (consensus==NULL) {
5338                                                 consensus=laserhits[i];
5339                                         } else {
5340                                                 if (laserhits[i]!=consensus) {
5341                                                         consensus=NULL;
5342                                                 }
5343                                         }
5344                                 }
5345                         } while (i--);
5346                         break;
5347                 case 3:
5348                         if ((laserhits[0]==laserhits[1])||(laserhits[0]==laserhits[2])) {
5349                                 consensus=laserhits[0];
5350                         } else if (laserhits[1]==laserhits[2]) {
5351                                 consensus=laserhits[1];
5352                         } else {
5353                                 consensus=NULL;
5354                         }
5355                         break;
5356         }
5357 
5358         predatorStatusPointer->Pred_Laser_On=1;
5359 
5360         if (predatorStatusPointer->Target==NULL) {
5361                 return(0);
5362         }
5363 
5364         if (consensus==predatorStatusPointer->Target) {
5365                 return(1);
5366         } else {
5367                 return(0);
5368         }
5369 
5370 }
5371 
Execute_PNS_EngageWithStaff(STRATEGYBLOCK * sbPtr)5372 static PRED_RETURN_CONDITION Execute_PNS_EngageWithStaff(STRATEGYBLOCK *sbPtr)
5373 {
5374         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5375         VECTORCH velocityDirection = {0,0,0};
5376         VECTORCH targetPosition;
5377         int targetIsAirduct = 0;
5378         int range;
5379 
5380         /* Same as wristblade version. */
5381         LOCALASSERT(sbPtr);
5382         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5383         LOCALASSERT(predatorStatusPointer);
5384 
5385         PredatorHandleMovingAnimation(sbPtr);
5386 
5387         predatorStatusPointer->patience-=NormalFrameTime;
5388         /* Have we become impatient? */
5389         if (predatorStatusPointer->patience<=0) {
5390                 return(PRC_Request_Swap);
5391         }
5392 
5393         /* now check for state changes... firstly, if we can no longer attack the target, go
5394         to wander */
5395         if(!(PredatorIsAwareOfTarget(sbPtr)))
5396         {
5397                 return(PRC_Request_Hunt);
5398                 /* Drop out null targets. */
5399         } else {
5400 
5401                 /* We have a target that we are aware of. */
5402 
5403                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
5404 
5405                 /* Wanna Cloak? */
5406                 if (range<10000) {
5407                         /* Decloak when close. */
5408                         PredatorCloakOff(predatorStatusPointer);
5409                 } else if (predatorStatusPointer->CloakStatus==PCLOAK_Off) {
5410                         PredatorCloakOn(predatorStatusPointer);
5411                 }
5412 
5413                 /* if we are close... go directly to firing */
5414                 if(range < PRED_STAFF_ATTACK_RANGE)
5415                 {
5416                         /* switch directly to firing, at this distance */
5417 
5418                         return(PRC_Request_Attack);
5419                 }
5420 
5421                 /* if our state timer has run out in approach state, see if we can fire*/
5422                 if(predatorStatusPointer->stateTimer > 0) {
5423                         predatorStatusPointer->stateTimer -= NormalFrameTime;
5424                 }
5425 
5426                 if(predatorStatusPointer->stateTimer <= 0)
5427                 {
5428                         /* A moment of decision... */
5429                         /* Might want to withdraw. */
5430                         if(!PredatorCanSeeTarget(sbPtr))
5431                         {
5432                                 /* Lost sight of him! */
5433 
5434                                 return(PRC_Request_Hunt);
5435                         }
5436                         else
5437                         {
5438                                 /* renew approach state */
5439                                 predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
5440                                 /* Whatever. */
5441                         }
5442                 }
5443         }
5444 
5445         /* See which way we want to go. */
5446         {
5447 
5448                 AIMODULE *targetModule;
5449                 MODULE *tcm;
5450                 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
5451 
5452                 GLOBALASSERT(predatorStatusPointer->Target!=NULL);
5453 
5454                 if (predatorStatusPointer->Target->containingModule) {
5455                         tcm=predatorStatusPointer->Target->containingModule;
5456                 } else {
5457                         tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
5458                 }
5459 
5460                 if (tcm) {
5461                         targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
5462                 } else {
5463                         targetModule=NULL;
5464                 }
5465 
5466                 if (targetModule==sbPtr->containingModule->m_aimodule) {
5467                         /* Try going for it, we still can't see them. */
5468                         NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
5469                         NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager);
5470                 } else if (!targetModule) {
5471                         /* Must be inaccessible. */
5472                         if (ShowPredoStats) {
5473                                 if (predatorStatusPointer->Target->containingModule) {
5474                                         PrintDebuggingText("I can see you, but I can't get there!\n");
5475                                 } else {
5476                                         PrintDebuggingText("Hey, you've got no Containing Module!\n");
5477                                 }
5478                         }
5479                         return(PRC_No_Change);
5480                 } else {
5481 
5482                         thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
5483                         if (!thisEp) {
5484                                 LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
5485                                         (*(targetModule->m_module_ptrs))->name,
5486                                         sbPtr->containingModule->name));
5487                                 GLOBALASSERT(thisEp);
5488                         }
5489 
5490                         /* If that fired, there's a farped adjacency. */
5491                         predatorStatusPointer->wanderData.worldPosition=thisEp->position;
5492                         predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
5493                         predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
5494                         predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
5495 
5496                         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
5497                 }
5498 
5499         }
5500 
5501         /* Should have a velocity set now. */
5502         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
5503 
5504         /* test here for impeding collisions, and not being able to reach target... */
5505         if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager))
5506         {
5507                 /* Go to all new avoidance. */
5508             return(PRC_Request_Avoidance);
5509         }
5510 
5511         return(PRC_No_Change);
5512 }
5513 
Execute_PNS_AttackWithStaff(STRATEGYBLOCK * sbPtr)5514 static PRED_RETURN_CONDITION Execute_PNS_AttackWithStaff(STRATEGYBLOCK *sbPtr)
5515 {
5516         VECTORCH orientationDirn;
5517         int i;
5518         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5519         DYNAMICSBLOCK *dynPtr;
5520 
5521         LOCALASSERT(sbPtr);
5522         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5523         LOCALASSERT(predatorStatusPointer);
5524         LOCALASSERT (sbPtr->DynPtr);
5525 
5526         /* zero linear velocity in dynamics block */
5527         LOCALASSERT(sbPtr->DynPtr);
5528         sbPtr->DynPtr->LinVelocity.vx = 0;
5529         sbPtr->DynPtr->LinVelocity.vy = 0;
5530         sbPtr->DynPtr->LinVelocity.vz = 0;
5531 
5532         dynPtr = sbPtr->DynPtr;
5533 
5534         if (predatorStatusPointer->Target==NULL) {
5535                 /* Bomb out. */
5536                 return(PRC_Request_Wander);
5537         }
5538 
5539         /* De-cloak. */
5540         if(predatorStatusPointer->CloakStatus==PCLOAK_On)
5541         {
5542                 PredatorCloakOff(predatorStatusPointer);
5543         }
5544 
5545         GLOBALASSERT(predatorStatusPointer->Target);
5546         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
5547 
5548         /* check for state changes: */
5549         if(VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)) > PRED_STAFF_ATTACK_RANGE)
5550         {
5551                 if (((FastRandom()&65535)>40000)&&(predatorStatusPointer->enableSwap)) {
5552                         /* Quite like the staff. */
5553                         return(PRC_Request_Swap);
5554                 } else {
5555                         /* switch back to engage. */
5556                         GLOBALASSERT(predatorStatusPointer->Target);
5557                         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
5558                         return(PRC_Request_Engage);
5559                 }
5560         }
5561 
5562         /* Orientate towards player, just to make sure we're facing */
5563         orientationDirn.vx = predatorStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
5564         orientationDirn.vy = 0;
5565         orientationDirn.vz = predatorStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
5566         /* Fudge? */
5567         orientationDirn.vx+=(predatorStatusPointer->Target->DynPtr->OrientMat.mat11>>8);
5568         orientationDirn.vz+=(predatorStatusPointer->Target->DynPtr->OrientMat.mat13>>8);
5569         i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
5570 
5571         /* Decrement the near state timer */
5572         predatorStatusPointer->stateTimer -= NormalFrameTime;
5573 
5574         PredatorNearDamageShell(sbPtr);
5575 
5576         #if 0
5577         /* Staff damage. */
5578         {
5579                 SECTION_DATA *tip1,*mid,*tip2;
5580 
5581                 tip1=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff a blade");
5582                 mid=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff center");
5583                 tip2=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff b blade");
5584 
5585                 GLOBALASSERT(tip1);
5586                 GLOBALASSERT(mid);
5587                 GLOBALASSERT(tip2);
5588 
5589                 Staff_Manager(&TemplateAmmo[AMMO_NPC_PRED_STAFF].MaxDamage[AvP.Difficulty],tip1,mid,tip2,sbPtr);
5590 
5591         }
5592         #endif
5593 
5594         if (predatorStatusPointer->HModelController.keyframe_flags&1) {
5595 
5596                 //predatorStatusPointer->enableSwap=1;
5597                 StartPredStaffAttackSequence(sbPtr);
5598                 predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
5599                 /* Shrug. */
5600         }
5601 
5602         return(PRC_No_Change);
5603 
5604 }
5605 
Execute_PFS_Pathfinder(STRATEGYBLOCK * sbPtr)5606 static PRED_RETURN_CONDITION Execute_PFS_Pathfinder(STRATEGYBLOCK *sbPtr)
5607 {
5608         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5609         AIMODULE *targetModule = 0;
5610         int nextModuleIndex;
5611 
5612         LOCALASSERT(sbPtr);
5613         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5614     LOCALASSERT(predatorStatusPointer);
5615 
5616         /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */
5617 
5618         /* Decrement the Far state timer */
5619         predatorStatusPointer->stateTimer -= NormalFrameTime;
5620         /* check if far state timer has timed-out. If so, it is time
5621         to do something. Otherwise just return. */
5622         if(predatorStatusPointer->stateTimer > 0) return(PRC_No_Change);
5623 
5624         /* check for state changes */
5625         if(PredatorIsAwareOfTarget(sbPtr))
5626         /* Hack! */
5627         {
5628                 /* we should be engaging */
5629                 return(PRC_Request_Engage);
5630         }
5631 
5632         /* Ignore alerts. */
5633 
5634         /* Never break out of pathfinder unless your life is in danger! */
5635 
5636         /* Okay, so where are we exactly? */
5637 
5638         if ((predatorStatusPointer->stepnumber<0)||(predatorStatusPointer->path<0)) {
5639                 /* Get OUT! */
5640                 return(PRC_Request_Wander);
5641         }
5642 
5643         targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
5644 
5645         if (targetModule==NULL) {
5646                 /* Oh, to heck with this.  Try to wander. */
5647                 return(PRC_Request_Wander);
5648         }
5649 
5650         /* Right, so there is a somewhere to get to. */
5651 
5652         if (targetModule!=sbPtr->containingModule->m_aimodule) {
5653                 /* But we're nowhere near it.  Geeze... */
5654                 predatorStatusPointer->missionmodule=targetModule;
5655                 return(PRC_Request_Return);
5656         }
5657 
5658         /* Okay, so now we need to know where to go now. */
5659 
5660         nextModuleIndex=GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
5661         GLOBALASSERT(nextModuleIndex>=0);
5662         /* If that fires, it's Richard's fault. */
5663         targetModule=TranslatePathIndex(nextModuleIndex,predatorStatusPointer->path);
5664         GLOBALASSERT(targetModule);
5665         /* Ditto. */
5666         predatorStatusPointer->stepnumber=nextModuleIndex;
5667 
5668         /* Examine target, and decide what to do */
5669         GLOBALASSERT(AIModuleIsPhysical(targetModule));
5670         ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
5671         /* reset timer */
5672         predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
5673         return(PRC_No_Change);
5674 }
5675 
Execute_PNS_Pathfinder(STRATEGYBLOCK * sbPtr)5676 static PRED_RETURN_CONDITION Execute_PNS_Pathfinder(STRATEGYBLOCK *sbPtr)
5677 {
5678         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5679         DYNAMICSBLOCK *dynPtr;
5680         AIMODULE *targetModule;
5681         VECTORCH velocityDirection = {0,0,0};
5682 
5683         LOCALASSERT(sbPtr);
5684         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5685         dynPtr = sbPtr->DynPtr;
5686         LOCALASSERT(predatorStatusPointer);
5687         LOCALASSERT(dynPtr);
5688 
5689         PredatorHandleMovingAnimation(sbPtr);
5690 
5691         /* should we change to approach state? */
5692         if(PredatorIsAwareOfTarget(sbPtr))
5693         {
5694                 /* doesn't require a sequence change */
5695                 return(PRC_Request_Engage);
5696         }
5697 
5698         predatorStatusPointer->stateTimer-=NormalFrameTime;
5699 
5700         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5701         {
5702                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
5703         }
5704         if ((predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5705                 ||(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) {
5706 
5707                 FARENTRYPOINT *thisEp;
5708                 int nextModuleIndex;
5709                 /* Okay, so where are we exactly? */
5710 
5711                 if ((predatorStatusPointer->stepnumber<0)||(predatorStatusPointer->path<0)) {
5712                         /* Get OUT! */
5713                         return(PRC_Request_Wander);
5714                 }
5715 
5716                 targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
5717 
5718                 if (targetModule==NULL) {
5719                         /* Oh, to heck with this.  Try to wander. */
5720                         return(PRC_Request_Wander);
5721                 }
5722 
5723                 /* Right, so there is a somewhere to get to. */
5724 
5725                 if (targetModule!=sbPtr->containingModule->m_aimodule) {
5726                         /* But we're nowhere near it.  Geeze... */
5727                         predatorStatusPointer->missionmodule=targetModule;
5728                         return(PRC_Request_Return);
5729                 }
5730 
5731                 /* Okay, so now we need to know where to go now. */
5732 
5733                 nextModuleIndex=GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
5734                 GLOBALASSERT(nextModuleIndex>=0);
5735                 /* If that fires, it's Richard's fault. */
5736                 targetModule=TranslatePathIndex(nextModuleIndex,predatorStatusPointer->path);
5737                 GLOBALASSERT(targetModule);
5738                 /* Ditto. */
5739                 predatorStatusPointer->stepnumber=nextModuleIndex;
5740 
5741                 thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
5742                 if(thisEp) {
5743                         /* aha. an ep!... */
5744                         VECTORCH thisEpWorld = thisEp->position;
5745 
5746                         thisEpWorld.vx += targetModule->m_world.vx;
5747                         thisEpWorld.vy += targetModule->m_world.vy;
5748                         thisEpWorld.vz += targetModule->m_world.vz;
5749 
5750                         predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
5751                         predatorStatusPointer->wanderData.worldPosition = thisEpWorld;
5752 
5753                 } else {
5754                         /* Failure case. */
5755                         predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
5756                 }
5757 
5758         }
5759 
5760         /* if we still haven't got one, wander for a bit. */
5761         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5762         {
5763                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
5764                 NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0);
5765         }
5766 
5767         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) {
5768                 /* STILL broken!  Okay, just... wander forever, then. */
5769                 return(PRC_Request_Wander);
5770         }
5771 
5772         /* ok: should have a current target at this stage... */
5773         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
5774         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
5775 
5776         /* test here for impeding collisions, and not being able to reach target... */
5777         #if ALL_NEW_AVOIDANCE_PRED
5778         {
5779                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
5780                         /* Go to all new avoidance. */
5781                         return(PRC_Request_Avoidance);
5782                 }
5783         }
5784         #else
5785         {
5786                 STRATEGYBLOCK *destructableObject = NULL;
5787                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
5788                 if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter))
5789                 {
5790                         /* go to avoidance */
5791                         return(PRC_Request_Avoidance);
5792                 }
5793                 if(predatorStatusPointer->obstruction.destructableObject)
5794                 {
5795                         LOCALASSERT(destructableObject);
5796                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
5797                 }
5798         }
5799 
5800         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection))
5801         {
5802                 /* go to avoidance */
5803                 /* no sequence change required */
5804 
5805                 predatorStatusPointer->obstruction.environment=1;
5806                 predatorStatusPointer->obstruction.destructableObject=0;
5807                 predatorStatusPointer->obstruction.otherCharacter=0;
5808                 predatorStatusPointer->obstruction.anySingleObstruction=0;
5809 
5810                 return(PRC_Request_Avoidance);
5811         }
5812         #endif
5813         return(PRC_No_Change);
5814 }
5815 
Execute_PFS_Return(STRATEGYBLOCK * sbPtr)5816 static PRED_RETURN_CONDITION Execute_PFS_Return(STRATEGYBLOCK *sbPtr)
5817 {
5818         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5819         AIMODULE *targetModule = 0;
5820 
5821         LOCALASSERT(sbPtr);
5822         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5823     LOCALASSERT(predatorStatusPointer);
5824 
5825         /* Decrement the Far state timer */
5826         predatorStatusPointer->stateTimer -= NormalFrameTime;
5827         /* check if far state timer has timed-out. If so, it is time
5828         to do something. Otherwise just return. */
5829         if(predatorStatusPointer->stateTimer > 0) return(SRC_No_Change);
5830 
5831         /* check for state changes */
5832         if(PredatorIsAwareOfTarget(sbPtr))
5833         /* Hack! */
5834         {
5835                 /* we should be engaging */
5836                 return(PRC_Request_Engage);
5837         }
5838 
5839         if (sbPtr->containingModule->m_aimodule==predatorStatusPointer->missionmodule) {
5840                 return(PRC_Request_Pathfind);
5841         }
5842 
5843         /* get the target module... */
5844 
5845         targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0);
5846 
5847         /* If there is no target module, we're way out there.  Better wander a bit more. */
5848         if(!targetModule)
5849         {
5850                 targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL,0);
5851         }
5852         /* Examine target, and decide what to do */
5853         GLOBALASSERT(AIModuleIsPhysical(targetModule));
5854         ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
5855         /* reset timer */
5856         predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
5857         return(PRC_No_Change);
5858 }
5859 
Execute_PNS_Return(STRATEGYBLOCK * sbPtr)5860 static PRED_RETURN_CONDITION Execute_PNS_Return(STRATEGYBLOCK *sbPtr)
5861 {
5862         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5863         DYNAMICSBLOCK *dynPtr;
5864         AIMODULE *targetModule;
5865         VECTORCH velocityDirection = {0,0,0};
5866 
5867         LOCALASSERT(sbPtr);
5868         predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5869         dynPtr = sbPtr->DynPtr;
5870         LOCALASSERT(predatorStatusPointer);
5871         LOCALASSERT(dynPtr);
5872 
5873         PredatorHandleMovingAnimation(sbPtr);
5874 
5875         /* should we change to approach state? */
5876         if(PredatorIsAwareOfTarget(sbPtr))
5877         {
5878                 /* doesn't require a sequence change */
5879                 return(PRC_Request_Engage);
5880         }
5881 
5882         predatorStatusPointer->stateTimer-=NormalFrameTime;
5883 
5884         /* Are we there yet? */
5885         if (sbPtr->containingModule->m_aimodule==predatorStatusPointer->missionmodule) {
5886                 return(PRC_Request_Pathfind);
5887         }
5888 
5889         /* Target module aquisition. */
5890 
5891         LOCALASSERT(sbPtr->containingModule);
5892 
5893         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5894         {
5895                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
5896         }
5897         if ((predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5898                 ||(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) {
5899 
5900                 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0);
5901 
5902                 if (targetModule) {
5903                         FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
5904                         if(thisEp) {
5905                                 /* aha. an ep!... */
5906                                 VECTORCH thisEpWorld = thisEp->position;
5907 
5908                                 thisEpWorld.vx += targetModule->m_world.vx;
5909                                 thisEpWorld.vy += targetModule->m_world.vy;
5910                                 thisEpWorld.vz += targetModule->m_world.vz;
5911 
5912                                 predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
5913                                 predatorStatusPointer->wanderData.worldPosition = thisEpWorld;
5914 
5915                         } else {
5916                                 /* Failure case. */
5917                                 predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
5918                         }
5919 
5920                 } else {
5921                         /* Another failure case. */
5922                         predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
5923                 }
5924         }
5925 
5926         /* if we still haven't got one, bimble about in this one for a bit. */
5927         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
5928         {
5929                 NPC_InitMovementData(&(predatorStatusPointer->moveData));
5930                 NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0);
5931         }
5932 
5933         if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) {
5934                 /* STILL broken!  Okay, just... wander, then. */
5935                 return(PRC_Request_Wander);
5936         }
5937 
5938         /* ok: should have a current target at this stage... */
5939         NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager);
5940         NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
5941 
5942         /* test here for impeding collisions, and not being able to reach target... */
5943         #if ALL_NEW_AVOIDANCE_PRED
5944         {
5945                 if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) {
5946                         /* Go to all new avoidance. */
5947                         return(PRC_Request_Avoidance);
5948                 }
5949         }
5950         #else
5951         {
5952                 STRATEGYBLOCK *destructableObject = NULL;
5953                 NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject);
5954                 if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter))
5955                 {
5956                         /* go to avoidance */
5957                         return(PRC_Request_Avoidance);
5958                 }
5959                 if(predatorStatusPointer->obstruction.destructableObject)
5960                 {
5961                         LOCALASSERT(destructableObject);
5962                         CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
5963                 }
5964         }
5965 
5966         if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection))
5967         {
5968                 /* go to avoidance */
5969                 /* no sequence change required */
5970 
5971                 predatorStatusPointer->obstruction.environment=1;
5972                 predatorStatusPointer->obstruction.destructableObject=0;
5973                 predatorStatusPointer->obstruction.otherCharacter=0;
5974                 predatorStatusPointer->obstruction.anySingleObstruction=0;
5975 
5976                 return(PRC_Request_Avoidance);
5977         }
5978         #endif
5979         return(PRC_No_Change);
5980 }
5981 
Execute_PNS_Recover(STRATEGYBLOCK * sbPtr)5982 static PRED_RETURN_CONDITION Execute_PNS_Recover(STRATEGYBLOCK *sbPtr) {
5983 
5984         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
5985         NPC_DATA *NpcData;
5986 
5987         LOCALASSERT(sbPtr);
5988         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
5989         LOCALASSERT(predatorStatusPointer);
5990 
5991         /* zero linear velocity in dynamics block */
5992         LOCALASSERT(sbPtr->DynPtr);
5993         sbPtr->DynPtr->LinVelocity.vx = 0;
5994         sbPtr->DynPtr->LinVelocity.vy = 0;
5995         sbPtr->DynPtr->LinVelocity.vz = 0;
5996 
5997         if (!sbPtr->SBdptr) {
5998                 /* We're far... do the timer! */
5999                 ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
6000         }
6001 
6002         /* Stay where you are and regain health. */
6003 
6004         NpcData=GetThisNpcData(I_NPC_Predator);
6005 
6006         if (sbPtr->SBDamageBlock.Health>0) {
6007                 int health_increment;
6008 
6009                 health_increment=DIV_FIXED((NpcData->StartingStats.Health*NormalFrameTime),PRED_REGEN_TIME);
6010                 sbPtr->SBDamageBlock.Health+=health_increment;
6011 
6012                 if (sbPtr->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
6013                         sbPtr->SBDamageBlock.Health=(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT);
6014                 }
6015 
6016                 HModel_Regen(&predatorStatusPointer->HModelController,PRED_REGEN_TIME);
6017         }
6018 
6019         /* Are we fully healed? */
6020         if (sbPtr->SBDamageBlock.Health==(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
6021                 return(PRC_Request_Swap);
6022         }
6023 
6024         if (PredatorCanSeeTarget(sbPtr)) {
6025                 return(PRC_Request_Swap);
6026         }
6027 
6028         /* Sequence should be set? */
6029 
6030         return(PRC_No_Change);
6031 
6032 }
6033 
Execute_PNS_Taunting(STRATEGYBLOCK * sbPtr)6034 static PRED_RETURN_CONDITION Execute_PNS_Taunting(STRATEGYBLOCK *sbPtr)
6035 {
6036 
6037         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6038 
6039         LOCALASSERT(sbPtr);
6040         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6041     LOCALASSERT(predatorStatusPointer);
6042 
6043         /* zero linear velocity in dynamics block */
6044         LOCALASSERT(sbPtr->DynPtr);
6045         sbPtr->DynPtr->LinVelocity.vx = 0;
6046         sbPtr->DynPtr->LinVelocity.vy = 0;
6047         sbPtr->DynPtr->LinVelocity.vz = 0;
6048 
6049         #if 0
6050         if (predatorStatusPointer->HModelController.keyframe_flags) {
6051 			#if 0
6052       		Sound_Play(SID_PRED_NEWROAR,"d",&sbPtr->DynPtr->Position);
6053 			#else
6054 			DoPredatorTauntSound(sbPtr);
6055 			#endif
6056         }
6057         #endif
6058 
6059         if (!sbPtr->SBdptr) {
6060                 /* We're far... do the timer! */
6061                 ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
6062         }
6063 
6064         if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) {
6065                 return(PRC_Request_Engage);
6066         } else {
6067                 return(PRC_No_Change);
6068         }
6069 
6070 }
6071 
Execute_PNS_DischargeSpeargun(STRATEGYBLOCK * sbPtr)6072 static PRED_RETURN_CONDITION Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr)
6073 {
6074         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6075         VECTORCH orientationDirn,relPos,relPos2;
6076         int correctlyOrientated,range;
6077 
6078         LOCALASSERT(sbPtr);
6079         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6080         LOCALASSERT(predatorStatusPointer);
6081 
6082         /* zero linear velocity in dynamics block */
6083         LOCALASSERT(sbPtr->DynPtr);
6084         sbPtr->DynPtr->LinVelocity.vx = 0;
6085         sbPtr->DynPtr->LinVelocity.vy = 0;
6086         sbPtr->DynPtr->LinVelocity.vz = 0;
6087 
6088         if (predatorStatusPointer->Target==NULL) {
6089                 /* Bomb out. */
6090                 return(PRC_Request_Wander);
6091         }
6092 
6093         /* Always turn to face... */
6094         GLOBALASSERT(predatorStatusPointer->Target);
6095         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
6096 
6097         /* Fix weapon target! */
6098         {
6099                 predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat21,
6100                         300);
6101                 predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat22,
6102                         300);
6103                 predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat23,
6104                         300);
6105         }
6106 
6107         /* orientate to firing point first */
6108         if (predatorStatusPointer->My_Elevation_Section) {
6109                 /* Assume range large w.r.t. half shoulder width... */
6110                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
6111                 orientationDirn.vy = 0;
6112                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
6113         } else {
6114                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
6115                 orientationDirn.vy = 0;
6116                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
6117         }
6118         /* Target shift? */
6119         correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
6120 
6121         /* Decloaking? */
6122         if (predatorStatusPointer->CloakStatus==PCLOAK_On) {
6123                 PredatorCloakOff(predatorStatusPointer);
6124         }
6125 
6126         /* If still tweening, pause. */
6127         if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
6128                 return(PRC_No_Change);
6129         }
6130 
6131         if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate) {
6132 
6133                 predatorStatusPointer->HModelController.Playing=0;
6134 
6135                 /* Only terminate if you haven't fired yet... */
6136                 if(!PredatorCanSeeTarget(sbPtr))
6137                 {
6138                         #if 1
6139                         /* ... and remove the gunflash */
6140                         #endif
6141 
6142                         return(PRC_Request_Engage);
6143                 }
6144 
6145                 /* we are not correctly orientated to the target: this could happen because we have
6146                 just entered this state, or the target has moved during firing*/
6147                 if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off))
6148                 {
6149                         #if 1
6150                         /* stop visual and audio cues: technically, we're not firing at this moment */
6151                         #endif
6152                         return(PRC_No_Change);
6153                 }
6154 
6155                 /* If you are correctly oriented, you can now fire! */
6156 
6157                 predatorStatusPointer->HModelController.Playing=1;
6158                 predatorStatusPointer->HModelController.sequence_timer=0;
6159 
6160                 relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
6161                 relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
6162                 relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
6163 
6164                 relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx);
6165                 relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy);
6166                 relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz);
6167 
6168                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
6169 
6170                 #if 1
6171                 /* look after the gun flash */
6172                 #endif
6173 
6174                 /* look after the sound */
6175                 Sound_Play(SID_PRED_LASER,"d",&(sbPtr->DynPtr->Position));
6176 
6177                 /* Now fire a spear... */
6178 
6179                 {
6180                         SECTION_DATA *muzzle;
6181                         VECTORCH shotVector;
6182 
6183                         muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
6184 
6185                         shotVector.vx=muzzle->SecMat.mat31;
6186                         shotVector.vy=muzzle->SecMat.mat32;
6187                         shotVector.vz=muzzle->SecMat.mat33;
6188 
6189                         FindPolygonInLineOfSight(&shotVector,&muzzle->World_Offset,0,sbPtr->SBdptr);
6190 
6191                         /* Now deal with LOS_ObjectHitPtr. */
6192                         if (LOS_ObjectHitPtr) {
6193                                 if (LOS_HModel_Section) {
6194                                         if (LOS_ObjectHitPtr->ObStrategyBlock) {
6195                                                 if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) {
6196                                                         GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller);
6197                                                 }
6198                                         }
6199                                 }
6200                                 HandleSpearImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_PRED_RIFLE,&shotVector, 1, LOS_HModel_Section);
6201                         }
6202 
6203                         predatorStatusPointer->volleySize++;
6204                 }
6205 
6206                 if (predatorStatusPointer->volleySize>0) { /* Was 3 for pistol. */
6207                         predatorStatusPointer->enableSwap=1;
6208                 }
6209         }
6210 
6211         predatorStatusPointer->stateTimer -= NormalFrameTime;
6212 
6213         /* You must have fired already. */
6214 
6215         if(predatorStatusPointer->stateTimer > 0)       {
6216                 return(PRC_No_Change);
6217         }
6218 
6219         if(range < predatorStatusPointer->Selected_Weapon->MinRange)
6220         {
6221                 /* renew firing, as we are still too close to approach */
6222                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6223                 predatorStatusPointer->volleySize = 0;
6224                 return(PRC_No_Change);
6225         }
6226         else
6227         {
6228                 NPC_DATA *NpcData;
6229                 /* we are far enough away, so return to approach? */
6230 
6231                 NpcData=GetThisNpcData(I_NPC_Predator);
6232 
6233                 if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
6234                         &&(sbPtr->SBDamageBlock.Health>0)) {
6235                         /* 50% health? */
6236                         if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) {
6237                                 return(PRC_Request_Withdraw);
6238                         } else {
6239                                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6240                                 return(PRC_No_Change);
6241                         }
6242                 }
6243 
6244                 if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) {
6245                         if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) {
6246                                 /* Change weapon! */
6247                                 return(PRC_Request_Swap);
6248                         } else {
6249                                 return(PRC_Request_Engage);
6250                         }
6251                 } else {
6252                         /* And another! */
6253                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6254                         return(PRC_No_Change);
6255                 }
6256         }
6257         return(PRC_No_Change);
6258 }
6259 
Execute_PNS_AttackBrutallyWithPlasmaCaster(STRATEGYBLOCK * sbPtr)6260 static PRED_RETURN_CONDITION Execute_PNS_AttackBrutallyWithPlasmaCaster(STRATEGYBLOCK *sbPtr)
6261 {
6262         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6263         VECTORCH orientationDirn,relPos,relPos2;
6264         int correctlyOrientated,range,onTarget;
6265 
6266         LOCALASSERT(sbPtr);
6267         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6268         LOCALASSERT(predatorStatusPointer);
6269 
6270         /* zero linear velocity in dynamics block */
6271         LOCALASSERT(sbPtr->DynPtr);
6272         sbPtr->DynPtr->LinVelocity.vx = 0;
6273         sbPtr->DynPtr->LinVelocity.vy = 0;
6274         sbPtr->DynPtr->LinVelocity.vz = 0;
6275 
6276         if (predatorStatusPointer->Target==NULL) {
6277                 /* Bomb out. */
6278                 return(PRC_Request_Wander);
6279         }
6280 
6281         /* No messing, no taunting, no decloaking. */
6282 
6283         if (predatorStatusPointer->internalState==0) {
6284                 if (predatorStatusPointer->HModelController.Tweening==Controller_NoTweening) {
6285                         predatorStatusPointer->HModelController.Playing=0;
6286                 }
6287         }
6288 
6289         /* Always turn to face... */
6290         GLOBALASSERT(predatorStatusPointer->Target);
6291         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
6292 
6293         /* orientate to firing point first */
6294         if (predatorStatusPointer->My_Elevation_Section) {
6295                 /* Assume range large w.r.t. half shoulder width... */
6296                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
6297                 orientationDirn.vy = 0;
6298                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
6299         } else {
6300                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
6301                 orientationDirn.vy = 0;
6302                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
6303         }
6304         /* Target shift? */
6305         correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
6306 
6307         /* Cloaking? */
6308         if (predatorStatusPointer->CloakStatus==PCLOAK_Off) {
6309                 /* Stay unfair. */
6310                 PredatorCloakOn(predatorStatusPointer);
6311         }
6312 
6313         /* Project three dots? */
6314         onTarget=DoPredatorLaserTargeting(sbPtr);
6315 
6316         predatorStatusPointer->stateTimer -= NormalFrameTime;
6317 
6318         /* Only terminate if you haven't fired yet... */
6319         if(!PredatorCanSeeTarget(sbPtr))
6320         {
6321                 #if 1
6322                 /* ... and remove the gunflash */
6323                 #endif
6324 
6325                 return(PRC_Request_Engage);
6326         }
6327 
6328         if (predatorStatusPointer->internalState==1) {
6329                 /* Using stateTimer, thanks! */
6330         } else if(predatorStatusPointer->stateTimer > 0) {
6331                 return(PRC_No_Change);
6332         }
6333 
6334         /* State timed out - try to fire! */
6335 
6336         /* we are not correctly orientated to the target: this could happen because we have
6337         just entered this state, or the target has moved during firing*/
6338         if (!correctlyOrientated)
6339         {
6340                 #if 1
6341                 /* stop visual and audio cues: technically, we're not firing at this moment */
6342                 #endif
6343                 return(PRC_No_Change);
6344         }
6345 
6346         /* Ready to fire... */
6347 
6348         if (correctlyOrientated&&(predatorStatusPointer->internalState!=2)) {
6349                 if (predatorStatusPointer->internalState!=1) {
6350                         predatorStatusPointer->internalState=1;
6351                         /* Disable pausing... */
6352                         predatorStatusPointer->stateTimer=0;
6353                 }
6354         }
6355 
6356         range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
6357 
6358         if ((predatorStatusPointer->internalState==1)&&(predatorStatusPointer->stateTimer<=0)) {
6359                 if (onTarget) {
6360 
6361                         /* If you are correctly oriented, you can now fire! */
6362 
6363                         predatorStatusPointer->enableTaunt=0;
6364                         /* No taunting here, we're busy. */
6365 
6366                         predatorStatusPointer->HModelController.Playing=1;
6367                         predatorStatusPointer->HModelController.Looped=0;
6368                         predatorStatusPointer->HModelController.sequence_timer=0;
6369                         predatorStatusPointer->internalState=2;
6370 
6371                         relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
6372                         relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
6373                         relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
6374 
6375                         relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx);
6376                         relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy);
6377                         relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz);
6378 
6379                         #if 1
6380                         /* look after the gun flash */
6381                         #endif
6382 
6383                         /* look after the sound */
6384                         Sound_Play(SID_PRED_LAUNCHER,"d",&(sbPtr->DynPtr->Position));
6385 
6386                         /* Now fire a bolt. */
6387 
6388                         {
6389                                 SECTION_DATA *muzzle;
6390 
6391                                 muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
6392 
6393                                 Pred_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty];
6394 
6395                                 Pred_Weapon_Damage.Impact               =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Impact         ,10000);
6396                                 Pred_Weapon_Damage.Cutting              =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting        ,10000);
6397                                 Pred_Weapon_Damage.Penetrative  =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,10000);
6398                                 Pred_Weapon_Damage.Fire                 =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire           ,10000);
6399                                 Pred_Weapon_Damage.Electrical   =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical     ,10000);
6400                                 Pred_Weapon_Damage.Acid                 =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid           ,10000);
6401 
6402                                 Pred_Weapon_Damage.BlowUpSections=1;
6403                                 Pred_Weapon_Damage.Special=0;
6404 
6405                                 InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat,0,&Pred_Weapon_Damage,65536);
6406                                 predatorStatusPointer->volleySize++;
6407                         }
6408                         predatorStatusPointer->enableSwap=1;
6409                         return(SRC_No_Change);
6410                 } else {
6411 
6412                         /* You think you're correctly orientated - but you're still not hitting. */
6413                         if (predatorStatusPointer->stateTimer<=0) {
6414                                 /* Oh, just give up. */
6415                                 predatorStatusPointer->HModelController.Playing=1;
6416                                 predatorStatusPointer->HModelController.Looped=0;
6417                                 predatorStatusPointer->HModelController.sequence_timer=0;
6418                                 predatorStatusPointer->internalState=2;
6419                         }
6420                 }
6421         }
6422 
6423         if (predatorStatusPointer->internalState==2) {
6424 
6425                 /* After shot. */
6426 
6427                 #if 0
6428                 if (!(HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))) {
6429                         /* Still playing. */
6430                         return(PRC_No_Change);
6431                 }
6432                 #endif
6433 
6434                 if(range < predatorStatusPointer->Selected_Weapon->MinRange)
6435                 {
6436                         /* renew firing, as we are still too close to approach */
6437                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6438                         predatorStatusPointer->volleySize = 0;
6439                         predatorStatusPointer->internalState=0;
6440                         return(PRC_No_Change);
6441                 }
6442                 else
6443                 {
6444                         NPC_DATA *NpcData;
6445                         /* we are far enough away, so return to approach? */
6446 
6447                         NpcData=GetThisNpcData(I_NPC_Predator);
6448 
6449                         if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
6450                                 &&(sbPtr->SBDamageBlock.Health>0)) {
6451                                 /* 50% health? */
6452                                 if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) {
6453                                         return(PRC_Request_Withdraw);
6454                                 } else {
6455                                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6456                                         predatorStatusPointer->internalState=0;
6457                                         return(PRC_No_Change);
6458                                 }
6459                         }
6460 
6461                         if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) {
6462                                 if (range<PRED_CLOSE_ATTACK_RANGE) {
6463                                         /* Change weapon?  No random chance... */
6464                                         return(PRC_Request_Swap);
6465                                 } else {
6466                                         #if 0
6467                                         return(PRC_Request_Engage);
6468                                         #else
6469                                         /* Heck, if we can still see them... */
6470                                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6471                                         predatorStatusPointer->internalState=0;
6472                                         return(PRC_No_Change);
6473                                         #endif
6474                                 }
6475                         } else {
6476                                 /* And another! */
6477                                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6478                                 predatorStatusPointer->internalState=0;
6479                                 return(PRC_No_Change);
6480                         }
6481                 }
6482 
6483         }
6484 
6485         return(PRC_No_Change);
6486 }
6487 
6488 #if 0
6489 static PRED_RETURN_CONDITION Predator_ThreatAnalysis(STRATEGYBLOCK *sbPtr) {
6490 
6491         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6492 
6493         LOCALASSERT(sbPtr);
6494         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6495         LOCALASSERT(predatorStatusPointer);
6496 
6497         /* A bit of an experimental function. */
6498         if (predatorStatusPointer->Target==NULL) {
6499                 /* There ain't no threat! */
6500                 NPC_DATA *NpcData;
6501 
6502                 NpcData=GetThisNpcData(I_NPC_Predator);
6503 
6504                 if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
6505                         &&(sbPtr->SBDamageBlock.Health>0)) {
6506                         /* 50% health? */
6507                         return(PRC_Request_Withdraw);
6508                 } else {
6509                         return(PRC_Request_Wander);
6510                 }
6511         }
6512 
6513         GLOBALASSERT(predatorStatusPointer->Target);
6514         /* Now, what manner of threat do we face? */
6515 
6516         /* Frankly, this needs discussing before I do anything major. */
6517 
6518         return(PRC_Request_Swap);
6519 
6520 }
6521 
6522 static PRED_RETURN_CONDITION Execute_PNS_NewDischargePistol(STRATEGYBLOCK *sbPtr)
6523 {
6524         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6525         VECTORCH orientationDirn,relPos,relPos2;
6526         int correctlyOrientated,range;
6527 
6528         LOCALASSERT(sbPtr);
6529         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6530         LOCALASSERT(predatorStatusPointer);
6531 
6532         /* zero linear velocity in dynamics block */
6533         LOCALASSERT(sbPtr->DynPtr);
6534         sbPtr->DynPtr->LinVelocity.vx = 0;
6535         sbPtr->DynPtr->LinVelocity.vy = 0;
6536         sbPtr->DynPtr->LinVelocity.vz = 0;
6537 
6538         if (predatorStatusPointer->Target==NULL) {
6539                 /* Bomb out. */
6540                 return(PRC_Request_Wander);
6541         }
6542 
6543         /* Always turn to face... */
6544         GLOBALASSERT(predatorStatusPointer->Target);
6545         NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target);
6546 
6547         /* Fix weapon target! */
6548         {
6549                 predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
6550                         200);
6551                 predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
6552                         200);
6553                 predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
6554                         200);
6555         }
6556 
6557         /* orientate to firing point first */
6558         if (predatorStatusPointer->My_Elevation_Section) {
6559                 /* Assume range large w.r.t. half shoulder width... */
6560                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
6561                 orientationDirn.vy = 0;
6562                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
6563         } else {
6564                 orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
6565                 orientationDirn.vy = 0;
6566                 orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
6567         }
6568         /* Target shift? */
6569         correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
6570 
6571         /* Decloaking? */
6572         if (predatorStatusPointer->CloakStatus==PCLOAK_On) {
6573                 PredatorCloakOff(predatorStatusPointer);
6574         }
6575 
6576         /* If still tweening, pause. */
6577         if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
6578                 return(PRC_No_Change);
6579         }
6580 
6581         //if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate)
6582         {
6583 
6584                 //predatorStatusPointer->HModelController.Playing=0;
6585 
6586                 /* Only terminate if you haven't fired yet... */
6587                 if(!PredatorCanSeeTarget(sbPtr))
6588                 {
6589                         #if 1
6590                         /* ... and remove the gunflash */
6591                         #endif
6592 
6593                         return(PRC_Request_Engage);
6594                 }
6595 
6596                 /* we are not correctly orientated to the target: this could happen because we have
6597                 just entered this state, or the target has moved during firing*/
6598                 if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off))
6599                 {
6600                         #if 1
6601                         /* stop visual and audio cues: technically, we're not firing at this moment */
6602                         #endif
6603                         return(PRC_No_Change);
6604                 }
6605 
6606                 /* If you are correctly oriented, you can now fire! */
6607 
6608                 //predatorStatusPointer->HModelController.Playing=1;
6609                 //predatorStatusPointer->HModelController.sequence_timer=0;
6610 
6611                 relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
6612                 relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
6613                 relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
6614 
6615                 relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx);
6616                 relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy);
6617                 relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz);
6618 
6619                 range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
6620 
6621                 #if 1
6622                 /* look after the gun flash */
6623                 #endif
6624 
6625                 /* look after the sound */
6626                 Sound_Play(SID_PRED_PISTOL,"d",&(sbPtr->DynPtr->Position));
6627 
6628                 /* Now fire a volley... */
6629 
6630                 {
6631                         SECTION_DATA *muzzle;
6632                         VECTORCH null_vec;
6633 
6634                         muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash");
6635 
6636                         null_vec.vx=0;
6637                         null_vec.vy=0;
6638                         null_vec.vz=0;
6639 
6640                         GLOBALASSERT(muzzle);
6641 
6642                         FirePredPistolFlechettes(&muzzle->World_Offset,&null_vec,&muzzle->SecMat,0,&predatorStatusPointer->internalState,TRUE);
6643 
6644                 }
6645 
6646                 //if (predatorStatusPointer->volleySize>3) {
6647                 //      predatorStatusPointer->enableSwap=1;
6648                 //}
6649         }
6650 
6651         predatorStatusPointer->stateTimer -= NormalFrameTime;
6652 
6653                 /* Alex: I changed this 28/01/99 - it makes the Predator a bit easier, but also
6654                 a bit more interesting - it hopefully makes the end of Earthbound a bit more fun. */
6655             if(range < predatorStatusPointer->Selected_Weapon->MinRange)
6656                 {
6657                         predatorStatusPointer->enableSwap=1;
6658                         return(PRC_Request_Swap);
6659                 }
6660 
6661         /* You must have fired already. */
6662 
6663         if(predatorStatusPointer->stateTimer > 0)       {
6664                 return(PRC_No_Change);
6665         }
6666 
6667         /* Enable swap after a full burst. */
6668 //        predatorStatusPointer->enableSwap=1;
6669 
6670         #if 0
6671         {
6672                 /* renew firing, as we are still too close to approach */
6673                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6674                 predatorStatusPointer->volleySize = 0;
6675                 return(PRC_No_Change);
6676         }
6677         else
6678         {
6679                 NPC_DATA *NpcData;
6680                 /* we are far enough away, so return to approach? */
6681 
6682                 NpcData=GetThisNpcData(I_NPC_Predator);
6683 
6684                 if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1)))
6685                         &&(sbPtr->SBDamageBlock.Health>0)) {
6686                         /* 50% health? */
6687                         if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) {
6688                                 return(PRC_Request_Withdraw);
6689                         } else {
6690                                 predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6691                                 return(PRC_No_Change);
6692                         }
6693                 }
6694 
6695                 if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) {
6696                         if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) {
6697                                 /* Change weapon! */
6698                                 return(PRC_Request_Swap);
6699                         } else {
6700                                 return(PRC_Request_Engage);
6701                         }
6702                 } else {
6703                         /* And another! */
6704                         predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
6705                         return(PRC_No_Change);
6706                 }
6707         }
6708         #endif
6709         return(PRC_No_Change);
6710 }
6711 #endif
6712 
Execute_PNS_SelfDestruct(STRATEGYBLOCK * sbPtr)6713 static PRED_RETURN_CONDITION Execute_PNS_SelfDestruct(STRATEGYBLOCK *sbPtr)
6714 {
6715 
6716         PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6717 
6718         LOCALASSERT(sbPtr);
6719         predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6720     LOCALASSERT(predatorStatusPointer);
6721 
6722         /* zero linear velocity in dynamics block */
6723         LOCALASSERT(sbPtr->DynPtr);
6724         sbPtr->DynPtr->LinVelocity.vx = 0;
6725         sbPtr->DynPtr->LinVelocity.vy = 0;
6726         sbPtr->DynPtr->LinVelocity.vz = 0;
6727 
6728         if (!sbPtr->SBdptr) {
6729                 /* We're far... do the timer! */
6730                 ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
6731         }
6732 
6733         if (predatorStatusPointer->HModelController.Sub_Sequence==PCrSS_Det_Prog) {
6734                 if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) {
6735                         InitHModelTweening(&predatorStatusPointer->HModelController,(ONE_FIXED>>2),
6736                                 HMSQT_PredatorCrouch,PCrSS_Det_Laugh,-1,1);
6737                 }
6738         }
6739 
6740         /* And if we're playing Laugh, we'd better laugh... */
6741 
6742         if (predatorStatusPointer->internalState==0) {
6743                 /* Not yet activated. */
6744                 if (predatorStatusPointer->HModelController.keyframe_flags&1) {
6745                         predatorStatusPointer->stateTimer=PRED_SELF_DESTRUCT_TIMER;
6746                         predatorStatusPointer->internalState=1;
6747                 }
6748         } else if (predatorStatusPointer->internalState==1) {
6749                 predatorStatusPointer->stateTimer-=NormalFrameTime;
6750                 if (predatorStatusPointer->stateTimer<=0) {
6751                         /* Kaboom. */
6752                         predatorStatusPointer->internalState=2;
6753                         /* And kill the pred, for good measure? */
6754                         #if 0
6755                         predatorStatusPointer->GibbFactor=ONE_FIXED;
6756                         CauseDamageToObject(sbPtr,&certainDeath,ONE_FIXED,NULL);
6757                         StartPredatorSelfDestructExplosion(sbPtr);
6758                         /* So as not to confuse the corpse. */
6759 						#else
6760                         predatorStatusPointer->GibbFactor=ONE_FIXED;
6761 						predatorStatusPointer->Explode=1;
6762 						#endif
6763                 }
6764         }
6765 
6766         /* There's no escape from this other than death! */
6767         return(PRC_No_Change);
6768 
6769 }
6770 
StartPredatorSelfDestructExplosion(STRATEGYBLOCK * sbPtr)6771 void StartPredatorSelfDestructExplosion(STRATEGYBLOCK *sbPtr) {
6772 
6773         /* So it can be easily altered.  Also referenced by bh_corpse.c. */
6774 	#if 0
6775         HandleEffectsOfExplosion
6776         (
6777                 sbPtr,
6778                 &(sbPtr->DynPtr->Position),
6779                 TemplateAmmo[AMMO_SADAR_BLAST].MaxRange,
6780                 &TemplateAmmo[AMMO_SADAR_BLAST].MaxDamage[AvP.Difficulty],
6781                 TemplateAmmo[AMMO_SADAR_BLAST].ExplosionIsFlat
6782         );
6783         Sound_Play(SID_NICE_EXPLOSION,"d",&(sbPtr->DynPtr->Position));
6784 	#else
6785 	/* Copied from SelfDestructBehavFun. */
6786 	int i;
6787 
6788 	/* KJL 16:20:57 27/08/98 - let's do some pyrotechnics */
6789 	Sound_Play(SID_NICE_EXPLOSION,"d",&(Player->ObWorld));
6790 	MakeVolumetricExplosionAt(&Player->ObWorld,EXPLOSION_HUGE);
6791 	Player->ObStrategyBlock->SBDamageBlock.IsOnFire=1;
6792 
6793 	//blow up everone
6794 	for (i=0; i<NumActiveStBlocks; i++)
6795 	{
6796 		STRATEGYBLOCK *SbPtr = ActiveStBlockList[i];
6797 		if(SbPtr->I_SBtype==I_BehaviourAlien ||
6798 		   SbPtr->I_SBtype==I_BehaviourQueenAlien ||
6799 		   SbPtr->I_SBtype==I_BehaviourFaceHugger ||
6800 		   SbPtr->I_SBtype==I_BehaviourPredator ||
6801 		   SbPtr->I_SBtype==I_BehaviourXenoborg ||
6802 		   SbPtr->I_SBtype==I_BehaviourMarine ||
6803 		   SbPtr->I_SBtype==I_BehaviourSeal ||
6804 		   SbPtr->I_SBtype==I_BehaviourPredatorAlien ||
6805 		   SbPtr->I_SBtype==I_BehaviourAlien ||
6806 		   SbPtr->I_SBtype==I_BehaviourMarinePlayer ||
6807 		   SbPtr->I_SBtype==I_BehaviourPredatorPlayer ||
6808 		   SbPtr->I_SBtype==I_BehaviourAlienPlayer)
6809 		{
6810 	 		{
6811 	 			//kill the creature/player
6812 	 			VECTORCH direction={0,-ONE_FIXED,0};
6813 	 			CauseDamageToObject(SbPtr,&certainDeath,ONE_FIXED,&direction);
6814 
6815 			}
6816 		}
6817 	}
6818 	#endif
6819 }
6820 
DoPredatorHitSound(STRATEGYBLOCK * sbPtr)6821 void DoPredatorHitSound(STRATEGYBLOCK *sbPtr) {
6822 
6823 	DYNAMICSBLOCK *dynPtr;
6824 	int rand = FastRandom();
6825 	int pitch = (rand & 255) - 128;
6826 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6827 
6828 	GLOBALASSERT(sbPtr);
6829 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6830 	LOCALASSERT(predatorStatusPointer);
6831 	dynPtr = sbPtr->DynPtr;
6832 	LOCALASSERT(dynPtr);
6833 
6834 	if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
6835 		return;
6836 	}
6837 
6838 	/* This one is for PREDATOR DAMAGE SCREAM. */
6839 
6840 	if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
6841 		PlayPredatorSound(0,PSC_Scream_Hurt,pitch,
6842 			&predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position);
6843 	}
6844 
6845 }
6846 
DoPredatorAcidSound(STRATEGYBLOCK * sbPtr)6847 void DoPredatorAcidSound(STRATEGYBLOCK *sbPtr) {
6848 
6849 	DYNAMICSBLOCK *dynPtr;
6850 	int rand = FastRandom();
6851 	int pitch = (rand & 255) - 128;
6852 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6853 
6854 	GLOBALASSERT(sbPtr);
6855 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6856 	LOCALASSERT(predatorStatusPointer);
6857 	dynPtr = sbPtr->DynPtr;
6858 	LOCALASSERT(dynPtr);
6859 
6860 	if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
6861 		return;
6862 	}
6863 
6864 	/* This one is for PREDATOR ACID DAMAGE SCREAM. */
6865 
6866 	if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
6867 		PlayPredatorSound(0,PSC_Acid,pitch,
6868 			&predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position);
6869 	}
6870 
6871 }
6872 
DoPredatorDeathSound(STRATEGYBLOCK * sbPtr)6873 void DoPredatorDeathSound(STRATEGYBLOCK *sbPtr) {
6874 
6875 	DYNAMICSBLOCK *dynPtr;
6876 	int rand = FastRandom();
6877 	int pitch = (rand & 255) - 128;
6878 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6879 
6880 	GLOBALASSERT(sbPtr);
6881 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6882 	LOCALASSERT(predatorStatusPointer);
6883 	dynPtr = sbPtr->DynPtr;
6884 	LOCALASSERT(dynPtr);
6885 
6886 	if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
6887 		return;
6888 	}
6889 
6890 	/* This one is for PREDATOR DEATH SCREAM. */
6891 
6892 	if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
6893 		PlayPredatorSound(0,PSC_Scream_Dying,pitch,
6894 			&predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position);
6895 	}
6896 
6897 }
6898 
DoPredatorRandomSound(STRATEGYBLOCK * sbPtr)6899 void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr) {
6900 
6901 	DYNAMICSBLOCK *dynPtr;
6902 	int rand = FastRandom();
6903 	int pitch = (rand & 255) - 128;
6904 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6905 
6906 	GLOBALASSERT(sbPtr);
6907 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6908 	LOCALASSERT(predatorStatusPointer);
6909 	dynPtr = sbPtr->DynPtr;
6910 	LOCALASSERT(dynPtr);
6911 
6912 	if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
6913 		return;
6914 	}
6915 
6916 	/* This one is for PREDATOR GENERAL SCREAM. */
6917 
6918 	if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
6919 		PlayPredatorSound(0,PSC_Scream_General,pitch,
6920 			&predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position);
6921 	}
6922 
6923 }
6924 
DoPredatorTauntSound(STRATEGYBLOCK * sbPtr)6925 void DoPredatorTauntSound(STRATEGYBLOCK *sbPtr) {
6926 
6927 	DYNAMICSBLOCK *dynPtr;
6928 	int rand = FastRandom();
6929 	int pitch = (rand & 255) - 128;
6930 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6931 
6932 	GLOBALASSERT(sbPtr);
6933 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6934 	LOCALASSERT(predatorStatusPointer);
6935 	dynPtr = sbPtr->DynPtr;
6936 	LOCALASSERT(dynPtr);
6937 
6938 	if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
6939 		return;
6940 	}
6941 
6942 	/* This one is for PREDATOR TAUNT. */
6943 
6944 	if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
6945 		PlayPredatorSound(0,PSC_Taunt,pitch,
6946 			&predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position);
6947 	}
6948 
6949 }
6950 
DoPredatorAISwipeSound(STRATEGYBLOCK * sbPtr)6951 void DoPredatorAISwipeSound(STRATEGYBLOCK *sbPtr) {
6952 
6953 	DYNAMICSBLOCK *dynPtr;
6954 	PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6955 
6956 	GLOBALASSERT(sbPtr);
6957 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6958 	LOCALASSERT(predatorStatusPointer);
6959 	dynPtr = sbPtr->DynPtr;
6960 	LOCALASSERT(dynPtr);
6961 
6962 	/* This one is for PREDATOR SWIPE SOUND. */
6963 
6964 	PlayPredatorSound(0,PSC_Swipe,0,NULL,&sbPtr->DynPtr->Position);
6965 
6966 }
6967 
6968 
6969 /*--------------------**
6970 ** Loading and Saving **
6971 **--------------------*/
6972 #include "savegame.h"
6973 typedef struct predator_save_block
6974 {
6975 	SAVE_BLOCK_STRATEGY_HEADER header;
6976 
6977 //behaviour block stuff
6978 	signed int health;
6979 	PRED_BHSTATE behaviourState;
6980 	PRED_BHSTATE lastState;
6981 
6982 	int stateTimer;
6983 	int internalState;
6984 	int patience;
6985 	int enableSwap;
6986 	int enableTaunt;
6987 	VECTORCH weaponTarget;			/* target position for firing weapon at */
6988 	int volleySize;					/* used for weapon control */
6989 	NPC_OBSTRUCTIONREPORT obstruction;
6990 	NPC_WANDERDATA wanderData;
6991 
6992 	int IAmCrouched;
6993 	int personalNumber;				/* for predator personalisation */
6994 	int nearSpeed;
6995 	int GibbFactor;
6996 
6997 	int incidentFlag;
6998 	int incidentTimer;
6999 
7000 	PREDATOR_NPC_WEAPONS PrimaryWeapon;
7001 	PREDATOR_NPC_WEAPONS SecondaryWeapon;
7002 	PREDATOR_NPC_WEAPONS ChangeToWeapon;
7003 
7004 	/* these are for cloaking... */
7005 	PRED_CLOAKSTATE CloakStatus;
7006 	int CloakingEffectiveness;
7007 	int CloakTimer;
7008 
7009 	/* And these for the laser dots. */
7010 	THREE_LASER_DOT_DESC Pred_Laser_Sight;
7011 	int Pred_Laser_On	:1;
7012 	int Explode			:1;
7013 
7014 	int path;
7015 	int stepnumber;
7016 
7017 
7018 //annoying pointer related things
7019 
7020 	int weapon_id;
7021 	int currentAttackCode;
7022 	char Target_SBname[SB_NAME_LENGTH];
7023 
7024 	int missionmodule_index;
7025 	int fearmodule_index;
7026 
7027 //strategyblock stuff
7028 	int integrity;
7029 	DAMAGEBLOCK SBDamageBlock;
7030 	DYNAMICSBLOCK dynamics;
7031 
7032 }PREDATOR_SAVE_BLOCK;
7033 
7034 
7035 //defines for load/save macros
7036 #define SAVELOAD_BLOCK block
7037 #define SAVELOAD_BEHAV predatorStatusPointer
7038 
LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER * header)7039 void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header)
7040 {
7041 	STRATEGYBLOCK* sbPtr;
7042 	PREDATOR_STATUS_BLOCK* predatorStatusPointer;
7043 	PREDATOR_SAVE_BLOCK* block = (PREDATOR_SAVE_BLOCK*) header;
7044 
7045 	//check the size of the save block
7046 	if(header->size!=sizeof(*block)) return;
7047 
7048 	//find the existing strategy block
7049 	sbPtr = FindSBWithName(header->SBname);
7050 	if(!sbPtr) return;
7051 
7052 	/*
7053 	Check the strategy type.
7054 	Slight complication here , since it might be a dormant predator
7055 	(assuming that they are actually used in any of the levels)
7056 	*/
7057 
7058 	if(sbPtr->I_SBtype == I_BehaviourDormantPredator)
7059 	{
7060 		//best make it un-dormant then
7061 		ActivateDormantPredator(sbPtr);
7062 	}
7063 	else if(sbPtr->I_SBtype != I_BehaviourPredator)
7064 	{
7065 		return;
7066 	}
7067 
7068 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->SBdataptr;
7069 
7070 
7071 	//start copying stuff
7072 
7073 	COPYELEMENT_LOAD(health)
7074 	COPYELEMENT_LOAD(behaviourState)
7075 	COPYELEMENT_LOAD(lastState)
7076 	COPYELEMENT_LOAD(stateTimer)
7077 	COPYELEMENT_LOAD(internalState)
7078 	COPYELEMENT_LOAD(patience)
7079 	COPYELEMENT_LOAD(enableSwap)
7080 	COPYELEMENT_LOAD(enableTaunt)
7081 	COPYELEMENT_LOAD(weaponTarget)			/* target position for firing weapon at */
7082 	COPYELEMENT_LOAD(volleySize)					/* used for weapon control */
7083 	COPYELEMENT_LOAD(obstruction)
7084 	COPYELEMENT_LOAD(wanderData)
7085 	COPYELEMENT_LOAD(IAmCrouched)
7086 	COPYELEMENT_LOAD(personalNumber)				/* for predator personalisation */
7087 	COPYELEMENT_LOAD(nearSpeed)
7088 	COPYELEMENT_LOAD(GibbFactor)
7089 	COPYELEMENT_LOAD(incidentFlag)
7090 	COPYELEMENT_LOAD(incidentTimer)
7091 	COPYELEMENT_LOAD(PrimaryWeapon)
7092 	COPYELEMENT_LOAD(SecondaryWeapon)
7093 	COPYELEMENT_LOAD(ChangeToWeapon)
7094 	COPYELEMENT_LOAD(CloakStatus)
7095 	COPYELEMENT_LOAD(CloakingEffectiveness)
7096 	COPYELEMENT_LOAD(CloakTimer)
7097 	COPYELEMENT_LOAD(Pred_Laser_Sight)
7098 	COPYELEMENT_LOAD(Pred_Laser_On)
7099 	COPYELEMENT_LOAD(Explode)
7100 	COPYELEMENT_LOAD(path)
7101 	COPYELEMENT_LOAD(stepnumber)
7102 
7103 	//load ai module pointers
7104 	predatorStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index);
7105 	predatorStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index);
7106 
7107 	//load target
7108 	COPY_NAME(predatorStatusPointer->Target_SBname,block->Target_SBname);
7109 	predatorStatusPointer->Target = FindSBWithName(predatorStatusPointer->Target_SBname);
7110 
7111 	//get the predator's attack from the attack code
7112 	predatorStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode);
7113 
7114 	//get marine's weapon
7115 	predatorStatusPointer->Selected_Weapon = GetThisNPCPredatorWeapon(block->weapon_id);
7116 
7117 	//copy strategy block stuff
7118 	*sbPtr->DynPtr = block->dynamics;
7119 	sbPtr->integrity = block->integrity;
7120 	sbPtr->SBDamageBlock = block->SBDamageBlock;
7121 
7122 	//load hierarchy
7123 	{
7124 		SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
7125 		if(hier_header)
7126 		{
7127 			LoadHierarchy(hier_header,&predatorStatusPointer->HModelController);
7128 		}
7129 	}
7130 
7131 
7132     //sort out section pointers
7133     predatorStatusPointer->My_Gun_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->GunName);
7134     predatorStatusPointer->My_Elevation_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName);
7135 
7136 
7137 	Load_SoundState(&predatorStatusPointer->soundHandle);
7138 
7139 }
7140 
SaveStrategy_Predator(STRATEGYBLOCK * sbPtr)7141 void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr)
7142 {
7143 	PREDATOR_SAVE_BLOCK *block;
7144 	PREDATOR_STATUS_BLOCK* predatorStatusPointer;
7145 
7146 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
7147 	predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->SBdataptr;
7148 
7149 
7150 	//start copying stuff
7151 
7152 	COPYELEMENT_SAVE(health)
7153 	COPYELEMENT_SAVE(behaviourState)
7154 	COPYELEMENT_SAVE(lastState)
7155 	COPYELEMENT_SAVE(stateTimer)
7156 	COPYELEMENT_SAVE(internalState)
7157 	COPYELEMENT_SAVE(patience)
7158 	COPYELEMENT_SAVE(enableSwap)
7159 	COPYELEMENT_SAVE(enableTaunt)
7160 	COPYELEMENT_SAVE(weaponTarget)			/* target position for firing weapon at */
7161 	COPYELEMENT_SAVE(volleySize)					/* used for weapon control */
7162 	COPYELEMENT_SAVE(obstruction)
7163 	COPYELEMENT_SAVE(wanderData)
7164 	COPYELEMENT_SAVE(IAmCrouched)
7165 	COPYELEMENT_SAVE(personalNumber)				/* for predator personalisation */
7166 	COPYELEMENT_SAVE(nearSpeed)
7167 	COPYELEMENT_SAVE(GibbFactor)
7168 	COPYELEMENT_SAVE(incidentFlag)
7169 	COPYELEMENT_SAVE(incidentTimer)
7170 	COPYELEMENT_SAVE(PrimaryWeapon)
7171 	COPYELEMENT_SAVE(SecondaryWeapon)
7172 	COPYELEMENT_SAVE(ChangeToWeapon)
7173 	COPYELEMENT_SAVE(CloakStatus)
7174 	COPYELEMENT_SAVE(CloakingEffectiveness)
7175 	COPYELEMENT_SAVE(CloakTimer)
7176 	COPYELEMENT_SAVE(Pred_Laser_Sight)
7177 	COPYELEMENT_SAVE(Pred_Laser_On)
7178 	COPYELEMENT_SAVE(Explode)
7179 	COPYELEMENT_SAVE(path)
7180 	COPYELEMENT_SAVE(stepnumber)
7181 
7182 	//save ai module pointers
7183 	block->missionmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->missionmodule);
7184 	block->fearmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->fearmodule);
7185 
7186 	//save target
7187 	COPY_NAME(block->Target_SBname,predatorStatusPointer->Target_SBname);
7188 
7189 	//save attack code
7190 	if(predatorStatusPointer->current_attack)
7191 	{
7192 		block->currentAttackCode = predatorStatusPointer->current_attack->Unique_Code;
7193 	}
7194 	else
7195 	{
7196 		block->currentAttackCode = -1;
7197 	}
7198 
7199 	//save predator's weapon
7200 	if(predatorStatusPointer->Selected_Weapon)
7201 		block->weapon_id = predatorStatusPointer->Selected_Weapon->id;
7202 	else
7203 		block->weapon_id = -1;
7204 
7205 	//copy strategy block stuff
7206 	block->dynamics = *sbPtr->DynPtr;
7207 	block->dynamics.CollisionReportPtr=0;
7208 
7209 	block->integrity = sbPtr->integrity;
7210 	block->SBDamageBlock = sbPtr->SBDamageBlock;
7211 
7212 	//save the hierarchy
7213 	SaveHierarchy(&predatorStatusPointer->HModelController);
7214 
7215 	Save_SoundState(&predatorStatusPointer->soundHandle);
7216 }
7217