1 /* KJL 16:23:20 10/25/96 - I'm moved all the weapon stuff to the newly created weapon.c,
2 so player.c is looking a bit bare at the moment. */
3 #include "3dc.h"
4 #include "module.h"
5 #include "inline.h"
6 
7 #include "stratdef.h"
8 #include "gamedef.h"
9 #include "bh_types.h"
10 #include "inventry.h"
11 #include "gameplat.h"
12 #include "dynblock.h"
13 #include "dynamics.h"
14 #include "comp_shp.h"
15 #include "weapons.h"
16 #include "vision.h"
17 #include "pheromon.h"
18 #include "avpview.h"
19 #include "particle.h"
20 #include "scream.h"
21 #include "savegame.h"
22 #include "game_statistics.h"
23 #include "pfarlocs.h"
24 #include "bh_ais.h"
25 
26 #define UseLocalAssert Yes
27 #include "ourasert.h"
28 
29 #include "psnd.h"
30 #include "psndplat.h"
31 #include "player.h"
32 
33 /* for win 95 net support */
34 #include "pldnet.h"
35 #include "pldghost.h"
36 //#include "dp_func.h"
37 
38 #include "showcmds.h"
39 #include "bonusabilities.h"
40 
41 extern DPID AVPDPNetID;
42 
43 #define PLAYER_HMODEL 0
44 
45 /*KJL****************************************************************************************
46 *  										G L O B A L S 	            					    *
47 ****************************************************************************************KJL*/
48 VECTORCH PlayerStartLocation;
49 MATRIXCH PlayerStartMat;
50 extern int NormalFrameTime;
51 extern ACTIVESOUNDSAMPLE ActiveSounds[];
52 extern int PlayerDamagedOverlayIntensity;
53 extern int playerNoise;
54 extern int predHUDSoundHandle;
55 extern int predOVision_SoundHandle;
56 
57 extern int AIModuleArraySize;
58 
59 int GimmeChargeCalls;
60 int HtoHStrikes;
61 int CurrentLightAtPlayer;
62 int TauntSoundPlayed;
63 
64 int TrickleCharge=9000;
65 int CloakDrain=12000;
66 int CloakThreshold=(5*ONE_FIXED);
67 int CloakPowerOnDrain=(2*ONE_FIXED);
68 
69 extern DPID myNetworkKillerId;
70 extern DPID myIgniterId;
71 extern int MyHitBodyPartId;
72 extern HMODELCONTROLLER PlayersWeaponHModelController;
73 extern SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */
74 
75 /*KJL****************************************************************************************
76 *                                    P R O T O T Y P E S	                                *
77 ****************************************************************************************KJL*/
78 void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type);
79 void MaintainPlayer(void);
80 void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming);
81 static void PlayerIsDead(DAMAGE_PROFILE *damage,int multiplier,VECTORCH* incoming);
82 
83 extern int LightIntensityAtPoint(VECTORCH *pointPtr);
84 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
85 extern int SlotForThisWeapon(enum WEAPON_ID weaponID);
86 extern void PointAlert(int level, VECTORCH *point);
87 extern void RemoveAllThisPlayersDiscs(void);
88 void ShowAdjacencies(void);
89 
90 extern int ShowAdj;
91 
92 /*KJL****************************************************************************************
93 *                                     F U N C T I O N S	                                    *
94 ****************************************************************************************KJL*/
95 
96 PLAYER_STATUS* PlayerStatusPtr = NULL;
97 static PLAYER_STATUS PlayerStatusBlock;
98 int ShowPredoStats=0;
99 int Observer=0;
100 
101 /* Patrick 22/8/97------------------------------------------------
102 Cloaking stuff
103 ------------------------------------------------------------------*/
104 void InitPlayerCloakingSystem(void);
105 static void DoPlayerCloakingSystem(void);
106 
InitPlayer(STRATEGYBLOCK * sbPtr,int sb_type)107 void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type)
108 {
109 	/*KJL**************************************************************************************
110 	* InitPlayer() was written by me. It attaches the extra player data to the strategy block *
111 	* and fills in some initial values.                                                       *
112 	**************************************************************************************KJL*/
113 
114 #if 0
115 	SECTION *root_section;
116 #endif
117 	PLAYER_STATUS *psPtr = &PlayerStatusBlock;
118 	GLOBALASSERT(psPtr);
119  	GLOBALASSERT(sbPtr);
120 
121 	// set up our global
122 
123 	PlayerStatusPtr = psPtr;
124 
125 
126 	sbPtr->I_SBtype = sb_type;
127 	sbPtr->SBdataptr = (void*)psPtr;
128 
129 	InitialisePlayersInventory(psPtr);
130 
131 	/* Initialise Player's stats */
132 	{
133 		NPC_DATA *NpcData;
134 		NPC_TYPES PlayerType;
135 
136 		switch(AvP.PlayerType)
137 		{
138 			case(I_Marine):
139 			{
140 				switch (AvP.Difficulty) {
141 					case I_Easy:
142 						PlayerType=I_PC_Marine_Easy;
143 						break;
144 					default:
145 					case I_Medium:
146 						PlayerType=I_PC_Marine_Medium;
147 						break;
148 					case I_Hard:
149 						PlayerType=I_PC_Marine_Hard;
150 						break;
151 					case I_Impossible:
152 						PlayerType=I_PC_Marine_Impossible;
153 						break;
154 				}
155 
156 				#if 0  //this hmodel isn't being set up for the moment - Richard
157 				root_section=GetNamedHierarchyFromLibrary("hnpcmarine","Template");
158 				if (!root_section) {
159 					GLOBALASSERT(0);
160 					/* Sorry, there's just no bouncing back from this one.  Fix it. */
161 					return;
162 				}
163 				#if PLAYER_HMODEL
164 				Create_HModel(&psPtr->HModelController,root_section);
165 				InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED);
166 				#endif
167 				/* Doesn't matter what the sequence is... */
168 				#endif
169 				break;
170 			}
171 			case(I_Predator):
172 			{
173 				switch (AvP.Difficulty) {
174 					case I_Easy:
175 						PlayerType=I_PC_Predator_Easy;
176 						break;
177 					default:
178 					case I_Medium:
179 						PlayerType=I_PC_Predator_Medium;
180 						break;
181 					case I_Hard:
182 						PlayerType=I_PC_Predator_Hard;
183 						break;
184 					case I_Impossible:
185 						PlayerType=I_PC_Predator_Impossible;
186 						break;
187 				}
188 
189 				#if 0  //this hmodel isn't being set up for the moment - Richard
190 				root_section=GetNamedHierarchyFromLibrary("hnpcpredator","Template");
191 				if (!root_section) {
192 					GLOBALASSERT(0);
193 					/* Sorry, there's just no bouncing back from this one.  Fix it. */
194 					return;
195 				}
196 				#if PLAYER_HMODEL
197 				Create_HModel(&psPtr->HModelController,root_section);
198 				InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED);
199 				#endif
200 				/* Doesn't matter what the sequence is... */
201 				#endif
202 				break;
203 			}
204 			case(I_Alien):
205 			{
206 				switch (AvP.Difficulty) {
207 					case I_Easy:
208 						PlayerType=I_PC_Alien_Easy;
209 						break;
210 					default:
211 					case I_Medium:
212 						PlayerType=I_PC_Alien_Medium;
213 						break;
214 					case I_Hard:
215 						PlayerType=I_PC_Alien_Hard;
216 						break;
217 					case I_Impossible:
218 						PlayerType=I_PC_Alien_Impossible;
219 						break;
220 				}
221 
222 				#if 0  //this hmodel isn't being set up for the moment - Richard
223 				root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien");
224 				if (!root_section) {
225 					GLOBALASSERT(0);
226 					/* Sorry, there's just no bouncing back from this one.  Fix it. */
227 					return;
228 				}
229 				#if PLAYER_HMODEL
230 				Create_HModel(&psPtr->HModelController,root_section);
231 				InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED);
232 				#endif
233 				/* Doesn't matter what the sequence is... */
234 				#endif
235 				break;
236 
237 			}
238 			default:
239 			{
240 				LOCALASSERT(1==0);
241 				break;
242 			}
243 		}
244 
245 		NpcData=GetThisNpcData(PlayerType);
246 		LOCALASSERT(NpcData);
247 		sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
248 		sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
249 		sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
250 		sbPtr->SBDamageBlock.IsOnFire=0;
251 
252 		//{
253 		//	int *nptr,i;
254 		//	nptr=(int *)sbPtr->SBname;
255 		//	for (i=0; i<(SB_NAME_LENGTH>>2); i++) {
256 		//		*nptr=FastRandom();
257 		//		nptr++;
258 		//	}
259 		//	sbPtr->SBname[SB_NAME_LENGTH-1]=3; /* Just to make sure... */
260 		//}
261 		AssignNewSBName(sbPtr);
262 	}
263 
264     //psPtr->Health=STARTOFGAME_MARINE_HEALTH;
265     psPtr->Energy=STARTOFGAME_MARINE_ENERGY;
266     //psPtr->Armour=STARTOFGAME_MARINE_ARMOUR;
267 
268 	psPtr->Encumberance.MovementMultiple=ONE_FIXED;
269 	psPtr->Encumberance.TurningMultiple=ONE_FIXED;
270 	psPtr->Encumberance.JumpingMultiple=ONE_FIXED;
271 	psPtr->Encumberance.CanCrouch=1;
272 	psPtr->Encumberance.CanRun=1;
273 
274 	psPtr->incidentFlag=0;
275 	psPtr->incidentTimer=0;
276 
277 	/* CDF 16/9/97 Now, those health and armour stats are those of the last cycle. */
278 
279 	psPtr->Health=sbPtr->SBDamageBlock.Health;
280 	psPtr->Armour=sbPtr->SBDamageBlock.Armour;
281 
282 	psPtr->IsAlive = 1;
283 	psPtr->IHaveAPlacedAutogun = 0;
284 	psPtr->MyFaceHugger=NULL;
285 	psPtr->MyCorpse=NULL;
286 	psPtr->tauntTimer=0;
287 	TauntSoundPlayed=0;
288 	psPtr->fireTimer=0;
289 	psPtr->invulnerabilityTimer=0;
290 	/* Better safe than sorry. */
291 	psPtr->soundHandle=SOUND_NOACTIVEINDEX;
292 	psPtr->soundHandle3=SOUND_NOACTIVEINDEX;
293 	psPtr->soundHandle4=SOUND_NOACTIVEINDEX;
294 	psPtr->soundHandle5=SOUND_NOACTIVEINDEX;
295 	psPtr->soundHandleForPredatorCloakDamaged=SOUND_NOACTIVEINDEX;
296 	InitPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */
297 
298     /* KJL 12:06:01 11/14/96 - allocate dynamics block & fill from template */
299 	sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER);
300 	/* for the time being get world position and orientation from the displayblock */
301 	{
302 		DISPLAYBLOCK *dPtr = sbPtr->SBdptr;
303 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
304 		GLOBALASSERT(dPtr);
305 		GLOBALASSERT(dynPtr);
306 
307 		dynPtr->Position = PlayerStartLocation;
308 		dynPtr->OrientMat = PlayerStartMat;
309 		MatrixToEuler(&dynPtr->OrientMat,&dynPtr->OrientEuler);
310 		//dynPtr->OrientEuler = dPtr->ObEuler;
311 
312 
313 		dynPtr->PrevPosition = dynPtr->Position;
314 		dynPtr->PrevOrientMat = dynPtr->OrientMat;
315 		dynPtr->PrevOrientEuler = dynPtr->OrientEuler;
316 
317 		/* let alien walk on walls & ceiling */
318 		if (AvP.PlayerType == I_Alien)
319 		{
320 			dynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
321 		}
322 
323 		/* KJL 10:56:57 11/24/97 - set ObRadius to a sensible value */
324 		dPtr->ObRadius = 1200;
325 
326 										/*
327 		if (AvP.PlayerType == I_Alien) sbPtr->I_SBtype = I_BehaviourAlienPlayer;
328 		if (AvP.PlayerType == I_Predator) sbPtr->I_SBtype = I_BehaviourPredatorPlayer;*/
329 		/* KJL 18:30:09 11/11/98 - datum used for falling damage */
330 		{
331 			extern int PlayersMaxHeightWhilstNotInContactWithGround;
332 			PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy;
333 		}
334 	}
335 
336 	/* zero inertia values */
337 	psPtr->ForwardInertia=0;
338 	psPtr->StrafeInertia=0;
339 	psPtr->TurnInertia=0;
340 	psPtr->IsMovingInWater = 0;
341     PlayerDamagedOverlayIntensity = 0;
342 
343 	/* a little addition by patrick */
344 	InitPlayerMovementData(sbPtr);
345 
346 	/* security clearance */
347 	psPtr->securityClearances = 0;
348 
349 	/* thou art mortal */
350 	psPtr->IsImmortal = 0;
351 
352 	if (AvP.Network==I_No_Network)
353 	{
354 		SoundSys_FadeIn();
355 	}
356 	else
357 	{
358 		SoundSys_ResetFadeLevel();
359 	}
360 
361 	//restore the number of saves allowed
362 	ResetNumberOfSaves();
363 
364 	//choosing a start position now occurs later on
365 //	if(AvP.Network!=I_No_Network) TeleportNetPlayerToAStartingPosition(sbPtr, 1);
366 }
367 
ChangeToMarine()368 void ChangeToMarine()
369 {
370 	if(AvP.Network!=I_No_Network)
371 	{
372 		AvP.PlayerType=I_Marine;
373 		NetPlayerRespawn(Player->ObStrategyBlock);
374 		InitPlayerMovementData(Player->ObStrategyBlock);
375 		Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE;
376 		netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Marine;
377 
378 		//reorient the player
379 		{
380 			EULER e;
381 			MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e);
382 			e.EulerX=0;
383 			e.EulerZ=0;
384 
385 			CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat);
386 			TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat);
387 
388 			Player->ObStrategyBlock->DynPtr->UseStandardGravity=1;
389 		}
390 
391 		/* CDF 15/3/99, delete all discs... */
392 		RemoveAllThisPlayersDiscs();
393 
394 	}
395 }
ChangeToAlien()396 void ChangeToAlien()
397 {
398 	if(AvP.Network!=I_No_Network)
399 	{
400 		AvP.PlayerType=I_Alien;
401 		NetPlayerRespawn(Player->ObStrategyBlock);
402 		InitPlayerMovementData(Player->ObStrategyBlock);
403 		Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN;
404 
405 		netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Alien;
406 
407 		/* CDF 15/3/99, delete all discs... */
408 		RemoveAllThisPlayersDiscs();
409 	}
410 }
ChangeToPredator()411 void ChangeToPredator()
412 {
413 	if(AvP.Network!=I_No_Network)
414 	{
415 		AvP.PlayerType=I_Predator;
416 		NetPlayerRespawn(Player->ObStrategyBlock);
417 		InitPlayerMovementData(Player->ObStrategyBlock);
418 		Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE;
419 		netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Predator;
420 
421 		//reorient the player
422 		{
423 			EULER e;
424 			MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e);
425 			e.EulerX=0;
426 			e.EulerZ=0;
427 
428 			CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat);
429 			TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat);
430 
431 			Player->ObStrategyBlock->DynPtr->UseStandardGravity=1;
432 		}
433 
434 		/* CDF 15/3/99, delete all discs... */
435 		RemoveAllThisPlayersDiscs();
436 	}
437 }
438 
MaintainPlayer(void)439 void MaintainPlayer(void)
440 {
441 	int rand = FastRandom();
442 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
443 
444     if (playerStatusPtr->IsAlive)
445 	{
446 	    MaintainPlayersInventory();
447 	}
448 
449 	if (ShowAdj) {
450 		ShowAdjacencies();
451 	}
452 
453 	/* Set here, as first point. */
454 	playerNoise=0;
455 
456 	/* Incident handling. */
457 	playerStatusPtr->incidentFlag=0;
458 
459 	playerStatusPtr->incidentTimer-=NormalFrameTime;
460 
461 	if (playerStatusPtr->incidentTimer<0) {
462 		playerStatusPtr->incidentFlag=1;
463 		playerStatusPtr->incidentTimer=32767+(FastRandom()&65535);
464 	}
465 
466 	/* CDF 9/6/98 - I can't believe this isn't done!!! */
467   	Player->ObStrategyBlock->containingModule = playerPherModule;
468 
469 	if (Observer) {
470 		textprint("Observer Mode...\n");
471 	}
472 	textprint("HtoH Strikes %d\n",HtoHStrikes);
473 
474 	DoPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */
475    //	HandlePredatorVisionModes();
476 
477 	CurrentLightAtPlayer=LightIntensityAtPoint(&Player->ObStrategyBlock->DynPtr->Position);
478 
479 	#if 1
480 	textprint("PlayerLight %d\n",CurrentLightAtPlayer);
481 	#endif
482 
483 	if(AvP.Network==I_No_Network)
484 	{
485 		#if 1
486 		if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame)
487 		{
488 			// go to start menu
489 			AvP.MainLoopRunning = 0;
490 		}
491 		#endif
492 	}
493 	else
494 	if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame)
495 	{
496 		if (AvP.Network == I_Host)
497 		{
498 			TransmitEndOfGameNetMsg();
499 			netGameData.myGameState = NGS_EndGame;
500 		}
501 		else if	(AvP.Network == I_Peer)
502 		{
503 			TransmitPlayerLeavingNetMsg();
504 			netGameData.myGameState = NGS_Leaving;
505 		}
506 		// go to start menu
507 		AvP.MainLoopRunning = 0;
508 	}
509 
510 	//Update the player's invulnerabilty timer
511 	if(playerStatusPtr->invulnerabilityTimer>0)
512 	{
513 		playerStatusPtr->invulnerabilityTimer-=NormalFrameTime;
514 
515 		if(playerStatusPtr->invulnerabilityTimer<=0)
516 		{
517 			playerStatusPtr->invulnerabilityTimer=0;
518 		}
519 		//lose invulnerability if player is firing
520 
521 		if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon)
522 		{
523 			PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
524 			if(weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP)
525 			{
526 				playerStatusPtr->invulnerabilityTimer=0;
527 			}
528 		}
529 		if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon)
530 		{
531 			//not many weapons have an offensive secondary fire
532 			PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
533 			if(weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE ||
534 			   weaponPtr->WeaponIDNumber == WEAPON_CUDGEL ||
535 			   weaponPtr->WeaponIDNumber == WEAPON_MARINE_PISTOL ||
536 			   weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS ||
537 			   weaponPtr->WeaponIDNumber == WEAPON_PRED_WRISTBLADE ||
538 			   weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW)
539 			{
540 				playerStatusPtr->invulnerabilityTimer=0;
541 			}
542 		}
543 	}
544 
545 
546 	if (AvP.DestructTimer>0) {
547 		extern int NormalFrameTime;
548 
549 		AvP.DestructTimer-=NormalFrameTime;
550 		if (AvP.DestructTimer<0) AvP.DestructTimer=0;
551 
552 	} else if (AvP.DestructTimer==0) {
553 		// ...Destruct?
554 		CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_SADAR_TOW].MaxDamage[AvP.Difficulty], 25*ONE_FIXED,NULL);
555 		// That'll learn 'em.
556 	}
557 
558 	/* Take speed sample. */
559 	{
560 		int speed;
561 
562 		speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
563 		CurrentGameStats_SpeedSample(speed,NormalFrameTime);
564 	}
565 
566 	/* Is the player on fire? */
567 	if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) {
568 
569 		myNetworkKillerId=myIgniterId;
570 		CauseDamageToObject(Player->ObStrategyBlock,&firedamage,NormalFrameTime,NULL);
571 		myNetworkKillerId=AVPDPNetID;
572 
573 		if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) {
574 			if (ActiveSounds[playerStatusPtr->soundHandle3].soundIndex!=SID_FIRE) {
575 				Sound_Stop(playerStatusPtr->soundHandle3);
576 			 	Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127);
577 			} else {
578 				Sound_Update3d(playerStatusPtr->soundHandle3,&(Player->ObStrategyBlock->DynPtr->Position));
579 			}
580 		} else if (playerStatusPtr->IsAlive) {
581 		 	Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127);
582 		}
583 
584 		/* Put the fire out... */
585 
586 		#if 1
587 		{
588 			int speed;
589 			/* Go out? */
590 			speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
591 
592 			if (speed>22000) {
593 				/* Jumping alien. */
594 				playerStatusPtr->fireTimer-=(NormalFrameTime*6);
595 			} else if (speed>15000) {
596 				/* Running alien. */
597 				playerStatusPtr->fireTimer-=(NormalFrameTime<<2);
598 			} else {
599 				/* Normal bloke. */
600 				playerStatusPtr->fireTimer-=NormalFrameTime;
601 			}
602 
603 			if(playerStatusPtr->invulnerabilityTimer>0)
604 			{
605 				//player is invulnerable, so put him out.
606 				playerStatusPtr->fireTimer=0;
607 			}
608 
609 			if (playerStatusPtr->fireTimer<=0) {
610 				/* Go out. */
611 				Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0;
612 				playerStatusPtr->fireTimer=0;
613 			}
614 		}
615 		#else
616 		if (playerStatusPtr->incidentFlag) {
617 			int speed;
618 			/* Go out? */
619 			speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
620 
621 			if (speed>15000) {
622 				/* Running alien. */
623 				if ((FastRandom()&65535)<13107) {
624 					Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0;
625 				}
626 			} else {
627 				/* Normal bloke. */
628 				if ((FastRandom()&65535)<3000) {
629 					Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0;
630 				}
631 			}
632 		}
633 		#endif
634 	} else {
635 		if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) {
636 			Sound_Stop(playerStatusPtr->soundHandle3);
637 		}
638 	}
639 
640 	if (playerStatusPtr->IsMovingInWater)
641 	{
642 		#if 0
643 		if (playerStatusPtr->soundHandle4==SOUND_NOACTIVEINDEX) {
644 	 		switch (rand % 4) {
645 				case 0:
646 				 	Sound_Play(SID_SPLASH1,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127);
647 					break;
648 				case 1:
649 				 	Sound_Play(SID_SPLASH2,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127);
650 					break;
651 				case 2:
652 				 	Sound_Play(SID_SPLASH3,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127);
653 					break;
654 				default:
655 				 	Sound_Play(SID_SPLASH4,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127);
656 					break;
657 			}
658 		}
659 		#else
660 		/* KJL 19:07:57 25/05/98 - make a noise at most every 1/4 of a sec */
661 		if (playerStatusPtr->soundHandle4<=0)
662 		{
663 	 		switch (rand&3)
664 	 		{
665 				case 0:
666 				 	Sound_Play(SID_SPLASH1,"d",&(Player->ObStrategyBlock->DynPtr->Position));
667 					break;
668 				case 1:
669 				 	Sound_Play(SID_SPLASH2,"d",&(Player->ObStrategyBlock->DynPtr->Position));
670 					break;
671 				case 2:
672 				 	Sound_Play(SID_SPLASH3,"d",&(Player->ObStrategyBlock->DynPtr->Position));
673 					break;
674 				default:
675 				 	Sound_Play(SID_SPLASH4,"d",&(Player->ObStrategyBlock->DynPtr->Position));
676 					break;
677 
678 			}
679 			playerStatusPtr->soundHandle4=16384;
680 		}
681 		else
682 		{
683 			playerStatusPtr->soundHandle4-=NormalFrameTime;
684 		}
685 		#endif
686 	}
687 
688 
689 	/* KJL 14:54:48 25/05/98 - reset water flag to zero for next frame */
690 	playerStatusPtr->IsMovingInWater = 0;
691 
692 	/* Taunt effects. */
693 	if (playerStatusPtr->tauntTimer) {
694 		int ex,ey,ez;
695 
696 		playerNoise=1;
697 		/* An actual noise, too, would probably be good. */
698 
699 		if (AvP.PlayerType==I_Alien) {
700 
701 			//if (playerStatusPtr->tauntTimer>(TAUNT_LENGTH>>1)) {
702 			if (TauntSoundPlayed==0) {
703 				/* That should make sure we don't get more than one. */
704 				if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) {
705 					#if 0
706 					Sound_Play(SID_ALIEN_SCREAM,"de",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle);
707 					#else
708 					PlayAlienSound(0,ASC_Taunt,0,&playerStatusPtr->soundHandle,&(Player->ObStrategyBlock->DynPtr->Position));
709 					if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Taunt;
710 					#endif
711 					TauntSoundPlayed=1;
712 				}
713 			}
714 
715 			/* Wave the head around? */
716 			ex=0;
717 			ey=0;
718 			ez=0;
719 
720 			ex=MUL_FIXED(64,GetSin(((playerStatusPtr->tauntTimer>>6)&wrap360)));
721 			ey=MUL_FIXED(128,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360)));
722 			ez=MUL_FIXED(-64,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360)));
723 
724 			ex&=wrap360;
725 			ey&=wrap360;
726 			ez&=wrap360;
727 
728 			HeadOrientation.EulerX=ex;
729 			HeadOrientation.EulerY=ey;
730 			HeadOrientation.EulerZ=ez;
731 		} else if (AvP.PlayerType==I_Marine) {
732 			if (TauntSoundPlayed==0) {
733 				/* That should make sure we don't get more than one. */
734 				if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) {
735 					PlayMarineScream(0,SC_Taunt,0,&playerStatusPtr->soundHandle,NULL);
736 					if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Taunt;
737 					TauntSoundPlayed=1;
738 				}
739 			}
740 		} else if (AvP.PlayerType==I_Predator) {
741 			if (TauntSoundPlayed==0) {
742 				/* That should make sure we don't get more than one. */
743 				if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) {
744 					PlayPredatorSound(0,PSC_Taunt,0,&playerStatusPtr->soundHandle,NULL);
745 					if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Taunt;
746 					TauntSoundPlayed=1;
747 				}
748 			}
749 		} else {
750 			GLOBALASSERT(0);
751 		}
752 
753 	}
754 
755 	/* Decay alien superhealth. */
756 	if (AvP.PlayerType==I_Alien) {
757 		NPC_DATA *NpcData;
758 
759 		switch (AvP.Difficulty) {
760 			case I_Easy:
761 				NpcData=GetThisNpcData(I_PC_Alien_Easy);
762 				break;
763 			default:
764 			case I_Medium:
765 				NpcData=GetThisNpcData(I_PC_Alien_Medium);
766 				break;
767 			case I_Hard:
768 				NpcData=GetThisNpcData(I_PC_Alien_Hard);
769 				break;
770 			case I_Impossible:
771 				NpcData=GetThisNpcData(I_PC_Alien_Impossible);
772 				break;
773 		}
774 		LOCALASSERT(NpcData);
775 
776 		if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
777 			/* Decay health a bit. */
778 			Player->ObStrategyBlock->SBDamageBlock.Health-=(NormalFrameTime);
779 			if (Player->ObStrategyBlock->SBDamageBlock.Health<(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
780 				Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
781 			}
782 			PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
783 		}
784 	}
785 }
786 
PlayerIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiplier,VECTORCH * incoming)787 void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming)
788 {
789 	int rand = FastRandom();
790 	int pitch = (rand & 255) - 128;
791  	int deltaHealth;
792  	int deltaArmour;
793 
794 	/* access the extra data hanging off the strategy block */
795 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr);
796   GLOBALASSERT(playerStatusPtr);
797 
798 	deltaHealth=playerStatusPtr->Health-sbPtr->SBDamageBlock.Health;
799 	deltaArmour=playerStatusPtr->Armour-sbPtr->SBDamageBlock.Armour;
800 
801 	CurrentGameStats_DamageTaken(deltaHealth,deltaArmour);
802 
803 	/* Patrick 4/8/97--------------------------------------------------
804 	A little hack-et to make the predator tougher in multiplayer games
805 	------------------------------------------------------------------*/
806 	//if((AvP.Network!=I_No_Network)&&(AvP.PlayerType==I_Predator)) damage>>=1;
807 	/* ChrisF 16/9/97 No, predators are now... wait for it... tough. */
808 
809 	if (playerStatusPtr->IsAlive)
810 	{
811 		#if 0
812 		damage <<= 16;
813 		if (playerStatusPtr->Armour > 0)
814 		{
815 			if (playerStatusPtr->Armour >= damage/2)
816 			{
817 				playerStatusPtr->Armour -= damage/2;
818 				playerStatusPtr->Health -= damage/4;
819 			}
820 			else
821 			{
822 				damage -= playerStatusPtr->Armour*2;
823 				playerStatusPtr->Health -= playerStatusPtr->Armour/2 + damage;
824 				playerStatusPtr->Armour = 0;
825 			}
826 		}
827 		else
828 		{
829 			playerStatusPtr->Health -= damage;
830 		}
831 		#endif
832 		{
833 			int maxTilt = deltaHealth>>12;
834 			int halfTilt = maxTilt/2;
835 			if (maxTilt)
836 			{
837 				HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt;
838 				HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt;
839 				HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt;
840 
841 				if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096;
842 				if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096;
843 				if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096;
844 			}
845 		}
846 
847 		if ((playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX)&&(deltaHealth||deltaArmour)) {
848 	 		switch (AvP.PlayerType)
849 		 	{
850 				case I_Alien:
851 				{
852 					if ((damage->Impact==0)
853 						&&(damage->Cutting==0)
854 						&&(damage->Penetrative==0)
855 						&&(damage->Fire>0)
856 						&&(damage->Electrical==0)
857 						&&(damage->Acid==0)
858 						) {
859 						PlayAlienSound(0,ASC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL);
860 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_PC_OnFire;
861 					} else {
862 						PlayAlienSound(0,ASC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL);
863 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Scream_Hurt;
864 					}
865 					break;
866 				}
867 
868 				case I_Marine:
869 				{
870 					if (damage->Id==AMMO_FACEHUGGER) {
871 						PlayMarineScream(0,SC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL);
872 					} else if (damage->Id==AMMO_FALLING_POSTMAX) {
873 						PlayMarineScream(0,SC_Falling,pitch,&playerStatusPtr->soundHandle,NULL);
874 					} else if ((damage->Impact==0)
875 						&&(damage->Cutting==0)
876 						&&(damage->Penetrative==0)
877 						&&(damage->Fire==0)
878 						&&(damage->Electrical==0)
879 						&&(damage->Acid>0)
880 						) {
881 						PlayMarineScream(0,SC_Acid,pitch,&playerStatusPtr->soundHandle,NULL);
882 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Acid;
883 					} else if ((damage->Impact==0)
884 						&&(damage->Cutting==0)
885 						&&(damage->Penetrative==0)
886 						&&(damage->Fire>0)
887 						&&(damage->Electrical==0)
888 						&&(damage->Acid==0)
889 						) {
890 						PlayMarineScream(0,SC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL);
891 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_PC_OnFire;
892 					} else {
893 						PlayMarineScream(0,SC_Pain,pitch,&playerStatusPtr->soundHandle,NULL);
894 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Pain;
895 					}
896 					break;
897 				}
898 
899 				case I_Predator:
900 				{
901 					if (damage->Id==AMMO_FACEHUGGER) {
902 						PlayPredatorSound(0,PSC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL);
903 					} else if ((damage->Impact==0)
904 						&&(damage->Cutting==0)
905 						&&(damage->Penetrative==0)
906 						&&(damage->Fire==0)
907 						&&(damage->Electrical==0)
908 						&&(damage->Acid>0)
909 						) {
910 						PlayPredatorSound(0,PSC_Acid,pitch,&playerStatusPtr->soundHandle,NULL);
911 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Acid;
912 					} else if ((damage->Impact==0)
913 						&&(damage->Cutting==0)
914 						&&(damage->Penetrative==0)
915 						&&(damage->Fire>0)
916 						&&(damage->Electrical==0)
917 						&&(damage->Acid==0)
918 						) {
919 						PlayPredatorSound(0,PSC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL);
920 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_PC_OnFire;
921 					} else {
922 						PlayPredatorSound(0,PSC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL);
923 						if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Scream_Hurt;
924 					}
925 					break;
926 				}
927 
928 				default:
929 				{
930 					break;
931 				}
932 			}
933 			playerNoise=1;
934 			/* Alert marines, pretty much whoever you are. */
935 			if (AvP.PlayerType==I_Marine) {
936 				PointAlert(3, &Player->ObStrategyBlock->DynPtr->Position);
937 			} else {
938 				#if 0
939 				PointAlert(2, &Player->ObStrategyBlock->DynPtr->Position);
940 				#endif
941 			}
942 		}
943 
944 		{
945 			NPC_DATA *NpcData;
946 			int scaled_DeltaHealth;
947 
948 			switch (AvP.PlayerType)
949 			{
950 				case I_Marine:
951 					switch (AvP.Difficulty) {
952 						case I_Easy:
953 							NpcData=GetThisNpcData(I_PC_Marine_Easy);
954 							break;
955 						default:
956 						case I_Medium:
957 							NpcData=GetThisNpcData(I_PC_Marine_Medium);
958 							break;
959 						case I_Hard:
960 							NpcData=GetThisNpcData(I_PC_Marine_Hard);
961 							break;
962 						case I_Impossible:
963 							NpcData=GetThisNpcData(I_PC_Marine_Impossible);
964 							break;
965 					}
966 					break;
967 				case I_Alien:
968 					switch (AvP.Difficulty) {
969 						case I_Easy:
970 							NpcData=GetThisNpcData(I_PC_Alien_Easy);
971 							break;
972 						default:
973 						case I_Medium:
974 							NpcData=GetThisNpcData(I_PC_Alien_Medium);
975 							break;
976 						case I_Hard:
977 							NpcData=GetThisNpcData(I_PC_Alien_Hard);
978 							break;
979 						case I_Impossible:
980 							NpcData=GetThisNpcData(I_PC_Alien_Impossible);
981 							break;
982 					}
983 					break;
984 				case I_Predator:
985 					switch (AvP.Difficulty) {
986 						case I_Easy:
987 							NpcData=GetThisNpcData(I_PC_Predator_Easy);
988 							break;
989 						default:
990 						case I_Medium:
991 							NpcData=GetThisNpcData(I_PC_Predator_Medium);
992 							break;
993 						case I_Hard:
994 							NpcData=GetThisNpcData(I_PC_Predator_Hard);
995 							break;
996 						case I_Impossible:
997 							NpcData=GetThisNpcData(I_PC_Predator_Impossible);
998 							break;
999 					}
1000 					break;
1001 				default:
1002 					LOCALASSERT(0);
1003 					break;
1004 			}
1005 			/* Compute scaled deltaHealth... */
1006 			scaled_DeltaHealth=MUL_FIXED(deltaHealth,100);
1007 			scaled_DeltaHealth=DIV_FIXED(scaled_DeltaHealth,NpcData->StartingStats.Health);
1008 
1009 			if (scaled_DeltaHealth>PlayerDamagedOverlayIntensity)
1010 			{
1011 				PlayerDamagedOverlayIntensity=scaled_DeltaHealth;
1012 			}
1013 		}
1014 
1015 		if (deltaHealth>ONE_FIXED)
1016 		{
1017 			VECTORCH abovePosition = Global_VDB_Ptr->VDB_World;
1018 			abovePosition.vy-=1000;
1019 	 		switch (AvP.PlayerType)
1020 		 	{
1021 				case I_Alien:
1022 					MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_ALIEN_BLOOD);
1023 					break;
1024 				case I_Marine:
1025 					MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_HUMAN_BLOOD);
1026 					break;
1027 				case I_Predator:
1028 					MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_PREDATOR_BLOOD);
1029 					break;
1030 			}
1031 		}
1032 
1033 		if (sbPtr->SBDamageBlock.Health <= 0)
1034 		{
1035 			if (playerStatusPtr->IsImmortal) sbPtr->SBDamageBlock.Health=0;
1036 			else
1037 			{
1038 				PlayerIsDead(damage,multiplier,incoming);
1039 			}
1040 		}
1041 
1042 		playerStatusPtr->Health=sbPtr->SBDamageBlock.Health;
1043 		playerStatusPtr->Armour=sbPtr->SBDamageBlock.Armour;
1044 
1045 	}
1046 }
1047 
1048 extern EULER deathTargetOrientation;
1049 extern int deathFadeLevel;
1050 extern int weaponHandle;
1051 
PlayerIsDead(DAMAGE_PROFILE * damage,int multiplier,VECTORCH * incoming)1052 static void PlayerIsDead(DAMAGE_PROFILE* damage,int multiplier,VECTORCH* incoming)
1053 {
1054 	STRATEGYBLOCK *sbPtr = Player->ObStrategyBlock;
1055 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr);
1056 	DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1057 
1058 	/* Stop pred hud sound. */
1059 	if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) {
1060 		Sound_Stop(predHUDSoundHandle);
1061 	}
1062 	if(predOVision_SoundHandle != SOUND_NOACTIVEINDEX) {
1063 		Sound_Stop(predOVision_SoundHandle);
1064 	}
1065 	if(weaponHandle != SOUND_NOACTIVEINDEX) {
1066 		Sound_Stop(weaponHandle);
1067 	}
1068 
1069   // Do some death sounds
1070 
1071 	switch (AvP.PlayerType)
1072 	{
1073 		case I_Alien:
1074 		{
1075 			PlayAlienSound(0,ASC_Scream_Dying,0,NULL,NULL);
1076 		  break;
1077 		}
1078 		case I_Marine:
1079 		{
1080 			if (damage->Id==AMMO_FACEHUGGER) {
1081 				PlayMarineScream(0,SC_Facehugged,0,NULL,NULL);
1082 			} else {
1083 				PlayMarineScream(0,SC_Death,0,NULL,NULL);
1084 			}
1085 			break;
1086 		}
1087 		case I_Predator:
1088 		{
1089 			if (damage->Id==AMMO_FACEHUGGER) {
1090 				PlayPredatorSound(0,PSC_Facehugged,0,NULL,NULL);
1091 			} else {
1092 				PlayPredatorSound(0,PSC_Scream_Dying,0,NULL,NULL);
1093 			}
1094 
1095 			{
1096 				VECTORCH abovePosition = Global_VDB_Ptr->VDB_World;
1097 				abovePosition.vy-=1000;
1098 				MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, 200, PARTICLE_PREDATOR_BLOOD);
1099 			}
1100 			break;
1101 		}
1102 		default:
1103 		{
1104 			break;
1105 		}
1106 	}
1107 
1108 	/* Well, it was nice knowing you. */
1109 	//playerStatusPtr->Health = 0;
1110 	sbPtr->SBDamageBlock.Health=0;
1111 	playerStatusPtr->IsAlive = 0;
1112 
1113 	/* make player fall to the ground */
1114 //	Player->ObShape=I_ShapeMarinePlayerLieDown;
1115   //	MapBlockInit(Player);
1116 
1117 	/* give player a little bounce */
1118 	dynPtr->Elasticity = 16384;
1119 	/* but a lot of friction */
1120 //	dynPtr->Friction = 1<<20;
1121 //	dynPtr->Mass = 1<<20;
1122 
1123 	/* cancel any velocity */
1124 	dynPtr->LinVelocity.vx = 0;
1125 	dynPtr->LinVelocity.vy = 0;
1126 	dynPtr->LinVelocity.vz = 0;
1127 
1128 	deathTargetOrientation.EulerX = 0;//1024-(FastRandom()&255);
1129 	deathFadeLevel=65536;
1130 
1131 	/* if in single player, fade out sound... */
1132 	if (AvP.Network==I_No_Network)
1133 	{
1134 		SoundSys_FadeOut();
1135 	}
1136 
1137 	if (AvP.PlayerType == I_Alien)
1138 	{
1139 		sbPtr->DynPtr->UseStandardGravity=1;
1140 	}
1141 
1142 	/* network support... */
1143 	if(AvP.Network!=I_No_Network)
1144 	{
1145 		playerStatusPtr->MyCorpse=MakeNewCorpse();
1146 		AddNetMsg_PlayerKilled((*((int *)(&(playerStatusPtr->MyCorpse->SBname[4])))),damage);
1147 
1148 		/*---------------------------------------------------------**
1149 		** 		handle various special body being torn apart cases **
1150 		**---------------------------------------------------------*/
1151 
1152 		/*Note that we need to apply the damage to the corpse before we can determine a
1153 		suitable death anim sequence*/
1154 		if(damage)
1155 		{
1156 			HMODELCONTROLLER* hmodel=playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock;
1157 			//was the player killed by a jaw attack?
1158 			if(damage->Id==AMMO_ALIEN_BITE_KILLSECTION && AvP.PlayerType!=I_Alien)
1159 			{
1160 				//knock the head of the corpse
1161 				SECTION_DATA *head;
1162 				head=GetThisSectionData(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock->section_data,"head");
1163 				//do lots of damage to it
1164 				if(head)
1165 				{
1166 					CauseDamageToHModel(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock,playerStatusPtr->MyCorpse, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage[AvP.Difficulty],
1167 						ONE_FIXED,head,NULL,NULL,0);
1168 				}
1169 				//play the head being bitten off sound
1170 				Sound_Play(SID_ALIEN_JAW_ATTACK,"d",&(Player->ObStrategyBlock->DynPtr->Position));
1171 
1172 			}
1173 			//chopped by predator disc?
1174 			else if(damage->Id==AMMO_PRED_DISC && AvP.PlayerType!=I_Predator)
1175 			{
1176 				SECTION_DATA *firstSectionPtr;
1177 				SECTION_DATA *chest_section=0;
1178 
1179 				firstSectionPtr=hmodel->section_data;
1180 				LOCALASSERT(firstSectionPtr);
1181 				LOCALASSERT(firstSectionPtr->flags&section_data_initialised);
1182 
1183 				/* look for the object's torso in preference */
1184 				chest_section =GetThisSectionData(hmodel->section_data,"chest");
1185 
1186 				if (chest_section)
1187 				{
1188 					CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0);
1189 				}
1190 				else
1191 				{
1192 					CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,incoming);
1193 				}
1194 			}
1195 			//blown up by shoulder cannon?
1196 			else if(damage->Id==AMMO_PLASMACASTER_PCKILL && AvP.PlayerType!=I_Predator)
1197 			{
1198 				SECTION_DATA *firstSectionPtr;
1199 				SECTION_DATA *chest_section=0;
1200 
1201 				firstSectionPtr=hmodel->section_data;
1202 				LOCALASSERT(firstSectionPtr);
1203 				LOCALASSERT(firstSectionPtr->flags&section_data_initialised);
1204 
1205 				/* look for the object's torso in preference */
1206 				chest_section =GetThisSectionData(hmodel->section_data,"chest");
1207 
1208 				if (chest_section)
1209 				{
1210 					//spherical blood explosion for aliens
1211 					if(AvP.PlayerType==I_Alien)
1212 						CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,NULL,&chest_section->World_Offset,0);
1213 					else
1214 						CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0);
1215 				}
1216 				else
1217 				{
1218 					CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,NULL);
1219 				}
1220 			}
1221 			else
1222 			{
1223 				SECTION_DATA *section_data=0;
1224 				if(MyHitBodyPartId!=-1)
1225 				{
1226 					//we have the id of the section that was hit when we died
1227 					//so try to find the section
1228 					section_data=GetThisSectionData_FromID(hmodel->section_data,MyHitBodyPartId);
1229 				}
1230 				//damage the corpse with the fatal blow
1231 				if(section_data)
1232 				{
1233 					DISPLAYBLOCK *fragged_section=0;
1234 					fragged_section=CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage,
1235 										multiplier,section_data,incoming,NULL,0);
1236 
1237 					if(fragged_section && incoming && damage->Id==AMMO_PRED_RIFLE)
1238 					{
1239 					//a speargun has fragged off a body part , so we need to create a spear
1240 						VECTORCH direction=*incoming;
1241 						RotateVector(&direction,&Player->ObMat);
1242 						CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction);
1243 
1244 					}
1245 				}
1246 				else
1247 				{
1248 					CauseDamageToObject(playerStatusPtr->MyCorpse,damage,multiplier,incoming);
1249 				}
1250 			}
1251 		}
1252 		/*---------------------------------**
1253 		** 		Choose death anim sequence **
1254 		**---------------------------------*/
1255 		{
1256 			int deathId;
1257 			switch(AvP.PlayerType)
1258 			{
1259 				case I_Marine :
1260 					deathId = Deduce_PlayerMarineDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming);
1261 					break;
1262 
1263 				case I_Alien :
1264 					deathId = Deduce_PlayerAlienDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming);
1265 					break;
1266 
1267 				case I_Predator :
1268 					deathId = Deduce_PlayerPredatorDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming);
1269 					break;
1270 			}
1271 			//apply the animation
1272 			ApplyCorpseDeathAnim(playerStatusPtr->MyCorpse,deathId);
1273 			//tell everyone else about the chosen death
1274 			AddNetMsg_PlayerDeathAnim(deathId,*(int*)&playerStatusPtr->MyCorpse->SBname[4]);
1275 
1276 		}
1277 
1278 //		if(AvP.Network==I_Host) DoNetScoresForHostDeath();
1279 
1280 		//does this death require a change in character type?
1281 		if(netGameData.gameType==NGT_LastManStanding)
1282 		{
1283 			//Am I a marine or predator?
1284 			if(AvP.PlayerType!=I_Alien)
1285 			{
1286 				//was I killed by an alien?
1287 				if(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID)
1288 				{
1289 					int killer_index=PlayerIdInPlayerList(myNetworkKillerId);
1290 					GLOBALASSERT(killer_index!=NET_IDNOTINPLAYERLIST);
1291 					if(netGameData.playerData[killer_index].characterType==NGCT_Alien)
1292 					{
1293 						//set  the next character to be an alien then
1294 						netGameData.myNextCharacterType=NGCT_Alien;
1295 					}
1296 
1297 				}
1298 				else
1299 				{
1300 					//suicide , so become an alien anyway
1301 						netGameData.myNextCharacterType=NGCT_Alien;
1302 				}
1303 			}
1304 		}
1305 		else if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag)
1306 		{
1307 			//we may need to change character
1308 			extern void SpeciesTag_DetermineMyNextCharacterType();
1309 		    SpeciesTag_DetermineMyNextCharacterType();
1310 		}
1311 	}
1312 
1313 	if (playerStatusPtr->soundHandle!=SOUND_NOACTIVEINDEX) {
1314  		Sound_Stop(playerStatusPtr->soundHandle);
1315 	}
1316 	if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) {
1317  		Sound_Stop(playerStatusPtr->soundHandle3);
1318 	}
1319 
1320 	/* KJL 15:36:41 10/09/98 - don't hang around on my behalf */
1321 	DisengageGrapplingHook();
1322 
1323 }
1324 
ActivateSelfDestructSequence(int seconds)1325 void ActivateSelfDestructSequence (int seconds)
1326 {
1327 	// Currently does nothing, called when sequence is activated
1328 
1329 	if (AvP.DestructTimer==-1) {
1330 		AvP.DestructTimer=ONE_FIXED*seconds;	//2 1/2 mins.
1331 	}
1332 }
1333 
DeInitialisePlayer(void)1334 void DeInitialisePlayer(void) {
1335 	/* I thought it would be logical to put it here... */
1336 
1337   	int slot = MAX_NO_OF_WEAPON_SLOTS;
1338 #if 0
1339 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
1340 #endif
1341 
1342     do {
1343 		TXACTRLBLK *txactrl,*txactrl_next;
1344     	PLAYER_WEAPON_DATA *wdPtr = &PlayerStatusBlock.WeaponSlot[--slot];
1345 
1346 		txactrl_next = wdPtr->TxAnimCtrl;
1347 
1348 		while(txactrl_next)
1349 		{
1350 			txactrl = txactrl_next;
1351 			txactrl_next = txactrl->tac_next;
1352 			DeallocateMem((void*)txactrl);
1353 		}
1354 
1355 		wdPtr->TxAnimCtrl=NULL;
1356 	} while(slot);
1357 
1358 	#if 0  //this hmodel isn't being set up for the moment - Richard
1359 	Dispel_HModel(&playerStatusPtr->HModelController);
1360 	#endif
1361 
1362 }
1363 
1364 static int cloakDebounce = 1;
1365 
InitPlayerCloakingSystem(void)1366 void InitPlayerCloakingSystem(void)
1367 {
1368 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
1369 	LOCALASSERT(playerStatusPtr);
1370 
1371 	playerStatusPtr->cloakOn = 0;
1372 	playerStatusPtr->cloakPositionGivenAway = 0;
1373 	playerStatusPtr->CloakingEffectiveness = 0;
1374 
1375 	playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY;
1376 	playerStatusPtr->cloakPositionGivenAwayTimer = 0;
1377 	playerStatusPtr->PlasmaCasterCharge=0;
1378 
1379 	GimmeChargeCalls=0;
1380 	HtoHStrikes=0;
1381 	CurrentLightAtPlayer=0;
1382 }
1383 
DoPlayerCloakingSystem(void)1384 static void DoPlayerCloakingSystem(void)
1385 {
1386 	extern int NormalFrameTime;
1387 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
1388 	LOCALASSERT(playerStatusPtr);
1389 
1390 	if(AvP.PlayerType!=I_Predator) return;
1391 	if(!(playerStatusPtr->IsAlive)) return;
1392 
1393 	/* Handle controls. */
1394 	if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision)
1395 	{
1396 		if (cloakDebounce)
1397 		{
1398 			cloakDebounce = 0;
1399 			if (playerStatusPtr->cloakOn)
1400 			{
1401 				Sound_Play(SID_PRED_CLOAKOFF,"h");
1402 				playerStatusPtr->cloakOn = 0;
1403 				//playerNoise=1;
1404 			} else {
1405 				/* Check validity. */
1406 				if ((playerStatusPtr->FieldCharge>CloakThreshold)
1407 					&&(playerStatusPtr->FieldCharge>CloakPowerOnDrain)) {
1408 
1409 					PLAYER_WEAPON_DATA *weaponPtr;
1410 					TEMPLATE_WEAPON_DATA *twPtr;
1411 
1412 				    weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
1413 				    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
1414 					if (!(((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))
1415 						&&(twPtr->FireWhenCloaked==0)))
1416 					{
1417 						playerStatusPtr->FieldCharge-=CloakPowerOnDrain;
1418 						CurrentGameStats_ChargeUsed(CloakPowerOnDrain);
1419 						playerStatusPtr->cloakOn = 1;
1420 						playerStatusPtr->CloakingEffectiveness = 0;
1421 						Sound_Play(SID_PRED_CLOAKON,"h");
1422 						//playerNoise=1;
1423 					}
1424 				}
1425 			}
1426 		}
1427 	}
1428 	else
1429 	{
1430 		cloakDebounce = 1;
1431 
1432 		if (playerStatusPtr->cloakOn)
1433 		{
1434 			int maxPossibleEffectiveness;
1435 			VECTORCH velocity;
1436 			DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr;
1437 
1438 			velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx;
1439 			velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy;
1440 			velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz;
1441 
1442 			if (playerStatusPtr->IsMovingInWater)
1443 			{
1444 				maxPossibleEffectiveness = 0;
1445 				if(playerStatusPtr->soundHandleForPredatorCloakDamaged==SOUND_NOACTIVEINDEX)
1446 					Sound_Play(SID_PREDATOR_CLOAKING_DAMAGED,"el",playerStatusPtr->soundHandleForPredatorCloakDamaged);
1447 			}
1448 			else
1449 			{
1450 				if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX)
1451 					Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged);
1452 
1453 				maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*2,NormalFrameTime);
1454 				if (maxPossibleEffectiveness<0) maxPossibleEffectiveness = 0;
1455 			}
1456 
1457 			playerStatusPtr->CloakingEffectiveness += NormalFrameTime;
1458 			if (playerStatusPtr->CloakingEffectiveness>maxPossibleEffectiveness)
1459 			{
1460 				playerStatusPtr->CloakingEffectiveness = maxPossibleEffectiveness;
1461 			}
1462 		}
1463 		else
1464 		{
1465 			playerStatusPtr->CloakingEffectiveness -= NormalFrameTime;
1466 			if (playerStatusPtr->CloakingEffectiveness<0)
1467 			{
1468 				playerStatusPtr->CloakingEffectiveness=0;
1469 			}
1470 			if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX)
1471 				Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged);
1472 		}
1473 
1474 	}
1475 	#if 1
1476 
1477 	/* position-given-away-timer runs whatever state the cloak is in */
1478 	if(playerStatusPtr->cloakPositionGivenAway)
1479 	{
1480 		playerStatusPtr->cloakPositionGivenAwayTimer-=NormalFrameTime;
1481 		if(playerStatusPtr->cloakPositionGivenAwayTimer<=0)
1482 		{
1483 			playerStatusPtr->cloakPositionGivenAwayTimer = 0;
1484 			playerStatusPtr->cloakPositionGivenAway = 0;
1485 			playerStatusPtr->CloakingEffectiveness = 0;
1486 		}
1487 	}
1488 
1489 	/* now sort out energy discharge/recharge */
1490 	if(playerStatusPtr->cloakOn)
1491 	{
1492 		int chargeUsed;
1493 
1494 		chargeUsed=MUL_FIXED(NormalFrameTime,CloakDrain);
1495 
1496 		if (playerStatusPtr->IsMovingInWater) {
1497 			chargeUsed<<=2;
1498 		}
1499 
1500 		if (chargeUsed>playerStatusPtr->FieldCharge) {
1501 			chargeUsed=playerStatusPtr->FieldCharge;
1502 		}
1503 		playerStatusPtr->FieldCharge -= chargeUsed;
1504 		CurrentGameStats_ChargeUsed(chargeUsed);
1505 		if(playerStatusPtr->FieldCharge <= 0)
1506 		{
1507 			playerStatusPtr->FieldCharge = 0;
1508 			playerStatusPtr->cloakOn = 0;
1509 			playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1;
1510 			Sound_Play(SID_PRED_CLOAKOFF,"h");
1511 			//playerNoise=1;
1512 		}
1513 
1514 		/* TrickleCharge Difficulty Variation! */
1515 		if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
1516 			playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1));
1517 		} else {
1518 			playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge);
1519 		}
1520 
1521 		if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) {
1522 			playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY;
1523 		}
1524 
1525 	}
1526 	else
1527 	{
1528 		if(playerStatusPtr->FieldCharge < PLAYERCLOAK_MAXENERGY)
1529 		{
1530 
1531 			/* TrickleCharge Difficulty Variation! */
1532 			if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
1533 				playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1));
1534 			} else {
1535 				playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge);
1536 			}
1537 
1538 			if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) {
1539 				playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY;
1540 			}
1541 
1542 			#if 0
1543 			/* Infinite field charge? */
1544 			playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY;
1545 			#endif
1546 		}
1547 	}
1548 	#endif
1549 
1550 	if (ShowPredoStats) {
1551 		/* for testing */
1552 		PrintDebuggingText("Cloak on: %d \n",playerStatusPtr->cloakOn);
1553 		PrintDebuggingText("Field Charge: %d \n",playerStatusPtr->FieldCharge);
1554 		{
1555 			int a;
1556 			/* Speargun ammo count */
1557 			a=SlotForThisWeapon(WEAPON_PRED_RIFLE);
1558 			if (a!=-1) {
1559 				PrintDebuggingText("Speargun Rounds: %d Clips: %d\n",(playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining>>ONE_FIXED_SHIFT),playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining);
1560 			} else {
1561 				PrintDebuggingText("Speargun not possessed.\n");
1562 			}
1563 
1564 		}
1565 		PrintDebuggingText("Cloak given away: %d \n", playerStatusPtr->cloakPositionGivenAway);
1566 		PrintDebuggingText("Cloak given away timer: %d \n", playerStatusPtr->cloakPositionGivenAwayTimer);
1567 		PrintDebuggingText("Cloaking Effectiveness: %d \n", playerStatusPtr->CloakingEffectiveness);
1568 		PrintDebuggingText("Gimme_Charge Calls: %d \n",GimmeChargeCalls);
1569 	}
1570 	#if 1
1571 	/* now, if we are cloaked, lets see if we have given away our position...
1572 	if we have already given away our position, we may do so again */
1573 	if(playerStatusPtr->cloakOn)
1574 	{
1575 		PLAYER_WEAPON_DATA *weaponPtr;
1576 		TEMPLATE_WEAPON_DATA *twPtr;
1577 
1578 	    weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
1579 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
1580 
1581 		/* weapon fire ?*/
1582 		if(((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(!twPtr->PrimaryIsMeleeWeapon))||
1583 		   ((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(!twPtr->SecondaryIsMeleeWeapon)))
1584 		{
1585 			playerStatusPtr->cloakPositionGivenAway = 1;
1586 			playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME;
1587 		}
1588 		/* collision with npc ?*/
1589 		{
1590 			struct collisionreport *nextReport;
1591 			LOCALASSERT(Player->ObStrategyBlock->DynPtr);
1592 			nextReport = Player->ObStrategyBlock->DynPtr->CollisionReportPtr;
1593 
1594 			while(nextReport)
1595 			{
1596  				if(nextReport->ObstacleSBPtr)
1597  				{
1598 	 				if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlien)||
1599 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarine)||
1600 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)||
1601 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)||
1602 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)||
1603 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger)||
1604 					   (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourSeal))
1605 	 				{
1606 						playerStatusPtr->cloakPositionGivenAway = 1;
1607 						playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME;
1608 						break;
1609 					}
1610 				}
1611  				nextReport = nextReport->NextCollisionReportPtr;
1612 			}
1613 		}
1614 	}
1615 	#endif
1616 
1617 	if (playerStatusPtr->cloakOn) {
1618 		CurrentGameStats_CloakOn();
1619 	}
1620 }
1621 
GimmeCharge(void)1622 void GimmeCharge(void) {
1623 
1624 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
1625 	LOCALASSERT(playerStatusPtr);
1626 
1627 	if(AvP.PlayerType!=I_Predator) return;
1628 
1629 	playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY;
1630 
1631 	GimmeChargeCalls++;
1632 
1633 }
1634 
1635 #define AUTOSPOT_RANGE	(1000)
1636 
AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK * sbPtr)1637 int AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK *sbPtr) {
1638 
1639 	PLAYER_WEAPON_DATA *weaponPtr;
1640 	int range;
1641 	DYNAMICSBLOCK *dynPtr=(Player->ObStrategyBlock->DynPtr);
1642 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
1643 	LOCALASSERT(playerStatusPtr);
1644 	/* sbPtr is the viewer. */
1645 
1646 	if (AvP.PlayerType!=I_Alien) {
1647 		/* Just to be sure. */
1648 		return(1);
1649 	}
1650 
1651     weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
1652 
1653 	/* Set a default range? */
1654 	range=-1;
1655 	/* Maybe we also need an autospot range. */
1656 	if (sbPtr) {
1657 		VECTORCH offset;
1658 
1659 		offset.vx=dynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
1660 		offset.vy=dynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
1661 		offset.vz=dynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
1662 
1663 		range=Approximate3dMagnitude(&offset);
1664 
1665 		/* In fact, let's turn this around... */
1666 
1667 		if (playerStatusPtr->ShapeState==PMph_Standing) {
1668 			if (range>=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) {
1669 				return(0);
1670 			}
1671 		} else {
1672 			if (range>=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) {
1673 				/* Half that range if crouching? */
1674 				return(0);
1675 			}
1676 		}
1677 
1678 		/* I guess, if we're in _pitch_ darkness... see nothing outside that range? */
1679 		if (CurrentLightAtPlayer<=2560) {
1680 			if (playerStatusPtr->ShapeState==PMph_Standing) {
1681 				if (range<=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) {
1682 					return(1);
1683 				}
1684 			} else {
1685 				if (range<=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) {
1686 					/* Half that range if crouching? */
1687 					return(1);
1688 				}
1689 			}
1690 			return(0);
1691 		}
1692 
1693 	}
1694 
1695 
1696 	if (playerStatusPtr->ShapeState==PMph_Standing) {
1697 		/* Default to visible, unless stationary and in near darkness. */
1698 		if (weaponPtr->CurrentState!=WEAPONSTATE_IDLE) {
1699 			/* Don't even breathe. */
1700 			return(1);
1701 		}
1702 		if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)||
1703 			(dynPtr->Position.vy!=dynPtr->PrevPosition.vy)||
1704 			(dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) {
1705 			/* Stand perfectly still. */
1706 			return(1);
1707 		}
1708 		if (checktime) {
1709 			int chance;
1710 			/* There is a chance of being seen regardless. */
1711 			chance=32767; /* Lets say. */
1712 			if ((FastRandom()&65535)<chance) {
1713 				return(1);
1714 			}
1715 		}
1716 		if (CurrentLightAtPlayer<5000) {
1717 			return(0);
1718 		}
1719 		return(1);
1720 	} else {
1721 		int speed;
1722 
1723 		/* Crouching.  Default to cloaked, unless they get 'lucky'. */
1724 		if (weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY) {
1725 			/* Just don't claw. */
1726 			return(1);
1727 		}
1728 
1729 		if (CurrentLightAtPlayer>17000) {
1730 			/* It's too bright, mere crouching won't save you. */
1731 			return(1);
1732 		}
1733 		#if 0
1734 		if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)||
1735 			(dynPtr->Position.vy!=dynPtr->PrevPosition.vy)||
1736 			(dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) {
1737 			/* Stand perfectly still? */
1738 			return(1);
1739 		}
1740 		#else
1741 		speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
1742 		/* Speed: < 5000 = standing.  > 22000 = jumping.
1743 			In practice, walk/fall = 18000 ish, jump = 27000 ish. */
1744 		if (speed>22000) {
1745 			/* Not getting away with that, mate. */
1746 			return(1);
1747 		}
1748 		speed-=5000;
1749 		if (speed<0) {
1750 			speed=0;
1751 		}
1752 		/* Now should be 0->17000 ish. */
1753 		speed<<=1;
1754 		#endif
1755 		if (checktime) {
1756 			int chance;
1757 			/* There is a chance of being seen. */
1758 			chance=CurrentLightAtPlayer-5000;
1759 			#if 1
1760 			chance+=speed;
1761 			#endif
1762 			if ((FastRandom()&65535)<chance) {
1763 				return(1);
1764 			}
1765 		}
1766 		return(0);
1767 	}
1768 }
1769 
1770 #if 0
1771 static void HandlePredatorVisionModes(void)
1772 {
1773 	extern unsigned char DebouncedKeyboardInput[];
1774 
1775 	if (DebouncedKeyboardInput[KEY_K])
1776 	{
1777 		ChangePredatorVisionMode();
1778 	}
1779 }
1780 #endif
1781 
ShowAdjacencies(void)1782 void ShowAdjacencies(void) {
1783 
1784 	int moduleCounter;
1785 	AIMODULE **AdjModuleRefPtr;
1786 	AIMODULE *thisModule;
1787 	AIMODULE *ModuleListPointer;
1788 
1789 	/* Utility function... */
1790 	PrintDebuggingText("Adjacencies FROM Player's Module (%s):\n",
1791 		(*(playerPherModule->m_aimodule->m_module_ptrs))->name);
1792 
1793 	thisModule=playerPherModule->m_aimodule;
1794 
1795 	AdjModuleRefPtr = thisModule->m_link_ptrs;
1796 
1797     if(AdjModuleRefPtr)     /* check that there is a list of adjacent modules */
1798     {
1799     	while(*AdjModuleRefPtr != 0)
1800 	    {
1801 			/* Probably want some validity test for the link. */
1802 			if (AIModuleIsPhysical(*AdjModuleRefPtr)) {
1803 				/* Probably a valid link... */
1804 				if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) {
1805 					PrintDebuggingText("--AI Module of %s, general.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name);
1806 				} else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) {
1807 					PrintDebuggingText("--AI Module of %s, alien only.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name);
1808 				} else {
1809 					PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name);
1810 				}
1811 			}
1812 			/* next adjacent module reference pointer */
1813 			AdjModuleRefPtr++;
1814 		}
1815 	}
1816 
1817 	PrintDebuggingText("Adjacencies TO Player's Module:\n");
1818 
1819 	{
1820 		extern AIMODULE *AIModuleArray;
1821 
1822 		ModuleListPointer = AIModuleArray;
1823 	}
1824 
1825 	/* go through each aimodule in the environment  */
1826 	for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++)
1827 	{
1828 
1829 		/* get a pointer to the next current module */
1830 		thisModule = &(ModuleListPointer[moduleCounter]);
1831 		LOCALASSERT(thisModule);
1832 
1833 		AdjModuleRefPtr = thisModule->m_link_ptrs;
1834 
1835 	    if(AdjModuleRefPtr)     /* check that there is a list of adjacent modules */
1836 	    {
1837 	    	while(*AdjModuleRefPtr != 0)
1838 		    {
1839 				/* Probably want some validity test for the link. */
1840 				if (AIModuleIsPhysical(*AdjModuleRefPtr)) {
1841 					/* Is this the target? */
1842 					if ((*AdjModuleRefPtr)==(playerPherModule->m_aimodule)) {
1843 
1844 						/* Probably a valid link... */
1845 						if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) {
1846 							PrintDebuggingText("--AI Module of %s, general.\n",(*(thisModule->m_module_ptrs))->name);
1847 						} else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) {
1848 							PrintDebuggingText("--AI Module of %s, alien only.\n",(*(thisModule->m_module_ptrs))->name);
1849 						} else {
1850 							PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*(thisModule->m_module_ptrs))->name);
1851 						}
1852 
1853 					}
1854 				}
1855 				/* next adjacent module reference pointer */
1856 				AdjModuleRefPtr++;
1857 			}
1858 		}
1859 
1860 	}
1861 
1862 }
1863 
1864 
1865 
1866 /*---------------------------**
1867 ** Loading and saving player **
1868 **---------------------------*/
1869 
1870 
1871 typedef struct player_save_block
1872 {
1873 	SAVE_BLOCK_STRATEGY_HEADER header;
1874 
1875 //behaviour block things
1876 	PLAYER_WEAPON_DATA	WeaponSlot[MAX_NO_OF_WEAPON_SLOTS];
1877 
1878 	enum WEAPON_SLOT	SelectedWeaponSlot;
1879 	enum WEAPON_SLOT	SwapToWeaponSlot;
1880 	enum WEAPON_SLOT	PreviouslySelectedWeaponSlot;
1881 
1882     int	Health;	 /* in 16.16 */
1883 	int	Energy;	 /* in 16.16 */
1884 	int	Armour;	 /* in 16.16 */
1885 
1886 
1887 	enum player_morph_state ShapeState;		/* for controlling morphing */
1888 
1889 	signed int ForwardInertia;
1890 	signed int StrafeInertia;
1891 	signed int TurnInertia;
1892 
1893 	int ViewPanX; /* the looking up/down value that used to be in displayblock */
1894 
1895 	unsigned int securityClearances;
1896 
1897 	unsigned int IsAlive :1;
1898 	unsigned int IsImmortal :1;
1899 	unsigned int Mvt_AnalogueTurning :1;
1900 	unsigned int Mvt_AnaloguePitching :1;
1901 	unsigned int Absolute_Pitching :1;
1902 	unsigned int SwappingIsDebounced :1;
1903 	unsigned int DemoMode :1;
1904 	unsigned int IHaveAPlacedAutogun :1;
1905 	unsigned int IsMovingInWater :1;
1906 	unsigned int JetpackEnabled :1;
1907 	unsigned int GrapplingHookEnabled :1;
1908 
1909 	unsigned int MTrackerType;
1910 
1911 	unsigned int cloakOn :1;
1912 	unsigned int cloakPositionGivenAway :1;
1913 	int FieldCharge;
1914 	int cloakPositionGivenAwayTimer;
1915 	int PlasmaCasterCharge;
1916 
1917 	int CloakingEffectiveness;
1918 
1919 	ENCUMBERANCE_STATE Encumberance;
1920 	int tauntTimer;
1921 
1922 	int incidentFlag;
1923 	int incidentTimer;
1924 	int fireTimer;
1925 
1926 //some stuff for the weapon displayblock
1927 	VECTORCH Weapon_World;
1928 	EULER Weapon_Euler;
1929 	MATRIXCH Weapon_Matrix;
1930 
1931 
1932 //and  globals
1933 	enum VISION_MODE_ID CurrentVisionMode;
1934 	SMARTGUN_MODES SmartgunMode;
1935 	GRENADE_LAUNCHER_DATA GrenadeLauncherData;
1936 
1937 
1938 //strategy block stuff
1939 	DYNAMICSBLOCK dynamics;
1940 	int integrity;
1941 	DAMAGEBLOCK SBDamageBlock;
1942 
1943 }PLAYER_SAVE_BLOCK;
1944 
1945 //defines for load/save macros
1946 #define SAVELOAD_BLOCK block
1947 #define SAVELOAD_BEHAV playerStatusPtr
1948 
1949 
SaveStrategy_Player(STRATEGYBLOCK * sbPtr)1950 void SaveStrategy_Player(STRATEGYBLOCK* sbPtr)
1951 {
1952 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr);
1953 	PLAYER_SAVE_BLOCK* block;
1954 	int i;
1955 
1956 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
1957 
1958 
1959 	COPYELEMENT_SAVE(SelectedWeaponSlot)
1960 	COPYELEMENT_SAVE(SwapToWeaponSlot)
1961 	COPYELEMENT_SAVE(PreviouslySelectedWeaponSlot)
1962 
1963     COPYELEMENT_SAVE(Health)	 /* in 16.16 */
1964 	COPYELEMENT_SAVE(Energy)	 /* in 16.16 */
1965 	COPYELEMENT_SAVE(Armour)	 /* in 16.16 */
1966 
1967 
1968 	COPYELEMENT_SAVE(ShapeState)		/* for controlling morphing */
1969 
1970 	COPYELEMENT_SAVE(ForwardInertia)
1971 	COPYELEMENT_SAVE(StrafeInertia)
1972 	COPYELEMENT_SAVE(TurnInertia)
1973 
1974 	COPYELEMENT_SAVE(ViewPanX) /* the looking up/down value that used to be in displayblock */
1975 
1976 	COPYELEMENT_SAVE(securityClearances)
1977 
1978 	COPYELEMENT_SAVE(IsAlive)
1979 	COPYELEMENT_SAVE(IsImmortal)
1980 	COPYELEMENT_SAVE(Mvt_AnalogueTurning)
1981 	COPYELEMENT_SAVE(Mvt_AnaloguePitching)
1982 	COPYELEMENT_SAVE(Absolute_Pitching)
1983 	COPYELEMENT_SAVE(SwappingIsDebounced)
1984 	COPYELEMENT_SAVE(DemoMode)
1985 	COPYELEMENT_SAVE(IHaveAPlacedAutogun)
1986 	COPYELEMENT_SAVE(IsMovingInWater)
1987 	COPYELEMENT_SAVE(JetpackEnabled)
1988 	COPYELEMENT_SAVE(GrapplingHookEnabled )
1989 
1990 	COPYELEMENT_SAVE(MTrackerType)
1991 
1992 	COPYELEMENT_SAVE(cloakOn)
1993 	COPYELEMENT_SAVE(cloakPositionGivenAway)
1994 	COPYELEMENT_SAVE(FieldCharge)
1995 	COPYELEMENT_SAVE(cloakPositionGivenAwayTimer)
1996 	COPYELEMENT_SAVE(PlasmaCasterCharge)
1997 	COPYELEMENT_SAVE(CloakingEffectiveness)
1998 	COPYELEMENT_SAVE(Encumberance)
1999 	COPYELEMENT_SAVE(tauntTimer)
2000 
2001 	COPYELEMENT_SAVE(incidentFlag)
2002 	COPYELEMENT_SAVE(incidentTimer)
2003 	COPYELEMENT_SAVE(fireTimer)
2004 
2005 	for(i=0;i<MAX_NO_OF_WEAPON_SLOTS;i++)
2006 	{
2007 		block->WeaponSlot[i].WeaponIDNumber = playerStatusPtr->WeaponSlot[i].WeaponIDNumber;
2008 		block->WeaponSlot[i].CurrentState = playerStatusPtr->WeaponSlot[i].CurrentState;
2009 		block->WeaponSlot[i].StateTimeOutCounter = playerStatusPtr->WeaponSlot[i].StateTimeOutCounter;
2010 		block->WeaponSlot[i].PrimaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining;
2011 		block->WeaponSlot[i].SecondaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining;
2012 		block->WeaponSlot[i].PrimaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining;
2013 		block->WeaponSlot[i].SecondaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining;
2014 		block->WeaponSlot[i].PositionOffset = playerStatusPtr->WeaponSlot[i].PositionOffset;
2015 		block->WeaponSlot[i].DirectionOffset = playerStatusPtr->WeaponSlot[i].DirectionOffset;
2016 		block->WeaponSlot[i].Possessed = playerStatusPtr->WeaponSlot[i].Possessed;
2017 	}
2018 
2019 	//some stuff for the weapon displayblock
2020 	block->Weapon_World = PlayersWeapon.ObWorld;
2021 	block->Weapon_Euler = PlayersWeapon.ObEuler;
2022 	block->Weapon_Matrix = PlayersWeapon.ObMat;
2023 
2024 	//global
2025 	block->CurrentVisionMode = CurrentVisionMode;
2026 	block->SmartgunMode = SmartgunMode;
2027 	block->GrenadeLauncherData = GrenadeLauncherData;
2028 
2029 	//strategy block stuff
2030 
2031 	block->integrity = sbPtr->integrity;
2032 	block->SBDamageBlock = sbPtr->SBDamageBlock;
2033 
2034 	block->dynamics = *sbPtr->DynPtr;
2035 	block->dynamics.CollisionReportPtr=0;
2036 
2037 	//save the weapon hierarchy
2038 	SaveHierarchy(&PlayersWeaponHModelController);
2039 
2040 
2041 	Save_SoundState(&playerStatusPtr->soundHandle);
2042 	Save_SoundState(&playerStatusPtr->soundHandle3);
2043 	Save_SoundState(&playerStatusPtr->soundHandle5);
2044 	Save_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged);
2045 }
2046 
LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER * header)2047 void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header)
2048 {
2049 	PLAYER_SAVE_BLOCK* block = (PLAYER_SAVE_BLOCK*) header;
2050 	STRATEGYBLOCK* sbPtr = Player->ObStrategyBlock;
2051 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr);
2052 	int i;
2053 
2054 	if(block->header.size != sizeof(*block)) return;
2055 
2056 	COPY_NAME(sbPtr->SBname,header->SBname);
2057 
2058 
2059 
2060 	COPYELEMENT_LOAD(SelectedWeaponSlot)
2061 	COPYELEMENT_LOAD(SwapToWeaponSlot)
2062 	COPYELEMENT_LOAD(PreviouslySelectedWeaponSlot)
2063 
2064     COPYELEMENT_LOAD(Health)	 /* in 16.16 */
2065 	COPYELEMENT_LOAD(Energy)	 /* in 16.16 */
2066 	COPYELEMENT_LOAD(Armour)	 /* in 16.16 */
2067 
2068 
2069 	COPYELEMENT_LOAD(ShapeState)		/* for controlling morphing */
2070 
2071 	COPYELEMENT_LOAD(ForwardInertia)
2072 	COPYELEMENT_LOAD(StrafeInertia)
2073 	COPYELEMENT_LOAD(TurnInertia)
2074 
2075 	COPYELEMENT_LOAD(ViewPanX) /* the looking up/down value that used to be in displayblock */
2076 
2077 	COPYELEMENT_LOAD(securityClearances)
2078 
2079 	COPYELEMENT_LOAD(IsAlive)
2080 	COPYELEMENT_LOAD(IsImmortal)
2081 	COPYELEMENT_LOAD(Mvt_AnalogueTurning)
2082 	COPYELEMENT_LOAD(Mvt_AnaloguePitching)
2083 	COPYELEMENT_LOAD(Absolute_Pitching)
2084 	COPYELEMENT_LOAD(SwappingIsDebounced)
2085 	COPYELEMENT_LOAD(DemoMode)
2086 	COPYELEMENT_LOAD(IHaveAPlacedAutogun)
2087 	COPYELEMENT_LOAD(IsMovingInWater)
2088 	COPYELEMENT_LOAD(JetpackEnabled)
2089 	COPYELEMENT_LOAD(GrapplingHookEnabled )
2090 
2091 	COPYELEMENT_LOAD(MTrackerType)
2092 
2093 	COPYELEMENT_LOAD(cloakOn)
2094 	COPYELEMENT_LOAD(cloakPositionGivenAway)
2095 	COPYELEMENT_LOAD(FieldCharge)
2096 	COPYELEMENT_LOAD(cloakPositionGivenAwayTimer)
2097 	COPYELEMENT_LOAD(PlasmaCasterCharge)
2098 	COPYELEMENT_LOAD(CloakingEffectiveness)
2099 	COPYELEMENT_LOAD(Encumberance)
2100 	COPYELEMENT_LOAD(tauntTimer)
2101 
2102 	COPYELEMENT_LOAD(incidentFlag)
2103 	COPYELEMENT_LOAD(incidentTimer)
2104 	COPYELEMENT_LOAD(fireTimer)
2105 
2106 //	playerStatusPtr->SwapToWeaponSlot = block->SelectedWeaponSlot;
2107 
2108 
2109 
2110 	for(i=0;i<MAX_NO_OF_WEAPON_SLOTS;i++)
2111 	{
2112 		playerStatusPtr->WeaponSlot[i].WeaponIDNumber = block->WeaponSlot[i].WeaponIDNumber;
2113 		playerStatusPtr->WeaponSlot[i].CurrentState = block->WeaponSlot[i].CurrentState;
2114 		playerStatusPtr->WeaponSlot[i].StateTimeOutCounter = block->WeaponSlot[i].StateTimeOutCounter;
2115 		playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining = block->WeaponSlot[i].PrimaryRoundsRemaining;
2116 		playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining = block->WeaponSlot[i].SecondaryRoundsRemaining;
2117 		playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining = block->WeaponSlot[i].PrimaryMagazinesRemaining;
2118 		playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining = block->WeaponSlot[i].SecondaryMagazinesRemaining;
2119 		playerStatusPtr->WeaponSlot[i].PositionOffset = block->WeaponSlot[i].PositionOffset;
2120 		playerStatusPtr->WeaponSlot[i].DirectionOffset = block->WeaponSlot[i].DirectionOffset;
2121 		playerStatusPtr->WeaponSlot[i].Possessed = block->WeaponSlot[i].Possessed;
2122 	}
2123 
2124 	//some stuff for the weapon displayblock
2125 	PlayersWeapon.ObWorld = block->Weapon_World;
2126 	PlayersWeapon.ObEuler = block->Weapon_Euler;
2127 	PlayersWeapon.ObMat = block->Weapon_Matrix;
2128 
2129 	//global
2130 	CurrentVisionMode = block->CurrentVisionMode;
2131 	SmartgunMode = block->SmartgunMode;
2132 	GrenadeLauncherData = block->GrenadeLauncherData;
2133 
2134 	//strategy block stuff
2135 	*sbPtr->DynPtr = block->dynamics;
2136 	sbPtr->integrity = block->integrity;
2137 	sbPtr->SBDamageBlock = block->SBDamageBlock;
2138 
2139 
2140 
2141 
2142 	{
2143 		extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr;
2144 	   	sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
2145 		Global_VDB_Ptr->VDB_World = sbPtr->DynPtr->Position;
2146 	}
2147 
2148 
2149 	//load the weapon hierarchy
2150 	{
2151 		SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
2152 		if(hier_header)
2153 		{
2154 			LoadHierarchy(hier_header,&PlayersWeaponHModelController);
2155 		}
2156 		else
2157 		{
2158 			Dispel_HModel(&PlayersWeaponHModelController);
2159 		}
2160 	}
2161 
2162 
2163 	PlayersWeapon.HModelControlBlock = &PlayersWeaponHModelController;
2164 
2165 	//get the section data pointers
2166 	PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"dum flash");
2167 	if (PWMFSDP==NULL) {
2168 		PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum flash");
2169 	}
2170 
2171 	Load_SoundState(&playerStatusPtr->soundHandle);
2172 	Load_SoundState(&playerStatusPtr->soundHandle3);
2173 	Load_SoundState(&playerStatusPtr->soundHandle5);
2174 	Load_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged);
2175 
2176 }
2177 
2178