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§ion_data_notreal)
1834 &&(chest->flags§ion_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§ion_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§ion_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§ion_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§ion_flag_left_arm)
1975 ||(Section->sempai->flags§ion_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§ion_flag_right_arm)
1984 ||(Section->sempai->flags§ion_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§ion_flag_left_leg)
1993 ||(Section->sempai->flags§ion_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§ion_flag_right_leg)
2002 ||(Section->sempai->flags§ion_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