1 /*------------------------Patrick 6/11/96-----------------------------
2 Source file for alien AI behaviour functions....
3 --------------------------------------------------------------------*/
4 #include "3dc.h"
5
6 #include "inline.h"
7 #include "module.h"
8 #include "stratdef.h"
9 #include "gamedef.h"
10 #include "dynblock.h"
11 #include "dynamics.h"
12 #include "comp_shp.h"
13 #include "load_shp.h"
14 #include "bh_types.h"
15 #include "bh_debri.h"
16 #include "bh_far.h"
17 #include "bh_near.h"
18 #include "bh_gener.h"
19 #include "bh_pred.h"
20 #include "bh_alien.h"
21 #include "bh_marin.h"
22 #include "weapons.h"
23 #include "pheromon.h"
24 #include "pfarlocs.h"
25 #include "pvisible.h"
26 #include "psnd.h"
27 #include "psndplat.h"
28 #include "extents.h"
29 #include "huddefs.h"
30 #include "pldghost.h"
31 #include "bh_corpse.h"
32 #include "bh_dummy.h"
33 #include "game_statistics.h"
34 #include "scream.h"
35
36 #define UseLocalAssert Yes
37 #include "ourasert.h"
38 #include "pldnet.h"
39 #include "avp_userprofile.h"
40
41 /* external global variables used in this file */
42 extern int ModuleArraySize;
43 extern char *ModuleCurrVisArray;
44 extern int NormalFrameTime;
45 extern unsigned char Null_Name[8];
46 extern ACTIVESOUNDSAMPLE ActiveSounds[];
47
48 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
49 extern void StartAlienAttackSequence(STRATEGYBLOCK *sbPtr);
50
51 extern int NearAliens;
52 extern int Alt_NearAliens;
53 extern int FarAliens;
54 extern int Alt_FarAliens;
55 extern int ShowHiveState;
56
57 /* prototypes for this file */
58
59 void KillAlien(STRATEGYBLOCK *sbPtr, int wounds, DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming);
60 void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr);
61 STRATEGYBLOCK *Alien_GetNewTarget(VECTORCH *alienpos, STRATEGYBLOCK *me);
62 void CreateAlienBot(VECTORCH *Position,int type);
63
64 /*----------------------Patrick 15/11/96-----------------------------
65 Alien's map: used to generate display blocks for aliens when they
66 come into view
67
68 --------------------------------------------------------------------*/
69 /* KJL 17:16:34 11/25/96 - I've wrapped the necessary fields in the
70 mapblock with #if StandardStrategyAndCollisions */
71
72 MODULEMAPBLOCK AlienDefaultMap =
73 {
74 MapType_Sprite,
75 I_ShapeCube, /* default value */
76 {0,0,0},
77 {0,0,0},
78 ObFlag_NoInfLSrc|ObFlag_MultLSrc,
79 0,
80 0,
81 0,
82 0,
83 0,
84 {0,0,0},
85 0,
86 0,
87 0,
88 0,
89 {0,0,0}
90 };
91
92 /* CDF 12/2/98 */
93
CastAlienBot(void)94 void CastAlienBot(void) {
95
96 #define BOTRANGE 2000
97
98 VECTORCH position;
99 #if 0
100 if (AvP.Network!=I_No_Network) {
101 NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE");
102 return;
103 }
104 #endif
105 position=Player->ObStrategyBlock->DynPtr->Position;
106 position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
107 position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
108 position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
109
110 CreateAlienBot(&position,0);
111
112 }
113
CastPredAlienBot(void)114 void CastPredAlienBot(void) {
115
116 #define BOTRANGE 2000
117
118 VECTORCH position;
119 #if 0
120 if (AvP.Network!=I_No_Network) {
121 NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE");
122 return;
123 }
124 #endif
125 position=Player->ObStrategyBlock->DynPtr->Position;
126 position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
127 position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
128 position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
129
130 CreateAlienBot(&position,1);
131
132 }
133
CastPraetorianBot(void)134 void CastPraetorianBot(void) {
135
136 #define BOTRANGE 2000
137
138 VECTORCH position;
139 #if 0
140 if (AvP.Network!=I_No_Network) {
141 NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE");
142 return;
143 }
144 #endif
145 position=Player->ObStrategyBlock->DynPtr->Position;
146 position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
147 position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
148 position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
149
150 CreateAlienBot(&position,2);
151
152 }
153
CreateAlienBot(VECTORCH * Position,int type)154 void CreateAlienBot(VECTORCH *Position,int type)
155 {
156 STRATEGYBLOCK* sbPtr;
157
158 /* create and initialise a strategy block */
159 sbPtr = CreateActiveStrategyBlock();
160 if(!sbPtr) {
161 NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
162 return; /* failure */
163 }
164 InitialiseSBValues(sbPtr);
165
166 sbPtr->I_SBtype = I_BehaviourAlien;
167
168 AssignNewSBName(sbPtr);
169
170 /* create, initialise and attach a dynamics block */
171 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC);
172 if(sbPtr->DynPtr)
173 {
174 EULER zeroEuler = {0,0,0};
175 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
176 dynPtr->PrevPosition = dynPtr->Position = *Position;
177 dynPtr->OrientEuler = zeroEuler;
178 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
179 TransposeMatrixCH(&dynPtr->OrientMat);
180 }
181 else
182 {
183 /* dynamics block allocation failed... */
184 RemoveBehaviourStrategy(sbPtr);
185 NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
186 return;
187 }
188
189 sbPtr->shapeIndex = 0;
190
191 sbPtr->maintainVisibility = 1;
192 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
193
194 /* create, initialise and attach an alien data block */
195 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK));
196 if(sbPtr->SBdataptr)
197 {
198 SECTION *root_section;
199 ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr;
200 int i;
201
202 NPC_InitMovementData(&(alienStatus->moveData));
203 NPC_InitWanderData(&(alienStatus->wanderData));
204 switch (type) {
205 case 0:
206 default:
207 alienStatus->Type = AT_Standard;
208 break;
209 case 1:
210 alienStatus->Type = AT_Predalien;
211 break;
212 case 2:
213 alienStatus->Type = AT_Praetorian;
214 break;
215 }
216
217 /* Initialise alien's stats */
218 {
219 NPC_DATA *NpcData;
220
221 switch (alienStatus->Type) {
222 case AT_Standard:
223 NpcData=GetThisNpcData(I_NPC_Alien);
224 alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY;
225 alienStatus->EnableWaypoints=1;
226 alienStatus->PreferToCrouch=0;
227 sbPtr->DynPtr->Mass = ALIEN_MASS;
228 break;
229 case AT_Predalien:
230 NpcData=GetThisNpcData(I_NPC_PredatorAlien);
231 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR);
232 alienStatus->EnableWaypoints=1;
233 alienStatus->PreferToCrouch=0;
234 sbPtr->DynPtr->Mass = PREDALIEN_MASS;
235 break;
236 case AT_Praetorian:
237 NpcData=GetThisNpcData(I_NPC_PraetorianGuard);
238 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR));
239 alienStatus->EnableWaypoints=0;
240 alienStatus->PreferToCrouch=0;
241 sbPtr->DynPtr->Mass = PRAETORIAN_MASS;
242 break;
243 default:
244 GLOBALASSERT(0);
245 break;
246 }
247 LOCALASSERT(NpcData);
248 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
249 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
250 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
251 }
252
253
254 alienStatus->Health = ALIEN_STARTING_HEALTH;
255 alienStatus->GibbFactor=0;
256 alienStatus->Wounds=0;
257 alienStatus->last_anim_length=ONE_FIXED;
258 sbPtr->integrity = alienStatus->Health;
259 alienStatus->BehaviourState = ABS_Hunt;
260 alienStatus->current_attack=NULL;
261
262 alienStatus->Target=NULL;
263 COPY_NAME(alienStatus->Target_SBname,Null_Name);
264 alienStatus->Mission=AM_Hunt; /* Was GlobalHunt... */
265
266 alienStatus->my_containing_module=NULL;
267 alienStatus->huntingModule=NULL;
268
269 Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager);
270 InitWaypointManager(&alienStatus->waypointManager);
271
272 alienStatus->CurveRadius = 0;
273 alienStatus->CurveLength = 0;
274 alienStatus->CurveTimeOut = 0;
275 alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME;
276 alienStatus->NearStateTimer = 0;
277 alienStatus->IAmCrouched = 0;
278
279 alienStatus->soundHandle = SOUND_NOACTIVEINDEX;
280 alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
281
282 alienStatus->incidentFlag=0;
283 alienStatus->incidentTimer=0;
284
285 //alien created by generator won't have a death target
286 for(i=0;i<SB_NAME_LENGTH;i++) alienStatus->death_target_ID[i] =0;
287 alienStatus->death_target_sbptr=0;
288
289 //this alien wasn't produced by a generator
290 alienStatus->generator_sbptr=0;
291
292
293 alienStatus->HModelController.section_data=NULL;
294 alienStatus->HModelController.Deltas=NULL;
295
296 switch (alienStatus->Type) {
297 case AT_Standard:
298 root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien");
299 break;
300 case AT_Predalien:
301 root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE");
302 break;
303 case AT_Praetorian:
304 root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template");
305 break;
306 default:
307 GLOBALASSERT(0);
308 break;
309 }
310
311 if (!root_section) {
312 RemoveBehaviourStrategy(sbPtr);
313 NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL");
314 return;
315 }
316 Create_HModel(&alienStatus->HModelController,root_section);
317 InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED);
318
319 if (SLUGTRAIL_MODE) {
320 SECTION_DATA *leg;
321 /* Blow off a leg? */
322 leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh");
323 if (leg) {
324 Prune_HModel_Virtual(leg);
325 alienStatus->Wounds|=section_flag_left_leg;
326 alienStatus->Wounds|=section_flag_left_foot;
327
328 sbPtr->SBDamageBlock.Health-=(20<<ONE_FIXED_SHIFT);
329 RecomputeAlienSpeed(sbPtr);
330 }
331 }
332
333
334 if (HModelSequence_Exists(&alienStatus->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) {
335 DELTA_CONTROLLER *delta;
336 delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1);
337 GLOBALASSERT(delta);
338 delta->Playing=0;
339 }
340
341 /* Containment test NOW! */
342 if(!(sbPtr->containingModule))
343 {
344 /* no containing module can be found... abort*/
345 RemoveBehaviourStrategy(sbPtr);
346 NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE");
347 return;
348 }
349 LOCALASSERT(sbPtr->containingModule);
350
351 if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) {
352 alienStatus->JumpDetected=1;
353 } else {
354 alienStatus->JumpDetected=0;
355 }
356
357 if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) {
358 /* Pounce will be unset eventually. */
359 alienStatus->PounceDetected=1;
360 alienStatus->EnablePounce=1;
361 } else {
362 alienStatus->PounceDetected=0;
363 alienStatus->EnablePounce=0;
364 }
365
366 alienStatus->aliensIgniterId=0;
367
368 MakeAlienNear(sbPtr);
369
370 NewOnScreenMessage("ALIENBOT CREATED");
371
372 }
373 else
374 {
375 /* no data block can be allocated */
376 RemoveBehaviourStrategy(sbPtr);
377 NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE");
378 return;
379 }
380
381 }
382
383
384 /*----------------------Patrick 15/11/96-----------------------------
385 This function is called by the alien generators, to dynamically
386 create a new alien, during the game. The alien is initialised
387 as invisible.
388
389 1. create a new strategy block (no diplay block)
390 2. attach a dynamics block
391 3. attach an alien data block
392 4. initialise for far behaviour
393
394 NB the strategyblock passed here is a reference to the generator sb
395 --------------------------------------------------------------------*/
CreateAlienDynamic(STRATEGYBLOCK * Generator,ALIEN_TYPE type_of_alien)396 void CreateAlienDynamic(STRATEGYBLOCK *Generator, ALIEN_TYPE type_of_alien)
397 {
398 STRATEGYBLOCK* sbPtr;
399 //int i;
400
401
402 /* create and initialise a strategy block */
403 sbPtr = CreateActiveStrategyBlock();
404 if(!sbPtr) return; /* failure */
405 InitialiseSBValues(sbPtr);
406
407 sbPtr->I_SBtype = I_BehaviourAlien;
408
409 AssignNewSBName(sbPtr);
410
411 /* create, initialise and attach a dynamics block */
412 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC);
413 if(sbPtr->DynPtr)
414 {
415 EULER zeroEuler = {0,0,0};
416 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
417 dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->SBdataptr)->Position;
418 dynPtr->OrientEuler = zeroEuler;
419 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
420 TransposeMatrixCH(&dynPtr->OrientMat);
421 }
422 else
423 {
424 /* dynamics block allocation failed... */
425 RemoveBehaviourStrategy(sbPtr);
426 return;
427 }
428
429 sbPtr->shapeIndex = Generator->shapeIndex;
430
431 sbPtr->maintainVisibility = 1;
432 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
433 LOCALASSERT(sbPtr->containingModule);
434 if(!(sbPtr->containingModule))
435 {
436 /* no containing module can be found... abort*/
437 RemoveBehaviourStrategy(sbPtr);
438 return;
439 }
440
441 /* assert alien is starting as invisible */
442 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0);
443
444 /* create, initialise and attach an alien data block */
445 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK));
446 if(sbPtr->SBdataptr)
447 {
448 SECTION *root_section;
449 ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr;
450 int i;
451
452 NPC_InitMovementData(&(alienStatus->moveData));
453 NPC_InitWanderData(&(alienStatus->wanderData));
454
455 alienStatus->Type = type_of_alien;
456
457 /* Initialise alien's stats */
458 {
459 NPC_DATA *NpcData;
460
461 switch (alienStatus->Type) {
462 case AT_Standard:
463 NpcData=GetThisNpcData(I_NPC_Alien);
464 alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY;
465 alienStatus->EnableWaypoints=1;
466 alienStatus->PreferToCrouch=0;
467 sbPtr->DynPtr->Mass = ALIEN_MASS;
468 break;
469 case AT_Predalien:
470 NpcData=GetThisNpcData(I_NPC_PredatorAlien);
471 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR);
472 alienStatus->EnableWaypoints=1;
473 alienStatus->PreferToCrouch=0;
474 sbPtr->DynPtr->Mass = PREDALIEN_MASS;
475 break;
476 case AT_Praetorian:
477 NpcData=GetThisNpcData(I_NPC_PraetorianGuard);
478 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR));
479 alienStatus->EnableWaypoints=0;
480 alienStatus->PreferToCrouch=0;
481 sbPtr->DynPtr->Mass = PRAETORIAN_MASS;
482 break;
483 default:
484 GLOBALASSERT(0);
485 break;
486 }
487 LOCALASSERT(NpcData);
488 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
489 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
490 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
491 }
492
493
494 alienStatus->Health = ALIEN_STARTING_HEALTH;
495 alienStatus->GibbFactor=0;
496 alienStatus->Wounds=0;
497 alienStatus->last_anim_length=ONE_FIXED;
498 sbPtr->integrity = alienStatus->Health;
499 alienStatus->BehaviourState = ABS_Hunt;
500 alienStatus->current_attack=NULL;
501 alienStatus->Wounds=0;
502
503 alienStatus->Target=NULL;
504 COPY_NAME(alienStatus->Target_SBname,Null_Name);
505 alienStatus->Mission=AM_Hunt;
506
507 alienStatus->my_containing_module=NULL;
508 alienStatus->huntingModule=NULL;
509
510 alienStatus->CurveRadius = 0;
511 alienStatus->CurveLength = 0;
512 alienStatus->CurveTimeOut = 0;
513 alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME;
514 alienStatus->NearStateTimer = 0;
515 alienStatus->IAmCrouched = 0;
516
517 Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager);
518 InitWaypointManager(&alienStatus->waypointManager);
519
520 alienStatus->soundHandle = SOUND_NOACTIVEINDEX;
521 alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
522
523 alienStatus->incidentFlag=0;
524 alienStatus->incidentTimer=0;
525
526 //alien created by generator won't have a death target
527 for(i=0;i<SB_NAME_LENGTH;i++) alienStatus->death_target_ID[i] =0;
528 alienStatus->death_target_sbptr=0;
529
530 //note the generator that produced this alien
531 alienStatus->generator_sbptr=Generator;
532
533 switch (alienStatus->Type) {
534 case AT_Standard:
535 root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien");
536 break;
537 case AT_Predalien:
538 root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE");
539 break;
540 case AT_Praetorian:
541 root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template");
542 break;
543 default:
544 GLOBALASSERT(0);
545 break;
546 }
547
548 Create_HModel(&alienStatus->HModelController,root_section);
549 InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED);
550
551 if (SLUGTRAIL_MODE) {
552 SECTION_DATA *leg;
553 /* Blow off a leg? */
554 leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh");
555 if (leg) {
556 Prune_HModel_Virtual(leg);
557 alienStatus->Wounds|=section_flag_left_leg;
558 alienStatus->Wounds|=section_flag_left_foot;
559
560 sbPtr->SBDamageBlock.Health-=(20<<ONE_FIXED_SHIFT);
561 RecomputeAlienSpeed(sbPtr);
562 }
563 }
564
565 if (HModelSequence_Exists(&alienStatus->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) {
566 DELTA_CONTROLLER *delta;
567 delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1);
568 GLOBALASSERT(delta);
569 delta->Playing=0;
570 }
571
572 ProveHModel_Far(&alienStatus->HModelController,sbPtr);
573
574 if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) {
575 alienStatus->JumpDetected=1;
576 } else {
577 alienStatus->JumpDetected=0;
578 }
579
580 if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) {
581 /* Pounce will be unset eventually. */
582 alienStatus->PounceDetected=1;
583 alienStatus->EnablePounce=1;
584 } else {
585 alienStatus->PounceDetected=0;
586 alienStatus->EnablePounce=0;
587 }
588 alienStatus->aliensIgniterId=0;
589
590 }
591 else
592 {
593 /* no data block can be allocated */
594 RemoveBehaviourStrategy(sbPtr);
595 return;
596 }
597 }
598
599 /*----------------------Patrick 7/11/96-----------------------------
600 This function is used to initialise a riff-loaded in alien.
601 -------------------------------------------------------------------*/
InitAlienBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)602 void InitAlienBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
603 {
604 TOOLS_DATA_ALIEN *toolsData = (TOOLS_DATA_ALIEN *)bhdata;
605 int i;
606
607 /* check we're not in a net game */
608 if(AvP.Network != I_No_Network && !AvP.NetworkAIServer)
609 {
610 RemoveBehaviourStrategy(sbPtr);
611 return;
612 }
613
614 /* strategy block should be initialised to general default values:
615 I_behaviourAlien, shapeIndex, and everything else 0....
616
617 NB it is necessary that placed aliens are initialised without a
618 displayblock, otherwise far aliens will be re-initialised by
619 MakeAlienFar() to a hunting state instead of a wait state....*/
620 LOCALASSERT(!(sbPtr->SBdptr));
621
622 /* strategy block initialisation */
623 sbPtr->shapeIndex = toolsData->shapeIndex;
624
625 if(AvP.Network==I_No_Network)
626 {
627 for(i=0;i<SB_NAME_LENGTH;i++) sbPtr->SBname[i] = toolsData->nameID[i];
628 }
629 else
630 {
631 //in a network game , generate a new sb name (so that it gets a reasonably low value)
632 AssignNewSBName(sbPtr);
633 }
634
635 /* create, initialise and attach a dynamics block */
636 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC);
637 if(sbPtr->DynPtr)
638 {
639 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
640 dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
641 dynPtr->OrientEuler = toolsData->starteuler;
642 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
643 TransposeMatrixCH(&dynPtr->OrientMat);
644 }
645 else
646 {
647 /* no dynamics block can be allocated */
648 RemoveBehaviourStrategy(sbPtr);
649 return;
650 }
651
652 /* create, initialise and attach an alien data block */
653 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK));
654 if(sbPtr->SBdataptr)
655 {
656 SECTION *root_section;
657 ALIEN_STATUS_BLOCK * alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr;
658
659 NPC_InitMovementData(&(alienStatus->moveData));
660 NPC_InitWanderData(&(alienStatus->wanderData));
661
662 alienStatus->Type = toolsData->type;
663
664 /* Initialise alien's stats */
665 {
666 NPC_DATA *NpcData;
667
668 switch (alienStatus->Type) {
669 case AT_Standard:
670 NpcData=GetThisNpcData(I_NPC_Alien);
671 alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY;
672 alienStatus->EnableWaypoints=1;
673 alienStatus->PreferToCrouch=0;
674 sbPtr->DynPtr->Mass = ALIEN_MASS;
675 break;
676 case AT_Predalien:
677 NpcData=GetThisNpcData(I_NPC_PredatorAlien);
678 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR);
679 alienStatus->EnableWaypoints=1;
680 alienStatus->PreferToCrouch=0;
681 sbPtr->DynPtr->Mass = PREDALIEN_MASS;
682 break;
683 case AT_Praetorian:
684 NpcData=GetThisNpcData(I_NPC_PraetorianGuard);
685 alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR));
686 alienStatus->EnableWaypoints=0;
687 alienStatus->PreferToCrouch=0;
688 sbPtr->DynPtr->Mass = PRAETORIAN_MASS;
689 break;
690 default:
691 GLOBALASSERT(0);
692 break;
693 }
694 LOCALASSERT(NpcData);
695 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
696 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
697 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
698 }
699
700 alienStatus->Health = ALIEN_STARTING_HEALTH;
701 sbPtr->integrity = alienStatus->Health;
702 alienStatus->GibbFactor=0;
703 alienStatus->Wounds=0;
704 alienStatus->last_anim_length=ONE_FIXED;
705
706 if (toolsData->start_inactive) {
707 alienStatus->BehaviourState = ABS_Dormant;
708 } else {
709 alienStatus->BehaviourState = ABS_Wait;
710 }
711
712 alienStatus->current_attack=NULL;
713 alienStatus->Wounds=0;
714
715 alienStatus->Target=NULL;
716 COPY_NAME(alienStatus->Target_SBname,Null_Name);
717 alienStatus->Mission=AM_Hunt;
718
719 alienStatus->my_containing_module=NULL;
720 alienStatus->huntingModule=NULL;
721
722 alienStatus->CurveRadius = 0;
723 alienStatus->CurveLength = 0;
724 alienStatus->CurveTimeOut = 0;
725 alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME;
726 alienStatus->NearStateTimer = 0;
727 alienStatus->IAmCrouched = 0;
728
729 Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager);
730 InitWaypointManager(&alienStatus->waypointManager);
731
732 alienStatus->soundHandle = SOUND_NOACTIVEINDEX;
733 alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
734
735 alienStatus->incidentFlag=0;
736 alienStatus->incidentTimer=0;
737
738 for(i=0;i<SB_NAME_LENGTH;i++) alienStatus->death_target_ID[i] = toolsData->death_target_ID[i];
739 alienStatus->death_target_sbptr=0;
740
741 //this alien wasn't produced by a generator
742 alienStatus->generator_sbptr=0;
743
744
745 switch (alienStatus->Type) {
746 case AT_Standard:
747 root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien");
748 break;
749 case AT_Predalien:
750 root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE");
751 break;
752 case AT_Praetorian:
753 root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template");
754 break;
755 default:
756 GLOBALASSERT(0);
757 break;
758 }
759
760 Create_HModel(&alienStatus->HModelController,root_section);
761
762 if (toolsData->start_inactive) {
763 if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Dormant)) {
764 InitHModelSequence(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Dormant,-1);
765 } else {
766 InitHModelSequence(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Standard,ONE_FIXED);
767 }
768 } else {
769 InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED);
770 }
771
772 if (SLUGTRAIL_MODE) {
773 SECTION_DATA *leg;
774 /* Blow off a leg? */
775 leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh");
776 if (leg) {
777 Prune_HModel_Virtual(leg);
778 alienStatus->Wounds|=section_flag_left_leg;
779 alienStatus->Wounds|=section_flag_left_foot;
780
781 sbPtr->SBDamageBlock.Health-=(20<<ONE_FIXED_SHIFT);
782 RecomputeAlienSpeed(sbPtr);
783 }
784 }
785
786 if (HModelSequence_Exists(&alienStatus->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) {
787 DELTA_CONTROLLER *delta;
788 delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1);
789 GLOBALASSERT(delta);
790 delta->Playing=0;
791 }
792
793 ProveHModel_Far(&alienStatus->HModelController,sbPtr);
794
795 if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) {
796 alienStatus->JumpDetected=1;
797 } else {
798 alienStatus->JumpDetected=0;
799 }
800
801 if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) {
802 /* Pounce will be unset eventually. */
803 alienStatus->PounceDetected=1;
804 alienStatus->EnablePounce=1;
805 } else {
806 alienStatus->PounceDetected=0;
807 alienStatus->EnablePounce=0;
808 }
809
810 alienStatus->aliensIgniterId=0;
811
812 }
813 else
814 {
815 /* no data block can be allocated */
816 RemoveBehaviourStrategy(sbPtr);
817 return;
818 }
819 }
820
821
PlayerIsDeadAndNoLivingNetghosts()822 static BOOL PlayerIsDeadAndNoLivingNetghosts()
823 {
824 if(AvP.Network == I_No_Network)
825 {
826 //just need to check for the only player we have
827 return NPC_IsDead(Player->ObStrategyBlock);
828
829 }
830 else
831 {
832 int sbIndex;
833 //first check the host player
834 if(!NPC_IsDead(Player->ObStrategyBlock)) return FALSE;
835
836 /* go through the strategy blocks looking for players*/
837 for(sbIndex=0;sbIndex<NumActiveStBlocks;sbIndex++)
838 {
839 STRATEGYBLOCK *playerSbPtr = ActiveStBlockList[sbIndex];
840 NETGHOSTDATABLOCK *ghostData;
841 if(playerSbPtr->I_SBtype!=I_BehaviourNetGhost) continue;
842 ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr;
843
844 if(ghostData->type==I_BehaviourMarinePlayer ||
845 ghostData->type==I_BehaviourPredatorPlayer)
846 {
847 //found a nethost of a player
848 return FALSE;
849 }
850 }
851 }
852 //Dead, all dead.
853 return TRUE;
854 }
855
856 /*----------------------Patrick 7/11/96-----------------------------
857 AI alien behaviour execution shell:
858
859 1. patch to trap aliens who's current module is not set (and set it).
860 2. call the visibility checking function.
861 3. select either near or far behaviour functions.
862
863 NB the visibility checking function initialises near/far behaviour and
864 allocates/deallocates displayblock based on changes in visibility
865 for the alien's module. This will, in due course, be invoked by a
866 call back function from the module handler.
867 --------------------------------------------------------------------*/
868
AlienBehaviour(STRATEGYBLOCK * sbPtr)869 void AlienBehaviour(STRATEGYBLOCK *sbPtr)
870 {
871 /* get the alien's status block */
872 ALIEN_STATUS_BLOCK *alienStatusPointer;
873 int alienIsNear;
874
875 LOCALASSERT(sbPtr);
876 alienStatusPointer= (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
877 LOCALASSERT(alienStatusPointer);
878
879 /* test if we've got a containing module: if we haven't, do nothing.
880 This is important as the alien could have been marked for deletion by the visibility
881 management system...*/
882 if(!sbPtr->containingModule)
883 {
884 DestroyAnyStrategyBlock(sbPtr); /* just to make sure */
885 return;
886 }
887
888 if(sbPtr->SBdptr) {
889 alienIsNear=1;
890 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
891 } else {
892 alienIsNear=0;
893 }
894
895 /* Unset incident flag. */
896 alienStatusPointer->incidentFlag=0;
897
898 alienStatusPointer->incidentTimer-=NormalFrameTime;
899
900 if (alienStatusPointer->incidentTimer<0) {
901 alienStatusPointer->incidentFlag=1;
902 alienStatusPointer->incidentTimer=32767+(FastRandom()&65535);
903 }
904
905 if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(alienStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
906
907 if (sbPtr->SBDamageBlock.IsOnFire) {
908
909 if (alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
910 if (ActiveSounds[alienStatusPointer->soundHandle].soundIndex!=SID_FIRE) {
911 Sound_Stop(alienStatusPointer->soundHandle);
912 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&alienStatusPointer->soundHandle,127);
913 }
914 } else {
915 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&alienStatusPointer->soundHandle,127);
916 }
917 //for multiplayer games it is necessary to say who is doing this damage
918 //(that would be the person who set the alien on fire in the first place)
919 {
920 extern DPID myNetworkKillerId;
921 extern DPID AVPDPNetID;
922
923 myNetworkKillerId=alienStatusPointer->aliensIgniterId;
924 CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL);
925 myNetworkKillerId=AVPDPNetID;
926 }
927 if (sbPtr->I_SBtype==I_BehaviourNetCorpse) {
928 /* Gettin' out of here... */
929 return;
930 }
931 } else {
932 if (alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
933 if (ActiveSounds[alienStatusPointer->soundHandle].soundIndex==SID_FIRE) {
934 Sound_Stop(alienStatusPointer->soundHandle);
935 }
936 }
937 }
938
939 if (alienStatusPointer->GibbFactor) {
940 /* If you're gibbed, you're dead. */
941 sbPtr->SBDamageBlock.Health = 0;
942 }
943
944 /* check if we've been killed */
945 if ( (sbPtr->SBDamageBlock.Health <= 0)&&(alienStatusPointer->BehaviourState!=ABS_Dying) )
946 {
947 textprint("Zombie Alien!!! State is %d.\n",alienStatusPointer->BehaviourState);
948 return;
949 }
950
951 if ((alienStatusPointer->BehaviourState!=ABS_Dying)
952 &&(alienStatusPointer->BehaviourState!=ABS_Dormant)
953 &&(alienStatusPointer->BehaviourState!=ABS_Awakening)) {
954
955 /* Target handling. */
956 if (Validate_Target(alienStatusPointer->Target,alienStatusPointer->Target_SBname)==0) {
957
958 /* Target must be dead... */
959 alienStatusPointer->Target=NULL;
960 /* Now try to get a new target. */
961 }
962
963 if ((alienIsNear)||(alienStatusPointer->incidentFlag)) {
964 if (alienStatusPointer->Target==NULL) {
965
966 alienStatusPointer->Target=Alien_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr);
967
968 if (alienStatusPointer->Target!=NULL) {
969 textprint("Alien gets new target.\n");
970
971 COPY_NAME(alienStatusPointer->Target_SBname,alienStatusPointer->Target->SBname);
972
973 if (alienStatusPointer->BehaviourState!=ABS_Wait) {
974 alienStatusPointer->BehaviourState=ABS_Hunt;
975 }
976 alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME;
977 alienStatusPointer->NearStateTimer = 0;
978
979 } else {
980 textprint("Alien found no target!\n");
981 if (alienStatusPointer->BehaviourState!=ABS_Wait) {
982 AIMODULE *targetModule;
983 /* Hunt or wander? */
984 if ((AvP.PlayerType==I_Alien)||(Observer)) {
985 /* Eew! What a nasty hack! Eeeww! */
986 targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr);
987 } else {
988 /* This just makes them hunt a bit more... */
989 targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,1);
990 }
991
992 if ((!targetModule)||(PlayerIsDeadAndNoLivingNetghosts())) {
993 if (alienStatusPointer->BehaviourState!=ABS_Wander) {
994 NPC_InitMovementData(&(alienStatusPointer->moveData));
995 alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME;
996 alienStatusPointer->NearStateTimer = 0;
997 }
998 alienStatusPointer->BehaviourState=ABS_Wander;
999 } else {
1000 if (alienStatusPointer->BehaviourState!=ABS_Hunt) {
1001 alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME;
1002 alienStatusPointer->NearStateTimer = 0;
1003 }
1004 alienStatusPointer->BehaviourState=ABS_Hunt;
1005 }
1006 }
1007 }
1008 }
1009 }
1010 }
1011
1012 if(sbPtr->SBdptr)
1013 {
1014 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
1015 #if 0
1016 textprint("Near Alien in module %s \n",sbPtr->containingModule->name);
1017 #endif
1018 NearAlienBehaviour(sbPtr);
1019 Alt_NearAliens++;
1020 }
1021 else
1022 {
1023 /* NB if this assert fires, we may just have run out of displayblocks */
1024 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0);
1025 #if 0
1026 textprint("Far Alien in module %s \n",sbPtr->containingModule->name);
1027 #endif
1028 FarAlienBehaviour(sbPtr);
1029 Alt_FarAliens++;
1030 }
1031
1032 /* if we have actually died, we need to remove the strategyblock... so
1033 do this here */
1034 if((alienStatusPointer->BehaviourState == ABS_Dying)&&(alienStatusPointer->NearStateTimer <= 0)) {
1035
1036 if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle);
1037 if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle2);
1038 DestroyAnyStrategyBlock(sbPtr);
1039 }
1040
1041 /* Update containing module? */
1042 if (sbPtr->containingModule!=alienStatusPointer->my_containing_module) {
1043 /* This is to slow down new hunting target computation. */
1044 alienStatusPointer->my_containing_module=sbPtr->containingModule;
1045 }
1046
1047 /* Update delta playing flag. */
1048 {
1049 DELTA_CONTROLLER *hitdelta;
1050
1051 hitdelta=Get_Delta_Sequence(&alienStatusPointer->HModelController,"HitDelta");
1052
1053 if (hitdelta) {
1054 if (DeltaAnimation_IsFinished(hitdelta)) {
1055 hitdelta->Playing=0;
1056 }
1057 }
1058 }
1059 }
1060
1061
1062
1063 /*----------------------Patrick 7/11/96-----------------------------
1064 This pair of functions handle the alien visibility switching....
1065 Note that the ai-pheromone system is maintained by these functions.
1066 --------------------------------------------------------------------*/
MakeAlienNear(STRATEGYBLOCK * sbPtr)1067 void MakeAlienNear(STRATEGYBLOCK *sbPtr)
1068 {
1069 MODULE tempModule;
1070 DISPLAYBLOCK *dPtr;
1071 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1072 ALIEN_STATUS_BLOCK *alienStatusPointer= (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1073
1074 LOCALASSERT(alienStatusPointer);
1075 LOCALASSERT(dynPtr);
1076 LOCALASSERT(sbPtr->SBdptr == NULL);
1077
1078 /* first of all, see how many aliens are currently near: if there are too many,
1079 destroy this alien, and try to force a generator to make a replacement */
1080 if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS)
1081 {
1082 DestroyAnyStrategyBlock(sbPtr);
1083 ForceAGenerator();
1084 }
1085
1086 AlienDefaultMap.MapShape = sbPtr->shapeIndex;
1087 tempModule.m_mapptr = &AlienDefaultMap;
1088 tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
1089 tempModule.m_numlights = 0;
1090 tempModule.m_lightarray = (struct lightblock *)0;
1091 tempModule.m_extraitemdata = (struct extraitemdata *)0;
1092 tempModule.m_dptr=NULL;
1093 AllocateModuleObject(&tempModule);
1094 dPtr = tempModule.m_dptr;
1095 if(dPtr==NULL) return; /* cannot create displayblock: leave alien far */
1096
1097 sbPtr->SBdptr = dPtr;
1098 dPtr->ObStrategyBlock = sbPtr;
1099 dPtr->ObMyModule = NULL;
1100
1101
1102 /*Copy extents from the collision extents in extents.c*/
1103 dPtr->ObMinX=-CollisionExtents[CE_ALIEN].CollisionRadius;
1104 dPtr->ObMaxX=CollisionExtents[CE_ALIEN].CollisionRadius;
1105 dPtr->ObMinZ=-CollisionExtents[CE_ALIEN].CollisionRadius;
1106 dPtr->ObMaxZ=CollisionExtents[CE_ALIEN].CollisionRadius;
1107 dPtr->ObMinY=CollisionExtents[CE_ALIEN].CrouchingTop;
1108 dPtr->ObMaxY=CollisionExtents[CE_ALIEN].Bottom;
1109 dPtr->ObRadius = 1000;
1110 /* also need to initialise positional information in the new display block,
1111 from the existing dynamics block.
1112 NB this necessary because this function is (usually) called between the
1113 dynamics and rendering systems so it is not initialised by the dynamics
1114 system the first frame it is drawn. */
1115 dPtr->ObWorld = dynPtr->Position;
1116 dPtr->ObEuler = dynPtr->OrientEuler;
1117 dPtr->ObMat = dynPtr->OrientMat;
1118
1119 /* init state timers */
1120 alienStatusPointer->NearStateTimer = 0;
1121 alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME;
1122 alienStatusPointer->CurveRadius = 0;
1123 alienStatusPointer->CurveLength = 0;
1124 alienStatusPointer->CurveTimeOut = 0;
1125
1126 /* zero linear velocity in dynamics block */
1127 dynPtr->LinVelocity.vx = 0;
1128 dynPtr->LinVelocity.vy = 0;
1129 dynPtr->LinVelocity.vz = 0;
1130
1131 /* initialise our sequence data */
1132 //dPtr->ShapeAnimControlBlock = &alienStatusPointer->ShpAnimCtrl;
1133 dPtr->HModelControlBlock=&alienStatusPointer->HModelController;
1134
1135 ProveHModel(dPtr->HModelControlBlock,dPtr);
1136
1137 if(AlienShouldBeCrawling(sbPtr)) alienStatusPointer->IAmCrouched = 1;
1138 else alienStatusPointer->IAmCrouched = 0;
1139
1140 RecomputeAlienSpeed(sbPtr);
1141
1142 InitWaypointManager(&alienStatusPointer->waypointManager);
1143
1144 /* initialise our near state and specific sequence */
1145 if ((alienStatusPointer->BehaviourState == ABS_Dying)
1146 ||(alienStatusPointer->BehaviourState == ABS_Dormant)
1147 ||(alienStatusPointer->BehaviourState == ABS_Awakening)) {
1148 /* Do nothing. */
1149 } else if(alienStatusPointer->BehaviourState == ABS_Wait) {
1150 NPC_InitMovementData(&(alienStatusPointer->moveData));
1151 alienStatusPointer->BehaviourState = ABS_Wait;
1152 if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrouch,(int)ACrSS_Standard,ONE_FIXED);
1153 else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED);
1154 } else if(AlienIsAwareOfTarget(sbPtr)) {
1155 NPC_InitMovementData(&(alienStatusPointer->moveData));
1156 alienStatusPointer->BehaviourState = ABS_Approach;
1157 if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1);
1158 else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1);
1159 } else {
1160 NPC_InitMovementData(&(alienStatusPointer->moveData));
1161 /* Was Wander, now Hunt. Hunt should kick in wander if needed. */
1162 alienStatusPointer->BehaviourState = ABS_Hunt;
1163 if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1);
1164 else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1);
1165 }
1166 }
1167
MakeAlienFar(STRATEGYBLOCK * sbPtr)1168 void MakeAlienFar(STRATEGYBLOCK *sbPtr)
1169 {
1170 /* get the alien's status block */
1171 ALIEN_STATUS_BLOCK *alienStatusPointer;
1172 int i;
1173
1174 LOCALASSERT(sbPtr);
1175 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1176 LOCALASSERT(alienStatusPointer);
1177 LOCALASSERT(sbPtr->SBdptr != NULL);
1178
1179 /* get rid of the displayblock */
1180 if(sbPtr->SBdptr)
1181 {
1182 i = DestroyActiveObject(sbPtr->SBdptr);
1183 LOCALASSERT(i==0);
1184 sbPtr->SBdptr = NULL;
1185 }
1186
1187 if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle);
1188 if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle2);
1189
1190 /* initialise our far state */
1191 if ((alienStatusPointer->BehaviourState!=ABS_Dying)
1192 &&(alienStatusPointer->BehaviourState!=ABS_Dormant)
1193 &&(alienStatusPointer->BehaviourState!=ABS_Awakening)) {
1194 /* No zombie aliens here! */
1195 if(AlienIsAwareOfTarget(sbPtr))
1196 {
1197 alienStatusPointer->BehaviourState = ABS_Hunt;
1198 }
1199 else
1200 {
1201 alienStatusPointer->BehaviourState = ABS_Wander;
1202 }
1203 }
1204
1205 NPC_InitWanderData(&(alienStatusPointer->wanderData));
1206 /* init state timers */
1207 alienStatusPointer->NearStateTimer = 0;
1208 alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME;
1209
1210 /* zero linear velocity in dynamics block */
1211 LOCALASSERT(sbPtr->DynPtr);
1212 sbPtr->DynPtr->LinVelocity.vx = 0;
1213 sbPtr->DynPtr->LinVelocity.vy = 0;
1214 sbPtr->DynPtr->LinVelocity.vz = 0;
1215 }
1216
1217
DoAlienAIHiss(STRATEGYBLOCK * sbPtr)1218 static void DoAlienAIHiss(STRATEGYBLOCK *sbPtr) {
1219
1220 DYNAMICSBLOCK *dynPtr;
1221 int pitch = (FastRandom() & 255) - 128;
1222 SOUNDINDEX soundIndex;
1223 ALIEN_STATUS_BLOCK *alienStatusPointer;
1224
1225 GLOBALASSERT(sbPtr);
1226 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1227 LOCALASSERT(alienStatusPointer);
1228 dynPtr = sbPtr->DynPtr;
1229 LOCALASSERT(dynPtr);
1230 GLOBALASSERT(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX);
1231
1232 /* This one is for ALIEN DAMAGE SCREAM. */
1233
1234 soundIndex=SID_NOSOUND;
1235
1236 if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
1237 PlayAlienSound((int)alienStatusPointer->Type,ASC_Scream_Hurt,pitch,
1238 &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
1239
1240 if (AvP.Network != I_No_Network)
1241 {
1242 AddNetMsg_SpotAlienSound(ASC_Scream_Hurt,(int)alienStatusPointer->Type,pitch,&dynPtr->Position);
1243 }
1244
1245 }
1246
1247
1248 }
1249
DoAlienDeathScream(STRATEGYBLOCK * sbPtr)1250 static void DoAlienDeathScream(STRATEGYBLOCK *sbPtr) {
1251
1252 DYNAMICSBLOCK *dynPtr;
1253 SOUNDINDEX soundIndex;
1254 ALIEN_STATUS_BLOCK *alienStatusPointer;
1255
1256 GLOBALASSERT(sbPtr);
1257 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1258 LOCALASSERT(alienStatusPointer);
1259 dynPtr = sbPtr->DynPtr;
1260 LOCALASSERT(dynPtr);
1261 GLOBALASSERT(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX);
1262
1263 soundIndex=SID_NOSOUND;
1264
1265 /* This one is for ALIEN DEATH SCREAM. */
1266
1267 soundIndex=SID_NOSOUND;
1268
1269 if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
1270 PlayAlienSound((int)alienStatusPointer->Type,ASC_Scream_Dying,0,
1271 &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
1272
1273 if (AvP.Network != I_No_Network)
1274 {
1275 AddNetMsg_SpotAlienSound((int)ASC_Scream_Dying,(int)alienStatusPointer->Type,0,&dynPtr->Position);
1276 }
1277 }
1278
1279
1280 }
1281
DoAlienDeathSound(STRATEGYBLOCK * sbPtr)1282 static void DoAlienDeathSound(STRATEGYBLOCK *sbPtr) {
1283
1284 DYNAMICSBLOCK *dynPtr;
1285 SOUNDINDEX soundIndex;
1286 ALIEN_STATUS_BLOCK *alienStatusPointer;
1287
1288 GLOBALASSERT(sbPtr);
1289 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1290 LOCALASSERT(alienStatusPointer);
1291 dynPtr = sbPtr->DynPtr;
1292 LOCALASSERT(dynPtr);
1293
1294 soundIndex=SID_NOSOUND;
1295
1296 /* This one is for ALIEN DEATH SOUND. */
1297
1298 soundIndex=SID_NOSOUND;
1299
1300 PlayAlienSound((int)alienStatusPointer->Type,ASC_Death,0,
1301 NULL,&sbPtr->DynPtr->Position);
1302
1303 #if 0
1304 if (AvP.Network != I_No_Network)
1305 {
1306 soundIndex=ActiveSounds[alienStatusPointer->soundHandle2].soundIndex;
1307 if (soundIndex!=SID_NOSOUND) {
1308 AddNetMsg_SpotAlienSound(soundIndex,pitch,&dynPtr->Position);
1309 }
1310 }
1311 #endif
1312
1313 }
1314
DoAlienLimbLossSound(VECTORCH * position)1315 extern void DoAlienLimbLossSound(VECTORCH *position) {
1316
1317 /* This one is for ALIEN LIMBLOSS SOUND. */
1318
1319 PlayAlienSound(0,ASC_LimbLoss,0,NULL,position);
1320
1321 }
1322
1323 /*----------------------Patrick 7/11/96-----------------------------
1324 Handle weapon impact on an alien
1325 --------------------------------------------------------------------*/
1326 /* KJL 11:46:43 12/17/96 - rewritten */
1327
1328 // JB 16/6/97 rewritten
1329 // Patrick 29/7/97 rewritten again. again.
1330 // ChrisF 16/9/97 rewritten again again, again.
1331 // ChrisF 26/11/97 rewritten again, again, again, again.
1332 // ChrisF 1/4/98 rewritten again again again again again. Okay, 'modified' then. Added directional parameter.
1333 // ChrisF 20/11/98 rewritten again again again again again again, added hit delta support.
1334 // ChrisF 15/2/99 rewritten again again again again again again again, added fragging noise.
1335
AlienIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int wounds,SECTION_DATA * Section,VECTORCH * incoming,DISPLAYBLOCK * frag)1336 void AlienIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming, DISPLAYBLOCK *frag)
1337 {
1338
1339 int tkd;
1340 ALIEN_STATUS_BLOCK *alienStatusPointer;
1341 GLOBALASSERT(sbPtr);
1342
1343 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1344 LOCALASSERT(alienStatusPointer);
1345
1346 LOCALASSERT(sbPtr);
1347
1348 alienStatusPointer->Wounds|=wounds;
1349
1350 if (incoming) {
1351 textprint("Alien hit from %d %d %d\n",incoming->vx,incoming->vy,incoming->vz);
1352 /* Knockback effects? */
1353 }
1354
1355 if (frag) {
1356 DoAlienLimbLossSound(&sbPtr->DynPtr->Position);
1357 }
1358
1359 #if 0
1360 ALIEN_STATUS_BLOCK *alienStatusPointer;
1361 GLOBALASSERT(sbPtr);
1362
1363 /* reduce alien health */
1364 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1365 LOCALASSERT(alienStatusPointer);
1366 if(alienStatusPointer->Health>0) (alienStatusPointer->Health) -= damage;
1367 #endif
1368 /* Perhaps I'd better explain... I now handle damage
1369 for you. These functions now are only for special effects,
1370 and if you need to do anything when damage happens. */
1371
1372 if (alienStatusPointer->BehaviourState==ABS_Dormant) {
1373 Alien_Awaken(sbPtr);
1374 }
1375
1376 /* Speaking of which... */
1377 {
1378
1379 /* reduce alien health */
1380
1381 if (sbPtr->SBDamageBlock.Health <= 0) {
1382
1383 /* Oh yes, kill them, too. */
1384 if (alienStatusPointer->BehaviourState!=ABS_Dying)
1385 {
1386 if (AvP.PlayerType!=I_Alien) {
1387 CurrentGameStats_CreatureKilled(sbPtr,Section);
1388 }
1389 KillAlien(sbPtr,wounds,damage,multiple,incoming);
1390 }
1391
1392 } else {
1393 #if WOUNDING_SPEED_EFFECTS
1394 /* Alien wounding effects? */
1395 int factor;
1396 int changespeed;
1397
1398 RecomputeAlienSpeed(sbPtr);
1399
1400 /* Now, get anim speed. */
1401 factor=GetAlienSpeedFactor(sbPtr);
1402 changespeed=0;
1403
1404 switch (alienStatusPointer->Type) {
1405 case AT_Standard:
1406 if (factor!=ONE_FIXED) {
1407 changespeed=1;
1408 }
1409 break;
1410 case AT_Predalien:
1411 if (factor!=PREDALIEN_SPEED_FACTOR) {
1412 changespeed=1;
1413 }
1414 break;
1415 case AT_Praetorian:
1416 if (factor!=PRAETORIAN_SPEED_FACTOR) {
1417 changespeed=1;
1418 }
1419 break;
1420 default:
1421 GLOBALASSERT(0);
1422 break;
1423 }
1424
1425 if (changespeed) {
1426 int newspeed;
1427 /* ONE_FIXED implies we're playing an invariant length anim. */
1428 newspeed=DIV_FIXED(alienStatusPointer->last_anim_length,factor);
1429
1430 HModel_ChangeSpeed(&alienStatusPointer->HModelController,newspeed);
1431 }
1432 #endif
1433
1434 /* If you got here, you should still be alive. */
1435
1436 if ((alienStatusPointer->BehaviourState!=ABS_Dying)&&(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX)) {
1437 DoAlienAIHiss(sbPtr);
1438 }
1439
1440 tkd=TotalKineticDamage(damage);
1441
1442 if (tkd>=10) {
1443 /* If not dead, play a hit delta. */
1444 DELTA_CONTROLLER *hitdelta;
1445 int frontback;
1446
1447 hitdelta=Get_Delta_Sequence(&alienStatusPointer->HModelController,"HitDelta");
1448
1449 if (incoming) {
1450 if (incoming->vz>=0) {
1451 frontback=0;
1452 } else {
1453 frontback=1;
1454 }
1455 } else {
1456 /* Default to front. */
1457 frontback=1;
1458 }
1459
1460 /* Only do it from the front. */
1461 if ((hitdelta)&&(frontback)) {
1462 if (hitdelta->Playing==0) {
1463 /* A hierarchy with hit deltas! */
1464 int CrouchSubSequence;
1465 int StandSubSequence;
1466
1467 if (Section==NULL) {
1468 if ((FastRandom()&65535)<32767) {
1469 CrouchSubSequence=ACrSS_Hit_Left;
1470 StandSubSequence=ASSS_Hit_Left;
1471 } else {
1472 CrouchSubSequence=ACrSS_Hit_Right;
1473 StandSubSequence=ASSS_Hit_Right;
1474 }
1475 } else if ((Section->sempai->flags§ion_flag_left_arm)
1476 ||(Section->sempai->flags§ion_flag_left_hand)) {
1477
1478 CrouchSubSequence=ACrSS_Hit_Left;
1479 StandSubSequence=ASSS_Hit_Left;
1480 } else if ((Section->sempai->flags§ion_flag_right_arm)
1481 ||(Section->sempai->flags§ion_flag_right_hand)) {
1482
1483 CrouchSubSequence=ACrSS_Hit_Right;
1484 StandSubSequence=ASSS_Hit_Right;
1485
1486 } else {
1487 /* Chest or misc. hit. */
1488 if ((FastRandom()&65535)<32767) {
1489 CrouchSubSequence=ACrSS_Hit_Left;
1490 StandSubSequence=ASSS_Hit_Left;
1491 } else {
1492 CrouchSubSequence=ACrSS_Hit_Right;
1493 StandSubSequence=ASSS_Hit_Right;
1494 }
1495 }
1496
1497
1498 if(alienStatusPointer->IAmCrouched) {
1499 if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienCrouch,CrouchSubSequence)) {
1500 Start_Delta_Sequence(hitdelta,(int)HMSQT_AlienCrouch,CrouchSubSequence,-1);
1501 }
1502 } else {
1503 if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienStand,StandSubSequence)) {
1504 Start_Delta_Sequence(hitdelta,(int)HMSQT_AlienStand,StandSubSequence,-1);
1505 }
1506 }
1507 hitdelta->Playing=1;
1508 /* Not looped. */
1509 if (alienStatusPointer->BehaviourState==ABS_Attack) {
1510 StartAlienAttackSequence(sbPtr);
1511 alienStatusPointer->NearStateTimer = ALIEN_ATTACKTIME;
1512 }
1513 }
1514 }
1515 }
1516 }
1517 }
1518
1519 }
1520
1521 /* patrick 29/7/97 -----------------------------------
1522 This function to be called only from behaviour
1523 -- ChrisF 1/4/98 What a stupid idea. This function ---
1524 -- to be called only from AlienIsDamaged. ------------
1525 ------------------------------------------------------*/
KillAlien(STRATEGYBLOCK * sbPtr,int wounds,DAMAGE_PROFILE * damage,int multiple,VECTORCH * incoming)1526 void KillAlien(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming)
1527 {
1528 ALIEN_STATUS_BLOCK *alienStatusPointer;
1529 int tkd,deathtype;
1530 SECTION_DATA *head;
1531
1532 LOCALASSERT(sbPtr);
1533 LOCALASSERT(sbPtr->DynPtr);
1534
1535
1536 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1537
1538 /* make a sound. Just this once without a check. */
1539
1540 DoAlienDeathSound(sbPtr);
1541
1542 /*If alien has a death target ,send a request*/
1543 if(alienStatusPointer->death_target_sbptr)
1544 {
1545 RequestState(alienStatusPointer->death_target_sbptr,1, 0);
1546 }
1547
1548 /* Set up gibb factor. */
1549
1550 tkd=TotalKineticDamage(damage);
1551 deathtype=0;
1552
1553 if (damage->ExplosivePower==1) {
1554 /* Explosion case. */
1555 if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
1556 /* Okay, you can gibb now. */
1557 alienStatusPointer->GibbFactor=ONE_FIXED>>1;
1558 deathtype=2;
1559 }
1560 } else if ((tkd<40)&&((multiple>>16)>1)) {
1561 int newmult;
1562
1563 newmult=DIV_FIXED(multiple,NormalFrameTime);
1564 if (MUL_FIXED(tkd,newmult)>700) {
1565 /* Excessive bullets case 1. */
1566 alienStatusPointer->GibbFactor=ONE_FIXED>>2;
1567 deathtype=2;
1568 } else if (MUL_FIXED(tkd,newmult)>250) {
1569 /* Excessive bullets case 2. */
1570 alienStatusPointer->GibbFactor=ONE_FIXED>>3;
1571 deathtype=1;
1572 }
1573 }
1574
1575 /* Predaliens and preatorians only gibb for sadars. */
1576 if (alienStatusPointer->Type!=AT_Standard) {
1577 alienStatusPointer->GibbFactor=0;
1578 /* But retain deathtype. */
1579 }
1580
1581 if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) {
1582 /* Basically SADARS only. */
1583 if (alienStatusPointer->Type==AT_Standard) {
1584 alienStatusPointer->GibbFactor=ONE_FIXED;
1585 } else {
1586 alienStatusPointer->GibbFactor=ONE_FIXED>>2;
1587 }
1588 deathtype=3;
1589 }
1590
1591 if (damage->ForceBoom) {
1592 deathtype+=damage->ForceBoom;
1593 }
1594
1595 if ( (damage->Impact==0)
1596 &&(damage->Cutting==0)
1597 &&(damage->Penetrative==0)
1598 &&(damage->Fire!=0)
1599 &&(damage->Electrical==0)
1600 &&(damage->Acid==0))
1601 {
1602 /* that sounds like the flamethrower... */
1603 alienStatusPointer->GibbFactor=ONE_FIXED>>2;
1604 /* Gibb just a little for now. */
1605 }
1606
1607 if (damage->Id==AMMO_PREDPISTOL_STRIKE) {
1608 /* Blow up if hit by the bolt. */
1609 alienStatusPointer->GibbFactor=ONE_FIXED>>3;
1610 } else if (damage->Id==AMMO_FLECHETTE_POSTMAX) {
1611 alienStatusPointer->GibbFactor=ONE_FIXED>>2;
1612 }
1613
1614 {
1615 SECTION_DATA *chest=GetThisSectionData(alienStatusPointer->HModelController.section_data,"chest");
1616
1617 if (chest==NULL) {
1618 /* I'm impressed. */
1619 deathtype+=2;
1620 } else if ((chest->flags§ion_data_notreal)
1621 &&(chest->flags§ion_data_terminate_here)) {
1622 /* That's gotta hurt. */
1623 deathtype++;
1624 }
1625 }
1626
1627 /* Gibb noise? */
1628 if (alienStatusPointer->GibbFactor) {
1629 DoAlienLimbLossSound(&sbPtr->DynPtr->Position);
1630 } else {
1631 /* make a sound... if you have a head. */
1632 head=GetThisSectionData(alienStatusPointer->HModelController.section_data,"head");
1633
1634 /* Is it still attached? */
1635 if (head) {
1636 if (head->flags§ion_data_notreal) {
1637 head=NULL;
1638 }
1639 }
1640
1641 if ((alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX)&&(head)) {
1642 DoAlienDeathScream(sbPtr);
1643 }
1644 }
1645
1646 /* More restrained death than before... */
1647 {
1648
1649
1650 DEATH_DATA *this_death;
1651 HIT_FACING facing;
1652 int electrical;
1653
1654 facing.Front=0;
1655 facing.Back=0;
1656 facing.Left=0;
1657 facing.Right=0;
1658
1659 if (incoming) {
1660 if (incoming->vz>0) {
1661 facing.Back=1;
1662 } else {
1663 facing.Front=1;
1664 }
1665 if (incoming->vx>0) {
1666 facing.Right=1;
1667 } else {
1668 facing.Left=1;
1669 }
1670 }
1671
1672 if ((damage->Impact==0)
1673 &&(damage->Cutting==0)
1674 &&(damage->Penetrative==0)
1675 &&(damage->Fire==0)
1676 &&(damage->Electrical>0)
1677 &&(damage->Acid==0)
1678 ) {
1679 electrical=1;
1680 } else {
1681 electrical=0;
1682 }
1683
1684 this_death=GetAlienDeathSequence(&alienStatusPointer->HModelController,NULL,alienStatusPointer->Wounds,alienStatusPointer->Wounds,
1685 deathtype,&facing,0,alienStatusPointer->IAmCrouched,electrical);
1686
1687 #if 0
1688 GLOBALASSERT(this_death);
1689
1690 SetAlienShapeAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence,
1691 this_death->Sequence_Length,this_death->TweeningTime);
1692
1693 alienStatusPointer->NearStateTimer=ALIEN_DYINGTIME;
1694 alienStatusPointer->HModelController.Looped=0;
1695 alienStatusPointer->HModelController.LoopAfterTweening=0;
1696 /* switch state */
1697 alienStatusPointer->BehaviourState=ABS_Dying;
1698
1699 /* stop sound, if we have one */
1700 if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle);
1701
1702 /* stop motion */
1703 LOCALASSERT(sbPtr->DynPtr);
1704 sbPtr->DynPtr->Friction = 400000;
1705 sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx;
1706 sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy;
1707 sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz;
1708 sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
1709 sbPtr->DynPtr->IgnoreSameObjectsAsYou = 1;
1710 /* Experiment... */
1711 sbPtr->DynPtr->UseStandardGravity=1;
1712 sbPtr->DynPtr->Mass = 160;
1713 /* Okay... */
1714 #else
1715 Convert_Alien_To_Corpse(sbPtr,this_death,damage);
1716 #endif
1717 }
1718 }
1719
Execute_Alien_Dying(STRATEGYBLOCK * sbPtr)1720 void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr)
1721 {
1722 ALIEN_STATUS_BLOCK *alienStatusPointer;
1723
1724 LOCALASSERT(sbPtr);
1725 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1726 LOCALASSERT(alienStatusPointer);
1727
1728 //sbPtr->DynPtr->LinVelocity.vx = 0;
1729 //sbPtr->DynPtr->LinVelocity.vy = 0;
1730 //sbPtr->DynPtr->LinVelocity.vz = 0;
1731
1732 //sbPtr->DynPtr->LinImpulse.vx = 0;
1733 //sbPtr->DynPtr->LinImpulse.vy = 0;
1734 //sbPtr->DynPtr->LinImpulse.vz = 0;
1735
1736 {
1737 DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
1738 /* do we have a displayblock? */
1739 if (dispPtr)
1740 {
1741 dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
1742 dispPtr->ObFlags2 = alienStatusPointer->NearStateTimer/2;
1743
1744 }
1745 }
1746 alienStatusPointer->NearStateTimer -= NormalFrameTime;
1747 }
1748
RecomputeAlienSpeed(STRATEGYBLOCK * sbPtr)1749 void RecomputeAlienSpeed(STRATEGYBLOCK *sbPtr) {
1750
1751 ALIEN_STATUS_BLOCK *alienStatusPointer;
1752 int factor,basespeed;
1753
1754 LOCALASSERT(sbPtr);
1755 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1756 LOCALASSERT(alienStatusPointer);
1757
1758 /* Change max speed. */
1759 factor=GetAlienSpeedFactor_ForSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard);
1760
1761 switch (alienStatusPointer->Type) {
1762 case AT_Standard:
1763 default:
1764 basespeed=ALIEN_FORWARDVELOCITY;
1765 break;
1766 case AT_Predalien:
1767 basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR);
1768 break;
1769 case AT_Praetorian:
1770 /* Could this be dependent on crouching? */
1771 if (alienStatusPointer->IAmCrouched) {
1772 basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_CRAWLSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR));
1773 } else {
1774 basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR));
1775 }
1776 break;
1777 }
1778
1779 alienStatusPointer->MaxSpeed=MUL_FIXED(factor,basespeed);
1780
1781 }
1782
1783 /* Wounding effect function... */
1784
GetAlienSpeedFactor(STRATEGYBLOCK * sbPtr)1785 int GetAlienSpeedFactor(STRATEGYBLOCK *sbPtr) {
1786
1787 ALIEN_STATUS_BLOCK *alienStatusPointer;
1788 HMODEL_SEQUENCE_TYPES sequence_type;
1789 int subsequence;
1790
1791 LOCALASSERT(sbPtr);
1792 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1793 LOCALASSERT(alienStatusPointer);
1794
1795 sequence_type=(HMODEL_SEQUENCE_TYPES)alienStatusPointer->HModelController.Sequence_Type;
1796 subsequence=alienStatusPointer->HModelController.Sub_Sequence;
1797 /* That is what the controller thinks the shape is playing. */
1798
1799 return(GetAlienSpeedFactor_ForSequence(sbPtr,sequence_type,subsequence));
1800
1801 }
1802
GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES sequence_type,int subsequence)1803 int GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES sequence_type,int subsequence) {
1804
1805 ALIEN_STATUS_BLOCK *alienStatusPointer;
1806 int factor,factortype;
1807
1808 LOCALASSERT(sbPtr);
1809 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
1810 LOCALASSERT(alienStatusPointer);
1811
1812 factortype=-1;
1813
1814 switch (sequence_type) {
1815
1816 case HMSQT_AlienRun:
1817 switch ((ALIENRUN_SUBSEQUENCES)subsequence) {
1818 case ARSS_Standard:
1819 factortype=2;
1820 break;
1821 case ARSS_Attack_Swipe:
1822 case ARSS_Jump:
1823 factortype=1;
1824 break;
1825 case ARSS_Dies:
1826 factortype=0;
1827 break;
1828 default:
1829 GLOBALASSERT(0);
1830 break;
1831 }
1832 break;
1833 case HMSQT_AlienCrawl:
1834 switch ((ALIENCRAWL_SUBSEQUENCES)subsequence) {
1835 case ACSS_Standard:
1836 case ACSS_Crawl_Hurt:
1837 case ACSS_Scamper:
1838 factortype=2;
1839 break;
1840 case ACSS_Attack_Bite:
1841 case ACSS_Attack_Tail:
1842 factortype=1;
1843 break;
1844 case ACSS_Dies:
1845 case ACSS_Pain_Fall_Fwd:
1846 case ACSS_Pain_Fall_Back:
1847 case ACSS_Pain_Fall_Left:
1848 case ACSS_Pain_Fall_Right:
1849 case ACSS_Boom_Fall_Fwd:
1850 case ACSS_Boom_Fall_Back:
1851 case ACSS_Boom_Fall_Left:
1852 case ACSS_Boom_Fall_Right:
1853 factortype=0;
1854 break;
1855 default:
1856 GLOBALASSERT(0);
1857 break;
1858 }
1859 break;
1860 case HMSQT_AlienStand:
1861 switch ((ALIENSTAND_SUBSEQUENCES)subsequence) {
1862 case ASSS_Taunt:
1863 case ASSS_Taunt2:
1864 case ASSS_Taunt3:
1865 case ASSS_Fear:
1866 case ASSS_Standard:
1867 case ASSS_FidgetA:
1868 case ASSS_FidgetB:
1869 case ASSS_Attack_Right_Swipe_In:
1870 case ASSS_Attack_Left_Swipe_In:
1871 case ASSS_Attack_Both_In:
1872 case ASSS_Attack_Both_Down:
1873 case ASSS_Attack_Bite:
1874 case ASSS_Attack_Tail:
1875 case ASSS_Attack_Low_Left_Swipe:
1876 case ASSS_Attack_Low_Right_Swipe:
1877 case ASSS_Feed:
1878 case ASSS_Unfurl:
1879 case ASSS_Dormant:
1880 factortype=1;
1881 break;
1882 case ASSS_Dies:
1883 case ASSS_Pain_Fall_Fwd:
1884 case ASSS_Pain_Fall_Back:
1885 case ASSS_Pain_Fall_Left:
1886 case ASSS_Pain_Fall_Right:
1887 case ASSS_Boom_Fall_Fwd:
1888 case ASSS_Boom_Fall_Back:
1889 case ASSS_Boom_Fall_Left:
1890 case ASSS_Boom_Fall_Right:
1891 case ASSS_Spin_Clockwise:
1892 case ASSS_Spin_Anticlockwise:
1893 case ASSS_BurningDeath:
1894 factortype=0;
1895 break;
1896 default:
1897 GLOBALASSERT(0);
1898 break;
1899 }
1900 break;
1901 case HMSQT_AlienCrouch:
1902 switch ((ALIENCROUCH_SUBSEQUENCES)subsequence) {
1903 case ACrSS_Standard:
1904 factortype=2;
1905 break;
1906 case ACrSS_Attack_Bite:
1907 case ACrSS_Attack_Tail:
1908 case ACrSS_Attack_Swipe:
1909 case ACrSS_Pounce:
1910 case ACrSS_Taunt:
1911 factortype=1;
1912 break;
1913 case ACrSS_Dies:
1914 case ACrSS_Dies_Thrash:
1915 factortype=0;
1916 break;
1917 default:
1918 GLOBALASSERT(0);
1919 break;
1920 }
1921 break;
1922 case HMSQT_Hugger:
1923 default:
1924 /* Nooooo! */
1925 GLOBALASSERT(0);
1926 break;
1927 }
1928
1929 LOCALASSERT(factortype!=-1);
1930
1931 switch (factortype) {
1932 case 0:
1933 return(ONE_FIXED);
1934 break;
1935 case 1:
1936 {
1937 /* Affected by alien type. */
1938 int prefactor;
1939
1940 switch (alienStatusPointer->Type) {
1941 case AT_Standard:
1942 prefactor=ONE_FIXED;
1943 break;
1944 case AT_Predalien:
1945 prefactor=PREDALIEN_SPEED_FACTOR;
1946 break;
1947 case AT_Praetorian:
1948 prefactor=PRAETORIAN_SPEED_FACTOR;
1949 break;
1950 default:
1951 GLOBALASSERT(0);
1952 break;
1953 }
1954
1955 return(prefactor);
1956
1957 }
1958 break;
1959 case 2:
1960 {
1961 /* More complex. Affected by alien type and health. */
1962 NPC_DATA *NpcData;
1963 int prefactor;
1964
1965 switch (alienStatusPointer->Type) {
1966 case AT_Standard:
1967 NpcData=GetThisNpcData(I_NPC_Alien);
1968 prefactor=ONE_FIXED;
1969 break;
1970 case AT_Predalien:
1971 NpcData=GetThisNpcData(I_NPC_PredatorAlien);
1972 prefactor=PREDALIEN_SPEED_FACTOR;
1973 break;
1974 case AT_Praetorian:
1975 NpcData=GetThisNpcData(I_NPC_PraetorianGuard);
1976 prefactor=PRAETORIAN_SPEED_FACTOR;
1977 break;
1978 default:
1979 GLOBALASSERT(0);
1980 break;
1981 }
1982
1983 LOCALASSERT(NpcData);
1984
1985 factor=sbPtr->SBDamageBlock.Health/NpcData->StartingStats.Health;
1986 /* ONE_FIXED shift already included. */
1987 LOCALASSERT(factor<=ONE_FIXED);
1988
1989 factor+=ONE_FIXED;
1990 factor>>=1;
1991
1992 /* Wounding effects. */
1993 if (alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) {
1994 /* Missing a leg. */
1995 factor-=(ONE_FIXED/3);
1996 } else if ((alienStatusPointer->Wounds§ion_flag_left_foot)
1997 &&(alienStatusPointer->Wounds§ion_flag_right_foot)) {
1998 /* Missing both feet. */
1999 factor-=(ONE_FIXED>>2);
2000 } else if ((alienStatusPointer->Wounds§ion_flag_left_foot)
2001 ||(alienStatusPointer->Wounds§ion_flag_right_foot)) {
2002 /* Missing one foot. */
2003 factor-=(ONE_FIXED>>3);
2004 }
2005
2006 if (factor<(ONE_FIXED>>3)) {
2007 factor=(ONE_FIXED>>3);
2008 }
2009
2010 if (prefactor!=ONE_FIXED) {
2011 factor=MUL_FIXED(prefactor,factor);
2012 }
2013
2014 return(factor);
2015 }
2016 break;
2017 default:
2018 GLOBALASSERT(0);
2019 break;
2020 }
2021
2022 return(0);
2023
2024 }
2025
Alien_TargetFilter(STRATEGYBLOCK * candidate)2026 int Alien_TargetFilter(STRATEGYBLOCK *candidate) {
2027
2028 switch (candidate->I_SBtype) {
2029 case I_BehaviourAlienPlayer:
2030 case I_BehaviourMarinePlayer:
2031 case I_BehaviourPredatorPlayer:
2032 {
2033 if (Observer) {
2034 return(0);
2035 }
2036
2037 if(AvP.Network != I_No_Network)
2038 {
2039 //In multiplayer games we don't want the aliens to be going after
2040 //the host once he's dead.
2041 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (candidate->SBdataptr);
2042 if(!playerStatusPtr->IsAlive)
2043 {
2044 return(0);
2045 }
2046 }
2047
2048 switch(AvP.PlayerType)
2049 {
2050 case I_Marine:
2051 case I_Predator:
2052 return(1);
2053 break;
2054 case I_Alien:
2055 return(0);
2056 break;
2057 default:
2058 GLOBALASSERT(0);
2059 return(0);
2060 break;
2061 }
2062 break;
2063 }
2064 case I_BehaviourDummy:
2065 {
2066 DUMMY_STATUS_BLOCK *dummyStatusPointer;
2067 dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr);
2068 LOCALASSERT(dummyStatusPointer);
2069 switch (dummyStatusPointer->PlayerType) {
2070 case I_Marine:
2071 case I_Predator:
2072 return(1);
2073 break;
2074 case I_Alien:
2075 return(0);
2076 break;
2077 default:
2078 GLOBALASSERT(0);
2079 return(0);
2080 break;
2081 }
2082 break;
2083 }
2084 case I_BehaviourQueenAlien:
2085 case I_BehaviourFaceHugger:
2086 case I_BehaviourAlien:
2087 {
2088 return(0);
2089 break;
2090 }
2091 case I_BehaviourPredator:
2092 case I_BehaviourXenoborg:
2093 case I_BehaviourMarine:
2094 case I_BehaviourSeal:
2095 case I_BehaviourPredatorAlien:
2096 /* Valid. */
2097 return(1);
2098 break;
2099 case I_BehaviourNetGhost:
2100 {
2101 NETGHOSTDATABLOCK *dataptr;
2102 dataptr=candidate->SBdataptr;
2103 switch (dataptr->type) {
2104 case I_BehaviourMarinePlayer:
2105 case I_BehaviourPredatorPlayer:
2106 return(1);
2107 //return(0);
2108 break;
2109 case I_BehaviourAlienPlayer:
2110 default:
2111 return(0);
2112 break;
2113 }
2114 }
2115 break;
2116 default:
2117 return(0);
2118 break;
2119 }
2120
2121 }
2122
Alien_GetNewTarget(VECTORCH * alienpos,STRATEGYBLOCK * me)2123 STRATEGYBLOCK *Alien_GetNewTarget(VECTORCH *alienpos, STRATEGYBLOCK *me) {
2124
2125 int neardist;
2126 STRATEGYBLOCK *nearest;
2127 int a;
2128 STRATEGYBLOCK *candidate;
2129 MODULE *dmod;
2130
2131 dmod=ModuleFromPosition(alienpos,playerPherModule);
2132
2133 LOCALASSERT(dmod);
2134
2135 nearest=NULL;
2136 neardist=ONE_FIXED;
2137
2138 for (a=0; a<NumActiveStBlocks; a++) {
2139 candidate=ActiveStBlockList[a];
2140 if (candidate!=me) {
2141 if (candidate->DynPtr) {
2142 if (Alien_TargetFilter(candidate)) {
2143 VECTORCH offset;
2144 int dist;
2145
2146 offset.vx=alienpos->vx-candidate->DynPtr->Position.vx;
2147 offset.vy=alienpos->vy-candidate->DynPtr->Position.vy;
2148 offset.vz=alienpos->vz-candidate->DynPtr->Position.vz;
2149
2150 dist=Approximate3dMagnitude(&offset);
2151 /* Preferentially ignore predators? */
2152 if (candidate->I_SBtype==I_BehaviourPredator) {
2153 dist<<=2;
2154 }
2155
2156 if (dist<neardist) {
2157 /* Check visibility? */
2158 //if (candidate->SBdptr) {
2159 if (!NPC_IsDead(candidate)) {
2160 if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
2161 nearest=candidate;
2162 neardist=dist;
2163 }
2164 }
2165 //}
2166 }
2167 }
2168 }
2169 }
2170 }
2171
2172 #if 0
2173 if (nearest==NULL) {
2174 if (Alien_TargetFilter(Player->ObStrategyBlock)) {
2175 nearest=Player->ObStrategyBlock;
2176 } else {
2177 nearest=NULL; /* Erk! */
2178 }
2179 }
2180 #endif
2181
2182 return(nearest);
2183
2184 }
2185
Alien_Awaken(STRATEGYBLOCK * sbPtr)2186 void Alien_Awaken(STRATEGYBLOCK *sbPtr) {
2187
2188 ALIEN_STATUS_BLOCK *alienStatusPointer;
2189
2190 LOCALASSERT(sbPtr);
2191 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
2192 LOCALASSERT(alienStatusPointer);
2193
2194 alienStatusPointer->BehaviourState = ABS_Awakening;
2195
2196 if(HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienStand,ASSS_Unfurl)) {
2197 SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Unfurl,-1,(ONE_FIXED>>2));
2198 } else {
2199 SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Standard,(ONE_FIXED),(ONE_FIXED>>2));
2200 }
2201 alienStatusPointer->HModelController.LoopAfterTweening=0;
2202
2203 }
2204
2205
Alien_GoToApproach(STRATEGYBLOCK * sbPtr)2206 void Alien_GoToApproach(STRATEGYBLOCK *sbPtr) {
2207
2208 ALIEN_STATUS_BLOCK *alienStatusPointer;
2209
2210 LOCALASSERT(sbPtr);
2211 alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
2212 LOCALASSERT(alienStatusPointer);
2213
2214 NPC_InitMovementData(&(alienStatusPointer->moveData));
2215 alienStatusPointer->BehaviourState = ABS_Approach;
2216 InitWaypointManager(&alienStatusPointer->waypointManager);
2217 if(alienStatusPointer->IAmCrouched) {
2218 SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1);
2219 } else {
2220 SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1);
2221 }
2222 RecomputeAlienSpeed(sbPtr);
2223 alienStatusPointer->CurveTimeOut = 0;
2224 alienStatusPointer->NearStateTimer = 0;
2225
2226 }
2227
AlienIsCrawling(STRATEGYBLOCK * sbPtr)2228 int AlienIsCrawling(STRATEGYBLOCK *sbPtr) {
2229
2230 /* For external calls. */
2231
2232 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2233 LOCALASSERT(dynPtr);
2234
2235 if (sbPtr->I_SBtype!=I_BehaviourAlien) {
2236 return(0);
2237 }
2238
2239 if (dynPtr->UseStandardGravity!=0) {
2240 return(0);
2241 } else {
2242 return(1);
2243 }
2244 }
2245
2246
2247
2248 /*--------------------**
2249 ** Loading and Saving **
2250 **--------------------*/
2251 #include "savegame.h"
2252 typedef struct alien_save_block
2253 {
2254 SAVE_BLOCK_STRATEGY_HEADER header;
2255
2256 ALIEN_TYPE Type;
2257 signed char Health;
2258 int GibbFactor;
2259 int Wounds;
2260 int last_anim_length;
2261 ALIEN_BHSTATE BehaviourState;
2262 int PounceDetected;
2263 int JumpDetected;
2264 int EnablePounce;
2265
2266
2267 int incidentFlag;
2268 int incidentTimer;
2269
2270 ALIEN_MISSION Mission;
2271
2272 int CurveRadius;
2273 int CurveLength;
2274 int CurveTimeOut;
2275 int FarStateTimer;
2276 int NearStateTimer;
2277 int IAmCrouched;
2278
2279
2280 int huntingModuleIndex;
2281 int currentAttackCode;
2282 // NPC_MOVEMENTDATA moveData;
2283 NPC_WANDERDATA wanderData;
2284
2285 // HMODELCONTROLLER HModelController;
2286
2287 // STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator
2288
2289 char Target_SBname[SB_NAME_LENGTH];
2290
2291 char Generator_SBname[SB_NAME_LENGTH];
2292
2293 //strategyblock stuff
2294 int integrity;
2295 DAMAGEBLOCK SBDamageBlock;
2296 DYNAMICSBLOCK dynamics;
2297 }ALIEN_SAVE_BLOCK;
2298
2299
2300
2301 //defines for load/save macros
2302 #define SAVELOAD_BLOCK block
2303 #define SAVELOAD_BEHAV alienStatusPointer
2304
2305
LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER * header)2306 void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header)
2307 {
2308 STRATEGYBLOCK* sbPtr;
2309 ALIEN_STATUS_BLOCK* alienStatusPointer;
2310 ALIEN_SAVE_BLOCK* block = (ALIEN_SAVE_BLOCK*) header;
2311
2312 //check the size of the save block
2313 if(header->size!=sizeof(*block)) return;
2314
2315 //find the existing strategy block
2316 sbPtr = FindSBWithName(header->SBname);
2317
2318 if(sbPtr)
2319 {
2320 //make sure the strategy found is of the right type
2321 if(sbPtr->I_SBtype != I_BehaviourAlien) return;
2322 }
2323 else
2324 {
2325 //we will have to generate an alien then
2326 TOOLS_DATA_ALIEN tda;
2327
2328 //make sure the alien is in a module
2329 if(!ModuleFromPosition(&block->dynamics.Position,NULL)) return;
2330
2331 sbPtr = CreateActiveStrategyBlock();
2332 if(!sbPtr) return;
2333
2334 sbPtr->I_SBtype = I_BehaviourAlien;
2335 sbPtr->shapeIndex = 0;
2336 sbPtr->maintainVisibility = 1;
2337 COPY_NAME(sbPtr->SBname,block->header.SBname);
2338
2339 //create using a fake tools data
2340 tda.position = block->dynamics.Position;
2341 tda.shapeIndex = 0;
2342 COPY_NAME(tda.nameID,block->header.SBname);
2343 COPY_NAME(tda.death_target_ID,Null_Name);
2344 tda.type = block->Type;
2345 tda.start_inactive = 0;
2346
2347 tda.starteuler.EulerX = 0;
2348 tda.starteuler.EulerY = 0;
2349 tda.starteuler.EulerZ = 0;
2350
2351 EnableBehaviourType(sbPtr,I_BehaviourAlien , &tda );
2352
2353 }
2354
2355
2356 alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr;
2357
2358 //start copying stuff
2359
2360 COPYELEMENT_LOAD(Type)
2361 COPYELEMENT_LOAD(Health)
2362 COPYELEMENT_LOAD(GibbFactor)
2363 COPYELEMENT_LOAD(Wounds)
2364 COPYELEMENT_LOAD(last_anim_length)
2365 COPYELEMENT_LOAD(BehaviourState)
2366 COPYELEMENT_LOAD(PounceDetected)
2367 COPYELEMENT_LOAD(JumpDetected)
2368 COPYELEMENT_LOAD(EnablePounce)
2369 COPYELEMENT_LOAD(incidentFlag)
2370 COPYELEMENT_LOAD(incidentTimer)
2371 COPYELEMENT_LOAD(Mission)
2372 COPYELEMENT_LOAD(CurveRadius)
2373 COPYELEMENT_LOAD(CurveLength)
2374 COPYELEMENT_LOAD(CurveTimeOut)
2375 COPYELEMENT_LOAD(FarStateTimer)
2376 COPYELEMENT_LOAD(NearStateTimer)
2377 COPYELEMENT_LOAD(IAmCrouched)
2378 COPYELEMENT_LOAD(wanderData)
2379
2380 //load target
2381 COPY_NAME(alienStatusPointer->Target_SBname,block->Target_SBname);
2382 alienStatusPointer->Target = FindSBWithName(alienStatusPointer->Target_SBname);
2383
2384 //load hunting module
2385 if(block->huntingModuleIndex>=0 && block->huntingModuleIndex< AIModuleArraySize)
2386 {
2387 alienStatusPointer->huntingModule = &AIModuleArray[block->huntingModuleIndex];
2388 }
2389 else
2390 {
2391 alienStatusPointer->huntingModule = NULL;
2392 }
2393
2394 //get the alien's attack from the attack code
2395 alienStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode);
2396
2397 *sbPtr->DynPtr = block->dynamics;
2398 sbPtr->integrity = block->integrity;
2399 sbPtr->SBDamageBlock = block->SBDamageBlock;
2400
2401 //find the alien's generator
2402 alienStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname);
2403
2404 //load the aliens hierarchy
2405 {
2406 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
2407 if(hier_header)
2408 {
2409 LoadHierarchy(hier_header,&alienStatusPointer->HModelController);
2410 }
2411 }
2412
2413 Load_SoundState(&alienStatusPointer->soundHandle);
2414 Load_SoundState(&alienStatusPointer->soundHandle2);
2415 }
2416
2417
SaveStrategy_Alien(STRATEGYBLOCK * sbPtr)2418 void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr)
2419 {
2420 ALIEN_SAVE_BLOCK *block;
2421 ALIEN_STATUS_BLOCK* alienStatusPointer;
2422
2423
2424 alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr;
2425
2426 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
2427
2428 //start copying stuff
2429
2430 COPYELEMENT_SAVE(Type)
2431 COPYELEMENT_SAVE(Health)
2432 COPYELEMENT_SAVE(GibbFactor)
2433 COPYELEMENT_SAVE(Wounds)
2434 COPYELEMENT_SAVE(last_anim_length)
2435 COPYELEMENT_SAVE(BehaviourState)
2436 COPYELEMENT_SAVE(PounceDetected)
2437 COPYELEMENT_SAVE(JumpDetected)
2438 COPYELEMENT_SAVE(EnablePounce)
2439 COPYELEMENT_SAVE(incidentFlag)
2440 COPYELEMENT_SAVE(incidentTimer)
2441 COPYELEMENT_SAVE(Mission)
2442 COPYELEMENT_SAVE(CurveRadius)
2443 COPYELEMENT_SAVE(CurveLength)
2444 COPYELEMENT_SAVE(CurveTimeOut)
2445 COPYELEMENT_SAVE(FarStateTimer)
2446 COPYELEMENT_SAVE(NearStateTimer)
2447 COPYELEMENT_SAVE(IAmCrouched)
2448 COPYELEMENT_SAVE(wanderData)
2449
2450
2451 //save target
2452 COPY_NAME(block->Target_SBname,alienStatusPointer->Target_SBname);
2453
2454 //save hunting module
2455 if(alienStatusPointer->huntingModule)
2456 {
2457 block->huntingModuleIndex = alienStatusPointer->huntingModule->m_index;
2458 }
2459 else
2460 {
2461 block->huntingModuleIndex = -1;
2462 }
2463
2464 //save attack code
2465 if(alienStatusPointer->current_attack)
2466 {
2467 block->currentAttackCode = alienStatusPointer->current_attack->Unique_Code;
2468 }
2469 else
2470 {
2471 block->currentAttackCode = -1;
2472 }
2473
2474 //save the alien's generator name
2475 if(alienStatusPointer->generator_sbptr)
2476 {
2477 COPY_NAME(block->Generator_SBname,alienStatusPointer->generator_sbptr->SBname);
2478 }
2479 else
2480 {
2481 COPY_NAME(block->Generator_SBname,Null_Name);
2482 }
2483
2484
2485 block->dynamics = *sbPtr->DynPtr;
2486 block->dynamics.CollisionReportPtr=0;
2487
2488 block->integrity = sbPtr->integrity;
2489 block->SBDamageBlock = sbPtr->SBDamageBlock;
2490
2491 //save the aliens hierarchy
2492 SaveHierarchy(&alienStatusPointer->HModelController);
2493
2494 Save_SoundState(&alienStatusPointer->soundHandle);
2495 Save_SoundState(&alienStatusPointer->soundHandle2);
2496 }
2497