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&section_flag_left_arm)
1476 							||(Section->sempai->flags&section_flag_left_hand)) {
1477 
1478 							CrouchSubSequence=ACrSS_Hit_Left;
1479 							StandSubSequence=ASSS_Hit_Left;
1480 						} else if ((Section->sempai->flags&section_flag_right_arm)
1481 							||(Section->sempai->flags&section_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&section_data_notreal)
1621 			&&(chest->flags&section_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&section_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&section_flag_left_foot)
1997 					&&(alienStatusPointer->Wounds&section_flag_right_foot)) {
1998 					/* Missing both feet. */
1999 					factor-=(ONE_FIXED>>2);
2000 				} else if ((alienStatusPointer->Wounds&section_flag_left_foot)
2001 					||(alienStatusPointer->Wounds&section_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