1 /* Patrick 4/7/97 ----------------------------------------------------
2   Source file for Xenoborg AI behaviour functions....
3   --------------------------------------------------------------------*/
4 
5 /* ChrisF 6/7/98.  Hopeless.  I'll have to take off and nuke the
6  entire site from orbit. */
7 #include "3dc.h"
8 
9 #include "inline.h"
10 #include "module.h"
11 #include "stratdef.h"
12 #include "gamedef.h"
13 #include "bh_types.h"
14 #include "comp_shp.h"
15 #include "dynblock.h"
16 #include "dynamics.h"
17 #include "pfarlocs.h"
18 #include "pvisible.h"
19 #include "bh_pred.h"
20 #include "bh_xeno.h"
21 #include "lighting.h"
22 #include "bh_weap.h"
23 #include "weapons.h"
24 #include "bh_debri.h"
25 #include "plat_shp.h"
26 #include "particle.h"
27 #include "ai_sight.h"
28 #include "sequnces.h"
29 #include "huddefs.h"
30 #include "showcmds.h"
31 #include "sfx.h"
32 #include "bh_marin.h"
33 #include "bh_far.h"
34 #include "pldghost.h"
35 #include "pheromon.h"
36 #include "targeting.h"
37 #include "dxlog.h"
38 #include "los.h"
39 #include "bh_alien.h"
40 #include "bh_corpse.h"
41 #include "bh_dummy.h"
42 #include "game_statistics.h"
43 
44 #define UseLocalAssert Yes
45 #include "ourasert.h"
46 
47 #include "psnd.h"
48 
49 #define XENO_SENTRYTIME	(20)
50 #define FAR_XENO_ACTIVITY	0
51 #define FAR_XENO_FIRING		0
52 
53 #define XENO_WALKING_ANIM_SPEED	(ONE_FIXED<<1)
54 #define XENO_TURNING_ANIM_SPEED	(ONE_FIXED<<1)
55 
56 /* external global variables used in this file */
57 extern int ModuleArraySize;
58 extern char *ModuleCurrVisArray;
59 extern int NormalFrameTime;
60 extern unsigned char Null_Name[8];
61 
62 VECTORCH null_vec={0,0,0};
63 
64 extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name);
65 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
66 extern void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer);
67 
68 int ShowXenoStats=0;
69 
70 int RATweak=40;
71 
72 void EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime);
73 void SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime);
74 void SetXenoborgShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length);
75 void XenoborgHandleMovingAnimation(STRATEGYBLOCK *sbPtr);
76 
77 static void ComputeDeltaValues(STRATEGYBLOCK *sbPtr);
78 static void KillXeno(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming);
79 void CreateXenoborg(VECTORCH *Position,int type);
80 void Xenoborg_ActivateAllDeltas(STRATEGYBLOCK *sbPtr);
81 void Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK *sbPtr);
82 STRATEGYBLOCK *Xenoborg_GetNewTarget(VECTORCH *xenopos, STRATEGYBLOCK *me);
83 void Xenoborg_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint);
84 void Xeno_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr);
85 int Xeno_Activation_Test(STRATEGYBLOCK *sbPtr);
86 
87 void Xeno_HeadMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate);
88 void Xeno_HeadMovement_ScanUpDown(STRATEGYBLOCK *sbPtr,int rate);
89 void Xeno_LeftArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate);
90 void Xeno_LeftArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate);
91 void Xeno_RightArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate);
92 void Xeno_RightArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate);
93 void Xeno_TorsoMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate);
94 void Xeno_LeftArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate);
95 void Xeno_RightArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate);
96 void Xeno_TorsoMovement_TrackToAngle(STRATEGYBLOCK *sbPtr,int rate,int in_anglex);
97 
98 void Xenoborg_MaintainLeftGun(STRATEGYBLOCK *sbPtr);
99 void Xenoborg_MaintainRightGun(STRATEGYBLOCK *sbPtr);
100 void Xeno_MaintainLasers(STRATEGYBLOCK *sbPtr);
101 void Xeno_SwitchLED(STRATEGYBLOCK *sbPtr,int state);
102 void Xeno_Stomp(STRATEGYBLOCK *sbPtr);
103 void Xeno_MaintainSounds(STRATEGYBLOCK *sbPtr);
104 
105 int Xeno_HeadMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley);
106 void Xeno_TorsoMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex);
107 int Xeno_LeftArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley);
108 int Xeno_RightArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley);
109 void Xeno_TorsoMovement_Centre(STRATEGYBLOCK *sbPtr,int rate);
110 void Xeno_LeftArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate);
111 void Xeno_RightArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate);
112 void Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK *sbPtr);
113 
114 void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr);
115 void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr);
116 void Xeno_Enter_ActiveWait_State(STRATEGYBLOCK *sbPtr);
117 void Xeno_Enter_Dormant_State(STRATEGYBLOCK *sbPtr);
118 void Xeno_Enter_TurnToFace_State(STRATEGYBLOCK *sbPtr);
119 void Xeno_Enter_Following_State(STRATEGYBLOCK *sbPtr);
120 void Xeno_Enter_Returning_State(STRATEGYBLOCK *sbPtr);
121 void Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK *sbPtr);
122 
123 void Execute_Xeno_Dying(STRATEGYBLOCK *sbPtr);
124 void Execute_Xeno_Inactive(STRATEGYBLOCK *sbPtr);
125 void Execute_Xeno_PowerUp(STRATEGYBLOCK *sbPtr);
126 void Execute_Xeno_PowerDown(STRATEGYBLOCK *sbPtr);
127 void Execute_Xeno_ActiveWait(STRATEGYBLOCK *sbPtr);
128 void Execute_Xeno_TurnToFace(STRATEGYBLOCK *sbPtr);
129 void Execute_Xeno_Follow(STRATEGYBLOCK *sbPtr);
130 void Execute_Xeno_Return(STRATEGYBLOCK *sbPtr);
131 void Execute_Xeno_Avoidance(STRATEGYBLOCK *sbPtr);
132 void Execute_Xeno_ShootTheRoof(STRATEGYBLOCK *sbPtr);
133 
134 void Execute_Xeno_ActiveWait_Far(STRATEGYBLOCK *sbPtr);
135 void Execute_Xeno_TurnToFace_Far(STRATEGYBLOCK *sbPtr);
136 void Execute_Xeno_Follow_Far(STRATEGYBLOCK *sbPtr);
137 void Execute_Xeno_Return_Far(STRATEGYBLOCK *sbPtr);
138 void Execute_Xeno_Avoidance_Far(STRATEGYBLOCK *sbPtr);
139 
140 int XenoActivation_FrustrumReject(VECTORCH *localOffset);
141 
142 /* Begin Code! */
143 
CastXenoborg(void)144 void CastXenoborg(void) {
145 
146 	#define BOTRANGE 2000
147 
148 	VECTORCH position;
149 
150 	if (AvP.Network!=I_No_Network) {
151 		NewOnScreenMessage("NO XENOBORGS IN MULTIPLAYER MODE");
152 		return;
153 	}
154 
155 	position=Player->ObStrategyBlock->DynPtr->Position;
156 	position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
157 	position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
158 	position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
159 
160 	CreateXenoborg(&position, 0);
161 
162 }
163 
CreateXenoborg(VECTORCH * Position,int type)164 void CreateXenoborg(VECTORCH *Position,int type)
165 {
166 	STRATEGYBLOCK* sbPtr;
167 	int i;
168 
169 	/* create and initialise a strategy block */
170 	sbPtr = CreateActiveStrategyBlock();
171 	if(!sbPtr) {
172 		NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
173 		return; /* failure */
174 	}
175 	InitialiseSBValues(sbPtr);
176 
177 	sbPtr->I_SBtype = I_BehaviourXenoborg;
178 
179 	AssignNewSBName(sbPtr);
180 
181 	/* create, initialise and attach a dynamics block */
182 	sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
183 	if(sbPtr->DynPtr)
184 	{
185 		EULER zeroEuler = {0,0,0};
186 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
187 		GLOBALASSERT(dynPtr);
188       	dynPtr->PrevPosition = dynPtr->Position = *Position;
189 		dynPtr->OrientEuler = zeroEuler;
190 		CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
191 		TransposeMatrixCH(&dynPtr->OrientMat);
192 
193 		dynPtr->Mass=500; /* As opposed to 160. */
194 	}
195 	else
196 	{
197 		/* dynamics block allocation failed... */
198 		RemoveBehaviourStrategy(sbPtr);
199 		NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
200 		return;
201 	}
202 
203 	sbPtr->shapeIndex = 0;
204 
205 	sbPtr->maintainVisibility = 1;
206 	sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
207 
208 	/* create, initialise and attach an alien data block */
209 	sbPtr->SBdataptr = (void *)AllocateMem(sizeof(XENO_STATUS_BLOCK));
210 	if(sbPtr->SBdataptr)
211 	{
212 		SECTION *root_section;
213 		XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbPtr->SBdataptr;
214 
215 		NPC_InitMovementData(&(xenoStatus->moveData));
216 		NPC_InitWanderData(&(xenoStatus->wanderData));
217 		InitWaypointManager(&xenoStatus->waypointManager);
218 
219 		/* Initialise xenoborg's stats */
220 		{
221 			NPC_DATA *NpcData;
222 
223 			NpcData=GetThisNpcData(I_NPC_Xenoborg);
224 			LOCALASSERT(NpcData);
225 			sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
226 			sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
227 			sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
228 		}
229 
230 		xenoStatus->behaviourState=XS_Inactive;
231 		xenoStatus->lastState=XS_Inactive;
232 		xenoStatus->Target=NULL;
233 		COPY_NAME(xenoStatus->Target_SBname,Null_Name);
234 		xenoStatus->targetTrackPos.vx=0;
235 		xenoStatus->targetTrackPos.vy=0;
236 		xenoStatus->targetTrackPos.vz=0;
237 
238 		xenoStatus->Wounds=0;
239 		xenoStatus->GibbFactor=0;
240 		xenoStatus->stateTimer=XENO_POWERDOWN_TIME;
241 		xenoStatus->my_module=sbPtr->containingModule->m_aimodule;
242 		xenoStatus->my_spot_therin=sbPtr->DynPtr->Position;
243 		{
244 			/* Pull out my_orientdir_therin. */
245 			xenoStatus->my_orientdir_therin.vx=0;
246 			xenoStatus->my_orientdir_therin.vx=0;
247 			xenoStatus->my_orientdir_therin.vz=1000;
248 
249 			RotateVector(&xenoStatus->my_orientdir_therin,&sbPtr->DynPtr->OrientMat);
250 		}
251 		xenoStatus->module_range=7;
252 		xenoStatus->UpTime=XENO_SENTRYTIME*ONE_FIXED;
253 		xenoStatus->Head_Pan=0;
254 		xenoStatus->Head_Tilt=0;
255 		xenoStatus->Left_Arm_Pan=0;
256 		xenoStatus->Left_Arm_Tilt=0;
257 		xenoStatus->Right_Arm_Pan=0;
258 		xenoStatus->Right_Arm_Tilt=0;
259 		xenoStatus->Torso_Twist=0;
260 
261 		xenoStatus->headpandir=0;
262 		xenoStatus->headtiltdir=0;
263 		xenoStatus->leftarmpandir=0;
264 		xenoStatus->leftarmtiltdir=0;
265 		xenoStatus->rightarmpandir=0;
266 		xenoStatus->rightarmtiltdir=0;
267 		xenoStatus->torsotwistdir=0;
268 
269 		xenoStatus->Old_Head_Pan=0;
270 		xenoStatus->Old_Head_Tilt=0;
271 		xenoStatus->Old_Left_Arm_Pan=0;
272 		xenoStatus->Old_Left_Arm_Tilt=0;
273 		xenoStatus->Old_Right_Arm_Pan=0;
274 		xenoStatus->Old_Right_Arm_Tilt=0;
275 		xenoStatus->Old_Torso_Twist=0;
276 
277 		xenoStatus->headLock=0;
278 		xenoStatus->leftArmLock=0;
279 		xenoStatus->rightArmLock=0;
280 		xenoStatus->targetSightTest=0;
281 		xenoStatus->IAmFar=1;
282 		xenoStatus->ShotThisFrame=0;
283 
284 		xenoStatus->obstruction.environment=0;
285 		xenoStatus->obstruction.destructableObject=0;
286 		xenoStatus->obstruction.otherCharacter=0;
287 		xenoStatus->obstruction.anySingleObstruction=0;
288 
289 		/* Init beams. */
290 		xenoStatus->LeftMainBeam.BeamIsOn = 0;
291 		xenoStatus->RightMainBeam.BeamIsOn = 0;
292 		xenoStatus->TargetingLaser[0].SourcePosition=null_vec;
293 		xenoStatus->TargetingLaser[0].TargetPosition=null_vec;
294 		xenoStatus->TargetingLaser[0].BeamHasHitPlayer=0;
295 		xenoStatus->TargetingLaser[0].BeamIsOn=0;
296 
297 		xenoStatus->TargetingLaser[1].SourcePosition=null_vec;
298 		xenoStatus->TargetingLaser[1].TargetPosition=null_vec;
299 		xenoStatus->TargetingLaser[1].BeamHasHitPlayer=0;
300 		xenoStatus->TargetingLaser[1].BeamIsOn=0;
301 
302 		xenoStatus->TargetingLaser[2].SourcePosition=null_vec;
303 		xenoStatus->TargetingLaser[2].TargetPosition=null_vec;
304 		xenoStatus->TargetingLaser[2].BeamHasHitPlayer=0;
305 		xenoStatus->TargetingLaser[2].BeamIsOn=0;
306 
307 		xenoStatus->FiringLeft=0;
308 		xenoStatus->FiringRight=0;
309 
310 		xenoStatus->UseHeadLaser=0;
311 		xenoStatus->UseLALaser=0;
312 		xenoStatus->UseRALaser=0;
313 
314 		xenoStatus->head_moving=0;
315 		xenoStatus->la_moving=0;
316 		xenoStatus->ra_moving=0;
317 		xenoStatus->torso_moving=0;
318 
319 		xenoStatus->HeadLaserOnTarget=0;
320 		xenoStatus->LALaserOnTarget=0;
321 		xenoStatus->RALaserOnTarget=0;
322 
323 		xenoStatus->soundHandle1=SOUND_NOACTIVEINDEX;
324 		xenoStatus->soundHandle2=SOUND_NOACTIVEINDEX;
325 
326 		xenoStatus->incidentFlag=0;
327 		xenoStatus->incidentTimer=0;
328 
329 		xenoStatus->head_whirr=SOUND_NOACTIVEINDEX;
330 		xenoStatus->left_arm_whirr=SOUND_NOACTIVEINDEX;
331 		xenoStatus->right_arm_whirr=SOUND_NOACTIVEINDEX;
332 		xenoStatus->torso_whirr=SOUND_NOACTIVEINDEX;
333 
334 		xenoStatus->HModelController.section_data=NULL;
335 		xenoStatus->HModelController.Deltas=NULL;
336 
337 		for(i=0;i<SB_NAME_LENGTH;i++) xenoStatus->death_target_ID[i] =0;
338 		xenoStatus->death_target_sbptr=0;
339 		xenoStatus->death_target_request=0;
340 
341 		root_section=GetNamedHierarchyFromLibrary("hnpc_xenoborg","xenobasic");
342 
343 		if (!root_section) {
344 			RemoveBehaviourStrategy(sbPtr);
345 			NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL");
346 			return;
347 		}
348 		Create_HModel(&xenoStatus->HModelController,root_section);
349 		InitHModelSequence(&xenoStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED);
350 
351 		{
352 			DELTA_CONTROLLER *delta;
353 
354 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0);
355 			GLOBALASSERT(delta);
356 			delta->timer=32767;
357 			delta->Active=0;
358 
359 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0);
360 			GLOBALASSERT(delta);
361 			delta->timer=32767;
362 			delta->Active=0;
363 
364 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Vertical_Delta,0);
365 			GLOBALASSERT(delta);
366 			delta->timer=32767;
367 			delta->Active=0;
368 
369 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmPan",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Horizontal_Delta,0);
370 			GLOBALASSERT(delta);
371 			delta->timer=32767;
372 			delta->Active=0;
373 
374 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Vertical_Delta,0);
375 			GLOBALASSERT(delta);
376 			delta->timer=32767;
377 			delta->Active=0;
378 
379 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmPan",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Horizontal_Delta,0);
380 			GLOBALASSERT(delta);
381 			delta->timer=32767;
382 			delta->Active=0;
383 
384 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"TorsoTwist",(int)HMSQT_Xenoborg,(int)XBSS_Torso_Delta,0);
385 			GLOBALASSERT(delta);
386 			delta->timer=32767;
387 			delta->Active=0;
388 
389 		}
390 
391 		/* Containment test NOW! */
392 		if(!(sbPtr->containingModule))
393 		{
394 			/* no containing module can be found... abort*/
395 			RemoveBehaviourStrategy(sbPtr);
396 			NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE");
397 			return;
398 		}
399 		LOCALASSERT(sbPtr->containingModule);
400 		Xeno_SwitchLED(sbPtr,0);
401 
402 		MakeXenoborgNear(sbPtr);
403 
404 		NewOnScreenMessage("XENOBORG CREATED");
405 	}
406 	else
407 	{
408 		/* no data block can be allocated */
409 		RemoveBehaviourStrategy(sbPtr);
410 		NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE");
411 		return;
412 	}
413 }
414 
VerifyDeltaControllers(STRATEGYBLOCK * sbPtr)415 static void VerifyDeltaControllers(STRATEGYBLOCK *sbPtr) {
416 
417 	XENO_STATUS_BLOCK *xenoStatusPointer;
418 
419 	LOCALASSERT(sbPtr);
420 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
421 	LOCALASSERT(xenoStatusPointer);
422 
423 	/* Nothing has deltas like a xenoborg does. */
424 
425 	xenoStatusPointer->head_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadPan");
426 	GLOBALASSERT(xenoStatusPointer->head_pan);
427 
428 	xenoStatusPointer->head_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadTilt");
429 	GLOBALASSERT(xenoStatusPointer->head_tilt);
430 
431 	xenoStatusPointer->left_arm_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmPan");
432 	GLOBALASSERT(xenoStatusPointer->left_arm_pan);
433 
434 	xenoStatusPointer->left_arm_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmTilt");
435 	GLOBALASSERT(xenoStatusPointer->left_arm_tilt);
436 
437 	xenoStatusPointer->right_arm_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmPan");
438 	GLOBALASSERT(xenoStatusPointer->right_arm_pan);
439 
440 	xenoStatusPointer->right_arm_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmTilt");
441 	GLOBALASSERT(xenoStatusPointer->right_arm_tilt);
442 
443 	xenoStatusPointer->torso_twist=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"TorsoTwist");
444 	GLOBALASSERT(xenoStatusPointer->torso_twist);
445 
446 }
447 
448 /* Patrick 4/7/97 ----------------------------------------------------
449   Xenoborg initialiser, visibility management, behaviour shell, and
450   damage functions
451 
452  ChrisF 6/7/98.  I don't think so...
453   --------------------------------------------------------------------*/
InitXenoborgBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)454 void InitXenoborgBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
455 {
456 	TOOLS_DATA_XENO *toolsData;
457 	int i;
458 
459 	LOCALASSERT(bhdata);
460 	toolsData = (TOOLS_DATA_XENO *)bhdata;
461 	LOCALASSERT(sbPtr);
462 
463 	/* check we're not in a net game */
464 	if(AvP.Network != I_No_Network)
465 	{
466 		RemoveBehaviourStrategy(sbPtr);
467 		return;
468 	}
469 
470 	/* make the assumption that the loader has initialised the strategy block sensibly...
471 	so just set the shapeIndex from the tools data & copy the name id*/
472 	sbPtr->shapeIndex = toolsData->shapeIndex;
473 	for(i=0;i<SB_NAME_LENGTH;i++) sbPtr->SBname[i] = toolsData->nameID[i];
474 
475 	/* create, initialise and attach a dynamics block */
476 	sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
477 	if(sbPtr->DynPtr)
478 	{
479 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
480 		GLOBALASSERT(dynPtr);
481       	dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
482 		dynPtr->OrientEuler = toolsData->starteuler;
483 		CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
484 		TransposeMatrixCH(&dynPtr->OrientMat);
485 
486 		dynPtr->Mass=1000; /* As opposed to 160. */
487 	}
488 	else
489 	{
490 		/* dynamics block allocation failed... */
491 		RemoveBehaviourStrategy(sbPtr);
492 		return;
493 	}
494 
495 	sbPtr->maintainVisibility = 1;
496 	sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
497 
498 	/* create, initialise and attach a xeno data block */
499 	sbPtr->SBdataptr = (void *)AllocateMem(sizeof(XENO_STATUS_BLOCK));
500 	if(sbPtr->SBdataptr)
501 	{
502 		SECTION *root_section;
503 		XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbPtr->SBdataptr;
504 
505 		NPC_InitMovementData(&(xenoStatus->moveData));
506 		NPC_InitWanderData(&(xenoStatus->wanderData));
507 		InitWaypointManager(&xenoStatus->waypointManager);
508 
509 		/* Initialise xenoborg's stats */
510 		{
511 			NPC_DATA *NpcData;
512 
513 			NpcData=GetThisNpcData(I_NPC_Xenoborg);
514 			LOCALASSERT(NpcData);
515 			sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
516 			sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
517 			sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
518 		}
519 
520 		xenoStatus->behaviourState=XS_Inactive;
521 		xenoStatus->lastState=XS_Inactive;
522 		xenoStatus->Target=NULL;
523 		COPY_NAME(xenoStatus->Target_SBname,Null_Name);
524 		xenoStatus->targetTrackPos.vx=0;
525 		xenoStatus->targetTrackPos.vy=0;
526 		xenoStatus->targetTrackPos.vz=0;
527 
528 		xenoStatus->Wounds=0;
529 		xenoStatus->GibbFactor=0;
530 		xenoStatus->stateTimer=XENO_POWERDOWN_TIME;
531 		xenoStatus->my_module=sbPtr->containingModule->m_aimodule;
532 		xenoStatus->my_spot_therin=sbPtr->DynPtr->Position;
533 		{
534 			/* Pull out my_orientdir_therin. */
535 			xenoStatus->my_orientdir_therin.vx=0;
536 			xenoStatus->my_orientdir_therin.vx=0;
537 			xenoStatus->my_orientdir_therin.vz=1000;
538 
539 			RotateVector(&xenoStatus->my_orientdir_therin,&sbPtr->DynPtr->OrientMat);
540 		}
541 		xenoStatus->module_range=toolsData->ModuleRange;
542 		xenoStatus->UpTime=toolsData->UpTime*ONE_FIXED;
543 		xenoStatus->Head_Pan=0;
544 		xenoStatus->Head_Tilt=0;
545 		xenoStatus->Left_Arm_Pan=0;
546 		xenoStatus->Left_Arm_Tilt=0;
547 		xenoStatus->Right_Arm_Pan=0;
548 		xenoStatus->Right_Arm_Tilt=0;
549 		xenoStatus->Torso_Twist=0;
550 
551 		xenoStatus->headpandir=0;
552 		xenoStatus->headtiltdir=0;
553 		xenoStatus->leftarmpandir=0;
554 		xenoStatus->leftarmtiltdir=0;
555 		xenoStatus->rightarmpandir=0;
556 		xenoStatus->rightarmtiltdir=0;
557 		xenoStatus->torsotwistdir=0;
558 
559 		xenoStatus->Old_Head_Pan=0;
560 		xenoStatus->Old_Head_Tilt=0;
561 		xenoStatus->Old_Left_Arm_Pan=0;
562 		xenoStatus->Old_Left_Arm_Tilt=0;
563 		xenoStatus->Old_Right_Arm_Pan=0;
564 		xenoStatus->Old_Right_Arm_Tilt=0;
565 		xenoStatus->Old_Torso_Twist=0;
566 
567 		xenoStatus->headLock=0;
568 		xenoStatus->leftArmLock=0;
569 		xenoStatus->rightArmLock=0;
570 		xenoStatus->targetSightTest=0;
571 		xenoStatus->IAmFar=1;
572 		xenoStatus->ShotThisFrame=0;
573 
574 		xenoStatus->obstruction.environment=0;
575 		xenoStatus->obstruction.destructableObject=0;
576 		xenoStatus->obstruction.otherCharacter=0;
577 		xenoStatus->obstruction.anySingleObstruction=0;
578 
579 		/* Init beams. */
580 		xenoStatus->LeftMainBeam.BeamIsOn = 0;
581 		xenoStatus->RightMainBeam.BeamIsOn = 0;
582 		xenoStatus->TargetingLaser[0].SourcePosition=null_vec;
583 		xenoStatus->TargetingLaser[0].TargetPosition=null_vec;
584 		xenoStatus->TargetingLaser[0].BeamHasHitPlayer=0;
585 		xenoStatus->TargetingLaser[0].BeamIsOn=0;
586 
587 		xenoStatus->TargetingLaser[1].SourcePosition=null_vec;
588 		xenoStatus->TargetingLaser[1].TargetPosition=null_vec;
589 		xenoStatus->TargetingLaser[1].BeamHasHitPlayer=0;
590 		xenoStatus->TargetingLaser[1].BeamIsOn=0;
591 
592 		xenoStatus->TargetingLaser[2].SourcePosition=null_vec;
593 		xenoStatus->TargetingLaser[2].TargetPosition=null_vec;
594 		xenoStatus->TargetingLaser[2].BeamHasHitPlayer=0;
595 		xenoStatus->TargetingLaser[2].BeamIsOn=0;
596 
597 		xenoStatus->FiringLeft=0;
598 		xenoStatus->FiringRight=0;
599 
600 		xenoStatus->UseHeadLaser=0;
601 		xenoStatus->UseLALaser=0;
602 		xenoStatus->UseRALaser=0;
603 
604 		xenoStatus->head_moving=0;
605 		xenoStatus->la_moving=0;
606 		xenoStatus->ra_moving=0;
607 		xenoStatus->torso_moving=0;
608 
609 		xenoStatus->HeadLaserOnTarget=0;
610 		xenoStatus->LALaserOnTarget=0;
611 		xenoStatus->RALaserOnTarget=0;
612 
613 
614 		xenoStatus->soundHandle1=SOUND_NOACTIVEINDEX;
615 		xenoStatus->soundHandle2=SOUND_NOACTIVEINDEX;
616 
617 		xenoStatus->incidentFlag=0;
618 		xenoStatus->incidentTimer=0;
619 
620 		xenoStatus->head_whirr=SOUND_NOACTIVEINDEX;
621 		xenoStatus->left_arm_whirr=SOUND_NOACTIVEINDEX;
622 		xenoStatus->right_arm_whirr=SOUND_NOACTIVEINDEX;
623 		xenoStatus->torso_whirr=SOUND_NOACTIVEINDEX;
624 
625 		xenoStatus->HModelController.section_data=NULL;
626 		xenoStatus->HModelController.Deltas=NULL;
627 
628 		for(i=0;i<SB_NAME_LENGTH;i++) xenoStatus->death_target_ID[i] = toolsData->death_target_ID[i];
629 		xenoStatus->death_target_sbptr=0;
630 		xenoStatus->death_target_request=toolsData->death_target_request;
631 
632 		root_section=GetNamedHierarchyFromLibrary("hnpc_xenoborg","xenobasic");
633 
634 		GLOBALASSERT(root_section);
635 
636 		Create_HModel(&xenoStatus->HModelController,root_section);
637 		InitHModelSequence(&xenoStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED);
638 
639 		{
640 			DELTA_CONTROLLER *delta;
641 
642 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0);
643 			GLOBALASSERT(delta);
644 			delta->timer=32767;
645 			delta->Active=0;
646 
647 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0);
648 			GLOBALASSERT(delta);
649 			delta->timer=32767;
650 			delta->Active=0;
651 
652 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Vertical_Delta,0);
653 			GLOBALASSERT(delta);
654 			delta->timer=32767;
655 			delta->Active=0;
656 
657 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmPan",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Horizontal_Delta,0);
658 			GLOBALASSERT(delta);
659 			delta->timer=32767;
660 			delta->Active=0;
661 
662 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Vertical_Delta,0);
663 			GLOBALASSERT(delta);
664 			delta->timer=32767;
665 			delta->Active=0;
666 
667 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmPan",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Horizontal_Delta,0);
668 			GLOBALASSERT(delta);
669 			delta->timer=32767;
670 			delta->Active=0;
671 
672 			delta=Add_Delta_Sequence(&xenoStatus->HModelController,"TorsoTwist",(int)HMSQT_Xenoborg,(int)XBSS_Torso_Delta,0);
673 			GLOBALASSERT(delta);
674 			delta->timer=32767;
675 			delta->Active=0;
676 
677 		}
678 
679 		/* Containment test NOW! */
680 		GLOBALASSERT(sbPtr->containingModule);
681 		Xeno_SwitchLED(sbPtr,0);
682 
683 	}
684 	else
685 	{
686 		/* no data block can be allocated */
687 		RemoveBehaviourStrategy(sbPtr);
688 		return;
689 	}
690 
691 }
692 
XenoborgBehaviour(STRATEGYBLOCK * sbPtr)693 void XenoborgBehaviour(STRATEGYBLOCK *sbPtr)
694 {
695 	XENO_STATUS_BLOCK *xenoStatusPointer;
696 	NPC_DATA *NpcData;
697 	int xenoborgIsNear;
698 
699 	LOCALASSERT(sbPtr);
700 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
701 	LOCALASSERT(xenoStatusPointer);
702 
703 	NpcData=GetThisNpcData(I_NPC_Xenoborg);
704 
705 	/* test if we've got a containing module: if we haven't, do nothing.
706 	This is important as the object could have been marked for deletion by the visibility
707 	management system...*/
708 	if(!sbPtr->containingModule)
709 	{
710 		DestroyAnyStrategyBlock(sbPtr); /* just to make sure */
711 		return;
712 	}
713 
714 	if(sbPtr->SBdptr) {
715 		xenoborgIsNear=1;
716 		LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
717 	} else {
718 		xenoborgIsNear=0;
719 	}
720 
721 	VerifyDeltaControllers(sbPtr);
722 
723 	#if 0
724 	/* zero velocity */
725 	LOCALASSERT(sbPtr->DynPtr);
726 	sbPtr->DynPtr->LinVelocity.vx = 0;
727 	sbPtr->DynPtr->LinVelocity.vy = 0;
728 	sbPtr->DynPtr->LinVelocity.vz = 0;
729 	#endif
730 
731 	InitWaypointSystem(0);
732 
733 	if (sbPtr->SBdptr) {
734 		xenoStatusPointer->IAmFar=0;
735 	} else {
736 		xenoStatusPointer->IAmFar=1;
737 	}
738 
739 	/* Store angles. */
740 	xenoStatusPointer->Old_Head_Pan			=xenoStatusPointer->Head_Pan;
741 	xenoStatusPointer->Old_Head_Tilt		=xenoStatusPointer->Head_Tilt;
742 	xenoStatusPointer->Old_Left_Arm_Pan		=xenoStatusPointer->Left_Arm_Pan;
743 	xenoStatusPointer->Old_Left_Arm_Tilt	=xenoStatusPointer->Left_Arm_Tilt;
744 	xenoStatusPointer->Old_Right_Arm_Pan	=xenoStatusPointer->Right_Arm_Pan;
745 	xenoStatusPointer->Old_Right_Arm_Tilt	=xenoStatusPointer->Right_Arm_Tilt;
746 	xenoStatusPointer->Old_Torso_Twist		=xenoStatusPointer->Torso_Twist;
747 
748 	xenoStatusPointer->head_moving=0;
749 	xenoStatusPointer->la_moving=0;
750 	xenoStatusPointer->ra_moving=0;
751 	xenoStatusPointer->torso_moving=0;
752 
753 	/* Target handling. */
754 	if (Validate_Target(xenoStatusPointer->Target,xenoStatusPointer->Target_SBname)==0) {
755 		xenoStatusPointer->Target=NULL;
756 	}
757 
758 	xenoStatusPointer->FiringLeft=0;
759 	xenoStatusPointer->FiringRight=0;
760 
761 	xenoStatusPointer->UseHeadLaser=0;
762 	xenoStatusPointer->UseLALaser=0;
763 	xenoStatusPointer->UseRALaser=0;
764 
765 	xenoStatusPointer->LeftMainBeam.BeamIsOn = 0;
766 	xenoStatusPointer->RightMainBeam.BeamIsOn = 0;
767 	xenoStatusPointer->TargetingLaser[0].BeamIsOn=0;
768 	xenoStatusPointer->TargetingLaser[1].BeamIsOn=0;
769 	xenoStatusPointer->TargetingLaser[2].BeamIsOn=0;
770 
771 	if (xenoStatusPointer->Target==NULL) {
772 		if ((xenoborgIsNear)||(xenoStatusPointer->incidentFlag)) {
773 			/* Get new target. */
774 			xenoStatusPointer->Target=Xenoborg_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr);
775 			xenoStatusPointer->targetSightTest=0;
776 			if (xenoStatusPointer->Target) {
777 				COPY_NAME(xenoStatusPointer->Target_SBname,xenoStatusPointer->Target->SBname);
778 				xenoStatusPointer->targetSightTest=1;
779 			}
780 			Xeno_UpdateTargetTrackPos(sbPtr);
781 			xenoStatusPointer->headLock=0;
782 			xenoStatusPointer->leftArmLock=0;
783 			xenoStatusPointer->rightArmLock=0;
784 		}
785 	} else if (NPCCanSeeTarget(sbPtr,xenoStatusPointer->Target,XENO_NEAR_VIEW_WIDTH)) {
786 		Xeno_UpdateTargetTrackPos(sbPtr);
787 		xenoStatusPointer->targetSightTest=1;
788 	} else {
789 		/* We have a target that we can't see. */
790 		xenoStatusPointer->headLock=0;
791 		xenoStatusPointer->leftArmLock=0;
792 		xenoStatusPointer->rightArmLock=0;
793 		xenoStatusPointer->targetSightTest=0;
794 	}
795 
796 	if (xenoStatusPointer->GibbFactor) {
797 		/* If you're gibbed, you're dead. */
798 		sbPtr->SBDamageBlock.Health = 0;
799 	}
800 
801 	/* Unset incident flag. */
802 	xenoStatusPointer->incidentFlag=0;
803 
804 	xenoStatusPointer->incidentTimer-=NormalFrameTime;
805 
806 	if (xenoStatusPointer->incidentTimer<0) {
807 		xenoStatusPointer->incidentFlag=1;
808 		xenoStatusPointer->incidentTimer=32767+(FastRandom()&65535);
809 	}
810 
811 	if (sbPtr->SBDamageBlock.IsOnFire) {
812 
813 		/* Why not? */
814 		CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL);
815 
816 		if (sbPtr->I_SBtype==I_BehaviourNetCorpse) {
817 			/* Gettin' out of here... */
818 			return;
819 		}
820 
821 		if (xenoStatusPointer->incidentFlag) {
822 			if ((FastRandom()&65535)<32767) {
823 				sbPtr->SBDamageBlock.IsOnFire=0;
824 			}
825 		}
826 
827 	}
828 
829 	/* Now, switch by state. */
830 
831 	switch (xenoStatusPointer->behaviourState) {
832 		case XS_ActiveWait:
833 			if (xenoStatusPointer->IAmFar) {
834 				Execute_Xeno_ActiveWait_Far(sbPtr);
835 			} else {
836 				Execute_Xeno_ActiveWait(sbPtr);
837 			}
838 			break;
839 		case XS_TurnToFace:
840 			if (xenoStatusPointer->IAmFar) {
841 				Execute_Xeno_TurnToFace_Far(sbPtr);
842 			} else {
843 				Execute_Xeno_TurnToFace(sbPtr);
844 			}
845 			break;
846 		case XS_Following:
847 			if (xenoStatusPointer->IAmFar) {
848 				Execute_Xeno_Follow_Far(sbPtr);
849 			} else {
850 				Execute_Xeno_Follow(sbPtr);
851 			}
852 			break;
853 		case XS_Returning:
854 			if (xenoStatusPointer->IAmFar) {
855 				Execute_Xeno_Return_Far(sbPtr);
856 			} else {
857 				Execute_Xeno_Return(sbPtr);
858 			}
859 			break;
860 		case XS_Avoidance:
861 			if (xenoStatusPointer->IAmFar) {
862 				Execute_Xeno_Avoidance_Far(sbPtr);
863 			} else {
864 				Execute_Xeno_Avoidance(sbPtr);
865 			}
866 			break;
867   		case XS_Inactive:
868 			Execute_Xeno_Inactive(sbPtr);
869 			break;
870 		case XS_Activating:
871 			Execute_Xeno_PowerUp(sbPtr);
872 			break;
873   		case XS_Deactivating:
874 			Execute_Xeno_PowerDown(sbPtr);
875 			break;
876 		case XS_Regenerating:
877 			break;
878 		case XS_Dying:
879 			Execute_Xeno_Dying(sbPtr);
880 			break;
881 		case XS_ShootingTheRoof:
882 			if (xenoStatusPointer->IAmFar) {
883 				Execute_Xeno_ShootTheRoof(sbPtr);
884 			} else {
885 				Execute_Xeno_ShootTheRoof(sbPtr);
886 			}
887 			break;
888 		default:
889 			/* No action? */
890 			break;
891 	}
892 
893 	/* if we have actually died, we need to remove the strategyblock... so
894 	do this here */
895 	if((xenoStatusPointer->behaviourState == XS_Dying)&&(xenoStatusPointer->stateTimer <= 0)) {
896 
897 		DestroyAnyStrategyBlock(sbPtr);
898 	}
899 
900 	if ((xenoStatusPointer->behaviourState!=XS_Dying)
901 		&&(xenoStatusPointer->behaviourState!=XS_Inactive)
902 		&&(xenoStatusPointer->behaviourState!=XS_Activating)
903 		&&(xenoStatusPointer->behaviourState!=XS_Deactivating)) {
904 		/* Time to regenerate? */
905 		if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-2)))
906 			&&(sbPtr->SBDamageBlock.Health>0)) {
907 			/* 25% health or less. */
908 			Xeno_Enter_PowerDown_State(sbPtr);
909 		}
910 	}
911 
912 	ComputeDeltaValues(sbPtr);
913 
914 	ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr);
915 
916 	#if (FAR_XENO_FIRING==0)
917 	if (xenoStatusPointer->IAmFar) {
918 		xenoStatusPointer->FiringLeft=0;
919 		xenoStatusPointer->FiringRight=0;
920 	}
921 	#endif
922 
923 	/* Now lets deal with the sounds. */
924 	Xeno_MaintainSounds(sbPtr);
925 
926 	if (xenoStatusPointer->IAmFar) {
927 		/* No lasers if far. */
928 		xenoStatusPointer->UseHeadLaser=0;
929 		xenoStatusPointer->UseLALaser=0;
930 		xenoStatusPointer->UseRALaser=0;
931 	}
932 
933 	/* Now consider the lasers. */
934 	Xeno_MaintainLasers(sbPtr);
935 	Xeno_Stomp(sbPtr);
936 
937 	/* Now, are we firing? */
938 	Xenoborg_MaintainLeftGun(sbPtr);
939 	Xenoborg_MaintainRightGun(sbPtr);
940 
941 	/* Unset shot flag. */
942 	xenoStatusPointer->ShotThisFrame=0;
943 }
944 
MakeXenoborgNear(STRATEGYBLOCK * sbPtr)945 void MakeXenoborgNear(STRATEGYBLOCK *sbPtr)
946 {
947 	extern MODULEMAPBLOCK AlienDefaultMap;
948 
949 	MODULE tempModule;
950 	DISPLAYBLOCK *dPtr;
951 	DYNAMICSBLOCK *dynPtr;
952 	XENO_STATUS_BLOCK *xenoStatusPointer;
953 
954 	LOCALASSERT(sbPtr);
955 	dynPtr = sbPtr->DynPtr;
956 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
957     LOCALASSERT(xenoStatusPointer);
958     LOCALASSERT(dynPtr);
959 	LOCALASSERT(sbPtr->SBdptr == NULL);
960 
961 	AlienDefaultMap.MapShape = sbPtr->shapeIndex;
962 	tempModule.m_mapptr = &AlienDefaultMap;
963 	tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
964 	tempModule.m_numlights = 0;
965 	tempModule.m_lightarray = (struct lightblock *)0;
966 	tempModule.m_extraitemdata = (struct extraitemdata *)0;
967 	tempModule.m_dptr = NULL;
968 	AllocateModuleObject(&tempModule);
969 	dPtr = tempModule.m_dptr;
970 	if(dPtr==NULL) return; /* if cannot create displayblock, leave far */
971 
972 	sbPtr->SBdptr = dPtr;
973 	dPtr->ObStrategyBlock = sbPtr;
974 	dPtr->ObMyModule = NULL;
975 
976 	/* need to initialise positional information in the new display block */
977 	dPtr->ObWorld = dynPtr->Position;
978 	dPtr->ObEuler = dynPtr->OrientEuler;
979 	dPtr->ObMat = dynPtr->OrientMat;
980 	/* zero linear velocity in dynamics block */
981 	sbPtr->DynPtr->LinVelocity.vx = 0;
982 	sbPtr->DynPtr->LinVelocity.vy = 0;
983 	sbPtr->DynPtr->LinVelocity.vz = 0;
984 
985    	/* state and sequence init */
986 	NPC_InitMovementData(&(xenoStatusPointer->moveData));
987 	InitWaypointManager(&xenoStatusPointer->waypointManager);
988 
989 	dPtr->ShapeAnimControlBlock = NULL;
990 	dPtr->ObTxAnimCtrlBlks = NULL;
991 
992 	dPtr->HModelControlBlock=&xenoStatusPointer->HModelController;
993 
994 	ProveHModel(dPtr->HModelControlBlock,dPtr);
995 
996 	xenoStatusPointer->IAmFar=0;
997 
998 	/* make a sound */
999 	//Sound_Play(SID_ALIEN_HISS,"d",&sbPtr->DynPtr->Position);
1000 }
1001 
MakeXenoborgFar(STRATEGYBLOCK * sbPtr)1002 void MakeXenoborgFar(STRATEGYBLOCK *sbPtr)
1003 {
1004 	XENO_STATUS_BLOCK *xenoStatusPointer;
1005 	int i;
1006 
1007 	LOCALASSERT(sbPtr);
1008 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1009 	LOCALASSERT(xenoStatusPointer);
1010 	LOCALASSERT(sbPtr->SBdptr != NULL);
1011 
1012 	/* get rid of the displayblock */
1013 	i = DestroyActiveObject(sbPtr->SBdptr);
1014 	LOCALASSERT(i==0);
1015 	sbPtr->SBdptr = NULL;
1016 
1017 	/* xenoborg data block init */
1018 	if(xenoStatusPointer->behaviourState != XS_Dying) {
1019    		xenoStatusPointer->stateTimer=0;
1020 	}
1021 
1022 	/* zero linear velocity in dynamics block */
1023 	sbPtr->DynPtr->LinVelocity.vx = 0;
1024 	sbPtr->DynPtr->LinVelocity.vy = 0;
1025 	sbPtr->DynPtr->LinVelocity.vz = 0;
1026 
1027 	xenoStatusPointer->IAmFar=1;
1028 
1029 }
1030 
Xenoborg_ActivateAllDeltas(STRATEGYBLOCK * sbPtr)1031 void Xenoborg_ActivateAllDeltas(STRATEGYBLOCK *sbPtr)
1032 {
1033 	XENO_STATUS_BLOCK *xenoStatusPointer;
1034 
1035 	LOCALASSERT(sbPtr);
1036 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1037 	LOCALASSERT(xenoStatusPointer);
1038 
1039 	if (xenoStatusPointer->head_pan) {
1040 		xenoStatusPointer->head_pan->Active=1;
1041 	}
1042 
1043 	if (xenoStatusPointer->head_tilt) {
1044 		xenoStatusPointer->head_tilt->Active=1;
1045 	}
1046 
1047 	if (xenoStatusPointer->left_arm_pan) {
1048 		xenoStatusPointer->left_arm_pan->Active=1;
1049 	}
1050 
1051 	if (xenoStatusPointer->left_arm_tilt) {
1052 		xenoStatusPointer->left_arm_tilt->Active=1;
1053 	}
1054 
1055 	if (xenoStatusPointer->right_arm_pan) {
1056 		xenoStatusPointer->right_arm_pan->Active=1;
1057 	}
1058 
1059 	if (xenoStatusPointer->right_arm_tilt) {
1060 		xenoStatusPointer->right_arm_tilt->Active=1;
1061 	}
1062 
1063 	if (xenoStatusPointer->torso_twist) {
1064 		xenoStatusPointer->torso_twist->Active=1;
1065 	}
1066 
1067 }
1068 
Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK * sbPtr)1069 void Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK *sbPtr)
1070 {
1071 	XENO_STATUS_BLOCK *xenoStatusPointer;
1072 
1073 	LOCALASSERT(sbPtr);
1074 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1075 	LOCALASSERT(xenoStatusPointer);
1076 
1077 	if (xenoStatusPointer->head_pan) {
1078 		xenoStatusPointer->head_pan->Active=0;
1079 	}
1080 	xenoStatusPointer->Head_Pan=0;
1081 
1082 	if (xenoStatusPointer->head_tilt) {
1083 		xenoStatusPointer->head_tilt->Active=0;
1084 	}
1085 	xenoStatusPointer->Head_Tilt=0;
1086 
1087 	if (xenoStatusPointer->left_arm_pan) {
1088 		xenoStatusPointer->left_arm_pan->Active=0;
1089 	}
1090 	xenoStatusPointer->Left_Arm_Pan=0;
1091 
1092 	if (xenoStatusPointer->left_arm_tilt) {
1093 		xenoStatusPointer->left_arm_tilt->Active=0;
1094 	}
1095 	xenoStatusPointer->Left_Arm_Tilt=0;
1096 
1097 	if (xenoStatusPointer->right_arm_pan) {
1098 		xenoStatusPointer->right_arm_pan->Active=0;
1099 	}
1100 	xenoStatusPointer->Right_Arm_Pan=0;
1101 
1102 	if (xenoStatusPointer->right_arm_tilt) {
1103 		xenoStatusPointer->right_arm_tilt->Active=0;
1104 	}
1105 	xenoStatusPointer->Right_Arm_Tilt=0;
1106 
1107 	if (xenoStatusPointer->torso_twist) {
1108 		xenoStatusPointer->torso_twist->Active=0;
1109 	}
1110 	xenoStatusPointer->Torso_Twist=0;
1111 
1112 }
1113 
XenoborgIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int wounds,VECTORCH * incoming)1114 void XenoborgIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming)
1115 {
1116 
1117 	XENO_STATUS_BLOCK *xenoStatusPointer;
1118 	LOCALASSERT(sbPtr);
1119 	LOCALASSERT(sbPtr->DynPtr);
1120 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1121 	LOCALASSERT(xenoStatusPointer);
1122 
1123 	xenoStatusPointer->Wounds|=wounds;
1124 	xenoStatusPointer->ShotThisFrame=1;
1125 
1126 	if (sbPtr->SBDamageBlock.Health <= 0) {
1127 
1128 		/* Oh yes, kill them, too. */
1129 		if (xenoStatusPointer->behaviourState!=XS_Dying) {
1130 			CurrentGameStats_CreatureKilled(sbPtr,NULL);
1131 			KillXeno(sbPtr,wounds,damage,multiple,incoming);
1132 		}
1133 	}
1134 
1135 	if (xenoStatusPointer->behaviourState==XS_Inactive) {
1136 		if (xenoStatusPointer->stateTimer>=XENO_POWERDOWN_TIME) {
1137 			/* Ow, that hurt. */
1138 			Xeno_Enter_PowerUp_State(sbPtr);
1139 		}
1140 	}
1141 
1142 	xenoStatusPointer->Target=NULL;
1143 }
1144 
1145 /* patrick 29/7/97 -----------------------------------
1146 Thess functions to be called only from behaviour
1147 ------------------------------------------------------*/
KillXeno(STRATEGYBLOCK * sbPtr,int wounds,DAMAGE_PROFILE * damage,int multiple,VECTORCH * incoming)1148 static void KillXeno(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming)
1149 {
1150 	XENO_STATUS_BLOCK *xenoStatusPointer;
1151 	int deathtype,tkd;
1152 
1153 	LOCALASSERT(sbPtr);
1154 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1155 	LOCALASSERT(xenoStatusPointer);
1156 
1157 	/* make an explosion sound */
1158     Sound_Play(SID_SENTRYGUNDEST,"d",&sbPtr->DynPtr->Position);
1159 
1160 	xenoStatusPointer->stateTimer=XENO_DYINGTIME;
1161 	xenoStatusPointer->HModelController.Looped=0;
1162 	xenoStatusPointer->HModelController.LoopAfterTweening=0;
1163 	/* switch state */
1164 	xenoStatusPointer->behaviourState=XS_Dying;
1165 
1166 	Xenoborg_DeactivateAllDeltas(sbPtr);
1167 	Xeno_SwitchLED(sbPtr,0);
1168 
1169 	if(xenoStatusPointer->death_target_sbptr)
1170 	{
1171 		RequestState(xenoStatusPointer->death_target_sbptr,xenoStatusPointer->death_target_request, 0);
1172 	}
1173 
1174 
1175 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1176 		/* Well, it shouldn't be! */
1177 		Sound_Stop(xenoStatusPointer->soundHandle1);
1178 	}
1179 	if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
1180 		/* Well, it shouldn't be! */
1181 		Sound_Stop(xenoStatusPointer->soundHandle2);
1182 	}
1183 	if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) {
1184 		/* Well, it shouldn't be! */
1185 		Sound_Stop(xenoStatusPointer->head_whirr);
1186 	}
1187 	if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) {
1188 		/* Well, it shouldn't be! */
1189 		Sound_Stop(xenoStatusPointer->left_arm_whirr);
1190 	}
1191 	if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) {
1192 		/* Well, it shouldn't be! */
1193 		Sound_Stop(xenoStatusPointer->right_arm_whirr);
1194 	}
1195 	if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) {
1196 		/* Well, it shouldn't be! */
1197 		Sound_Stop(xenoStatusPointer->torso_whirr);
1198 	}
1199 
1200 	/* Set up gibb factor. */
1201 
1202 	tkd=TotalKineticDamage(damage);
1203 	deathtype=0;
1204 
1205 	if (tkd>40) {
1206 	 	/* Explosion case. */
1207 	 	if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
1208 	 		/* Okay, you can gibb now. */
1209 	 		xenoStatusPointer->GibbFactor=-(ONE_FIXED>>3);
1210 			deathtype=2;
1211 	 	}
1212 	} else if ( (multiple>>16)>1 ) {
1213 	 	int newmult;
1214 
1215 	 	newmult=DIV_FIXED(multiple,NormalFrameTime);
1216 	 	if (MUL_FIXED(tkd,newmult)>700) {
1217 	 		/* Excessive bullets case 1. */
1218 	 		xenoStatusPointer->GibbFactor=-(ONE_FIXED>>5);
1219 			deathtype=2;
1220 	 	} else if (MUL_FIXED(tkd,newmult)>250) {
1221 	 		/* Excessive bullets case 2. */
1222 	 		//xenoStatusPointer->GibbFactor=ONE_FIXED>>6;
1223 			deathtype=1;
1224 	 	}
1225 	}
1226 
1227 	if (tkd>200) {
1228 		/* Basically SADARS only. */
1229 		xenoStatusPointer->GibbFactor=-(ONE_FIXED>>2);
1230 
1231 		deathtype=3;
1232 	}
1233 
1234 	/* No gibbing for flamethrower. */
1235 
1236 	{
1237 		SECTION_DATA *chest=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"chest");
1238 
1239 		if (chest==NULL) {
1240 			/* I'm impressed. */
1241 			deathtype+=2;
1242 		} else if ((chest->flags&section_data_notreal)
1243 			&&(chest->flags&section_data_terminate_here)) {
1244 			/* That's gotta hurt. */
1245 			deathtype++;
1246 		}
1247 	}
1248 
1249 
1250 	{
1251 		DEATH_DATA *this_death;
1252 		HIT_FACING facing;
1253 
1254 		facing.Front=0;
1255 		facing.Back=0;
1256 		facing.Left=0;
1257 		facing.Right=0;
1258 
1259 		if (incoming) {
1260 			if (incoming->vz>0) {
1261 				facing.Back=1;
1262 			} else {
1263 				facing.Front=1;
1264 			}
1265 			if (incoming->vx>0) {
1266 				facing.Right=1;
1267 			} else {
1268 				facing.Left=1;
1269 			}
1270 		}
1271 
1272 		this_death=GetXenoborgDeathSequence(&xenoStatusPointer->HModelController,NULL,
1273 			xenoStatusPointer->Wounds,(xenoStatusPointer->Wounds&(
1274 			section_flag_left_leg|section_flag_right_leg|section_flag_left_foot|section_flag_right_foot)),
1275 			deathtype,&facing,0,0,0);
1276 
1277 		GLOBALASSERT(this_death);
1278 
1279 		Convert_Xenoborg_To_Corpse(sbPtr,this_death);
1280 	}
1281 
1282 }
1283 
Execute_Xeno_Dying(STRATEGYBLOCK * sbPtr)1284 void Execute_Xeno_Dying(STRATEGYBLOCK *sbPtr)
1285 {
1286 	XENO_STATUS_BLOCK *xenoStatusPointer;
1287 
1288 	LOCALASSERT(sbPtr);
1289 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1290 	LOCALASSERT(xenoStatusPointer);
1291 
1292 	{
1293 		DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
1294 		/* do we have a displayblock? */
1295 		if (dispPtr)
1296 		{
1297 			dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
1298 			dispPtr->ObFlags2 = xenoStatusPointer->stateTimer/2;
1299 			if (dispPtr->ObFlags2<ONE_FIXED) {
1300 				xenoStatusPointer->HModelController.DisableBleeding=1;
1301 			}
1302 		}
1303 	}
1304 	xenoStatusPointer->stateTimer -= NormalFrameTime;
1305 }
1306 
EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES type,int subtype,int length,int tweeningtime)1307 void EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) {
1308 
1309 	XENO_STATUS_BLOCK *xenoStatus;
1310 
1311 	xenoStatus=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1312 
1313 	if ((xenoStatus->HModelController.Sequence_Type==type)
1314 		&&(xenoStatus->HModelController.Sub_Sequence==subtype)) {
1315 		return;
1316 	} else {
1317 		SetXenoborgShapeAnimSequence_Core(sbPtr,type,subtype,length,tweeningtime);
1318 	}
1319 }
1320 
SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES type,int subtype,int length,int tweeningtime)1321 void SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime)
1322 {
1323 
1324 	XENO_STATUS_BLOCK *xenoStatus=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1325 
1326 	GLOBALASSERT(length!=0);
1327 
1328 	if (tweeningtime<=0) {
1329 		InitHModelSequence(&xenoStatus->HModelController,(int)type,subtype,length);
1330 	} else {
1331 		InitHModelTweening(&xenoStatus->HModelController, tweeningtime, (int)type,subtype,length, 1);
1332 		//xenoStatus->HModelController.ElevationTweening=1;
1333 	}
1334 
1335 	xenoStatus->HModelController.Playing=1;
1336 	/* Might be unset... */
1337 }
1338 
SetXenoborgShapeAnimSequence(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES type,int subtype,int length)1339 void SetXenoborgShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length) {
1340 
1341 	SetXenoborgShapeAnimSequence_Core(sbPtr,type,subtype,length,(ONE_FIXED>>2));
1342 
1343 }
1344 
Xenoborg_GetRelativeAngles(STRATEGYBLOCK * sbPtr,int * anglex,int * angley,VECTORCH * pivotPoint)1345 void Xenoborg_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) {
1346 
1347 	XENO_STATUS_BLOCK *xenoStatusPointer;
1348 	MATRIXCH WtoL;
1349 	VECTORCH targetPos;
1350 
1351 	LOCALASSERT(sbPtr);
1352 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1353 	LOCALASSERT(xenoStatusPointer);
1354 
1355 	/* First, extract relative angle. */
1356 
1357 	WtoL=sbPtr->DynPtr->OrientMat;
1358 	TransposeMatrixCH(&WtoL);
1359 	targetPos=xenoStatusPointer->targetTrackPos;
1360 	targetPos.vx-=pivotPoint->vx;
1361 	targetPos.vy-=pivotPoint->vy;
1362 	targetPos.vz-=pivotPoint->vz;
1363 	RotateVector(&targetPos,&WtoL);
1364 
1365 	/* Now... */
1366 	{
1367 		int offsetx,offsety,offsetz,offseta;
1368 
1369 		offsetx=(targetPos.vx);
1370 		offsety=(targetPos.vz);
1371 		offseta=-(targetPos.vy);
1372 
1373 		while( (offsetx>(ONE_FIXED>>2))
1374 			||(offsety>(ONE_FIXED>>2))
1375 			||(offseta>(ONE_FIXED>>2))
1376 			||(offsetx<-(ONE_FIXED>>2))
1377 			||(offsety<-(ONE_FIXED>>2))
1378 			||(offseta<-(ONE_FIXED>>2))) {
1379 
1380 			offsetx>>=1;
1381 			offsety>>=1;
1382 			offseta>>=1;
1383 
1384 		}
1385 
1386 		offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
1387 
1388 		if (angley) {
1389 			(*angley)=ArcTan(offseta,offsetz);
1390 
1391 			if ((*angley)>=3072) (*angley)-=4096;
1392 			if ((*angley)>=2048) (*angley)=(*angley)-3072;
1393 			if ((*angley)> 1024) (*angley)=2048-(*angley);
1394 
1395 		}
1396 		if (anglex) {
1397 			(*anglex)=ArcTan(offsetx,offsety);
1398 
1399 			if ((*anglex)>=3072) (*anglex)-=4096;
1400 			if ((*anglex)>=2048) (*anglex)=(*anglex)-4096;
1401 
1402 		}
1403 	}
1404 
1405 }
1406 
Execute_Xeno_Inactive(STRATEGYBLOCK * sbPtr)1407 void Execute_Xeno_Inactive(STRATEGYBLOCK *sbPtr)
1408 {
1409 	XENO_STATUS_BLOCK *xenoStatusPointer;
1410 	NPC_DATA *NpcData;
1411 
1412 	LOCALASSERT(sbPtr);
1413 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1414 	LOCALASSERT(xenoStatusPointer);
1415 
1416 	NpcData=GetThisNpcData(I_NPC_Xenoborg);
1417 
1418 	if (ShowXenoStats) {
1419 		PrintDebuggingText("In Inactive.\n");
1420 	}
1421 
1422 	if (!sbPtr->SBdptr) {
1423 		/* We're far... do the timer! */
1424 		ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr);
1425 	}
1426 
1427 	/* Regenerate a bit? */
1428 
1429 	if (sbPtr->SBDamageBlock.Health>0) {
1430 		int health_increment;
1431 
1432 		health_increment=DIV_FIXED((NpcData->StartingStats.Health*NormalFrameTime),XENO_REGEN_TIME);
1433 		sbPtr->SBDamageBlock.Health+=health_increment;
1434 
1435 		if (sbPtr->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
1436 			sbPtr->SBDamageBlock.Health=(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT);
1437 		}
1438 
1439 		HModel_Regen(&xenoStatusPointer->HModelController,XENO_REGEN_TIME);
1440 	}
1441 
1442 	if (xenoStatusPointer->stateTimer<XENO_POWERDOWN_TIME) {
1443 		xenoStatusPointer->stateTimer+=NormalFrameTime;
1444 	} else {
1445 		/* Tum te tum te tum. */
1446 
1447 		if (Xeno_Activation_Test(sbPtr)) {
1448 			/* Oh well, orange alert. */
1449 			Xeno_Enter_PowerUp_State(sbPtr);
1450 		}
1451 	}
1452 }
1453 
Xeno_Enter_PowerUp_State(STRATEGYBLOCK * sbPtr)1454 void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr)
1455 {
1456 	XENO_STATUS_BLOCK *xenoStatusPointer;
1457 
1458 	LOCALASSERT(sbPtr);
1459 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1460 	LOCALASSERT(xenoStatusPointer);
1461 
1462 	if (xenoStatusPointer->behaviourState!=XS_Inactive) {
1463 		/* Ha! */
1464 		return;
1465 	}
1466 
1467 	xenoStatusPointer->Target=NULL;
1468 	xenoStatusPointer->stateTimer=0;
1469 	xenoStatusPointer->behaviourState=XS_Activating;
1470 
1471 	GLOBALASSERT(xenoStatusPointer->HModelController.Sequence_Type==HMSQT_Xenoborg);
1472 	GLOBALASSERT(xenoStatusPointer->HModelController.Sub_Sequence==XBSS_Powered_Down_Standard);
1473 
1474 	SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Up,(ONE_FIXED*4),(ONE_FIXED>>2));
1475 
1476 	xenoStatusPointer->HModelController.LoopAfterTweening=0;
1477 
1478 	Xenoborg_ActivateAllDeltas(sbPtr);
1479 	Xeno_SwitchLED(sbPtr,1);
1480 
1481 	/* Now play with a sound. */
1482 
1483 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1484 		/* Well, it shouldn't be! */
1485 		Sound_Stop(xenoStatusPointer->soundHandle1);
1486 	}
1487 	if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
1488 		/* Well, it shouldn't be! */
1489 		Sound_Stop(xenoStatusPointer->soundHandle2);
1490 	}
1491 	Sound_Play(SID_POWERUP,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1492 }
1493 
Xeno_Enter_PowerDown_State(STRATEGYBLOCK * sbPtr)1494 void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr)
1495 {
1496 	XENO_STATUS_BLOCK *xenoStatusPointer;
1497 
1498 	LOCALASSERT(sbPtr);
1499 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1500 	LOCALASSERT(xenoStatusPointer);
1501 
1502 	if (xenoStatusPointer->behaviourState==XS_Inactive) {
1503 		/* Ha! */
1504 		return;
1505 	}
1506 
1507 	xenoStatusPointer->Target=NULL;
1508 	xenoStatusPointer->stateTimer=0;
1509 	xenoStatusPointer->behaviourState=XS_Deactivating;
1510 
1511 	SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2));
1512 
1513 	xenoStatusPointer->HModelController.LoopAfterTweening=0;
1514 
1515 	/* zero velocity */
1516 	LOCALASSERT(sbPtr->DynPtr);
1517 	sbPtr->DynPtr->LinVelocity.vx = 0;
1518 	sbPtr->DynPtr->LinVelocity.vy = 0;
1519 	sbPtr->DynPtr->LinVelocity.vz = 0;
1520 
1521 	Xenoborg_DeactivateAllDeltas(sbPtr);
1522 	Xeno_SwitchLED(sbPtr,0);
1523 
1524 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1525 		/* Well, it shouldn't be! */
1526 		Sound_Stop(xenoStatusPointer->soundHandle1);
1527 	}
1528 	if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
1529 		/* Stop BorgOn. */
1530 		Sound_Stop(xenoStatusPointer->soundHandle2);
1531 	}
1532 	Sound_Play(SID_POWERDN,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1533 
1534 }
1535 
Xeno_Enter_ActiveWait_State(STRATEGYBLOCK * sbPtr)1536 void Xeno_Enter_ActiveWait_State(STRATEGYBLOCK *sbPtr)
1537 {
1538 	XENO_STATUS_BLOCK *xenoStatusPointer;
1539 
1540 	LOCALASSERT(sbPtr);
1541 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1542 	LOCALASSERT(xenoStatusPointer);
1543 
1544 	xenoStatusPointer->stateTimer=0;
1545 	xenoStatusPointer->behaviourState=XS_ActiveWait;
1546 
1547 	SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2));
1548 
1549 	/* zero velocity */
1550 	LOCALASSERT(sbPtr->DynPtr);
1551 	sbPtr->DynPtr->LinVelocity.vx = 0;
1552 	sbPtr->DynPtr->LinVelocity.vy = 0;
1553 	sbPtr->DynPtr->LinVelocity.vz = 0;
1554 
1555 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1556 		/* Well, it shouldn't be! */
1557 		Sound_Stop(xenoStatusPointer->soundHandle1);
1558 	}
1559 
1560 }
1561 
Xeno_Enter_TurnToFace_State(STRATEGYBLOCK * sbPtr)1562 void Xeno_Enter_TurnToFace_State(STRATEGYBLOCK *sbPtr)
1563 {
1564 	XENO_STATUS_BLOCK *xenoStatusPointer;
1565 
1566 	LOCALASSERT(sbPtr);
1567 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1568 	LOCALASSERT(xenoStatusPointer);
1569 
1570 	xenoStatusPointer->stateTimer=0;
1571 	xenoStatusPointer->behaviourState=XS_TurnToFace;
1572 
1573 	/* Sequence handled in the behaviour. */
1574 
1575 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1576 		/* Well, it shouldn't be! */
1577 		Sound_Stop(xenoStatusPointer->soundHandle1);
1578 	}
1579 	Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1580 
1581 	/* zero velocity */
1582 	LOCALASSERT(sbPtr->DynPtr);
1583 	sbPtr->DynPtr->LinVelocity.vx = 0;
1584 	sbPtr->DynPtr->LinVelocity.vy = 0;
1585 	sbPtr->DynPtr->LinVelocity.vz = 0;
1586 
1587 }
1588 
Xeno_Enter_Following_State(STRATEGYBLOCK * sbPtr)1589 void Xeno_Enter_Following_State(STRATEGYBLOCK *sbPtr)
1590 {
1591 	XENO_STATUS_BLOCK *xenoStatusPointer;
1592 
1593 	LOCALASSERT(sbPtr);
1594 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1595 	LOCALASSERT(xenoStatusPointer);
1596 
1597 	xenoStatusPointer->stateTimer=0;
1598 	xenoStatusPointer->behaviourState=XS_Following;
1599 	InitWaypointManager(&xenoStatusPointer->waypointManager);
1600 
1601 	/* Sequence handled in the behaviour. */
1602 
1603 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1604 		/* Well, it shouldn't be! */
1605 		Sound_Stop(xenoStatusPointer->soundHandle1);
1606 	}
1607 	Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1608 
1609 }
1610 
Xeno_Enter_Returning_State(STRATEGYBLOCK * sbPtr)1611 void Xeno_Enter_Returning_State(STRATEGYBLOCK *sbPtr)
1612 {
1613 	XENO_STATUS_BLOCK *xenoStatusPointer;
1614 
1615 	LOCALASSERT(sbPtr);
1616 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1617 	LOCALASSERT(xenoStatusPointer);
1618 
1619 	xenoStatusPointer->stateTimer=0;
1620 	xenoStatusPointer->behaviourState=XS_Returning;
1621 	InitWaypointManager(&xenoStatusPointer->waypointManager);
1622 
1623 	/* Sequence handled in the behaviour. */
1624 
1625 	xenoStatusPointer->Target=NULL;
1626 	/* Forget your target, too. */
1627 
1628 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1629 		/* Well, it shouldn't be! */
1630 		Sound_Stop(xenoStatusPointer->soundHandle1);
1631 	}
1632 	Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1633 
1634 }
1635 
Xeno_Enter_Dormant_State(STRATEGYBLOCK * sbPtr)1636 void Xeno_Enter_Dormant_State(STRATEGYBLOCK *sbPtr)
1637 {
1638 	XENO_STATUS_BLOCK *xenoStatusPointer;
1639 
1640 	LOCALASSERT(sbPtr);
1641 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1642 	LOCALASSERT(xenoStatusPointer);
1643 
1644 	xenoStatusPointer->stateTimer=0;
1645 	xenoStatusPointer->behaviourState=XS_Inactive;
1646 
1647 	SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED,(ONE_FIXED>>2));
1648 
1649 	if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
1650 		/* Well, it shouldn't be! */
1651 		Sound_Stop(xenoStatusPointer->soundHandle2);
1652 	}
1653 	/* soundHandle1 might be still powering down. */
1654 
1655 	/* zero velocity */
1656 	LOCALASSERT(sbPtr->DynPtr);
1657 	sbPtr->DynPtr->LinVelocity.vx = 0;
1658 	sbPtr->DynPtr->LinVelocity.vy = 0;
1659 	sbPtr->DynPtr->LinVelocity.vz = 0;
1660 
1661 }
1662 
Xeno_Enter_Avoidance_State(STRATEGYBLOCK * sbPtr)1663 void Xeno_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) {
1664 
1665 	XENO_STATUS_BLOCK *xenoStatusPointer;
1666 
1667 	LOCALASSERT(sbPtr);
1668 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1669 	LOCALASSERT(xenoStatusPointer);
1670 
1671 	/* Make sure obstruction is set! */
1672 
1673 	NPC_InitMovementData(&(xenoStatusPointer->moveData));
1674 	NPCGetAvoidanceDirection(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn),&xenoStatusPointer->obstruction);
1675 	xenoStatusPointer->lastState=xenoStatusPointer->behaviourState;
1676 	xenoStatusPointer->behaviourState = XS_Avoidance;
1677 	xenoStatusPointer->stateTimer = NPC_AVOIDTIME;
1678 	InitWaypointManager(&xenoStatusPointer->waypointManager);
1679 
1680 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1681 		/* Well, it shouldn't be! */
1682 		Sound_Stop(xenoStatusPointer->soundHandle1);
1683 	}
1684 	Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1685 
1686 }
1687 
Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK * sbPtr)1688 void Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK *sbPtr)
1689 {
1690 	XENO_STATUS_BLOCK *xenoStatusPointer;
1691 
1692 	LOCALASSERT(sbPtr);
1693 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1694 	LOCALASSERT(xenoStatusPointer);
1695 
1696 	xenoStatusPointer->stateTimer=0;
1697 	xenoStatusPointer->behaviourState=XS_ShootingTheRoof;
1698 
1699 	/* Sequence handled in the behaviour. */
1700 
1701 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1702 		/* Well, it shouldn't be! */
1703 		Sound_Stop(xenoStatusPointer->soundHandle1);
1704 	}
1705 	Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1706 
1707 	/* zero velocity */
1708 	LOCALASSERT(sbPtr->DynPtr);
1709 	sbPtr->DynPtr->LinVelocity.vx = 0;
1710 	sbPtr->DynPtr->LinVelocity.vy = 0;
1711 	sbPtr->DynPtr->LinVelocity.vz = 0;
1712 
1713 }
1714 
Xeno_CopeWithLossOfHome(STRATEGYBLOCK * sbPtr)1715 void Xeno_CopeWithLossOfHome(STRATEGYBLOCK *sbPtr) {
1716 
1717 	XENO_STATUS_BLOCK *xenoStatusPointer;
1718 
1719 	LOCALASSERT(sbPtr);
1720 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1721 	LOCALASSERT(xenoStatusPointer);
1722 
1723 	/* Ooh, yuck. */
1724 
1725 	xenoStatusPointer->my_module=sbPtr->containingModule->m_aimodule;
1726 	xenoStatusPointer->my_spot_therin=sbPtr->DynPtr->Position;
1727 
1728 }
1729 
Execute_Xeno_PowerUp(STRATEGYBLOCK * sbPtr)1730 void Execute_Xeno_PowerUp(STRATEGYBLOCK *sbPtr)
1731 {
1732 	XENO_STATUS_BLOCK *xenoStatusPointer;
1733 
1734 	LOCALASSERT(sbPtr);
1735 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1736 	LOCALASSERT(xenoStatusPointer);
1737 
1738 	/* Wait to finish, I guess... */
1739 
1740 	if (ShowXenoStats) {
1741 		PrintDebuggingText("In PowerUp.\n");
1742 	}
1743 
1744 	if (!sbPtr->SBdptr) {
1745 		/* We're far... do the timer! */
1746 		ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr);
1747 	}
1748 
1749 	xenoStatusPointer->Target=NULL;
1750 	xenoStatusPointer->stateTimer+=NormalFrameTime;
1751 
1752 	if (xenoStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
1753 		if (xenoStatusPointer->stateTimer>((ONE_FIXED*5)/2)) {
1754 			/* Time to start the BorgOn sound. */
1755 			Sound_Play(SID_BORGON,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle2);
1756 		}
1757 	}
1758 	if ((xenoStatusPointer->HModelController.Tweening==Controller_NoTweening)
1759 		&&(xenoStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) {
1760 
1761 		Xeno_Enter_ActiveWait_State(sbPtr);
1762 	}
1763 
1764 
1765 }
1766 
Execute_Xeno_PowerDown(STRATEGYBLOCK * sbPtr)1767 void Execute_Xeno_PowerDown(STRATEGYBLOCK *sbPtr)
1768 {
1769 	XENO_STATUS_BLOCK *xenoStatusPointer;
1770 
1771 	LOCALASSERT(sbPtr);
1772 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1773 	LOCALASSERT(xenoStatusPointer);
1774 
1775 	if (ShowXenoStats) {
1776 		PrintDebuggingText("In PowerDown.\n");
1777 	}
1778 
1779 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2));
1780 	xenoStatusPointer->HModelController.LoopAfterTweening=0;
1781 	xenoStatusPointer->HModelController.Looped=0;
1782 
1783 	if (!sbPtr->SBdptr) {
1784 		/* We're far... do the timer! */
1785 		ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr);
1786 	}
1787 
1788 	/* Wait to finish, I guess... */
1789 
1790 	xenoStatusPointer->Target=NULL;
1791 
1792 	if ((xenoStatusPointer->HModelController.Tweening==Controller_NoTweening)
1793 		&&(xenoStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) {
1794 
1795 		Xeno_Enter_Dormant_State(sbPtr);
1796 	}
1797 
1798 
1799 }
1800 
Xeno_TurnAndTarget(STRATEGYBLOCK * sbPtr,int * ref_anglex,int * ref_angley)1801 void Xeno_TurnAndTarget(STRATEGYBLOCK *sbPtr, int *ref_anglex,int *ref_angley) {
1802 
1803 	XENO_STATUS_BLOCK *xenoStatusPointer;
1804 	int anglex,angley;
1805 
1806 	LOCALASSERT(sbPtr);
1807 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1808 	LOCALASSERT(xenoStatusPointer);
1809 
1810 	{
1811 		SECTION_DATA *head_section;
1812 
1813 		head_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"neck");
1814 		GLOBALASSERT(head_section);
1815 
1816 		Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&head_section->World_Offset);
1817 
1818 	}
1819 
1820 	*ref_anglex=anglex;
1821 	*ref_angley=angley;
1822 
1823 	/* Start turning / targeting procedure. */
1824 	#if 0
1825 	if ((xenoStatusPointer->headLock)
1826 		||(anglex>((((xenoStatusPointer->Torso_Twist>>4)+XENO_HEADPAN_GIMBALL)*7)/8))
1827 		||(anglex<((((xenoStatusPointer->Torso_Twist>>4)-XENO_HEADPAN_GIMBALL)*7)/8))) {
1828 
1829 		Xeno_TorsoMovement_TrackToAngle(sbPtr,XENO_TORSO_TWIST_RATE,anglex);
1830 
1831 	}
1832 	#else
1833 	/* Always torso twist. */
1834 	Xeno_TorsoMovement_TrackToAngle(sbPtr,XENO_TORSO_TWIST_RATE,anglex);
1835 	#endif
1836 	xenoStatusPointer->headLock=Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_LOCK_RATE,anglex,angley);
1837 
1838 	/* Now the arm. */
1839 
1840 	if ((xenoStatusPointer->headLock)
1841 		&&((anglex<XENO_LEFTARM_ACW_GIMBALL)||(anglex>-XENO_LEFTARM_CW_GIMBALL))) {
1842 
1843 		SECTION_DATA *this_section;
1844 		int arm_anglex,arm_angley;
1845 
1846 		this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left bicep");
1847 		if (this_section) {
1848 			Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset);
1849 		} else {
1850 			arm_anglex=0;
1851 		}
1852 
1853 		this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left forearm");
1854 		if (this_section) {
1855 			Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset);
1856 		} else {
1857 			arm_angley=0;
1858 		}
1859 
1860 		xenoStatusPointer->leftArmLock=Xeno_LeftArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley);
1861 	}
1862 
1863 	if ((xenoStatusPointer->headLock)
1864 		&&((anglex<XENO_RIGHTARM_ACW_GIMBALL)||(anglex>-XENO_RIGHTARM_CW_GIMBALL))) {
1865 
1866 		SECTION_DATA *this_section;
1867 		int arm_anglex,arm_angley;
1868 
1869 		this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right bicep");
1870 		if (this_section) {
1871 			Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset);
1872 		} else {
1873 			arm_anglex=0;
1874 		}
1875 
1876 		this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right forearm");
1877 		if (this_section) {
1878 			Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset);
1879 		} else {
1880 			arm_angley=0;
1881 		}
1882 		xenoStatusPointer->rightArmLock=Xeno_RightArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley);
1883 	}
1884 	xenoStatusPointer->UseHeadLaser=1;
1885 }
1886 
Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK * sbPtr)1887 void Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK *sbPtr) {
1888 
1889 	XENO_STATUS_BLOCK *xenoStatusPointer;
1890 
1891 	LOCALASSERT(sbPtr);
1892 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1893 	LOCALASSERT(xenoStatusPointer);
1894 
1895 
1896 	Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
1897 	Xeno_LeftArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE);
1898 	Xeno_LeftArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE);
1899 	Xeno_RightArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE);
1900 	Xeno_RightArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE);
1901 	#if 0
1902 	Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
1903 	Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2);
1904 	#else
1905 	Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_SCAN_RATE,0,XENO_HEADTILT_GIMBALL);
1906 	#endif
1907 	xenoStatusPointer->UseHeadLaser=0;
1908 	xenoStatusPointer->UseRALaser=1;
1909 	xenoStatusPointer->UseLALaser=1;
1910 	xenoStatusPointer->FiringLeft=1;
1911 	xenoStatusPointer->FiringRight=1;
1912 
1913 }
1914 
Execute_Xeno_ActiveWait(STRATEGYBLOCK * sbPtr)1915 void Execute_Xeno_ActiveWait(STRATEGYBLOCK *sbPtr)
1916 {
1917 	XENO_STATUS_BLOCK *xenoStatusPointer;
1918 	int anglex,angley,correctlyOrientated;
1919 
1920 	LOCALASSERT(sbPtr);
1921 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
1922 	LOCALASSERT(xenoStatusPointer);
1923 
1924 	/* What to do?  Do we have a target? */
1925 
1926 	if (ShowXenoStats) {
1927 		PrintDebuggingText("In ActiveWait.\n");
1928 	}
1929 
1930 	if (xenoStatusPointer->Target==NULL) {
1931 		/* Let's wave the head around. */
1932 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
1933 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
1934 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
1935 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
1936 		Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2);
1937 		xenoStatusPointer->UseHeadLaser=1;
1938 		/* Are we at home? */
1939 		if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) {
1940 			Xeno_Enter_Returning_State(sbPtr);
1941 			return;
1942 		}
1943 		/* Are we facing the right way? */
1944 
1945 		correctlyOrientated = NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL);
1946 
1947 		if (!correctlyOrientated) {
1948 
1949 			SECTION_DATA *master_section;
1950 
1951 			master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley");
1952 			GLOBALASSERT(master_section);
1953 
1954 			Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset);
1955 
1956 			if (anglex>0) {
1957 				EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
1958 			} else {
1959 				EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
1960 			}
1961 			if (xenoStatusPointer->soundHandle1==SOUND_NOACTIVEINDEX) {
1962 				Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
1963 			}
1964 
1965 		} else {
1966 
1967 			/* Otherwise just wait? */
1968 			if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
1969 				/* Well, it shouldn't be! */
1970 				Sound_Stop(xenoStatusPointer->soundHandle1);
1971 			}
1972 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2));
1973 			xenoStatusPointer->stateTimer+=NormalFrameTime;
1974 			if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) {
1975 				Xeno_Enter_PowerDown_State(sbPtr);
1976 				/* Voluntary powerdown! */
1977 				xenoStatusPointer->stateTimer=XENO_POWERDOWN_TIME;
1978 			}
1979 		}
1980 		return;
1981 	}
1982 
1983 	GLOBALASSERT(xenoStatusPointer->Target);
1984 	xenoStatusPointer->stateTimer=0;
1985 	/* Now we have a target.  Can we see it? */
1986 	if (xenoStatusPointer->targetSightTest==0) {
1987 		/* Can't see them.  Are we out of range? */
1988 		if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
1989 			xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) {
1990 			Xeno_Enter_Returning_State(sbPtr);
1991 		} else {
1992 			Xeno_Enter_Following_State(sbPtr);
1993 		}
1994 		return;
1995 	}
1996 
1997 	Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
1998 
1999 	#if 0
2000 	if ((anglex>(((XENO_HEADPAN_GIMBALL)*7)/8))
2001 		||(anglex<-(((XENO_HEADPAN_GIMBALL)*7)/8))) {
2002 
2003 		Xeno_Enter_TurnToFace_State(sbPtr);
2004 
2005 	}
2006 	#else
2007 	/* Always turn to face too? */
2008 	Xeno_Enter_TurnToFace_State(sbPtr);
2009 	#endif
2010 
2011 }
2012 
Execute_Xeno_TurnToFace(STRATEGYBLOCK * sbPtr)2013 void Execute_Xeno_TurnToFace(STRATEGYBLOCK *sbPtr)
2014 {
2015 	XENO_STATUS_BLOCK *xenoStatusPointer;
2016 	int correctlyOrientated;
2017 	int anglex,angley;
2018 
2019 	LOCALASSERT(sbPtr);
2020 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2021 	LOCALASSERT(xenoStatusPointer);
2022 
2023 	/* Do we have a target? */
2024 
2025 	if (ShowXenoStats) {
2026 		PrintDebuggingText("In Turn To Face.\n");
2027 	}
2028 
2029 	if (xenoStatusPointer->Target==NULL) {
2030 		Xeno_Enter_ActiveWait_State(sbPtr);
2031 		/* Otherwise just wait? */
2032 		return;
2033 	}
2034 
2035 	/* Now we have a target. */
2036 	GLOBALASSERT(xenoStatusPointer->Target);
2037 
2038 	/* Set up animation... Which Way? */
2039 	{
2040 		SECTION_DATA *master_section;
2041 		VECTORCH orientationDirn;
2042 
2043 		master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley");
2044 		GLOBALASSERT(master_section);
2045 
2046 		Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset);
2047 
2048 		if (anglex>0) {
2049 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
2050 		} else {
2051 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
2052 		}
2053 
2054 		/* Then turn to face it, of course. */
2055 
2056 		orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx;
2057 		orientationDirn.vy = 0;
2058 		orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz;
2059 		correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL);
2060 
2061 	}
2062 
2063 	Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
2064 
2065 	if (angley>=XENO_HEADTILT_GIMBALL) {
2066 		Xeno_Enter_ShootingTheRoof_State(sbPtr);
2067 		return;
2068 	}
2069 
2070 	if (correctlyOrientated) {
2071 		Xeno_Enter_ActiveWait_State(sbPtr);
2072 	}
2073 
2074 }
2075 
Execute_Xeno_ShootTheRoof(STRATEGYBLOCK * sbPtr)2076 void Execute_Xeno_ShootTheRoof(STRATEGYBLOCK *sbPtr)
2077 {
2078 	XENO_STATUS_BLOCK *xenoStatusPointer;
2079 	int correctlyOrientated;
2080 	int anglex,angley;
2081 
2082 	LOCALASSERT(sbPtr);
2083 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2084 	LOCALASSERT(xenoStatusPointer);
2085 
2086 	/* Do we have a target? */
2087 
2088 	if (ShowXenoStats) {
2089 		PrintDebuggingText("In Shoot The Roof.\n");
2090 	}
2091 
2092 	if ((xenoStatusPointer->Target==NULL)||(xenoStatusPointer->IAmFar)) {
2093 		Xeno_Enter_ActiveWait_State(sbPtr);
2094 		/* Otherwise just wait? */
2095 		return;
2096 	}
2097 
2098 	/* Now we have a target. */
2099 	GLOBALASSERT(xenoStatusPointer->Target);
2100 
2101 	/* Set up animation... Which Way?  Keep TurnToFace functionality? */
2102 	{
2103 		SECTION_DATA *master_section;
2104 		VECTORCH orientationDirn;
2105 
2106 		master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley");
2107 		GLOBALASSERT(master_section);
2108 
2109 		Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset);
2110 
2111 		anglex=512;
2112 
2113 		if (anglex>0) {
2114 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
2115 		} else {
2116 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
2117 		}
2118 
2119 		#if 0
2120 		/* Then turn to face it, of course. */
2121 
2122 		orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx;
2123 		orientationDirn.vy = 0;
2124 		orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz;
2125 		#else
2126 		/* Synthesize a new orientationDirn. */
2127 		orientationDirn.vx=sbPtr->DynPtr->OrientMat.mat11;
2128 		orientationDirn.vy=sbPtr->DynPtr->OrientMat.mat12;
2129 		orientationDirn.vz=sbPtr->DynPtr->OrientMat.mat13;
2130 		#endif
2131 		correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL);
2132 
2133 	}
2134 
2135 	Xeno_Limbs_ShootTheRoof(sbPtr);
2136 
2137 	if (angley<XENO_HEADTILT_GIMBALL) {
2138 		Xeno_Enter_TurnToFace_State(sbPtr);
2139 		return;
2140 	}
2141 
2142 }
2143 
Execute_Xeno_Follow(STRATEGYBLOCK * sbPtr)2144 void Execute_Xeno_Follow(STRATEGYBLOCK *sbPtr)
2145 {
2146 	XENO_STATUS_BLOCK *xenoStatusPointer;
2147 	VECTORCH velocityDirection = {0,0,0};
2148 	VECTORCH targetPosition;
2149 	int targetIsAirduct = 0;
2150 	int anglex,angley;
2151 
2152 	LOCALASSERT(sbPtr);
2153 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2154 	LOCALASSERT(xenoStatusPointer);
2155 
2156 	/* In theory, we're following the target, and can't see it. */
2157 
2158 	if (ShowXenoStats) {
2159 		PrintDebuggingText("In Follow.\n");
2160 	}
2161 
2162 	if (xenoStatusPointer->Target==NULL) {
2163 		/* Let's wave the head around. */
2164 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
2165 		/* Do we want to do this? */
2166 		Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2);
2167 		xenoStatusPointer->UseHeadLaser=1;
2168 		/* And return to my module. */
2169 		Xeno_Enter_Returning_State(sbPtr);
2170 		return;
2171 	}
2172 
2173 	GLOBALASSERT(xenoStatusPointer->Target);
2174 	/* Now we know have a target.  Can we see it yet? */
2175 
2176 	if (xenoStatusPointer->targetSightTest==0) {
2177 
2178 		AIMODULE *targetModule;
2179 		FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
2180 
2181 		/* Can't see them.  Never mind.  Go to the next module? */
2182 		if (xenoStatusPointer->Target->containingModule==NULL) {
2183 			/* Fall through for now. */
2184 			targetModule=NULL;
2185 		} else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
2186 			xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) {
2187 			/* Too Far! */
2188 			Xeno_Enter_ActiveWait_State(sbPtr);
2189 			return;
2190 		} else {
2191 			/* Still in range: keep going. */
2192 			targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
2193 				xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0);
2194 
2195 		}
2196 
2197 		if (targetModule==NULL) {
2198 			/* They're way away. */
2199 			Xeno_Enter_Returning_State(sbPtr);
2200 			return;
2201 		}
2202 
2203 		if (targetModule==sbPtr->containingModule->m_aimodule) {
2204 			/* Good Grief, Penfold!  He's right there, but I can't see him! */
2205 			NPCGetMovementDirection(sbPtr, &velocityDirection, &xenoStatusPointer->targetTrackPos,&xenoStatusPointer->waypointManager);
2206 			NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED);
2207 			targetPosition=xenoStatusPointer->targetTrackPos;
2208 			if (ShowXenoStats) {
2209 				PrintDebuggingText("Direct movement - no LOS.\n");
2210 			}
2211 			/* Oh, well. Go to last known position? */
2212 		} else {
2213 			thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
2214 			if (!thisEp) {
2215 				LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
2216 					(*(targetModule->m_module_ptrs))->name,
2217 					sbPtr->containingModule->name));
2218 				GLOBALASSERT(thisEp);
2219 			}
2220 			/* If that fired, there's a farped adjacency. */
2221 
2222 			xenoStatusPointer->wanderData.worldPosition=thisEp->position;
2223 			xenoStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
2224 			xenoStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
2225 			xenoStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
2226 
2227 			NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager);
2228 			NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED);
2229 			targetPosition=xenoStatusPointer->wanderData.worldPosition;
2230 		}
2231 	} else {
2232 		/* Re-aquired!  Get a bit closer? */
2233 		int range;
2234 
2235 		if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
2236 			xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) {
2237 			/* Too Far! */
2238 			Xeno_Enter_ActiveWait_State(sbPtr);
2239 			return;
2240 		}
2241 
2242 		range=VectorDistance((&xenoStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
2243 
2244 		if (range>XENO_CLOSE_APPROACH_DISTANCE) {
2245 			NPCGetMovementTarget(sbPtr, xenoStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
2246 			NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&xenoStatusPointer->waypointManager);
2247 			NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED);
2248 			if (ShowXenoStats) {
2249 				PrintDebuggingText("Direct movement - LOS Okay.\n");
2250 			}
2251 		} else {
2252 			/* Return to ActiveWait. */
2253 			Xeno_Enter_ActiveWait_State(sbPtr);
2254 			return;
2255 		}
2256 
2257 	}
2258 
2259 	#if 0
2260 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
2261 	#else
2262 	XenoborgHandleMovingAnimation(sbPtr);
2263 	#endif
2264 
2265 	if (xenoStatusPointer->targetSightTest==0) {
2266 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
2267 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2268 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2269 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
2270 		xenoStatusPointer->UseHeadLaser=1;
2271 	} else {
2272 		Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
2273 	}
2274 
2275 	/* test here for impeding collisions, and not being able to reach target... */
2276 	{
2277 		STRATEGYBLOCK *destructableObject = NULL;
2278 
2279 		NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&xenoStatusPointer->obstruction,&destructableObject);
2280 		#if 1
2281 		if(xenoStatusPointer->obstruction.environment)
2282 		{
2283 			/* go to avoidance */
2284 			Xeno_Enter_Avoidance_State(sbPtr);
2285 			return;
2286 		}
2287 		#endif
2288 		if(xenoStatusPointer->obstruction.destructableObject)
2289 		{
2290 			LOCALASSERT(destructableObject);
2291 			CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2292 		}
2293 	}
2294 
2295 	if(NPC_CannotReachTarget(&(xenoStatusPointer->moveData), &targetPosition, &velocityDirection))
2296 	{
2297 
2298 		xenoStatusPointer->obstruction.environment=1;
2299 		xenoStatusPointer->obstruction.destructableObject=0;
2300 		xenoStatusPointer->obstruction.otherCharacter=0;
2301 		xenoStatusPointer->obstruction.anySingleObstruction=0;
2302 
2303 		Xeno_Enter_Avoidance_State(sbPtr);
2304 		return;
2305 	}
2306 
2307 }
2308 
Execute_Xeno_Return(STRATEGYBLOCK * sbPtr)2309 void Execute_Xeno_Return(STRATEGYBLOCK *sbPtr)
2310 {
2311 	XENO_STATUS_BLOCK *xenoStatusPointer;
2312 	VECTORCH velocityDirection = {0,0,0};
2313 	VECTORCH *targetPosition=NULL;
2314 
2315 	LOCALASSERT(sbPtr);
2316 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2317 	LOCALASSERT(xenoStatusPointer);
2318 
2319 	/* In theory, we're following the target, and can't see it. */
2320 
2321 	if (ShowXenoStats) {
2322 		PrintDebuggingText("In Return.\n");
2323 	}
2324 
2325 	if (xenoStatusPointer->Target!=NULL) {
2326 		/* Saw something! */
2327 		/* Go to active wait. */
2328 		Xeno_Enter_ActiveWait_State(sbPtr);
2329 		return;
2330 	}
2331 
2332 	GLOBALASSERT(xenoStatusPointer->Target==NULL);
2333 	/* Find our way home. */
2334 
2335 	{
2336 
2337 		AIMODULE *targetModule;
2338 		FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
2339 
2340 		/* Go to the next module. */
2341 		targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
2342 			xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0);
2343 		/* Just to be on the safe side. */
2344 
2345 		if (targetModule==NULL) {
2346 			/* Emergency! */
2347 			targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
2348 				xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0);
2349 			if (targetModule==NULL) {
2350 				/* Totally broken.  Stay here. */
2351 				Xeno_CopeWithLossOfHome(sbPtr);
2352 				return;
2353 			}
2354 		}
2355 
2356 		if (targetModule!=sbPtr->containingModule->m_aimodule) {
2357 
2358 			thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
2359 			if (!thisEp) {
2360 				LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
2361 					(*(targetModule->m_module_ptrs))->name,
2362 					sbPtr->containingModule->name));
2363 				GLOBALASSERT(thisEp);
2364 			}
2365 			/* If that fired, there's a farped adjacency. */
2366 
2367 			xenoStatusPointer->wanderData.worldPosition=thisEp->position;
2368 			xenoStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
2369 			xenoStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
2370 			xenoStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
2371 
2372 			NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager);
2373 			NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED);
2374 			targetPosition=&(xenoStatusPointer->wanderData.worldPosition);
2375 		} else {
2376 			VECTORCH offset;
2377 			int dist;
2378 			/* In our own home module! */
2379 
2380 			offset.vx=sbPtr->DynPtr->Position.vx-xenoStatusPointer->my_spot_therin.vx;
2381 			offset.vy=sbPtr->DynPtr->Position.vy-xenoStatusPointer->my_spot_therin.vy;
2382 			offset.vz=sbPtr->DynPtr->Position.vz-xenoStatusPointer->my_spot_therin.vz;
2383 			/* Fix for midair start points, grrrr. */
2384 			offset.vy>>=2;
2385 
2386 			/* Find distance off spot. */
2387 			dist=Approximate3dMagnitude(&offset);
2388 
2389 			if (dist<XENO_SENTRY_SENSITIVITY) {
2390 				Xeno_Enter_ActiveWait_State(sbPtr);
2391 				return;
2392 			} else {
2393 				NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->my_spot_therin),&xenoStatusPointer->waypointManager);
2394 				NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED);
2395 				targetPosition=&(xenoStatusPointer->my_spot_therin);
2396 			}
2397 		}
2398 	}
2399 
2400 	#if 0
2401 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
2402 	#else
2403 	XenoborgHandleMovingAnimation(sbPtr);
2404 	#endif
2405 
2406 	Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
2407 	Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2408 	Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2409 	Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
2410 	xenoStatusPointer->UseHeadLaser=1;
2411 
2412 	/* test here for impeding collisions, and not being able to reach target... */
2413 	{
2414 		STRATEGYBLOCK *destructableObject = NULL;
2415 
2416 		NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&xenoStatusPointer->obstruction,&destructableObject);
2417 		#if 1
2418 		if(xenoStatusPointer->obstruction.environment)
2419 		{
2420 			/* go to avoidance */
2421 			Xeno_Enter_Avoidance_State(sbPtr);
2422 			return;
2423 		}
2424 		#endif
2425 		if(xenoStatusPointer->obstruction.destructableObject)
2426 		{
2427 			LOCALASSERT(destructableObject);
2428 			CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2429 		}
2430 	}
2431 
2432 	if(NPC_CannotReachTarget(&(xenoStatusPointer->moveData), targetPosition, &velocityDirection))
2433 	{
2434 
2435 		xenoStatusPointer->obstruction.environment=1;
2436 		xenoStatusPointer->obstruction.destructableObject=0;
2437 		xenoStatusPointer->obstruction.otherCharacter=0;
2438 		xenoStatusPointer->obstruction.anySingleObstruction=0;
2439 
2440 		Xeno_Enter_Avoidance_State(sbPtr);
2441 		return;
2442 	}
2443 
2444 }
2445 
Execute_Xeno_Avoidance(STRATEGYBLOCK * sbPtr)2446 void Execute_Xeno_Avoidance(STRATEGYBLOCK *sbPtr)
2447 {
2448 	XENO_STATUS_BLOCK *xenoStatusPointer;
2449 	int terminateState = 0;
2450 	int anglex,angley;
2451 
2452 	LOCALASSERT(sbPtr);
2453 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2454 	LOCALASSERT(xenoStatusPointer);
2455 
2456 	if (ShowXenoStats) {
2457 		PrintDebuggingText("In Avoidance.\n");
2458 	}
2459 
2460 	/* Sequences... */
2461 	#if 0
2462 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
2463 	#else
2464 	XenoborgHandleMovingAnimation(sbPtr);
2465 	#endif
2466 
2467 	if (xenoStatusPointer->targetSightTest==0) {
2468 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
2469 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2470 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
2471 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
2472 		xenoStatusPointer->UseHeadLaser=1;
2473 	} else {
2474 		Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
2475 	}
2476 
2477 	/* set velocity */
2478 	LOCALASSERT((xenoStatusPointer->moveData.avoidanceDirn.vx!=0)||
2479 				(xenoStatusPointer->moveData.avoidanceDirn.vy!=0)||
2480 				(xenoStatusPointer->moveData.avoidanceDirn.vz!=0));
2481 	NPCSetVelocity(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn), (XENO_NEAR_SPEED));
2482 
2483 	/* decrement state timer */
2484 	xenoStatusPointer->stateTimer -= NormalFrameTime;
2485 	if(xenoStatusPointer->stateTimer <= 0) terminateState = 1;
2486 
2487 	{
2488 		STRATEGYBLOCK *destructableObject = NULL;
2489 		NPC_OBSTRUCTIONREPORT obstruction;
2490 		NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&obstruction,&destructableObject);
2491 		if(obstruction.anySingleObstruction)
2492 		{
2493 			terminateState = 1;
2494 		}
2495 	}
2496 
2497 	if(terminateState)
2498 	{
2499 
2500 		/* go to an appropriate state */
2501 		switch (xenoStatusPointer->lastState) {
2502 			case XS_Returning:
2503 				Xeno_Enter_Returning_State(sbPtr);
2504 				return;
2505 				break;
2506 			case XS_Following:
2507 				Xeno_Enter_Following_State(sbPtr);
2508 				return;
2509 				break;
2510 			default:
2511 				Xeno_Enter_ActiveWait_State(sbPtr);
2512 				return;
2513 				break;
2514 		}
2515 		/* Still here? */
2516 		return;
2517 
2518 	}
2519 	return;
2520 }
2521 
Xenoborg_TargetFilter(STRATEGYBLOCK * candidate)2522 int Xenoborg_TargetFilter(STRATEGYBLOCK *candidate) {
2523 
2524 	/* Let's face it, Xenos shoot everything but other xenos. */
2525 	switch (candidate->I_SBtype) {
2526 		case I_BehaviourMarinePlayer:
2527 		case I_BehaviourAlienPlayer:
2528 		case I_BehaviourPredatorPlayer:
2529 			{
2530 				if (Observer) {
2531 					return(0);
2532 				}
2533 
2534 				switch(AvP.PlayerType)
2535 				{
2536 					case I_Alien:
2537 					case I_Predator:
2538 					case I_Marine:
2539 						return(1);
2540 						break;
2541 					default:
2542 						GLOBALASSERT(0);
2543 						return(0);
2544 						break;
2545 				}
2546 				break;
2547 			}
2548 		case I_BehaviourDummy:
2549 			{
2550 				DUMMY_STATUS_BLOCK *dummyStatusPointer;
2551 				dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr);
2552 			    LOCALASSERT(dummyStatusPointer);
2553 				switch (dummyStatusPointer->PlayerType) {
2554 					case I_Marine:
2555 					case I_Predator:
2556 					case I_Alien:
2557 						return(1);
2558 						break;
2559 					default:
2560 						GLOBALASSERT(0);
2561 						return(0);
2562 						break;
2563 				}
2564 				break;
2565 			}
2566 		case I_BehaviourAlien:
2567 			{
2568 				if (NPC_IsDead(candidate)) {
2569 					return(0);
2570 				} else {
2571 					/* Are we inactive? */
2572 					ALIEN_STATUS_BLOCK *asb=(ALIEN_STATUS_BLOCK *)candidate->SBdataptr;
2573 					GLOBALASSERT(asb);
2574 					if (asb->BehaviourState==ABS_Dormant) {
2575 						return(0);
2576 					} else {
2577 						return(1);
2578 					}
2579 				}
2580 				break;
2581 			}
2582 		case I_BehaviourQueenAlien:
2583 		case I_BehaviourFaceHugger:
2584 		case I_BehaviourPredator:
2585 		case I_BehaviourSeal:
2586 		case I_BehaviourPredatorAlien:
2587 		case I_BehaviourMarine:
2588 			{
2589 				if (NPC_IsDead(candidate)) {
2590 					return(0);
2591 				} else {
2592 					return(1);
2593 				}
2594 				break;
2595 			}
2596 		case I_BehaviourXenoborg:
2597 			return(0);
2598 			break;
2599 		case I_BehaviourNetGhost:
2600 			{
2601 				NETGHOSTDATABLOCK *dataptr;
2602 				dataptr=candidate->SBdataptr;
2603 				switch (dataptr->type) {
2604 					case I_BehaviourMarinePlayer:
2605 					case I_BehaviourAlienPlayer:
2606 					case I_BehaviourPredatorPlayer:
2607 						return(1);
2608 						break;
2609 					default:
2610 						return(1);
2611 						break;
2612 				}
2613 			}
2614 			break;
2615 		default:
2616 			return(0);
2617 			break;
2618 	}
2619 
2620 }
2621 
Xenoborg_GetNewTarget(VECTORCH * xenopos,STRATEGYBLOCK * me)2622 STRATEGYBLOCK *Xenoborg_GetNewTarget(VECTORCH *xenopos, STRATEGYBLOCK *me) {
2623 
2624 	int neardist;
2625 	STRATEGYBLOCK *nearest;
2626 	int a;
2627 	STRATEGYBLOCK *candidate;
2628 	MODULE *dmod;
2629 
2630 	dmod=ModuleFromPosition(xenopos,playerPherModule);
2631 
2632 	LOCALASSERT(dmod);
2633 
2634 	nearest=NULL;
2635 	neardist=ONE_FIXED;
2636 
2637 	for (a=0; a<NumActiveStBlocks; a++) {
2638 		candidate=ActiveStBlockList[a];
2639 		if (candidate!=me) {
2640 			if (candidate->DynPtr) {
2641 				if (Xenoborg_TargetFilter(candidate)) {
2642 					VECTORCH offset;
2643 					int dist;
2644 
2645 					offset.vx=xenopos->vx-candidate->DynPtr->Position.vx;
2646 					offset.vy=xenopos->vy-candidate->DynPtr->Position.vy;
2647 					offset.vz=xenopos->vz-candidate->DynPtr->Position.vz;
2648 
2649 					dist=Approximate3dMagnitude(&offset);
2650 
2651 					if (dist<neardist) {
2652 						/* Check visibility? */
2653 						if (NPCCanSeeTarget(me,candidate,XENO_NEAR_VIEW_WIDTH)) {
2654 							if (!NPC_IsDead(candidate)) {
2655 								if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
2656 									nearest=candidate;
2657 								}
2658 							}
2659 						}
2660 					}
2661 				}
2662 			}
2663 		}
2664 	}
2665 
2666 	#if 0
2667 	if (nearest==NULL) {
2668 		if (Xenoborg_TargetFilter(Player->ObStrategyBlock)) {
2669 			nearest=Player->ObStrategyBlock;
2670 		} else {
2671 			nearest=NULL; /* Erk! */
2672 		}
2673 	}
2674 	#endif
2675 
2676 	return(nearest);
2677 
2678 }
2679 
ComputeDeltaValues(STRATEGYBLOCK * sbPtr)2680 static void ComputeDeltaValues(STRATEGYBLOCK *sbPtr)
2681 {
2682 	XENO_STATUS_BLOCK *xenoStatusPointer;
2683 	int angle;
2684 
2685 	LOCALASSERT(sbPtr);
2686 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2687 	LOCALASSERT(xenoStatusPointer);
2688 
2689 	/* Interpret all status block values, and apply to deltas. */
2690 	/* Head Pan first. */
2691 
2692 	angle=xenoStatusPointer->Head_Pan>>4;
2693 
2694 	if (angle>=3072) angle-=4096;
2695 	if (angle>=2048) angle=angle-4096;
2696 
2697 	/* Now, we have an angle. */
2698 
2699 	if (angle>XENO_HEADPAN_GIMBALL) {
2700 		angle=XENO_HEADPAN_GIMBALL;
2701 	} else if (angle<-XENO_HEADPAN_GIMBALL) {
2702 		angle=-XENO_HEADPAN_GIMBALL;
2703 	}
2704 
2705 	#if 0
2706 	angle=angle*2;
2707 
2708 	GLOBALASSERT(xenoStatusPointer->head_pan);
2709 
2710 	{
2711 		int fake_timer;
2712 
2713 		fake_timer=1024-angle;
2714 		fake_timer<<=5;
2715 		if (fake_timer==65536) fake_timer=65535;
2716 	#else
2717 	GLOBALASSERT(xenoStatusPointer->head_pan);
2718 
2719 	{
2720 		int fake_timer;
2721 
2722 		fake_timer=DIV_FIXED(angle,(XENO_HEADPAN_GIMBALL<<1));
2723 		fake_timer+=32767;
2724 		fake_timer=65536-fake_timer;
2725 		if (fake_timer>=65536) fake_timer=65535;
2726 		if (fake_timer<=0) fake_timer=0;
2727 
2728 	#endif
2729 
2730 		GLOBALASSERT(fake_timer>=0);
2731 		GLOBALASSERT(fake_timer<65536);
2732 
2733 		xenoStatusPointer->head_pan->timer=fake_timer;
2734 
2735 	}
2736 
2737 	/* Head tilt next. */
2738 	angle=xenoStatusPointer->Head_Tilt>>4;
2739 
2740 	if (angle>=3072) angle-=4096;
2741 	if (angle>=2048) angle=angle-3072;
2742 	if (angle> 1024) angle=2048-angle;
2743 
2744 	/* Now, we have an angle. */
2745 
2746 	if (angle>XENO_HEADTILT_GIMBALL) {
2747 		angle=XENO_HEADTILT_GIMBALL;
2748 	} else if (angle<-XENO_HEADTILT_GIMBALL) {
2749 		angle=-XENO_HEADTILT_GIMBALL;
2750 	}
2751 
2752 	angle=angle*2;
2753 
2754 	GLOBALASSERT(angle>=-1024);
2755 	GLOBALASSERT(angle<=1024);
2756 
2757 	GLOBALASSERT(xenoStatusPointer->head_tilt);
2758 
2759 	{
2760 		int fake_timer;
2761 
2762 		fake_timer=1024-angle;
2763 		fake_timer<<=5;
2764 		if (fake_timer==65536) fake_timer=65535;
2765 
2766 		GLOBALASSERT(fake_timer>=0);
2767 		GLOBALASSERT(fake_timer<65536);
2768 
2769 		xenoStatusPointer->head_tilt->timer=fake_timer;
2770 
2771 	}
2772 
2773 	/* Left Arm Pan now. */
2774 
2775 	angle=xenoStatusPointer->Left_Arm_Pan>>4;
2776 
2777 	if (angle>=3072) angle-=4096;
2778 	if (angle>=2048) angle=angle-4096;
2779 
2780 	GLOBALASSERT(xenoStatusPointer->left_arm_pan);
2781 
2782 	/* Now, we have an angle. */
2783 
2784 	if (angle>XENO_LEFTARM_ACW_GIMBALL) {
2785 		angle=XENO_LEFTARM_ACW_GIMBALL;
2786 	} else if (angle<-XENO_LEFTARM_CW_GIMBALL) {
2787 		angle=-XENO_LEFTARM_CW_GIMBALL;
2788 	}
2789 
2790 	{
2791 		int fake_timer;
2792 
2793 		if (angle>0) {
2794 
2795 			fake_timer=DIV_FIXED(angle,(XENO_LEFTARM_ACW_GIMBALL<<1));
2796 			fake_timer+=32767;
2797 			fake_timer=65536-fake_timer;
2798 			if (fake_timer>=65536) fake_timer=65535;
2799 			if (fake_timer<=0) fake_timer=0;
2800 
2801 		} else {
2802 
2803 			fake_timer=DIV_FIXED(angle,(XENO_LEFTARM_CW_GIMBALL<<1));
2804 			fake_timer+=32767;
2805 			fake_timer=65536-fake_timer;
2806 			if (fake_timer>=65536) fake_timer=65535;
2807 			if (fake_timer<=0) fake_timer=0;
2808 
2809 		}
2810 
2811 		GLOBALASSERT(fake_timer>=0);
2812 		GLOBALASSERT(fake_timer<65536);
2813 
2814 		xenoStatusPointer->left_arm_pan->timer=fake_timer;
2815 
2816 	}
2817 
2818 	/* Left Arm Tilt... */
2819 
2820 	angle=xenoStatusPointer->Left_Arm_Tilt>>4;
2821 
2822 	if (angle>=3072) angle-=4096;
2823 	if (angle>=2048) angle=angle-3072;
2824 	if (angle> 1024) angle=2048-angle;
2825 
2826 	GLOBALASSERT(xenoStatusPointer->left_arm_tilt);
2827 
2828 	/* Now, we have an angle. */
2829 
2830 	if (angle>XENO_ARM_PITCH_GIMBALL) {
2831 		angle=XENO_ARM_PITCH_GIMBALL;
2832 	} else if (angle<-XENO_ARM_PITCH_GIMBALL) {
2833 		angle=-XENO_ARM_PITCH_GIMBALL;
2834 	}
2835 
2836 	GLOBALASSERT(angle>=-1024);
2837 	GLOBALASSERT(angle<=1024);
2838 
2839 	{
2840 		int fake_timer;
2841 
2842 		fake_timer=1024-angle;
2843 		fake_timer<<=5;
2844 		if (fake_timer==65536) fake_timer=65535;
2845 
2846 		GLOBALASSERT(fake_timer>=0);
2847 		GLOBALASSERT(fake_timer<65536);
2848 
2849 		xenoStatusPointer->left_arm_tilt->timer=fake_timer;
2850 
2851 	}
2852 
2853 	/* Right Arm Pan now. */
2854 
2855 	angle=xenoStatusPointer->Right_Arm_Pan>>4;
2856 
2857 	if (angle>=3072) angle-=4096;
2858 	if (angle>=2048) angle=angle-4096;
2859 
2860 	GLOBALASSERT(xenoStatusPointer->right_arm_pan);
2861 
2862 	/* Now, we have an angle. */
2863 
2864 	if (angle>XENO_RIGHTARM_ACW_GIMBALL) {
2865 		angle=XENO_RIGHTARM_ACW_GIMBALL;
2866 	} else if (angle<-XENO_RIGHTARM_CW_GIMBALL) {
2867 		angle=-XENO_RIGHTARM_CW_GIMBALL;
2868 	}
2869 
2870 	{
2871 		int fake_timer;
2872 
2873 		if (angle>0) {
2874 
2875 			fake_timer=DIV_FIXED(angle,(XENO_RIGHTARM_ACW_GIMBALL<<1));
2876 			fake_timer+=32767;
2877 			if (fake_timer>=65536) fake_timer=65535;
2878 
2879 		} else {
2880 
2881 			fake_timer=DIV_FIXED(angle,(XENO_RIGHTARM_CW_GIMBALL<<1));
2882 			fake_timer+=32767;
2883 			if (fake_timer<=0) fake_timer=0;
2884 
2885 		}
2886 
2887 		GLOBALASSERT(fake_timer>=0);
2888 		GLOBALASSERT(fake_timer<65536);
2889 
2890 		xenoStatusPointer->right_arm_pan->timer=fake_timer;
2891 
2892 	}
2893 
2894 	/* Right Arm Tilt... */
2895 
2896 	angle=xenoStatusPointer->Right_Arm_Tilt>>4;
2897 
2898 	if (angle>=3072) angle-=4096;
2899 	if (angle>=2048) angle=angle-3072;
2900 	if (angle> 1024) angle=2048-angle;
2901 
2902 	GLOBALASSERT(xenoStatusPointer->right_arm_pan);
2903 
2904 	/* Now, we have an angle. */
2905 
2906 	if (angle>XENO_ARM_PITCH_GIMBALL) {
2907 		angle=XENO_ARM_PITCH_GIMBALL;
2908 	} else if (angle<-XENO_ARM_PITCH_GIMBALL) {
2909 		angle=-XENO_ARM_PITCH_GIMBALL;
2910 	}
2911 
2912 	GLOBALASSERT(angle>=-1024);
2913 	GLOBALASSERT(angle<=1024);
2914 
2915 	{
2916 		int fake_timer;
2917 
2918 		fake_timer=1024-angle;
2919 		fake_timer<<=5;
2920 		if (fake_timer==65536) fake_timer=65535;
2921 
2922 		GLOBALASSERT(fake_timer>=0);
2923 		GLOBALASSERT(fake_timer<65536);
2924 
2925 		xenoStatusPointer->right_arm_tilt->timer=fake_timer;
2926 
2927 	}
2928 
2929 	/* ... and Torso Twist. */
2930 
2931 	angle=xenoStatusPointer->Torso_Twist>>4;
2932 
2933 	if (angle>=3072) angle-=4096;
2934 	if (angle>=2048) angle=angle-4096;
2935 
2936 	GLOBALASSERT(xenoStatusPointer->torso_twist);
2937 
2938 	/* Now, we have an angle. */
2939 
2940 	if (angle>XENO_TORSO_GIMBALL) {
2941 		angle=XENO_TORSO_GIMBALL;
2942 	} else if (angle<-XENO_TORSO_GIMBALL) {
2943 		angle=-XENO_TORSO_GIMBALL;
2944 	}
2945 
2946 	{
2947 		int fake_timer;
2948 
2949 		if (angle>0) {
2950 
2951 			fake_timer=DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1));
2952 			fake_timer+=32767;
2953 			if (fake_timer>=65536) fake_timer=65535;
2954 
2955 		} else {
2956 
2957 			fake_timer=DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1));
2958 			fake_timer+=32767;
2959 			if (fake_timer<=0) fake_timer=0;
2960 
2961 		}
2962 
2963 		GLOBALASSERT(fake_timer>=0);
2964 		GLOBALASSERT(fake_timer<65536);
2965 
2966 		xenoStatusPointer->torso_twist->timer=fake_timer;
2967 
2968 	}
2969 
2970 }
2971 
2972 void Xeno_HeadMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate)
2973 {
2974 	XENO_STATUS_BLOCK *xenoStatusPointer;
2975 
2976 	LOCALASSERT(sbPtr);
2977 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
2978 	LOCALASSERT(xenoStatusPointer);
2979 
2980 	/* Let's wave the head around. */
2981 	if (xenoStatusPointer->headpandir) {
2982 		xenoStatusPointer->Head_Pan+=(NormalFrameTime>>rate);
2983 		if (xenoStatusPointer->Head_Pan>(XENO_HEADPAN_GIMBALL<<4)) {
2984 			xenoStatusPointer->Head_Pan=(XENO_HEADPAN_GIMBALL<<4);
2985 			xenoStatusPointer->headpandir=0;
2986 		} else {
2987 			xenoStatusPointer->head_moving=1;
2988 		}
2989 	} else {
2990 		xenoStatusPointer->Head_Pan-=(NormalFrameTime>>rate);
2991 		if (xenoStatusPointer->Head_Pan<-(XENO_HEADPAN_GIMBALL<<4)) {
2992 			xenoStatusPointer->Head_Pan=-(XENO_HEADPAN_GIMBALL<<4);
2993 			xenoStatusPointer->headpandir=1;
2994 		} else {
2995 			xenoStatusPointer->head_moving=1;
2996 		}
2997 	}
2998 	if (xenoStatusPointer->head_pan) {
2999 		xenoStatusPointer->head_pan->Active=1;
3000 	}
3001 
3002 }
3003 
3004 void Xeno_HeadMovement_ScanUpDown(STRATEGYBLOCK *sbPtr,int rate)
3005 {
3006 	XENO_STATUS_BLOCK *xenoStatusPointer;
3007 
3008 	LOCALASSERT(sbPtr);
3009 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3010 	LOCALASSERT(xenoStatusPointer);
3011 
3012 	/* Let's wave the head around. */
3013 	if (xenoStatusPointer->headtiltdir) {
3014 		xenoStatusPointer->Head_Tilt+=(NormalFrameTime>>rate);
3015 		if (xenoStatusPointer->Head_Tilt>(XENO_HEADTILT_GIMBALL<<4)) {
3016 			xenoStatusPointer->Head_Tilt=(XENO_HEADTILT_GIMBALL<<4);
3017 			xenoStatusPointer->headtiltdir=0;
3018 		} else {
3019 			xenoStatusPointer->head_moving=1;
3020 		}
3021 	} else {
3022 		xenoStatusPointer->Head_Tilt-=(NormalFrameTime>>rate);
3023 		if (xenoStatusPointer->Head_Tilt<-(XENO_HEADTILT_GIMBALL<<4)) {
3024 			xenoStatusPointer->Head_Tilt=-(XENO_HEADTILT_GIMBALL<<4);
3025 			xenoStatusPointer->headtiltdir=1;
3026 		} else {
3027 			xenoStatusPointer->head_moving=1;
3028 		}
3029 	}
3030 	if (xenoStatusPointer->head_tilt) {
3031 		xenoStatusPointer->head_tilt->Active=1;
3032 	}
3033 
3034 }
3035 
3036 void Xeno_LeftArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate)
3037 {
3038 	XENO_STATUS_BLOCK *xenoStatusPointer;
3039 
3040 	LOCALASSERT(sbPtr);
3041 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3042 	LOCALASSERT(xenoStatusPointer);
3043 
3044 	/* Let's wave the left arm around. */
3045 	if (xenoStatusPointer->leftarmpandir) {
3046 		xenoStatusPointer->Left_Arm_Pan+=(NormalFrameTime>>rate);
3047 		if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) {
3048 			xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4);
3049 			xenoStatusPointer->leftarmpandir=0;
3050 		} else {
3051 			xenoStatusPointer->la_moving=1;
3052 		}
3053 	} else {
3054 		xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate);
3055 		if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) {
3056 			xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4);
3057 			xenoStatusPointer->leftarmpandir=1;
3058 		} else {
3059 			xenoStatusPointer->la_moving=1;
3060 		}
3061 	}
3062 
3063 	if (xenoStatusPointer->left_arm_pan) {
3064 		xenoStatusPointer->left_arm_pan->Active=1;
3065 	}
3066 
3067 }
3068 
3069 void Xeno_LeftArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate)
3070 {
3071 	XENO_STATUS_BLOCK *xenoStatusPointer;
3072 
3073 	LOCALASSERT(sbPtr);
3074 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3075 	LOCALASSERT(xenoStatusPointer);
3076 
3077 	/* Let's wave the left arm around. */
3078 	if (xenoStatusPointer->leftarmtiltdir) {
3079 		xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate);
3080 		if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3081 			xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3082 			xenoStatusPointer->leftarmtiltdir=0;
3083 		} else {
3084 			xenoStatusPointer->la_moving=1;
3085 		}
3086 	} else {
3087 		xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate);
3088 		if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3089 			xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3090 			xenoStatusPointer->leftarmtiltdir=1;
3091 		} else {
3092 			xenoStatusPointer->la_moving=1;
3093 		}
3094 	}
3095 
3096 	if (xenoStatusPointer->left_arm_tilt) {
3097 		xenoStatusPointer->left_arm_tilt->Active=1;
3098 	}
3099 
3100 }
3101 
3102 void Xeno_LeftArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate)
3103 {
3104 	XENO_STATUS_BLOCK *xenoStatusPointer;
3105 
3106 	LOCALASSERT(sbPtr);
3107 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3108 	LOCALASSERT(xenoStatusPointer);
3109 
3110 	/* Let's wave the left arm around. */
3111 	if (xenoStatusPointer->leftarmtiltdir) {
3112 		xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate);
3113 		if (xenoStatusPointer->Left_Arm_Tilt>-(XENO_HEADTILT_GIMBALL<<4)) {
3114 			xenoStatusPointer->Left_Arm_Tilt=-(XENO_HEADTILT_GIMBALL<<4);
3115 			xenoStatusPointer->leftarmtiltdir=0;
3116 		} else {
3117 			xenoStatusPointer->la_moving=1;
3118 		}
3119 	} else {
3120 		xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate);
3121 		if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3122 			xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3123 			xenoStatusPointer->leftarmtiltdir=1;
3124 		} else {
3125 			xenoStatusPointer->la_moving=1;
3126 		}
3127 	}
3128 
3129 	if (xenoStatusPointer->left_arm_tilt) {
3130 		xenoStatusPointer->left_arm_tilt->Active=1;
3131 	}
3132 
3133 }
3134 
3135 void Xeno_RightArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate)
3136 {
3137 	XENO_STATUS_BLOCK *xenoStatusPointer;
3138 
3139 	LOCALASSERT(sbPtr);
3140 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3141 	LOCALASSERT(xenoStatusPointer);
3142 
3143 	/* Let's wave the Right arm around. */
3144 	if (xenoStatusPointer->rightarmpandir) {
3145 		xenoStatusPointer->Right_Arm_Pan+=(NormalFrameTime>>rate);
3146 		if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) {
3147 			xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4);
3148 			xenoStatusPointer->rightarmpandir=0;
3149 		} else {
3150 			xenoStatusPointer->ra_moving=1;
3151 		}
3152 	} else {
3153 		xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate);
3154 		if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) {
3155 			xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4);
3156 			xenoStatusPointer->rightarmpandir=1;
3157 		} else {
3158 			xenoStatusPointer->ra_moving=1;
3159 		}
3160 	}
3161 
3162 	if (xenoStatusPointer->right_arm_pan) {
3163 		xenoStatusPointer->right_arm_pan->Active=1;
3164 	}
3165 
3166 }
3167 
3168 void Xeno_RightArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate)
3169 {
3170 	XENO_STATUS_BLOCK *xenoStatusPointer;
3171 
3172 	LOCALASSERT(sbPtr);
3173 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3174 	LOCALASSERT(xenoStatusPointer);
3175 
3176 	/* Let's wave the Right arm around. */
3177 	if (xenoStatusPointer->rightarmtiltdir) {
3178 		xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate);
3179 		if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3180 			xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3181 			xenoStatusPointer->rightarmtiltdir=0;
3182 		} else {
3183 			xenoStatusPointer->ra_moving=1;
3184 		}
3185 	} else {
3186 		xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate);
3187 		if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3188 			xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3189 			xenoStatusPointer->rightarmtiltdir=1;
3190 		} else {
3191 			xenoStatusPointer->ra_moving=1;
3192 		}
3193 	}
3194 
3195 	if (xenoStatusPointer->right_arm_tilt) {
3196 		xenoStatusPointer->right_arm_tilt->Active=1;
3197 	}
3198 
3199 }
3200 
3201 void Xeno_RightArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate)
3202 {
3203 	XENO_STATUS_BLOCK *xenoStatusPointer;
3204 
3205 	LOCALASSERT(sbPtr);
3206 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3207 	LOCALASSERT(xenoStatusPointer);
3208 
3209 	/* Let's wave the Right arm around. */
3210 	if (xenoStatusPointer->rightarmtiltdir) {
3211 		xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate);
3212 		if (xenoStatusPointer->Right_Arm_Tilt>-(XENO_HEADTILT_GIMBALL<<4)) {
3213 			xenoStatusPointer->Right_Arm_Tilt=-(XENO_HEADTILT_GIMBALL<<4);
3214 			xenoStatusPointer->rightarmtiltdir=0;
3215 		} else {
3216 			xenoStatusPointer->ra_moving=1;
3217 		}
3218 	} else {
3219 		xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate);
3220 		if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3221 			xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3222 			xenoStatusPointer->rightarmtiltdir=1;
3223 		} else {
3224 			xenoStatusPointer->ra_moving=1;
3225 		}
3226 	}
3227 
3228 	if (xenoStatusPointer->right_arm_tilt) {
3229 		xenoStatusPointer->right_arm_tilt->Active=1;
3230 	}
3231 
3232 }
3233 
3234 void Xeno_TorsoMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate)
3235 {
3236 	XENO_STATUS_BLOCK *xenoStatusPointer;
3237 
3238 	LOCALASSERT(sbPtr);
3239 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3240 	LOCALASSERT(xenoStatusPointer);
3241 
3242 	/* Let's twist the torso. */
3243 	if (xenoStatusPointer->torsotwistdir) {
3244 		xenoStatusPointer->Torso_Twist+=(NormalFrameTime>>rate);
3245 		if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) {
3246 			xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4);
3247 			xenoStatusPointer->torsotwistdir=0;
3248 		} else {
3249 			xenoStatusPointer->torso_moving=1;
3250 		}
3251 	} else {
3252 		xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate);
3253 		if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) {
3254 			xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4);
3255 			xenoStatusPointer->torsotwistdir=1;
3256 		} else {
3257 			xenoStatusPointer->torso_moving=1;
3258 		}
3259 	}
3260 
3261 	if (xenoStatusPointer->right_arm_tilt) {
3262 		xenoStatusPointer->right_arm_tilt->Active=1;
3263 	}
3264 
3265 }
3266 
3267 int Xeno_HeadMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley)
3268 {
3269 	XENO_STATUS_BLOCK *xenoStatusPointer;
3270 	int real_anglex,angley,online;
3271 
3272 	LOCALASSERT(sbPtr);
3273 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3274 	LOCALASSERT(xenoStatusPointer);
3275 
3276 	/* Turn the head to face a certain way. */
3277 
3278 	real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4);
3279 	angley=in_angley;
3280 	online=0;
3281 
3282 	/* Now fix multiples. */
3283 	while ((real_anglex>4095)||(real_anglex<0)) {
3284 		if (real_anglex<0) {
3285 			real_anglex+=4096;
3286 		} else if (real_anglex>4095) {
3287 			real_anglex-=4096;
3288 		}
3289 	}
3290 
3291 	if (real_anglex>=3072) real_anglex-=4096;
3292 	if (real_anglex>=2048) real_anglex=real_anglex-3072;
3293 	if (real_anglex> 1024) real_anglex=2048-real_anglex;
3294 
3295 	if (angley>=3072) angley-=4096;
3296 	if (angley>=2048) angley=angley-3072;
3297 	if (angley> 1024) angley=2048-angley;
3298 
3299 	GLOBALASSERT((real_anglex<=1024)&&(real_anglex>=-1024));
3300 	GLOBALASSERT((angley<=1024)&&(angley>=-1024));
3301 
3302 	if (ShowXenoStats) {
3303 		PrintDebuggingText("Target head angles: %d %d\n",real_anglex,angley);
3304 	}
3305 
3306 	real_anglex<<=4;
3307 	angley<<=4;
3308 
3309 	if (xenoStatusPointer->Head_Pan<real_anglex) {
3310 		xenoStatusPointer->Head_Pan+=(NormalFrameTime>>rate);
3311 		if (xenoStatusPointer->Head_Pan>(XENO_HEADPAN_GIMBALL<<4)) {
3312 			xenoStatusPointer->Head_Pan=(XENO_HEADPAN_GIMBALL<<4);
3313 		} else if (xenoStatusPointer->Head_Pan>real_anglex) {
3314 			xenoStatusPointer->Head_Pan=real_anglex;
3315 			online++;
3316 		}
3317 	} else if (xenoStatusPointer->Head_Pan>real_anglex) {
3318 		xenoStatusPointer->Head_Pan-=(NormalFrameTime>>rate);
3319 		if (xenoStatusPointer->Head_Pan<-(XENO_HEADPAN_GIMBALL<<4)) {
3320 			xenoStatusPointer->Head_Pan=-(XENO_HEADPAN_GIMBALL<<4);
3321 		} else if (xenoStatusPointer->Head_Pan<real_anglex) {
3322 			xenoStatusPointer->Head_Pan=real_anglex;
3323 			online++;
3324 		}
3325 	} else {
3326 		online++;
3327 	}
3328 
3329 	if (xenoStatusPointer->head_pan) {
3330 		xenoStatusPointer->head_pan->Active=1;
3331 	}
3332 
3333 	/* Now y. */
3334 	angley=-angley;
3335 	/* Oops. */
3336 
3337 	if (xenoStatusPointer->Head_Tilt<angley) {
3338 		xenoStatusPointer->Head_Tilt+=(NormalFrameTime>>rate);
3339 		if (xenoStatusPointer->Head_Tilt>(XENO_HEADTILT_GIMBALL<<4)) {
3340 			xenoStatusPointer->Head_Tilt=(XENO_HEADTILT_GIMBALL<<4);
3341 		} else if (xenoStatusPointer->Head_Tilt>angley) {
3342 			xenoStatusPointer->Head_Tilt=angley;
3343 			online++;
3344 		}
3345 	} else if (xenoStatusPointer->Head_Tilt>angley) {
3346 		xenoStatusPointer->Head_Tilt-=(NormalFrameTime>>rate);
3347 		if (xenoStatusPointer->Head_Tilt<-(XENO_HEADTILT_GIMBALL<<4)) {
3348 			xenoStatusPointer->Head_Tilt=-(XENO_HEADTILT_GIMBALL<<4);
3349 		} else if (xenoStatusPointer->Head_Tilt<angley) {
3350 			xenoStatusPointer->Head_Tilt=angley;
3351 			online++;
3352 		}
3353 	} else {
3354 		online++;
3355 	}
3356 
3357 	if (xenoStatusPointer->head_tilt) {
3358 		xenoStatusPointer->head_tilt->Active=1;
3359 	}
3360 
3361 	if (online<=1) {
3362 		/* Still moving! */
3363 		xenoStatusPointer->head_moving=1;
3364 	}
3365 
3366 	if (xenoStatusPointer->HeadLaserOnTarget) {
3367 		online=2;
3368 	}
3369 
3370 	if (online>1) {
3371 		return(1);
3372 	} else {
3373 		return(0);
3374 	}
3375 }
3376 
3377 void Xeno_TorsoMovement_TrackToAngle(STRATEGYBLOCK *sbPtr,int rate,int in_anglex)
3378 {
3379 	XENO_STATUS_BLOCK *xenoStatusPointer;
3380 	int anglex;
3381 
3382 	LOCALASSERT(sbPtr);
3383 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3384 	LOCALASSERT(xenoStatusPointer);
3385 
3386 	/* Turn the torso to face a certain way. No angley here. */
3387 
3388 	anglex=in_anglex;
3389 
3390 	if (anglex>=3072) anglex-=4096;
3391 	if (anglex>=2048) anglex=anglex-3072;
3392 	if (anglex> 1024) anglex=2048-anglex;
3393 
3394 	anglex<<=4;
3395 
3396 	if (xenoStatusPointer->Torso_Twist<anglex) {
3397 		xenoStatusPointer->Torso_Twist+=(NormalFrameTime>>rate);
3398 		if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) {
3399 			xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4);
3400 		} else if (xenoStatusPointer->Torso_Twist>anglex) {
3401 			xenoStatusPointer->Torso_Twist=anglex;
3402 		} else {
3403 			xenoStatusPointer->torso_moving=1;
3404 		}
3405 	} else if (xenoStatusPointer->Torso_Twist>anglex) {
3406 		xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate);
3407 		if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) {
3408 			xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4);
3409 		} else if (xenoStatusPointer->Torso_Twist<anglex) {
3410 			xenoStatusPointer->Torso_Twist=anglex;
3411 		} else {
3412 			xenoStatusPointer->torso_moving=1;
3413 		}
3414 	}
3415 
3416 	if (xenoStatusPointer->torso_twist) {
3417 		xenoStatusPointer->torso_twist->Active=1;
3418 	}
3419 
3420 }
3421 
3422 void Xeno_TorsoMovement_Centre(STRATEGYBLOCK *sbPtr,int rate)
3423 {
3424 	XENO_STATUS_BLOCK *xenoStatusPointer;
3425 
3426 	LOCALASSERT(sbPtr);
3427 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3428 	LOCALASSERT(xenoStatusPointer);
3429 
3430 	/* Turn the torso to face a certain way. No angley here. */
3431 
3432 	if (xenoStatusPointer->Torso_Twist<0) {
3433 		xenoStatusPointer->Torso_Twist+=(NormalFrameTime>>rate);
3434 		if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) {
3435 			xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4);
3436 		} else if (xenoStatusPointer->Torso_Twist>0) {
3437 			xenoStatusPointer->Torso_Twist=0;
3438 		} else {
3439 			xenoStatusPointer->torso_moving=1;
3440 		}
3441 	} else if (xenoStatusPointer->Torso_Twist>0) {
3442 		xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate);
3443 		if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) {
3444 			xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4);
3445 		} else if (xenoStatusPointer->Torso_Twist<0) {
3446 			xenoStatusPointer->Torso_Twist=0;
3447 		} else {
3448 			xenoStatusPointer->torso_moving=1;
3449 		}
3450 	}
3451 
3452 	if (xenoStatusPointer->torso_twist) {
3453 		xenoStatusPointer->torso_twist->Active=1;
3454 	}
3455 
3456 }
3457 
3458 int Xeno_LeftArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley)
3459 {
3460 	XENO_STATUS_BLOCK *xenoStatusPointer;
3461 	int real_anglex,angley,online;
3462 
3463 	LOCALASSERT(sbPtr);
3464 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3465 	LOCALASSERT(xenoStatusPointer);
3466 
3467 	/* Aim the Left Arm at a point. */
3468 
3469 	real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4);
3470 	angley=in_angley;
3471 	online=0;
3472 
3473 	/* Now fix multiples. */
3474 	while ((real_anglex>4095)||(real_anglex<0)) {
3475 		if (real_anglex<0) {
3476 			real_anglex+=4096;
3477 		} else if (real_anglex>4095) {
3478 			real_anglex-=4096;
3479 		}
3480 	}
3481 
3482 	if (real_anglex>=3072) real_anglex-=4096;
3483 	if (real_anglex>=2048) real_anglex=real_anglex-3072;
3484 	if (real_anglex> 1024) real_anglex=2048-real_anglex;
3485 
3486 	if (angley>=3072) angley-=4096;
3487 	if (angley>=2048) angley=angley-3072;
3488 	if (angley> 1024) angley=2048-angley;
3489 
3490 	real_anglex<<=4;
3491 	angley<<=4;
3492 
3493 	if (xenoStatusPointer->Left_Arm_Pan<real_anglex) {
3494 		xenoStatusPointer->Left_Arm_Pan+=(NormalFrameTime>>rate);
3495 		if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) {
3496 			xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4);
3497 		} else if (xenoStatusPointer->Left_Arm_Pan>real_anglex) {
3498 			xenoStatusPointer->Left_Arm_Pan=real_anglex;
3499 			online++;
3500 		}
3501 	} else if (xenoStatusPointer->Left_Arm_Pan>real_anglex) {
3502 		xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate);
3503 		if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) {
3504 			xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4);
3505 		} else if (xenoStatusPointer->Left_Arm_Pan<real_anglex) {
3506 			xenoStatusPointer->Left_Arm_Pan=real_anglex;
3507 			online++;
3508 		}
3509 	} else {
3510 		online++;
3511 	}
3512 
3513 	if (xenoStatusPointer->left_arm_pan) {
3514 		xenoStatusPointer->left_arm_pan->Active=1;
3515 	}
3516 
3517 	/* Now y. */
3518 	angley=-angley;
3519 	/* Oops. */
3520 
3521 	if (xenoStatusPointer->Left_Arm_Tilt<angley) {
3522 		xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate);
3523 		if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3524 			xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3525 		} else if (xenoStatusPointer->Left_Arm_Tilt>angley) {
3526 			xenoStatusPointer->Left_Arm_Tilt=angley;
3527 			online++;
3528 		}
3529 	} else if (xenoStatusPointer->Left_Arm_Tilt>angley) {
3530 		xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate);
3531 		if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3532 			xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3533 		} else if (xenoStatusPointer->Left_Arm_Tilt<angley) {
3534 			xenoStatusPointer->Left_Arm_Tilt=angley;
3535 			online++;
3536 		}
3537 	} else {
3538 		online++;
3539 	}
3540 
3541 	if (xenoStatusPointer->left_arm_tilt) {
3542 		xenoStatusPointer->left_arm_tilt->Active=1;
3543 	}
3544 
3545 	if (online<=1) {
3546 		/* Still going! */
3547 		xenoStatusPointer->la_moving=1;
3548 	}
3549 
3550 	if (xenoStatusPointer->HeadLaserOnTarget) {
3551 		xenoStatusPointer->UseLALaser=1;
3552 	}
3553 
3554 	if (xenoStatusPointer->LALaserOnTarget) {
3555 		online=2;
3556 	}
3557 
3558 	if (online>1) {
3559 		if (xenoStatusPointer->Target) {
3560 			/* What the heck! */
3561 			xenoStatusPointer->FiringLeft=1;
3562 		}
3563 		return(1);
3564 	} else {
3565 		return(0);
3566 	}
3567 
3568 }
3569 
3570 void Xeno_LeftArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate)
3571 {
3572 	XENO_STATUS_BLOCK *xenoStatusPointer;
3573 
3574 	LOCALASSERT(sbPtr);
3575 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3576 	LOCALASSERT(xenoStatusPointer);
3577 
3578 	/* Centre the Left Arm. */
3579 
3580 	if (xenoStatusPointer->Left_Arm_Pan<0) {
3581 		xenoStatusPointer->Left_Arm_Pan+=(NormalFrameTime>>rate);
3582 		if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) {
3583 			xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4);
3584 		} else if (xenoStatusPointer->Left_Arm_Pan>0) {
3585 			xenoStatusPointer->Left_Arm_Pan=0;
3586 		} else {
3587 			xenoStatusPointer->la_moving=1;
3588 		}
3589 	} else if (xenoStatusPointer->Left_Arm_Pan>0) {
3590 		xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate);
3591 		if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) {
3592 			xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4);
3593 		} else if (xenoStatusPointer->Left_Arm_Pan<0) {
3594 			xenoStatusPointer->Left_Arm_Pan=0;
3595 		} else {
3596 			xenoStatusPointer->la_moving=1;
3597 		}
3598 	}
3599 
3600 	if (xenoStatusPointer->left_arm_pan) {
3601 		xenoStatusPointer->left_arm_pan->Active=1;
3602 	}
3603 
3604 	/* Now y. */
3605 
3606 	if (xenoStatusPointer->Left_Arm_Tilt<0) {
3607 		xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate);
3608 		if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3609 			xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3610 		} else if (xenoStatusPointer->Left_Arm_Tilt>0) {
3611 			xenoStatusPointer->Left_Arm_Tilt=0;
3612 		} else {
3613 			xenoStatusPointer->la_moving=1;
3614 		}
3615 	} else if (xenoStatusPointer->Left_Arm_Tilt>0) {
3616 		xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate);
3617 		if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3618 			xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3619 		} else if (xenoStatusPointer->Left_Arm_Tilt<0) {
3620 			xenoStatusPointer->Left_Arm_Tilt=0;
3621 		} else {
3622 			xenoStatusPointer->la_moving=1;
3623 		}
3624 	}
3625 
3626 	if (xenoStatusPointer->left_arm_tilt) {
3627 		xenoStatusPointer->left_arm_tilt->Active=1;
3628 	}
3629 
3630 	return;
3631 
3632 }
3633 
3634 int Xeno_RightArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley)
3635 {
3636 	XENO_STATUS_BLOCK *xenoStatusPointer;
3637 	int real_anglex,angley,online;
3638 
3639 	LOCALASSERT(sbPtr);
3640 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3641 	LOCALASSERT(xenoStatusPointer);
3642 
3643 	/* Aim the Right Arm at a point. */
3644 
3645 	real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4)+RATweak;
3646 	angley=in_angley;
3647 	online=0;
3648 
3649 	/* Now fix multiples. */
3650 	while ((real_anglex>4095)||(real_anglex<0)) {
3651 		if (real_anglex<0) {
3652 			real_anglex+=4096;
3653 		} else if (real_anglex>4095) {
3654 			real_anglex-=4096;
3655 		}
3656 	}
3657 
3658 	if (real_anglex>=3072) real_anglex-=4096;
3659 	if (real_anglex>=2048) real_anglex=real_anglex-3072;
3660 	if (real_anglex> 1024) real_anglex=2048-real_anglex;
3661 
3662 	if (angley>=3072) angley-=4096;
3663 	if (angley>=2048) angley=angley-3072;
3664 	if (angley> 1024) angley=2048-angley;
3665 
3666 	real_anglex<<=4;
3667 	angley<<=4;
3668 
3669 	if (xenoStatusPointer->Right_Arm_Pan<real_anglex) {
3670 		xenoStatusPointer->Right_Arm_Pan+=(NormalFrameTime>>rate);
3671 		if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) {
3672 			xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4);
3673 		} else if (xenoStatusPointer->Right_Arm_Pan>real_anglex) {
3674 			xenoStatusPointer->Right_Arm_Pan=real_anglex;
3675 			online++;
3676 		}
3677 	} else if (xenoStatusPointer->Right_Arm_Pan>real_anglex) {
3678 		xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate);
3679 		if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) {
3680 			xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4);
3681 		} else if (xenoStatusPointer->Right_Arm_Pan<real_anglex) {
3682 			xenoStatusPointer->Right_Arm_Pan=real_anglex;
3683 			online++;
3684 		}
3685 	} else {
3686 		online++;
3687 	}
3688 
3689 	if (xenoStatusPointer->right_arm_pan) {
3690 		xenoStatusPointer->right_arm_pan->Active=1;
3691 	}
3692 
3693 	/* Now y. */
3694 	angley=-angley;
3695 	/* Oops. */
3696 
3697 	if (xenoStatusPointer->Right_Arm_Tilt<angley) {
3698 		xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate);
3699 		if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3700 			xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3701 		} else if (xenoStatusPointer->Right_Arm_Tilt>angley) {
3702 			xenoStatusPointer->Right_Arm_Tilt=angley;
3703 			online++;
3704 		}
3705 	} else if (xenoStatusPointer->Right_Arm_Tilt>angley) {
3706 		xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate);
3707 		if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3708 			xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3709 		} else if (xenoStatusPointer->Right_Arm_Tilt<angley) {
3710 			xenoStatusPointer->Right_Arm_Tilt=angley;
3711 			online++;
3712 		}
3713 	} else {
3714 		online++;
3715 	}
3716 
3717 	if (xenoStatusPointer->right_arm_tilt) {
3718 		xenoStatusPointer->right_arm_tilt->Active=1;
3719 	}
3720 
3721 	if (online<=1) {
3722 		/* Still moving! */
3723 		xenoStatusPointer->ra_moving=1;
3724 	}
3725 
3726 	if (xenoStatusPointer->HeadLaserOnTarget) {
3727 		xenoStatusPointer->UseRALaser=1;
3728 	}
3729 
3730 	if (xenoStatusPointer->RALaserOnTarget) {
3731 		online=2;
3732 	}
3733 
3734 	if (online>1) {
3735 		if (xenoStatusPointer->Target) {
3736 			/* What the heck! */
3737 			xenoStatusPointer->FiringRight=1;
3738 		}
3739 		return(1);
3740 	} else {
3741 		return(0);
3742 	}
3743 
3744 }
3745 
3746 void Xeno_RightArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate)
3747 {
3748 	XENO_STATUS_BLOCK *xenoStatusPointer;
3749 
3750 	LOCALASSERT(sbPtr);
3751 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3752 	LOCALASSERT(xenoStatusPointer);
3753 
3754 	/* Centre the Right Arm. */
3755 
3756 	if (xenoStatusPointer->Right_Arm_Pan<0) {
3757 		xenoStatusPointer->Right_Arm_Pan+=(NormalFrameTime>>rate);
3758 		if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) {
3759 			xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4);
3760 		} else if (xenoStatusPointer->Right_Arm_Pan>0) {
3761 			xenoStatusPointer->Right_Arm_Pan=0;
3762 		} else {
3763 			xenoStatusPointer->ra_moving=1;
3764 		}
3765 	} else if (xenoStatusPointer->Right_Arm_Pan>0) {
3766 		xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate);
3767 		if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) {
3768 			xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4);
3769 		} else if (xenoStatusPointer->Right_Arm_Pan<0) {
3770 			xenoStatusPointer->Right_Arm_Pan=0;
3771 		} else {
3772 			xenoStatusPointer->ra_moving=1;
3773 		}
3774 	}
3775 
3776 	if (xenoStatusPointer->right_arm_pan) {
3777 		xenoStatusPointer->right_arm_pan->Active=1;
3778 	}
3779 
3780 	/* Now y. */
3781 
3782 	if (xenoStatusPointer->Right_Arm_Tilt<0) {
3783 		xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate);
3784 		if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) {
3785 			xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4);
3786 		} else if (xenoStatusPointer->Right_Arm_Tilt>0) {
3787 			xenoStatusPointer->Right_Arm_Tilt=0;
3788 		} else {
3789 			xenoStatusPointer->ra_moving=1;
3790 		}
3791 	} else if (xenoStatusPointer->Right_Arm_Tilt>0) {
3792 		xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate);
3793 		if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) {
3794 			xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4);
3795 		} else if (xenoStatusPointer->Right_Arm_Tilt<0) {
3796 			xenoStatusPointer->Right_Arm_Tilt=0;
3797 		} else {
3798 			xenoStatusPointer->ra_moving=1;
3799 		}
3800 	}
3801 
3802 	if (xenoStatusPointer->right_arm_tilt) {
3803 		xenoStatusPointer->right_arm_tilt->Active=1;
3804 	}
3805 
3806 	return;
3807 
3808 }
3809 
3810 int XenoActivation_FrustrumReject(VECTORCH *localOffset) {
3811 
3812 	if ( (localOffset->vz <0)
3813 		&& (localOffset->vz <  localOffset->vx)
3814 		&& (localOffset->vz < -localOffset->vx)
3815 		&& (localOffset->vz <  localOffset->vy)
3816 		&& (localOffset->vz < -localOffset->vy) ) {
3817 
3818 		/* 90 horizontal, 90 vertical. */
3819 		return(1);
3820 	} else {
3821 		return(0);
3822 	}
3823 
3824 }
3825 
3826 int XenoSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset) {
3827 
3828 	XENO_STATUS_BLOCK *xenoStatusPointer;
3829 
3830 	LOCALASSERT(sbPtr);
3831 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3832 	LOCALASSERT(xenoStatusPointer);
3833 
3834 	if ( (localOffset->vx>0) ) {
3835 		/* 180 horizontal, 180 vertical. */
3836 		return(1);
3837 	} else {
3838 		if ((xenoStatusPointer->Target)||(xenoStatusPointer->ShotThisFrame)) {
3839 			return(1);
3840 		} else {
3841 			return(0);
3842 		}
3843 	}
3844 
3845 }
3846 
3847 void Xeno_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr) {
3848 
3849 	XENO_STATUS_BLOCK *xenoStatusPointer;
3850 
3851 	LOCALASSERT(sbPtr);
3852 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3853 	LOCALASSERT(xenoStatusPointer);
3854 
3855 	if (xenoStatusPointer->Target==NULL) {
3856 		xenoStatusPointer->targetTrackPos.vx=0;
3857 		xenoStatusPointer->targetTrackPos.vy=0;
3858 		xenoStatusPointer->targetTrackPos.vz=0;
3859 		return;
3860 	}
3861 
3862 	GetTargetingPointOfObject_Far(xenoStatusPointer->Target,&xenoStatusPointer->targetTrackPos);
3863 
3864 }
3865 
3866 static void ProcessFarXenoborgTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
3867 {
3868 	NPC_TARGETMODULESTATUS targetStatus;
3869 	XENO_STATUS_BLOCK *xenoStatusPointer;
3870 
3871 	LOCALASSERT(sbPtr);
3872 	LOCALASSERT(targetModule);
3873 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3874 	LOCALASSERT(xenoStatusPointer);
3875 
3876 	targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0);
3877 	switch(targetStatus)
3878 	{
3879 		case(NPCTM_NoEntryPoint):
3880 		{
3881 			/* do nothing */
3882 			FarNpc_FlipAround(sbPtr);
3883 			break;
3884 		}
3885 		case(NPCTM_NormalRoom):
3886 		{
3887 			/* locate to target	*/
3888 			LocateFarNPCInAIModule(sbPtr, targetModule);
3889 			break;
3890 		}
3891 		case(NPCTM_AirDuct):
3892 		{
3893 			/* loacate to target */
3894 			LocateFarNPCInAIModule(sbPtr, targetModule);
3895 			break;
3896 		}
3897 		case(NPCTM_LiftTeleport):
3898 		{
3899 			/* do nothing */
3900 			FarNpc_FlipAround(sbPtr);
3901 			break;
3902 		}
3903 		case(NPCTM_ProxDoorOpen):
3904 		{
3905 			LocateFarNPCInAIModule(sbPtr, targetModule);
3906 			break;
3907 		}
3908 		case(NPCTM_ProxDoorNotOpen):
3909 		{
3910 			MODULE *renderModule;
3911 			renderModule=*(targetModule->m_module_ptrs);
3912 			/* trigger the door, and set timer to quick so we can catch the door when it's open */
3913 			((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1;
3914 			break;
3915 		}
3916 		case(NPCTM_LiftDoorOpen):
3917 		{
3918 			/* do nothing - can't use lifts	*/
3919 			//FarNpc_FlipAround(sbPtr);
3920 			/* What the hell!!! */
3921 			LocateFarNPCInAIModule(sbPtr, targetModule);
3922 			break;
3923 		}
3924 		case(NPCTM_LiftDoorNotOpen):
3925 		{
3926 		   	/*  do nothing - can't open lift doors */
3927 			FarNpc_FlipAround(sbPtr);
3928 		   	break;
3929 		}
3930 		case(NPCTM_SecurityDoorOpen):
3931 		{
3932 			/* locate to target, and move thro' quick as we can't retrigger	*/
3933 			LocateFarNPCInAIModule(sbPtr, targetModule);
3934 			break;
3935 		}
3936 		case(NPCTM_SecurityDoorNotOpen):
3937 		{
3938 			MODULE *renderModule;
3939 			renderModule=*(targetModule->m_module_ptrs);
3940 			/* do some door opening stuff here. Door should stay open for long enough
3941 			for us to catch it open next time */
3942 			RequestState((renderModule->m_sbptr),1,0);
3943 		   	break;
3944 		}
3945 		default:
3946 		{
3947 			LOCALASSERT(1==0);
3948 		}
3949 	}
3950 }
3951 
3952 void Execute_Xeno_ActiveWait_Far(STRATEGYBLOCK *sbPtr)
3953 {
3954 	XENO_STATUS_BLOCK *xenoStatusPointer;
3955 	int anglex,angley,correctlyOrientated;
3956 
3957 	LOCALASSERT(sbPtr);
3958 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
3959 	LOCALASSERT(xenoStatusPointer);
3960 
3961 	/* What to do?  Do we have a target? */
3962 
3963 	if (ShowXenoStats) {
3964 		PrintDebuggingText("In ActiveWait Far.\n");
3965 	}
3966 
3967 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2));
3968 
3969 	if (xenoStatusPointer->Target==NULL) {
3970 		#if FAR_XENO_ACTIVITY
3971 		/* Let's wave the head around. */
3972 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
3973 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
3974 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
3975 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
3976 		Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2);
3977 		#endif
3978 
3979 		if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) {
3980 			Xeno_Enter_Returning_State(sbPtr);
3981 			return;
3982 		}
3983 
3984 		xenoStatusPointer->stateTimer+=NormalFrameTime;
3985 		if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) {
3986 			Xeno_Enter_PowerDown_State(sbPtr);
3987 		}
3988 
3989 		/* Are we at home? */
3990 		if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) {
3991 			Xeno_Enter_Returning_State(sbPtr);
3992 			return;
3993 		}
3994 		/* Are we facing the right way? */
3995 
3996 		correctlyOrientated = NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin,ONE_FIXED,NULL);
3997 
3998 		if (!correctlyOrientated) {
3999 
4000 			SECTION_DATA *master_section;
4001 
4002 			master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley");
4003 			GLOBALASSERT(master_section);
4004 
4005 			Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset);
4006 
4007 			if (anglex>0) {
4008 				EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
4009 			} else {
4010 				EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
4011 			}
4012 			#if FAR_XENO_ACTIVITY
4013 			if (xenoStatusPointer->soundHandle1==SOUND_NOACTIVEINDEX) {
4014 				Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1);
4015 			}
4016 			#endif
4017 		} else {
4018 
4019 			/* Otherwise just wait? */
4020 			if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
4021 				/* Well, it shouldn't be! */
4022 				Sound_Stop(xenoStatusPointer->soundHandle1);
4023 			}
4024 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2));
4025 			xenoStatusPointer->stateTimer+=NormalFrameTime;
4026 			if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) {
4027 				Xeno_Enter_PowerDown_State(sbPtr);
4028 			}
4029 		}
4030 		return;
4031 	}
4032 
4033 	GLOBALASSERT(xenoStatusPointer->Target);
4034 	/* Now we have a target.  Can we see it? */
4035 	if (xenoStatusPointer->targetSightTest==0) {
4036 		/* Can't see them.  Are we out of range? */
4037 		if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
4038 			xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) {
4039 			Xeno_Enter_Returning_State(sbPtr);
4040 		} else {
4041 			Xeno_Enter_Following_State(sbPtr);
4042 		}
4043 		return;
4044 	}
4045 
4046 	#if FAR_XENO_ACTIVITY
4047 	Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
4048 
4049 	if ((anglex>(((XENO_HEADPAN_GIMBALL)*7)/8))
4050 		||(anglex<-(((XENO_HEADPAN_GIMBALL)*7)/8))) {
4051 
4052 		Xeno_Enter_TurnToFace_State(sbPtr);
4053 
4054 	}
4055 	#endif
4056 
4057 	if (ShowXenoStats) {
4058 		PrintDebuggingText("Targets in module....\n");
4059 	}
4060 
4061 }
4062 
4063 void Execute_Xeno_TurnToFace_Far(STRATEGYBLOCK *sbPtr)
4064 {
4065 	XENO_STATUS_BLOCK *xenoStatusPointer;
4066 	int correctlyOrientated;
4067 	int anglex,angley;
4068 
4069 	LOCALASSERT(sbPtr);
4070 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4071 	LOCALASSERT(xenoStatusPointer);
4072 
4073 	/* Do we have a target? */
4074 
4075 	if (ShowXenoStats) {
4076 		PrintDebuggingText("In Turn To Face Far.\n");
4077 	}
4078 
4079 	if (xenoStatusPointer->Target==NULL) {
4080 		Xeno_Enter_ActiveWait_State(sbPtr);
4081 		/* Otherwise just wait? */
4082 		return;
4083 	}
4084 
4085 	/* Now we have a target. */
4086 	GLOBALASSERT(xenoStatusPointer->Target);
4087 
4088 	/* Set up animation... Which Way? */
4089 	{
4090 		SECTION_DATA *master_section;
4091 		VECTORCH orientationDirn;
4092 
4093 		master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley");
4094 		GLOBALASSERT(master_section);
4095 
4096 		Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset);
4097 
4098 		if (anglex<2048) {
4099 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
4100 		} else {
4101 			EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2));
4102 		}
4103 
4104 		/* Then turn to face it, of course. */
4105 
4106 		orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx;
4107 		orientationDirn.vy = 0;
4108 		orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz;
4109 		correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL);
4110 		/* Spin FAST. */
4111 	}
4112 
4113 	#if FAR_XENO_ACTIVITY
4114 	Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
4115 	#endif
4116 
4117 	if (correctlyOrientated) {
4118 		Xeno_Enter_ActiveWait_State(sbPtr);
4119 	}
4120 
4121 }
4122 
4123 void Execute_Xeno_Follow_Far(STRATEGYBLOCK *sbPtr)
4124 {
4125 	XENO_STATUS_BLOCK *xenoStatusPointer;
4126 #if FAR_XENO_ACTIVITY
4127 	int anglex,angley;
4128 #endif
4129 
4130 	LOCALASSERT(sbPtr);
4131 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4132 	LOCALASSERT(xenoStatusPointer);
4133 
4134 	/* In theory, we're following the target, and can't see it. */
4135 
4136 	if (ShowXenoStats) {
4137 		PrintDebuggingText("In Follow Far.\n");
4138 	}
4139 
4140 	if (xenoStatusPointer->Target==NULL) {
4141 		/* Let's wave the head around. */
4142 		#if FAR_XENO_ACTIVITY
4143 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
4144 		Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2);
4145 		#endif
4146 		/* And return to my module. */
4147 		Xeno_Enter_Returning_State(sbPtr);
4148 		return;
4149 	}
4150 
4151 	/* Increment the Far state timer */
4152 	xenoStatusPointer->stateTimer += NormalFrameTime;
4153 	/* check if far state timer has timed-out. If so, it is time
4154 	to do something. Otherwise just return. */
4155 	if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) {
4156 		#if FAR_XENO_ACTIVITY
4157 		Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
4158 		#endif
4159 		return;
4160 	}
4161 
4162 	GLOBALASSERT(xenoStatusPointer->Target);
4163 	/* Now we know have a target.  Can we see it yet? */
4164 
4165 	if (xenoStatusPointer->targetSightTest==0) {
4166 
4167 		AIMODULE *targetModule;
4168 
4169 		/* Can't see them.  Never mind.  Go to the next module? */
4170 		if (xenoStatusPointer->Target->containingModule==NULL) {
4171 			/* Fall through for now. */
4172 			targetModule=NULL;
4173 		} else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
4174 			xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) {
4175 			/* Too Far! */
4176 			Xeno_Enter_ActiveWait_State(sbPtr);
4177 			return;
4178 		} else {
4179 			/* Still in range: keep going. */
4180 			targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
4181 				xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0);
4182 
4183 		}
4184 
4185 		if (targetModule==NULL) {
4186 			/* They're way away. */
4187 			Xeno_Enter_Returning_State(sbPtr);
4188 			return;
4189 		}
4190 
4191 		if (targetModule!=xenoStatusPointer->Target->containingModule->m_aimodule) {
4192 
4193 			GLOBALASSERT(targetModule);
4194 			ProcessFarXenoborgTargetModule(sbPtr,targetModule);
4195 
4196 		} else {
4197 			/* In our target's module! */
4198 
4199 			Xeno_Enter_ActiveWait_State(sbPtr);
4200 
4201 		}
4202 
4203 	} else {
4204 		/* Re-aquired! */
4205 		Xeno_Enter_ActiveWait_State(sbPtr);
4206 		return;
4207 	}
4208 
4209 	xenoStatusPointer->stateTimer=0;
4210 
4211 	#if 0
4212 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
4213 	#else
4214 	XenoborgHandleMovingAnimation(sbPtr);
4215 	#endif
4216 
4217 	#if FAR_XENO_ACTIVITY
4218 	if (xenoStatusPointer->targetSightTest==0) {
4219 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
4220 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4221 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4222 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
4223 	} else {
4224 		Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
4225 	}
4226 	#endif
4227 
4228 }
4229 
4230 void Execute_Xeno_Return_Far(STRATEGYBLOCK *sbPtr)
4231 {
4232 	XENO_STATUS_BLOCK *xenoStatusPointer;
4233 
4234 	LOCALASSERT(sbPtr);
4235 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4236 	LOCALASSERT(xenoStatusPointer);
4237 
4238 	/* In theory, we're following the target, and can't see it. */
4239 
4240 	if (ShowXenoStats) {
4241 		PrintDebuggingText("In Return Far.\n");
4242 	}
4243 
4244 	if (xenoStatusPointer->Target!=NULL) {
4245 		/* Saw something! */
4246 		/* Go to active wait. */
4247 		Xeno_Enter_ActiveWait_State(sbPtr);
4248 		return;
4249 	}
4250 
4251 	/* Increment the Far state timer */
4252 	xenoStatusPointer->stateTimer += NormalFrameTime;
4253 	/* check if far state timer has timed-out. If so, it is time
4254 	to do something. Otherwise just return. */
4255 	if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) {
4256 		#if FAR_XENO_ACTIVITY
4257 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
4258 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
4259 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4260 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4261 		#endif
4262 		return;
4263 	}
4264 
4265 	GLOBALASSERT(xenoStatusPointer->Target==NULL);
4266 	/* Find our way home. */
4267 
4268 	{
4269 
4270 		AIMODULE *targetModule;
4271 
4272 		/* Go to the next module. */
4273 		targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
4274 			xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0);
4275 		/* Just to be on the safe side. */
4276 
4277 		if (targetModule==NULL) {
4278 			/* Emergency! */
4279 			targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
4280 				xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0);
4281 			if (targetModule==NULL) {
4282 				/* Totally broken.  Stay here. */
4283 				Xeno_CopeWithLossOfHome(sbPtr);
4284 				return;
4285 			}
4286 		}
4287 
4288 		if (targetModule!=sbPtr->containingModule->m_aimodule) {
4289 
4290 			GLOBALASSERT(targetModule);
4291 			ProcessFarXenoborgTargetModule(sbPtr,targetModule);
4292 
4293 		} else {
4294 			/* In our own home module! */
4295 
4296 			sbPtr->DynPtr->Position=xenoStatusPointer->my_spot_therin;
4297 
4298 			Xeno_Enter_ActiveWait_State(sbPtr);
4299 
4300 		}
4301 	}
4302 
4303 	xenoStatusPointer->stateTimer=0;
4304 
4305 	#if 0
4306 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
4307 	#else
4308 	XenoborgHandleMovingAnimation(sbPtr);
4309 	#endif
4310 
4311 	#if FAR_XENO_ACTIVITY
4312 	Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
4313 	Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4314 	Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4315 	Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
4316 	#endif
4317 
4318 }
4319 
4320 void Execute_Xeno_Avoidance_Far(STRATEGYBLOCK *sbPtr)
4321 {
4322 	XENO_STATUS_BLOCK *xenoStatusPointer;
4323 #if FAR_XENO_ACTIVITY
4324 	int anglex,angley;
4325 #endif
4326 
4327 	LOCALASSERT(sbPtr);
4328 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4329 	LOCALASSERT(xenoStatusPointer);
4330 
4331 	if (ShowXenoStats) {
4332 		PrintDebuggingText("In Avoidance Far.\n");
4333 	}
4334 
4335 	/* Sequences... */
4336 	#if 0
4337 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
4338 	#else
4339 	XenoborgHandleMovingAnimation(sbPtr);
4340 	#endif
4341 
4342 	#if FAR_XENO_ACTIVITY
4343 	if (xenoStatusPointer->targetSightTest==0) {
4344 		Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE);
4345 		Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4346 		Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE);
4347 		Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE);
4348 	} else {
4349 		Xeno_TurnAndTarget(sbPtr,&anglex,&angley);
4350 	}
4351 	#endif
4352 
4353 	{
4354 
4355 		/* go to an appropriate state */
4356 		switch (xenoStatusPointer->lastState) {
4357 			case XS_Returning:
4358 				Xeno_Enter_Returning_State(sbPtr);
4359 				return;
4360 				break;
4361 			case XS_Following:
4362 				Xeno_Enter_Following_State(sbPtr);
4363 				return;
4364 				break;
4365 			default:
4366 				Xeno_Enter_ActiveWait_State(sbPtr);
4367 				return;
4368 				break;
4369 		}
4370 		/* Still here? */
4371 		return;
4372 
4373 	}
4374 	return;
4375 }
4376 
4377 #define FIRING_RATE_LEFT	25
4378 
4379 void Xenoborg_MaintainLeftGun(STRATEGYBLOCK *sbPtr)
4380 {
4381 	XENO_STATUS_BLOCK *xenoStatusPointer;
4382 	SECTION_DATA *left_dum;
4383 	VECTORCH alpha;
4384 	VECTORCH beta;
4385 	int multiple;
4386 
4387 	LOCALASSERT(sbPtr);
4388 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4389 	LOCALASSERT(xenoStatusPointer);
4390 
4391 	left_dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy A");
4392 
4393 	if (xenoStatusPointer->Wounds&section_flag_left_hand) {
4394 		xenoStatusPointer->FiringLeft=0;
4395 	}
4396 
4397 	if ((xenoStatusPointer->FiringLeft==0)||(left_dum==NULL)||(xenoStatusPointer->IAmFar)) {
4398 		/* Not firing, go away. */
4399 		xenoStatusPointer->LeftMainBeam.BeamIsOn = 0;
4400 		return;
4401 	}
4402 
4403 	/* Okay, must be firing.  Did we get anyone? */
4404 
4405 	multiple=FIRING_RATE_LEFT*NormalFrameTime;
4406 
4407 	#if 0
4408 	LOS_Lambda = NPC_MAX_VIEWRANGE;
4409 	LOS_ObjectHitPtr = 0;
4410 	LOS_HModel_Section=NULL;
4411 	{
4412 	   	extern int NumActiveBlocks;
4413 		extern DISPLAYBLOCK* ActiveBlockList[];
4414 	   	int numberOfObjects = NumActiveBlocks;
4415 
4416 	   	while (numberOfObjects--)
4417 		{
4418 			DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects];
4419 
4420 			alpha = left_dum->World_Offset;
4421 
4422 			beta.vx=left_dum->SecMat.mat31;
4423 			beta.vy=left_dum->SecMat.mat32;
4424 			beta.vz=left_dum->SecMat.mat33;
4425 
4426 			GLOBALASSERT(objectPtr);
4427 
4428 			if (objectPtr!=sbPtr->SBdptr) {
4429 				/* Can't hit self. */
4430 				CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1);
4431 			}
4432 		}
4433 	}
4434 	#else
4435 	{
4436 		alpha = left_dum->World_Offset;
4437 
4438 		beta.vx=left_dum->SecMat.mat31;
4439 		beta.vy=left_dum->SecMat.mat32;
4440 		beta.vz=left_dum->SecMat.mat33;
4441 		FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr);
4442 	}
4443 	#endif
4444 
4445 	/* Now deal with LOS_ObjectHitPtr. */
4446 	if (LOS_ObjectHitPtr) {
4447 		if (LOS_HModel_Section) {
4448 			if (LOS_ObjectHitPtr->ObStrategyBlock) {
4449 				if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) {
4450 					GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller);
4451 				}
4452 			}
4453 		}
4454 		/* this fn needs updating to take amount of damage into account etc. */
4455 		HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_XENOBORG,&beta, multiple, LOS_HModel_Section);
4456 	}
4457 
4458 	/* Cheat for killing far targets? */
4459 	if (xenoStatusPointer->Target) {
4460 		if (xenoStatusPointer->Target->SBdptr==NULL) {
4461 			HandleWeaponImpact(&xenoStatusPointer->Target->DynPtr->Position,xenoStatusPointer->Target,AMMO_XENOBORG,&beta, multiple, NULL);
4462 		}
4463 	}
4464 
4465 	/* update beam SFX data */
4466 	xenoStatusPointer->LeftMainBeam.BeamIsOn = 1;
4467 	xenoStatusPointer->LeftMainBeam.SourcePosition = left_dum->World_Offset;
4468 
4469 	if (LOS_ObjectHitPtr) {
4470 		xenoStatusPointer->LeftMainBeam.TargetPosition = LOS_Point;
4471 	} else {
4472 		/* Must be hitting nothing... */
4473 		xenoStatusPointer->LeftMainBeam.TargetPosition=alpha;
4474 		xenoStatusPointer->LeftMainBeam.TargetPosition.vx+=(beta.vx>>3);
4475 		xenoStatusPointer->LeftMainBeam.TargetPosition.vy+=(beta.vy>>3);
4476 		xenoStatusPointer->LeftMainBeam.TargetPosition.vz+=(beta.vz>>3);
4477 	}
4478 
4479 	if (LOS_ObjectHitPtr==Player)
4480 	{
4481 		xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = 1;
4482 	}
4483 	else
4484 	{
4485 		xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = 0;
4486 	}
4487 }
4488 
4489 #define FIRING_RATE_RIGHT	25
4490 
4491 void Xenoborg_MaintainRightGun(STRATEGYBLOCK *sbPtr)
4492 {
4493 	XENO_STATUS_BLOCK *xenoStatusPointer;
4494 	SECTION_DATA *right_dum;
4495 	VECTORCH alpha;
4496 	VECTORCH beta;
4497 	int multiple;
4498 
4499 	LOCALASSERT(sbPtr);
4500 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4501 	LOCALASSERT(xenoStatusPointer);
4502 
4503 	right_dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy B");
4504 
4505 	if (xenoStatusPointer->Wounds&section_flag_right_hand) {
4506 		xenoStatusPointer->FiringRight=0;
4507 	}
4508 
4509 	if ((xenoStatusPointer->FiringRight==0)||(right_dum==NULL)||(xenoStatusPointer->IAmFar)) {
4510 		/* Not firing, go away. */
4511 		xenoStatusPointer->RightMainBeam.BeamIsOn = 0;
4512 		return;
4513 	}
4514 
4515 	/* Okay, must be firing.  Did we get anyone? */
4516 
4517 	multiple=FIRING_RATE_RIGHT*NormalFrameTime;
4518 
4519 	#if 0
4520 	LOS_Lambda = NPC_MAX_VIEWRANGE;
4521 	LOS_ObjectHitPtr = 0;
4522 	LOS_HModel_Section=NULL;
4523 	{
4524 	   	extern int NumActiveBlocks;
4525 		extern DISPLAYBLOCK* ActiveBlockList[];
4526 	   	int numberOfObjects = NumActiveBlocks;
4527 
4528 	   	while (numberOfObjects--)
4529 		{
4530 			DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects];
4531 
4532 			alpha = right_dum->World_Offset;
4533 
4534 			beta.vx=right_dum->SecMat.mat31;
4535 			beta.vy=right_dum->SecMat.mat32;
4536 			beta.vz=right_dum->SecMat.mat33;
4537 
4538 			GLOBALASSERT(objectPtr);
4539 
4540 			if (objectPtr!=sbPtr->SBdptr) {
4541 				/* Can't hit self. */
4542 				CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1);
4543 			}
4544 		}
4545 	}
4546 	#else
4547 	{
4548 		alpha = right_dum->World_Offset;
4549 
4550 		beta.vx=right_dum->SecMat.mat31;
4551 		beta.vy=right_dum->SecMat.mat32;
4552 		beta.vz=right_dum->SecMat.mat33;
4553 		FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr);
4554 	}
4555 	#endif
4556 	/* Now deal with LOS_ObjectHitPtr. */
4557 	if (LOS_ObjectHitPtr) {
4558 		if (LOS_HModel_Section) {
4559 			if (LOS_ObjectHitPtr->ObStrategyBlock) {
4560 				if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) {
4561 					GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller);
4562 				}
4563 			}
4564 		}
4565 		/* this fn needs updating to take amount of damage into account etc. */
4566 		HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_XENOBORG,&beta, multiple, LOS_HModel_Section);
4567 	}
4568 
4569 	/* Cheat for killing far targets? */
4570 	if (xenoStatusPointer->Target) {
4571 		if (xenoStatusPointer->Target->SBdptr==NULL) {
4572 			HandleWeaponImpact(&xenoStatusPointer->Target->DynPtr->Position,xenoStatusPointer->Target,AMMO_XENOBORG,&beta, multiple, NULL);
4573 		}
4574 	}
4575 
4576 	/* update beam SFX data */
4577 	xenoStatusPointer->RightMainBeam.BeamIsOn = 1;
4578 	xenoStatusPointer->RightMainBeam.SourcePosition = right_dum->World_Offset;
4579 
4580 	if (LOS_ObjectHitPtr) {
4581 		xenoStatusPointer->RightMainBeam.TargetPosition = LOS_Point;
4582 	} else {
4583 		/* Must be hitting nothing... */
4584 		xenoStatusPointer->RightMainBeam.TargetPosition=alpha;
4585 		xenoStatusPointer->RightMainBeam.TargetPosition.vx+=(beta.vx>>3);
4586 		xenoStatusPointer->RightMainBeam.TargetPosition.vy+=(beta.vy>>3);
4587 		xenoStatusPointer->RightMainBeam.TargetPosition.vz+=(beta.vz>>3);
4588 	}
4589 
4590 	if (LOS_ObjectHitPtr==Player)
4591 	{
4592 		xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = 1;
4593 	}
4594 	else
4595 	{
4596 		xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = 0;
4597 	}
4598 
4599 }
4600 
4601 int Xeno_Activation_Test(STRATEGYBLOCK *sbPtr) {
4602 
4603 	XENO_STATUS_BLOCK *xenoStatusPointer;
4604 	STRATEGYBLOCK *candidate;
4605 	MATRIXCH WtoL;
4606 	int a;
4607 	MODULE *dmod;
4608 
4609 	dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule);
4610 
4611 	LOCALASSERT(dmod);
4612 
4613 	LOCALASSERT(sbPtr);
4614 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4615 	LOCALASSERT(xenoStatusPointer);
4616 
4617 	WtoL=sbPtr->DynPtr->OrientMat;
4618 	TransposeMatrixCH(&WtoL);
4619 
4620 	for (a=0; a<NumActiveStBlocks; a++) {
4621 		candidate=ActiveStBlockList[a];
4622 		if (candidate!=sbPtr) {
4623 			if (candidate->DynPtr) {
4624 				if (Xenoborg_TargetFilter(candidate)) {
4625 					VECTORCH offset;
4626 
4627 					offset.vx=sbPtr->DynPtr->Position.vx-candidate->DynPtr->Position.vx;
4628 					offset.vy=sbPtr->DynPtr->Position.vy-candidate->DynPtr->Position.vy;
4629 					offset.vz=sbPtr->DynPtr->Position.vz-candidate->DynPtr->Position.vz;
4630 
4631 					RotateVector(&offset,&WtoL);
4632 
4633 					if (XenoActivation_FrustrumReject(&offset)) {
4634 						/* Check visibility? */
4635 						if (NPCCanSeeTarget(sbPtr,candidate,XENO_NEAR_VIEW_WIDTH)) {
4636 							if (!NPC_IsDead(candidate)) {
4637 								if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
4638 									return(1);
4639 								}
4640 							}
4641 						}
4642 					}
4643 				}
4644 			}
4645 		}
4646 	}
4647 	return(0);
4648 }
4649 
4650 void Xeno_MaintainLasers(STRATEGYBLOCK *sbPtr) {
4651 
4652 	XENO_STATUS_BLOCK *xenoStatusPointer;
4653 	SECTION_DATA *dum;
4654 	VECTORCH alpha;
4655 	VECTORCH beta;
4656 	int a,uselaser;
4657 
4658 	LOCALASSERT(sbPtr);
4659 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4660 	LOCALASSERT(xenoStatusPointer);
4661 
4662 	xenoStatusPointer->HeadLaserOnTarget=0;
4663 	xenoStatusPointer->LALaserOnTarget=0;
4664 	xenoStatusPointer->RALaserOnTarget=0;
4665 
4666 	#if (FAR_XENO_ACTIVITY==0)
4667 	if (xenoStatusPointer->IAmFar) {
4668 		xenoStatusPointer->TargetingLaser[0].BeamIsOn=0;
4669 		xenoStatusPointer->TargetingLaser[1].BeamIsOn=0;
4670 		xenoStatusPointer->TargetingLaser[2].BeamIsOn=0;
4671 		return;
4672 	}
4673 	#endif
4674 
4675 	for (a=0; a<3; a++) {
4676 
4677 		xenoStatusPointer->TargetingLaser[a].BeamIsOn=0;
4678 		switch (a) {
4679 			case 0:
4680 				dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummyZ");
4681 				if (xenoStatusPointer->UseHeadLaser) {
4682 					uselaser=1;
4683 				} else {
4684 					uselaser=0;
4685 				}
4686 				if (dum==NULL) {
4687 					uselaser=0;
4688 				}
4689 				break;
4690 			case 1:
4691 				dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy C");
4692 				if (xenoStatusPointer->UseLALaser) {
4693 					uselaser=1;
4694 				} else {
4695 					uselaser=0;
4696 				}
4697 				if (dum==NULL) {
4698 					uselaser=0;
4699 				}
4700 				break;
4701 			case 2:
4702 				dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy D");
4703 				if (xenoStatusPointer->UseRALaser) {
4704 					uselaser=1;
4705 				} else {
4706 					uselaser=0;
4707 				}
4708 				if (dum==NULL) {
4709 					uselaser=0;
4710 				}
4711 				break;
4712 			default:
4713 				GLOBALASSERT(0);
4714 				break;
4715 		}
4716 
4717 		if (uselaser) {
4718 
4719 			alpha = dum->World_Offset;
4720 
4721 			beta.vx=dum->SecMat.mat31;
4722 			beta.vy=dum->SecMat.mat32;
4723 			beta.vz=dum->SecMat.mat33;
4724 
4725 			FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr);
4726 
4727 			/* Now deal with LOS_ObjectHitPtr. */
4728 			if (LOS_ObjectHitPtr==Player) {
4729 				xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer=1;
4730 			} else {
4731 				xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer=0;
4732 			}
4733 
4734 			xenoStatusPointer->TargetingLaser[a].SourcePosition=alpha;
4735 			if (LOS_ObjectHitPtr) {
4736 				xenoStatusPointer->TargetingLaser[a].TargetPosition=LOS_Point;
4737 			} else {
4738 				/* Must be hitting nothing... */
4739 				xenoStatusPointer->TargetingLaser[a].TargetPosition=alpha;
4740 				xenoStatusPointer->TargetingLaser[a].TargetPosition.vx+=(beta.vx>>3);
4741 				xenoStatusPointer->TargetingLaser[a].TargetPosition.vy+=(beta.vy>>3);
4742 				xenoStatusPointer->TargetingLaser[a].TargetPosition.vz+=(beta.vz>>3);
4743 
4744 			}
4745 			xenoStatusPointer->TargetingLaser[a].BeamIsOn=1;
4746 
4747 			if (LOS_ObjectHitPtr) {
4748 				if (LOS_ObjectHitPtr->ObStrategyBlock==xenoStatusPointer->Target) {
4749 					switch (a) {
4750 						case 0:
4751 							xenoStatusPointer->HeadLaserOnTarget=1;
4752 							break;
4753 						case 1:
4754 							xenoStatusPointer->LALaserOnTarget=1;
4755 							break;
4756 						case 2:
4757 							xenoStatusPointer->RALaserOnTarget=1;
4758 							break;
4759 						default:
4760 							GLOBALASSERT(0);
4761 							break;
4762 					}
4763 				}
4764 			}
4765 		}
4766 	}
4767 
4768 }
4769 
4770 void Xeno_SwitchLED(STRATEGYBLOCK *sbPtr,int state) {
4771 
4772 	XENO_STATUS_BLOCK *xenoStatusPointer;
4773 	SECTION_DATA *led;
4774 
4775 	LOCALASSERT(sbPtr);
4776 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4777 	LOCALASSERT(xenoStatusPointer);
4778 
4779 	led=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"led");
4780 
4781 	if (led) {
4782 		if (led->tac_ptr) {
4783 			led->tac_ptr->tac_sequence = state ;
4784 			led->tac_ptr->tac_txah_s = GetTxAnimHeaderFromShape(led->tac_ptr, led->ShapeNum);
4785 		}
4786 	}
4787 }
4788 
4789 void Xeno_Stomp(STRATEGYBLOCK *sbPtr) {
4790 
4791 	XENO_STATUS_BLOCK *xenoStatusPointer;
4792 	SECTION_DATA *foot;
4793 
4794 	LOCALASSERT(sbPtr);
4795 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4796 	LOCALASSERT(xenoStatusPointer);
4797 
4798 	foot=NULL;
4799 
4800 	if (xenoStatusPointer->HModelController.keyframe_flags&4) {
4801 		foot=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right foot");
4802 	} else if (xenoStatusPointer->HModelController.keyframe_flags&8) {
4803 		foot=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left foot");
4804 	}
4805 
4806 	if (foot) {
4807 		Sound_Play(SID_STOMP,"d",&foot->World_Offset);
4808 	}
4809 
4810 }
4811 
4812 void Xeno_MaintainSounds(STRATEGYBLOCK *sbPtr) {
4813 
4814 	XENO_STATUS_BLOCK *xenoStatusPointer;
4815 	SECTION_DATA *sec;
4816 
4817 	LOCALASSERT(sbPtr);
4818 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4819 	LOCALASSERT(xenoStatusPointer);
4820 
4821 	/* First, the two big system sounds. */
4822 	if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) {
4823 		Sound_Update3d(xenoStatusPointer->soundHandle1,&sbPtr->DynPtr->Position);
4824 	}
4825 	if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
4826 		Sound_Update3d(xenoStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
4827 	}
4828 
4829 	/* Now, all the lesser sounds: */
4830 	/* Head. */
4831 	sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"head");
4832 	if (sec==NULL) {
4833 		/* No sound. */
4834 		if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) {
4835 			Sound_Stop(xenoStatusPointer->head_whirr);
4836 		}
4837 	} else {
4838 		if (xenoStatusPointer->head_moving==0) {
4839 			/* Stationary. */
4840 			if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) {
4841 				Sound_Stop(xenoStatusPointer->head_whirr);
4842 				Sound_Play(SID_ARMEND,"d",&sec->World_Offset);
4843 			}
4844 		} else {
4845 			/* Moving! */
4846 			if (xenoStatusPointer->head_whirr==SOUND_NOACTIVEINDEX) {
4847 				Sound_Play(SID_ARMSTART,"d",&sec->World_Offset);
4848 				Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->head_whirr);
4849 			} else {
4850 				Sound_Update3d(xenoStatusPointer->head_whirr,&sec->World_Offset);
4851 			}
4852 		}
4853 	}
4854 	/* Left Arm. */
4855 	sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left bicep");
4856 	if (sec==NULL) {
4857 		/* No sound. */
4858 		if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) {
4859 			Sound_Stop(xenoStatusPointer->left_arm_whirr);
4860 		}
4861 	} else {
4862 		if (xenoStatusPointer->la_moving==0) {
4863 			/* Stationary. */
4864 			if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) {
4865 				Sound_Stop(xenoStatusPointer->left_arm_whirr);
4866 				Sound_Play(SID_ARMEND,"d",&sec->World_Offset);
4867 			}
4868 		} else {
4869 			/* Moving! */
4870 			if (xenoStatusPointer->left_arm_whirr==SOUND_NOACTIVEINDEX) {
4871 				Sound_Play(SID_ARMSTART,"d",&sec->World_Offset);
4872 				Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->left_arm_whirr);
4873 			} else {
4874 				Sound_Update3d(xenoStatusPointer->left_arm_whirr,&sec->World_Offset);
4875 			}
4876 		}
4877 	}
4878 	/* Right Arm. */
4879 	sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right bicep");
4880 	if (sec==NULL) {
4881 		/* No sound. */
4882 		if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) {
4883 			Sound_Stop(xenoStatusPointer->right_arm_whirr);
4884 		}
4885 	} else {
4886 		if (xenoStatusPointer->ra_moving==0) {
4887 			/* Stationary. */
4888 			if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) {
4889 				Sound_Stop(xenoStatusPointer->right_arm_whirr);
4890 				Sound_Play(SID_ARMEND,"d",&sec->World_Offset);
4891 			}
4892 		} else {
4893 			/* Moving! */
4894 			if (xenoStatusPointer->right_arm_whirr==SOUND_NOACTIVEINDEX) {
4895 				Sound_Play(SID_ARMSTART,"d",&sec->World_Offset);
4896 				Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->right_arm_whirr);
4897 			} else {
4898 				Sound_Update3d(xenoStatusPointer->right_arm_whirr,&sec->World_Offset);
4899 			}
4900 		}
4901 	}
4902 	/* Torso Twist. */
4903 	sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"chest");
4904 	if (sec==NULL) {
4905 		/* No sound. */
4906 		if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) {
4907 			Sound_Stop(xenoStatusPointer->torso_whirr);
4908 		}
4909 	} else {
4910 		if (xenoStatusPointer->torso_moving==0) {
4911 			/* Stationary. */
4912 			if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) {
4913 				Sound_Stop(xenoStatusPointer->torso_whirr);
4914 				Sound_Play(SID_ARMEND,"d",&sec->World_Offset);
4915 			}
4916 		} else {
4917 			/* Moving! */
4918 			if (xenoStatusPointer->torso_whirr==SOUND_NOACTIVEINDEX) {
4919 				Sound_Play(SID_ARMSTART,"d",&sec->World_Offset);
4920 				Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->torso_whirr);
4921 			} else {
4922 				Sound_Update3d(xenoStatusPointer->torso_whirr,&sec->World_Offset);
4923 			}
4924 		}
4925 	}
4926 }
4927 
4928 void XenoborgHandleMovingAnimation(STRATEGYBLOCK *sbPtr) {
4929 
4930 	XENO_STATUS_BLOCK *xenoStatusPointer;
4931 	VECTORCH offset;
4932 	int speed,animfactor;
4933 
4934 	LOCALASSERT(sbPtr);
4935 	xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
4936 	LOCALASSERT(xenoStatusPointer);
4937 
4938 	offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx;
4939 	offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
4940 	offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz;
4941 
4942 	/* ...compute speed factor... */
4943 	speed=Magnitude(&offset);
4944 	if (speed<(MUL_FIXED(NormalFrameTime,50))) {
4945 		/* Not moving much, are we?  Be stationary! */
4946 		if (ShowXenoStats) {
4947 			PrintDebuggingText("Forced stationary animation!\n");
4948 		}
4949 		EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2));
4950 		return;
4951 	}
4952 	speed=DIV_FIXED(speed,NormalFrameTime);
4953 
4954 	if (speed==0) {
4955 		animfactor=ONE_FIXED;
4956 	} else {
4957 		animfactor=DIV_FIXED(625,speed); // Was 512!  Difference to correct for rounding down...
4958 	}
4959 	GLOBALASSERT(animfactor>0);
4960 	if (ShowXenoStats) {
4961 		PrintDebuggingText("Anim Factor %d, Tweening %d\n",animfactor,xenoStatusPointer->HModelController.Tweening);
4962 	}
4963 
4964 	/* Start animation. */
4965 	EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2));
4966 
4967 	if (xenoStatusPointer->HModelController.Tweening==0) {
4968 		HModel_SetToolsRelativeSpeed(&xenoStatusPointer->HModelController,animfactor);
4969 	}
4970 
4971 }
4972 
4973 
4974 /*--------------------**
4975 ** Loading and Saving **
4976 **--------------------*/
4977 #include "savegame.h"
4978 
4979 typedef struct xenoborg_save_block
4980 {
4981 	SAVE_BLOCK_STRATEGY_HEADER header;
4982 
4983 //behaviour block stuff
4984 	signed int health;
4985 	XENO_BHSTATE behaviourState;
4986 	XENO_BHSTATE lastState;
4987 	int stateTimer;
4988 	NPC_WANDERDATA wanderData;
4989 	NPC_OBSTRUCTIONREPORT obstruction;
4990 	VECTORCH my_spot_therin;
4991 	VECTORCH my_orientdir_therin;
4992 	int module_range;
4993 	int UpTime;
4994 	int GibbFactor;
4995 	int Wounds;
4996 
4997 
4998 
4999 	VECTORCH targetTrackPos;
5000 
5001 	int Head_Pan;
5002 	int Head_Tilt;
5003 	int Left_Arm_Pan;
5004 	int Left_Arm_Tilt;
5005 	int Right_Arm_Pan;
5006 	int Right_Arm_Tilt;
5007 	int Torso_Twist;
5008 
5009 	int Old_Head_Pan;
5010 	int Old_Head_Tilt;
5011 	int Old_Left_Arm_Pan;
5012 	int Old_Left_Arm_Tilt;
5013 	int Old_Right_Arm_Pan;
5014 	int Old_Right_Arm_Tilt;
5015 	int Old_Torso_Twist;
5016 
5017  	LASER_BEAM_DESC LeftMainBeam;
5018  	LASER_BEAM_DESC RightMainBeam;
5019  	LASER_BEAM_DESC TargetingLaser[3];
5020 
5021 	unsigned int headpandir			:1;
5022 	unsigned int headtiltdir		:1;
5023 	unsigned int leftarmpandir		:1;
5024 	unsigned int leftarmtiltdir		:1;
5025 	unsigned int rightarmpandir		:1;
5026 	unsigned int rightarmtiltdir	:1;
5027 	unsigned int torsotwistdir		:1;
5028 
5029 	unsigned int headLock			:1;
5030 	unsigned int leftArmLock		:1;
5031 	unsigned int rightArmLock		:1;
5032 	unsigned int targetSightTest	:1;
5033 	unsigned int IAmFar				:1;
5034 	unsigned int ShotThisFrame		:1;
5035 
5036 	unsigned int FiringLeft			:1;
5037 	unsigned int FiringRight		:1;
5038 
5039 	unsigned int UseHeadLaser		:1;
5040 	unsigned int UseLALaser			:1;
5041 	unsigned int UseRALaser			:1;
5042 
5043 	unsigned int HeadLaserOnTarget	:1;
5044 	unsigned int LALaserOnTarget	:1;
5045 	unsigned int RALaserOnTarget	:1;
5046 
5047 	unsigned int head_moving		:1;
5048 	unsigned int la_moving			:1;
5049 	unsigned int ra_moving			:1;
5050 	unsigned int torso_moving		:1;
5051 
5052 	int incidentFlag;
5053 	int incidentTimer;
5054 
5055 	int head_whirr;
5056 	int left_arm_whirr;
5057 	int right_arm_whirr;
5058 	int torso_whirr;
5059 
5060 
5061 //annoying pointer related things
5062 	int my_module_index;
5063 
5064 	char Target_SBname[SB_NAME_LENGTH];
5065 
5066 //strategyblock stuff
5067 	int integrity;
5068 	DAMAGEBLOCK SBDamageBlock;
5069 	DYNAMICSBLOCK dynamics;
5070 }XENOBORG_SAVE_BLOCK;
5071 
5072 
5073 
5074 
5075 //defines for load/save macros
5076 #define SAVELOAD_BLOCK block
5077 #define SAVELOAD_BEHAV xenoStatusPointer
5078 
5079 
5080 void LoadStrategy_Xenoborg(SAVE_BLOCK_STRATEGY_HEADER* header)
5081 {
5082 	int i;
5083 	STRATEGYBLOCK* sbPtr;
5084 	XENO_STATUS_BLOCK* xenoStatusPointer;
5085 	XENOBORG_SAVE_BLOCK* block = (XENOBORG_SAVE_BLOCK*) header;
5086 
5087 	//check the size of the save block
5088 	if(header->size!=sizeof(*block)) return;
5089 
5090 	//find the existing strategy block
5091 	sbPtr = FindSBWithName(header->SBname);
5092 	if(!sbPtr) return;
5093 
5094 	//make sure the strategy found is of the right type
5095 	if(sbPtr->I_SBtype != I_BehaviourXenoborg) return;
5096 
5097 	xenoStatusPointer =(XENO_STATUS_BLOCK*) sbPtr->SBdataptr;
5098 
5099 
5100 	//start copying stuff
5101 	COPYELEMENT_LOAD(health)
5102 	COPYELEMENT_LOAD(behaviourState)
5103 	COPYELEMENT_LOAD(lastState)
5104 	COPYELEMENT_LOAD(stateTimer)
5105 	COPYELEMENT_LOAD(wanderData)
5106 	COPYELEMENT_LOAD(obstruction)
5107 	COPYELEMENT_LOAD(my_spot_therin)
5108 	COPYELEMENT_LOAD(my_orientdir_therin)
5109 	COPYELEMENT_LOAD(module_range)
5110 	COPYELEMENT_LOAD(UpTime)
5111 	COPYELEMENT_LOAD(GibbFactor)
5112 	COPYELEMENT_LOAD(Wounds)
5113 	COPYELEMENT_LOAD(targetTrackPos)
5114 	COPYELEMENT_LOAD(Head_Pan)
5115 	COPYELEMENT_LOAD(Head_Tilt)
5116 	COPYELEMENT_LOAD(Left_Arm_Pan)
5117 	COPYELEMENT_LOAD(Left_Arm_Tilt)
5118 	COPYELEMENT_LOAD(Right_Arm_Pan)
5119 	COPYELEMENT_LOAD(Right_Arm_Tilt)
5120 	COPYELEMENT_LOAD(Torso_Twist)
5121 	COPYELEMENT_LOAD(Old_Head_Pan)
5122 	COPYELEMENT_LOAD(Old_Head_Tilt)
5123 	COPYELEMENT_LOAD(Old_Left_Arm_Pan)
5124 	COPYELEMENT_LOAD(Old_Left_Arm_Tilt)
5125 	COPYELEMENT_LOAD(Old_Right_Arm_Pan)
5126 	COPYELEMENT_LOAD(Old_Right_Arm_Tilt)
5127 	COPYELEMENT_LOAD(Old_Torso_Twist)
5128  	COPYELEMENT_LOAD(LeftMainBeam)
5129  	COPYELEMENT_LOAD(RightMainBeam)
5130 
5131 
5132 	COPYELEMENT_LOAD(headpandir)
5133 	COPYELEMENT_LOAD(headtiltdir)
5134 	COPYELEMENT_LOAD(leftarmpandir)
5135 	COPYELEMENT_LOAD(leftarmtiltdir)
5136 	COPYELEMENT_LOAD(rightarmpandir)
5137 	COPYELEMENT_LOAD(rightarmtiltdir)
5138 	COPYELEMENT_LOAD(torsotwistdir)
5139 
5140 	COPYELEMENT_LOAD(headLock)
5141 	COPYELEMENT_LOAD(leftArmLock)
5142 	COPYELEMENT_LOAD(rightArmLock)
5143 	COPYELEMENT_LOAD(targetSightTest)
5144 	COPYELEMENT_LOAD(IAmFar)
5145 	COPYELEMENT_LOAD(ShotThisFrame)
5146 
5147 	COPYELEMENT_LOAD(FiringLeft)
5148 	COPYELEMENT_LOAD(FiringRight)
5149 
5150 	COPYELEMENT_LOAD(UseHeadLaser)
5151 	COPYELEMENT_LOAD(UseLALaser)
5152 	COPYELEMENT_LOAD(UseRALaser)
5153 
5154 	COPYELEMENT_LOAD(HeadLaserOnTarget)
5155 	COPYELEMENT_LOAD(LALaserOnTarget)
5156 	COPYELEMENT_LOAD(RALaserOnTarget)
5157 
5158 	COPYELEMENT_LOAD(head_moving)
5159 	COPYELEMENT_LOAD(la_moving)
5160 	COPYELEMENT_LOAD(ra_moving)
5161 	COPYELEMENT_LOAD(torso_moving)
5162 
5163 	COPYELEMENT_LOAD(incidentFlag)
5164 	COPYELEMENT_LOAD(incidentTimer)
5165 
5166 	COPYELEMENT_LOAD(head_whirr)
5167 	COPYELEMENT_LOAD(left_arm_whirr)
5168 	COPYELEMENT_LOAD(right_arm_whirr)
5169 	COPYELEMENT_LOAD(torso_whirr)
5170 
5171  	for(i=0;i<3;i++)
5172 	{
5173  		COPYELEMENT_LOAD(TargetingLaser[i])
5174 	}
5175 
5176 	//load ai module pointers
5177 	xenoStatusPointer->my_module = GetPointerFromAIModuleIndex(block->my_module_index);
5178 
5179 	//load target
5180 	COPY_NAME(xenoStatusPointer->Target_SBname,block->Target_SBname);
5181 	xenoStatusPointer->Target = FindSBWithName(xenoStatusPointer->Target_SBname);
5182 
5183 	//copy strategy block stuff
5184 	*sbPtr->DynPtr = block->dynamics;
5185 	sbPtr->integrity = block->integrity;
5186 	sbPtr->SBDamageBlock = block->SBDamageBlock;
5187 
5188 	//load hierarchy
5189 	{
5190 		SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
5191 		if(hier_header)
5192 		{
5193 			LoadHierarchy(hier_header,&xenoStatusPointer->HModelController);
5194 		}
5195 	}
5196 
5197 
5198 	//finally get the delta controller pointers
5199 	VerifyDeltaControllers(sbPtr);
5200 
5201 	Load_SoundState(&xenoStatusPointer->soundHandle1);
5202 	Load_SoundState(&xenoStatusPointer->soundHandle2);
5203 }
5204 
5205 
5206 void SaveStrategy_Xenoborg(STRATEGYBLOCK* sbPtr)
5207 {
5208 	int i;
5209 	XENO_STATUS_BLOCK* xenoStatusPointer;
5210 	XENOBORG_SAVE_BLOCK* block;
5211 
5212 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
5213 	xenoStatusPointer = (XENO_STATUS_BLOCK*) sbPtr->SBdataptr;
5214 
5215 	//start copying stuff
5216 
5217 	COPYELEMENT_SAVE(health)
5218 	COPYELEMENT_SAVE(behaviourState)
5219 	COPYELEMENT_SAVE(lastState)
5220 	COPYELEMENT_SAVE(stateTimer)
5221 	COPYELEMENT_SAVE(wanderData)
5222 	COPYELEMENT_SAVE(obstruction)
5223 	COPYELEMENT_SAVE(my_spot_therin)
5224 	COPYELEMENT_SAVE(my_orientdir_therin)
5225 	COPYELEMENT_SAVE(module_range)
5226 	COPYELEMENT_SAVE(UpTime)
5227 	COPYELEMENT_SAVE(GibbFactor)
5228 	COPYELEMENT_SAVE(Wounds)
5229 	COPYELEMENT_SAVE(targetTrackPos)
5230 	COPYELEMENT_SAVE(Head_Pan)
5231 	COPYELEMENT_SAVE(Head_Tilt)
5232 	COPYELEMENT_SAVE(Left_Arm_Pan)
5233 	COPYELEMENT_SAVE(Left_Arm_Tilt)
5234 	COPYELEMENT_SAVE(Right_Arm_Pan)
5235 	COPYELEMENT_SAVE(Right_Arm_Tilt)
5236 	COPYELEMENT_SAVE(Torso_Twist)
5237 	COPYELEMENT_SAVE(Old_Head_Pan)
5238 	COPYELEMENT_SAVE(Old_Head_Tilt)
5239 	COPYELEMENT_SAVE(Old_Left_Arm_Pan)
5240 	COPYELEMENT_SAVE(Old_Left_Arm_Tilt)
5241 	COPYELEMENT_SAVE(Old_Right_Arm_Pan)
5242 	COPYELEMENT_SAVE(Old_Right_Arm_Tilt)
5243 	COPYELEMENT_SAVE(Old_Torso_Twist)
5244  	COPYELEMENT_SAVE(LeftMainBeam)
5245  	COPYELEMENT_SAVE(RightMainBeam)
5246 
5247 
5248 	COPYELEMENT_SAVE(headpandir)
5249 	COPYELEMENT_SAVE(headtiltdir)
5250 	COPYELEMENT_SAVE(leftarmpandir)
5251 	COPYELEMENT_SAVE(leftarmtiltdir)
5252 	COPYELEMENT_SAVE(rightarmpandir)
5253 	COPYELEMENT_SAVE(rightarmtiltdir)
5254 	COPYELEMENT_SAVE(torsotwistdir)
5255 
5256 	COPYELEMENT_SAVE(headLock)
5257 	COPYELEMENT_SAVE(leftArmLock)
5258 	COPYELEMENT_SAVE(rightArmLock)
5259 	COPYELEMENT_SAVE(targetSightTest)
5260 	COPYELEMENT_SAVE(IAmFar)
5261 	COPYELEMENT_SAVE(ShotThisFrame)
5262 
5263 	COPYELEMENT_SAVE(FiringLeft)
5264 	COPYELEMENT_SAVE(FiringRight)
5265 
5266 	COPYELEMENT_SAVE(UseHeadLaser)
5267 	COPYELEMENT_SAVE(UseLALaser)
5268 	COPYELEMENT_SAVE(UseRALaser)
5269 
5270 	COPYELEMENT_SAVE(HeadLaserOnTarget)
5271 	COPYELEMENT_SAVE(LALaserOnTarget)
5272 	COPYELEMENT_SAVE(RALaserOnTarget)
5273 
5274 	COPYELEMENT_SAVE(head_moving)
5275 	COPYELEMENT_SAVE(la_moving)
5276 	COPYELEMENT_SAVE(ra_moving)
5277 	COPYELEMENT_SAVE(torso_moving)
5278 
5279 	COPYELEMENT_SAVE(incidentFlag)
5280 	COPYELEMENT_SAVE(incidentTimer)
5281 
5282 	COPYELEMENT_SAVE(head_whirr)
5283 	COPYELEMENT_SAVE(left_arm_whirr)
5284 	COPYELEMENT_SAVE(right_arm_whirr)
5285 	COPYELEMENT_SAVE(torso_whirr)
5286 
5287  	for(i=0;i<3;i++)
5288 	{
5289  		COPYELEMENT_SAVE(TargetingLaser[i])
5290 	}
5291 
5292 	//load ai module pointers
5293 	block->my_module_index = GetIndexFromAIModulePointer(xenoStatusPointer->my_module);
5294 
5295 	//save target
5296 	COPY_NAME(block->Target_SBname,xenoStatusPointer->Target_SBname);
5297 
5298 	//save strategy block stuff
5299 	block->dynamics = *sbPtr->DynPtr;
5300 	block->dynamics.CollisionReportPtr=0;
5301 
5302 	block->integrity = sbPtr->integrity;
5303 	block->SBDamageBlock = sbPtr->SBDamageBlock;
5304 
5305 	//save the hierarchy
5306 	SaveHierarchy(&xenoStatusPointer->HModelController);
5307 
5308 	Save_SoundState(&xenoStatusPointer->soundHandle1);
5309 	Save_SoundState(&xenoStatusPointer->soundHandle2);
5310 }
5311