1 /*KJL******************************************************************
2 * weapon.c - this is home to the weapon state machine and related fns *
3 ******************************************************************KJL*/
4 #include "3dc.h"
5 #include "module.h"
6 #include "inline.h"
7 
8 #include "stratdef.h"
9 #include "gamedef.h"
10 #include "gameplat.h"
11 
12 #include "bh_types.h"
13 #include "inventry.h"
14 #include "comp_shp.h"
15 #include "load_shp.h"
16 #include "huddefs.h"
17 
18 #define UseLocalAssert Yes
19 #include "ourasert.h"
20 
21 #include "dynblock.h"
22 #include "dynamics.h"
23 #include "lighting.h"
24 #include "pvisible.h"
25 #include "bh_alien.h"
26 #include "bh_pred.h"
27 #include "bh_xeno.h"
28 #include "bh_paq.h"
29 #include "bh_queen.h"
30 #include "bh_fhug.h"
31 #include "bh_marin.h"
32 #include "bh_debri.h"
33 #include "bh_weap.h"
34 #include "bh_agun.h"
35 #include "bh_light.h"
36 #include "bh_corpse.h"
37 #include "bh_ais.h"
38 #include "bh_videoscreen.h"
39 #include "bh_track.h"
40 #include "weapons.h"
41 #include "avpview.h"
42 
43 #include "psnd.h"
44 #include "vision.h"
45 #include "plat_shp.h"
46 
47 #include "particle.h"
48 #include "psndproj.h"
49 #include "psndplat.h"
50 #include "showcmds.h"
51 #include "projload.hpp"
52 
53 /* for win 95 net support */
54 #include "pldghost.h"
55 #include "pldnet.h"
56 
57 #include "los.h"
58 #include "kshape.h"
59 #include "targeting.h"
60 #include "extents.h"
61 #include "scream.h"
62 #include "avp_userprofile.h"
63 
64 #define BITE_HEALTH_RECOVERY	(50)
65 #define BITE_ARMOUR_RECOVERY	(30)
66 #define PULSERIFLE_MINIMUM_BURST	(4)
67 #define SMARTGUN_MINIMUM_BURST	(8)
68 
69 #define MEDICOMP_USE_THRESHOLD	(10*ONE_FIXED)
70 #define MEDICOMP_DRAIN_BLOCK	((10*ONE_FIXED)-1)
71 #define EXTINGUISHER_USE_THRESHOLD	(3*ONE_FIXED)
72 #define EXTINGUISHER_DRAIN_BLOCK	(3*ONE_FIXED)
73 #define GREENFLASH_INTENSITY	(5*ONE_FIXED)
74 
75 #define CASTER_CHARGERATIO (2)
76 /* Was 3... */
77 
78 #define PRED_PISTOL_SECONDARY_FIRE_CHARGE	(ONE_FIXED<<1)
79 
80 #define QUIRKAFLEEG	0
81 /* That turns on medicomp ammo.  Private joke.  :-) */
82 
83 /*KJL****************************************************************************************
84 *  										G L O B A L S 	            					    *
85 ****************************************************************************************KJL*/
86 
87 #if 0
88 static char tempstring[256];
89 #endif
90 
91 static int WBStrikeTime=(ONE_FIXED>>1);
92 static int ACStrikeTime=(ONE_FIXED/6);
93 int AutoSwap=-1;
94 
95 int PredPistol_ShotCost=120000;  /* Changed from 60000 (Fox value), 1/3/99 */
96 int Caster_Jumpstart=10000;
97 int Caster_Chargetime=150000;
98 int Caster_ChargeRatio=400000;
99 int Caster_TrickleRate=0;
100 int Caster_TrickleLevel=16384;
101 int Caster_MinCharge=0;
102 
103 int Caster_NPCKill=16384;
104 int Caster_PCKill=49151;
105 
106 static int AC_Speed_Factor=ONE_FIXED;
107 int Alien_Visible_Weapon;
108 static int Alien_Tail_Clock;
109 static int Wristblade_StrikeType;
110 STRATEGYBLOCK *Alien_Tail_Target;
111 char Alien_Tail_Target_SBname[SB_NAME_LENGTH];
112 
113 static DAMAGE_PROFILE Player_Weapon_Damage;
114 
115 extern SOUND3DDATA Explosion_SoundData;
116 
117 extern DISPLAYBLOCK* Player;
118 extern int NormalFrameTime;
119 extern unsigned char Null_Name[8];
120 extern int ShowPredoStats;
121 extern int playerNoise;
122 extern int PlayerDamagedOverlayIntensity;
123 
124 extern int NumOnScreenBlocks;
125 extern int NumActiveBlocks;
126 extern DISPLAYBLOCK *OnScreenBlockList[];
127 extern DISPLAYBLOCK *ActiveBlockList[];
128 extern DISPLAYBLOCK *SmartTarget_Object;
129 extern int HtoHStrikes;
130 extern int weaponHandle;
131 extern int predHUDSoundHandle;
132 extern ACTIVESOUNDSAMPLE ActiveSounds[];
133 extern NETGAME_GAMEDATA netGameData;
134 
135 int WeaponFidgetPlaying;
136 int Old_Minigun_SpinSpeed;
137 int Minigun_SpinSpeed;
138 int Weapon_ThisBurst;
139 EULER Minigun_MaxHeadJolt;
140 EULER Minigun_HeadJolt;
141 int Flamethrower_Timer;
142 
143 SECTION_DATA *PlayerStaff1=NULL;
144 SECTION_DATA *PlayerStaff2=NULL;
145 SECTION_DATA *PlayerStaff3=NULL;
146 int StaffAttack=-1;
147 STRATEGYBLOCK *Biting;
148 char Biting_SBname[SB_NAME_LENGTH];
149 int Bit=0;
150 
151 extern int Validate_Target(STRATEGYBLOCK *target,char *SBname);
152 
153 extern MODULEMAPBLOCK * MakeDefaultModuleMapblock();
154 extern void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage,int factor);
155 extern void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position);
156 extern void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section);
157 extern int Validate_Target(STRATEGYBLOCK *target,char *SBname);
158 extern int playerNoise;
159 extern int SlotForThisWeapon(enum WEAPON_ID weaponID);
160 extern void MakeBloodExplosion(VECTORCH *originPtr, int creationRadius, VECTORCH *blastPositionPtr, int noOfParticles, enum PARTICLE_ID particleID);
161 extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name);
162 extern void Crunch_Position_For_Players_Weapon(VECTORCH *position);
163 extern DISPLAYBLOCK *MakePistolCasing(VECTORCH *position,MATRIXCH *orient);
164 
165 int FriendlyFireDamageFilter(DAMAGE_PROFILE *damage);
166 static void MarineZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr);
167 static void PredatorZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr);
168 
169 /* Line Of Sight information used by FireLineOfSightWeapon() */
170 VECTORCH 		LOS_Point;	 		/* point in world space which player has hit */
171 int 			LOS_Lambda;			/* distance in mm to point from player */
172 DISPLAYBLOCK*	LOS_ObjectHitPtr;	/* pointer to object that was hit */
173 VECTORCH		LOS_ObjectNormal;	/* normal of the object's face which was hit */
174 SECTION_DATA*	LOS_HModel_Section;	/* Section of HModel hit */
175 
176 
177 /* unnormalised vector in the direction	which the gun's muzzle is pointing, IN VIEW SPACE */
178 /* very useful when considering sprites, which lie in a z-plane in view space */
179 VECTORCH GunMuzzleDirectionInVS;
180 
181 VECTORCH PlayerGunBarrelOffset;
182 
183 /* dir gun is pointing, normalised and in world space */
184 VECTORCH GunMuzzleDirectionInWS;
185 
186 DISPLAYBLOCK PlayersWeapon;
187 DISPLAYBLOCK PlayersWeaponMuzzleFlash;
188 HMODELCONTROLLER PlayersWeaponHModelController;
189 SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */
190 VECTORCH PlayersWeaponCameraOffset;
191 
192 struct Target PlayersTarget;
193 
194 int GrenadeLauncherSelectedAmmo;
195 int LastHand;  // For alien claws and two pistols
196 
197 int AllowGoldWeapons = 0; // flag to indicate the Gold version weapons should be allowed
198 
199 char *GrenadeLauncherBulletNames[6] = {
200 	"bulletF",	//05_
201 	"bulletA",	//_
202 	"bulletB",	//01_
203 	"bulletC",	//02_
204 	"bulletD",	//03_
205 	"bulletE",	//04_
206 };
207 
208 enum WEAPON_ID MarineWeaponHierarchy[] = {
209 
210 	WEAPON_PULSERIFLE,
211 	WEAPON_SMARTGUN,
212 	WEAPON_TWO_PISTOLS,
213 	WEAPON_MARINE_PISTOL,
214 	WEAPON_MINIGUN,
215 	WEAPON_FLAMETHROWER,
216 	WEAPON_GRENADELAUNCHER,
217 	WEAPON_SADAR,
218 	WEAPON_FRISBEE_LAUNCHER,
219 	WEAPON_CUDGEL,
220 	NULL_WEAPON
221 
222 };
223 
224 enum WEAPON_ID PredatorWeaponHierarchy[] = {
225 
226 	WEAPON_PRED_RIFLE,
227 	WEAPON_PRED_WRISTBLADE,
228 	NULL_WEAPON
229 
230 };
231 
232 extern void CastLOSSpear(STRATEGYBLOCK *sbPtr, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int inaccurate);
233 
234 VECTORCH SpreadfireSpears[] = {
235 	{0,0,	600,},
236 	{100,0,	600,},
237 	{-100,0,600,},
238 	{50,0,	600,},
239 	{-50,0,	600,},
240 	{25,50,	600,},
241 	{-25,50,600,},
242 	{75,50,	600,},
243 	{-75,50,600,},
244 	{25,-50,600,},
245 	{-25,-50,600,},
246 	{75,-50,600,},
247 	{-75,-50,600,},
248 	{-1,-1,-1,},
249 };
250 
251 SECTION_DATA *GrenadeLauncherSectionPointers[6];
252 
253 /* Used to calculate the damage of one projectile due to FRI
254    Only used by the flamethrower at the moment */
255 int ProjectilesFired;
256 
257 /*KJL****************************************************************************************
258 *                                    P R O T O T Y P E S	                                *
259 ****************************************************************************************KJL*/
260 extern void DoShapeAnimation (DISPLAYBLOCK * dptr);
261 void FindHitArea(DISPLAYBLOCK *dptr);
262 DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir);
263 DISPLAYBLOCK *AlienTail_TargetSelect(void);
264 STRATEGYBLOCK *GetBitingTarget(void);
265 SECTION_DATA *CheckBiteIntegrity(void);
266 /* Yes, whatever, but this was LESS TEDIOUS! */
267 STRATEGYBLOCK *GetTrophyTarget(SECTION_DATA **head_section_data);
268 
269 extern void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming);
270 
271 void UpdateWeaponStateMachine(void);
272 void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data);
273 static void WeaponStateIdle(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr,TEMPLATE_WEAPON_DATA *twPtr, int justfiredp,int justfireds, int ps);
274 static int RequestChangeOfWeapon(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr);
275 void ChangeHUDToAlternateShapeSet(char *riffname,char *setname);
276 
277 
278 
279 static void StateDependentMovement(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr);
280 
281 int FireAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr);
282 int FireNonAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr);
283 int FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA *weaponPtr);
284 int GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr);
285 int PredDiscChangeMode(PLAYER_WEAPON_DATA *weaponPtr);
286 int SmartgunSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr);
287 int DamageObjectInLineOfSight(PLAYER_WEAPON_DATA *weaponPtr);
288 int MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA *weaponPtr);
289 int MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA *weaponPtr);
290 int FireEmptyMinigun(PLAYER_WEAPON_DATA *weaponPtr);
291 
292 int Staff_Manager(DAMAGE_PROFILE *damage,SECTION_DATA *section1,SECTION_DATA *section2,SECTION_DATA *section3,
293 	STRATEGYBLOCK *wielder);
294 
295 static void PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID, int multiple);
296 extern void FireProjectileAmmo(enum AMMO_ID AmmoID);
297 
298 void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer);
299 
300 
301 void FireAutoGun(STRATEGYBLOCK *sbPtr);
302 void FindEndOfShape(VECTORCH* endPositionPtr, int shapeIndex);
303 static void CalculateTorque(EULER *rotationPtr, VECTORCH *directionPtr, STRATEGYBLOCK *sbPtr);
304 static void CalculateTorqueAtPoint(EULER *rotationPtr, VECTORCH *pointPtr, STRATEGYBLOCK *sbPtr);
305 
306 void PositionPlayersWeaponMuzzleFlash(void);
307 
308 void MeleeWeaponNullTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
309 
310 void AlienClawTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
311 void AlienClawEndTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
312 void AlienTailTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
313 
314 void PredWristbladeTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
315 void PredDiscThrowTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
316 
317 void ParticleBeamSwapping(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
318 void ParticleBeamReadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
319 void ParticleBeamUnreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
320 
321 void InitThisWeapon(PLAYER_WEAPON_DATA *pwPtr);
322 
323 static int RequestChangeOfWeaponWhilstSwapping(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr);
324 
325 static void DamageDamageBlock(DAMAGEBLOCK *DBPtr, DAMAGE_PROFILE *damage, int multiple);
326 DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data,VECTORCH *incoming, VECTORCH *position, int FromHost);
327 #if 0
328 void WeaponCreateStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr);
329 #endif
330 int PC_Alien_Eat_Attack(int hits);
331 int FirePredatorDisc(PLAYER_WEAPON_DATA *weaponPtr,SECTION_DATA *disc_section);
332 
333 void BiteAttack_AwardHealth(STRATEGYBLOCK *sbPtr,AVP_BEHAVIOUR_TYPE pre_bite_type);
334 void LimbRip_AwardHealth(void);
335 void GrenadeLauncher_EmergencyChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr);
336 int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr);
337 
338 #define Random16BitNumber (FastRandom()&65535)
339 /*KJL****************************************************************************************
340 *                                     F U N C T I O N S	                                    *
341 ****************************************************************************************KJL*/
342 
Predator_WantToChangeWeapon(PLAYER_STATUS * playerStatusPtr,PLAYER_WEAPON_DATA * weaponPtr)343 int Predator_WantToChangeWeapon(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr) {
344 
345 	if ((
346 		(weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)
347 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_WRISTBLADE)
348 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_STAFF)
349 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP)
350 		)||(
351 		(AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON)
352 		&&(playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart)
353 		&&(playerStatusPtr->FieldCharge<MUL_FIXED((Caster_Jumpstart-playerStatusPtr->PlasmaCasterCharge),Caster_ChargeRatio))
354 		)||(
355 		(AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL)
356 		&&(playerStatusPtr->FieldCharge<PredPistol_ShotCost)
357 		)) {
358 
359 		return(1);
360 
361 	} else {
362 
363 		return(0);
364 
365 	}
366 }
367 
Predator_WeaponHasAmmo(PLAYER_STATUS * playerStatusPtr,int slot)368 int Predator_WeaponHasAmmo(PLAYER_STATUS *playerStatusPtr, int slot) {
369 
370 	if (slot!=-1) {
371 		PLAYER_WEAPON_DATA *this_weaponPtr;
372 
373 	    this_weaponPtr = &(PlayerStatusPtr->WeaponSlot[slot]);
374 
375 		switch (this_weaponPtr->WeaponIDNumber) {
376 			default:
377 				{
378 					return(0);
379 				}
380 				break;
381 			case WEAPON_PRED_WRISTBLADE:
382 			case WEAPON_PRED_STAFF:
383 				{
384 					return(1);
385 				}
386 				break;
387 			case WEAPON_PRED_MEDICOMP:
388 				{
389 					if ((playerStatusPtr->FieldCharge<EXTINGUISHER_USE_THRESHOLD)
390 						&&(playerStatusPtr->FieldCharge<MEDICOMP_USE_THRESHOLD)) {
391 						return(0);
392 					} else {
393 						return(1);
394 					}
395 				}
396 				break;
397 			case WEAPON_PRED_RIFLE:
398 			case WEAPON_PRED_DISC:
399 				{
400 					if (this_weaponPtr->PrimaryRoundsRemaining==0 && this_weaponPtr->PrimaryMagazinesRemaining==0) {
401 						return(0);
402 					} else {
403 						return(1);
404 					}
405 				}
406 				break;
407 			case WEAPON_PRED_PISTOL:
408 				{
409 					if (playerStatusPtr->FieldCharge<PredPistol_ShotCost) {
410 						return(0);
411 					} else {
412 						return(1);
413 					}
414 				}
415 				break;
416 			case WEAPON_PRED_SHOULDERCANNON:
417 				{
418 					if ((playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart)
419 						&&(playerStatusPtr->FieldCharge<MUL_FIXED((Caster_Jumpstart-playerStatusPtr->PlasmaCasterCharge),Caster_ChargeRatio))) {
420 						return(0);
421 					} else {
422 						return(1);
423 					}
424 				}
425 				break;
426 		}
427 	}
428 
429 	return(0);
430 }
431 
Marine_WantToChangeWeapon(PLAYER_WEAPON_DATA * weaponPtr)432 int Marine_WantToChangeWeapon(PLAYER_WEAPON_DATA *weaponPtr) {
433 
434 	if (((weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining==0)
435 		&& (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0))
436 		|| (weaponPtr->WeaponIDNumber==WEAPON_CUDGEL)) {
437 		return(1);
438 	}
439 	return(0);
440 }
441 
WeaponHasAmmo(int slot)442 int WeaponHasAmmo(int slot) {
443 
444 	if (slot!=-1) {
445 		PLAYER_WEAPON_DATA *this_weaponPtr;
446 
447 	    this_weaponPtr = &(PlayerStatusPtr->WeaponSlot[slot]);
448 
449 		if ((this_weaponPtr->SecondaryRoundsRemaining!=0 || this_weaponPtr->SecondaryMagazinesRemaining!=0)
450 			|| (this_weaponPtr->PrimaryRoundsRemaining!=0 || this_weaponPtr->PrimaryMagazinesRemaining!=0)
451 			||	(this_weaponPtr->WeaponIDNumber==WEAPON_CUDGEL)
452 			|| (
453 				(this_weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER)
454 				&& (
455 				(GrenadeLauncherData.ProximityRoundsRemaining!=0)
456 			  	||(GrenadeLauncherData.FragmentationRoundsRemaining!=0)
457 			 	||(GrenadeLauncherData.StandardRoundsRemaining!=0)
458 				||(GrenadeLauncherData.ProximityMagazinesRemaining!=0)
459 			  	||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0)
460 			 	||(GrenadeLauncherData.StandardMagazinesRemaining!=0)
461 				)
462 			)
463 			) {
464 			return(1);
465 		}
466 	}
467 	return(0);
468 }
469 
SimilarPredWeapons(PLAYER_WEAPON_DATA * nwp,PLAYER_WEAPON_DATA * owp)470 int SimilarPredWeapons(PLAYER_WEAPON_DATA *nwp,PLAYER_WEAPON_DATA *owp) {
471 
472 	if ((nwp->WeaponIDNumber==WEAPON_PRED_WRISTBLADE)
473 		||(nwp->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON)
474 		||(nwp->WeaponIDNumber==WEAPON_PRED_MEDICOMP)) {
475 
476 		if ((owp->WeaponIDNumber==WEAPON_PRED_WRISTBLADE)
477 			||(owp->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON)
478 			||(owp->WeaponIDNumber==WEAPON_PRED_MEDICOMP)) {
479 
480 			if (nwp->WeaponIDNumber!=owp->WeaponIDNumber) {
481 				return(1);
482 			}
483 		}
484 	}
485 
486 	return(0);
487 
488 }
489 
GetBloodType(STRATEGYBLOCK * sbPtr)490 enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr) {
491 
492 	enum PARTICLE_ID blood_type=PARTICLE_NULL;
493 
494 	if (sbPtr==NULL) {
495 		return(PARTICLE_NULL);
496 	}
497 
498 	switch (sbPtr->I_SBtype) {
499 		default:
500 			blood_type=PARTICLE_NULL;
501 			break;
502 		case I_BehaviourHierarchicalFragment:
503 			{
504 				HDEBRIS_BEHAV_BLOCK *debrisStatusPointer;
505 
506 				debrisStatusPointer=(HDEBRIS_BEHAV_BLOCK *)(sbPtr->SBdataptr);
507 				GLOBALASSERT(debrisStatusPointer);
508 
509 				if (debrisStatusPointer->Android) {
510 					blood_type=PARTICLE_ANDROID_BLOOD;
511 				} else {
512 					blood_type=PARTICLE_HUMAN_BLOOD;
513 				}
514 			}
515 			break;
516 		case I_BehaviourSpeargunBolt:
517 			{
518 				SPEAR_BEHAV_BLOCK *debrisStatusPointer;
519 
520 				debrisStatusPointer=(SPEAR_BEHAV_BLOCK *)(sbPtr->SBdataptr);
521 				GLOBALASSERT(debrisStatusPointer);
522 
523 				if (debrisStatusPointer->Android) {
524 					blood_type=PARTICLE_ANDROID_BLOOD;
525 				} else {
526 					blood_type=PARTICLE_HUMAN_BLOOD;
527 				}
528 			}
529 			break;
530 		case I_BehaviourMarine:
531 		case I_BehaviourSeal:
532 			{
533 				MARINE_STATUS_BLOCK *marineStatusPointer;
534 
535 				marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
536 				GLOBALASSERT(marineStatusPointer);
537 
538 				if (marineStatusPointer->Android) {
539 					blood_type=PARTICLE_ANDROID_BLOOD;
540 				} else {
541 					blood_type=PARTICLE_HUMAN_BLOOD;
542 				}
543 			}
544 			break;
545 		case I_BehaviourAlien:
546 		case I_BehaviourQueenAlien:
547 			blood_type=PARTICLE_ALIEN_BLOOD;
548 			break;
549 		case I_BehaviourPredator:
550 			blood_type=PARTICLE_PREDATOR_BLOOD;
551 			break;
552 		case I_BehaviourXenoborg:
553 		case I_BehaviourAutoGun:
554 			blood_type=PARTICLE_SPARK;
555 			break;
556 		case I_BehaviourNetCorpse:
557 			{
558 				NETCORPSEDATABLOCK *corpseDataPtr;
559 
560 				corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
561 				LOCALASSERT(corpseDataPtr);
562 
563 				switch (corpseDataPtr->Type) {
564 					default:
565 						blood_type=PARTICLE_NULL;
566 						break;
567 					case I_BehaviourMarinePlayer :
568 					case I_BehaviourMarine:
569 					case I_BehaviourSeal:
570 						if (corpseDataPtr->Android) {
571 							blood_type=PARTICLE_ANDROID_BLOOD;
572 						} else {
573 							blood_type=PARTICLE_HUMAN_BLOOD;
574 						}
575 						break;
576 					case I_BehaviourAlienPlayer :
577 					case I_BehaviourAlien:
578 					case I_BehaviourQueenAlien:
579 						blood_type=PARTICLE_ALIEN_BLOOD;
580 						break;
581 					case I_BehaviourPredatorPlayer:
582 					case I_BehaviourPredator:
583 						blood_type=PARTICLE_PREDATOR_BLOOD;
584 						break;
585 					case I_BehaviourXenoborg:
586 					case I_BehaviourAutoGun:
587 						blood_type=PARTICLE_SPARK;
588 						break;
589 				}
590 
591 			}
592 			break;
593 		case I_BehaviourNetGhost:
594 			{
595 				NETGHOSTDATABLOCK *corpseDataPtr;
596 				corpseDataPtr=sbPtr->SBdataptr;
597 				switch (corpseDataPtr->type) {
598 					default:
599 						blood_type=PARTICLE_NULL;
600 						break;
601 					case I_BehaviourMarinePlayer :
602 					case I_BehaviourMarine:
603 					case I_BehaviourSeal:
604 						/* Add an Android test here? */
605 						blood_type=PARTICLE_HUMAN_BLOOD;
606 						break;
607 					case I_BehaviourAlienPlayer :
608 					case I_BehaviourAlien:
609 					case I_BehaviourQueenAlien:
610 						blood_type=PARTICLE_ALIEN_BLOOD;
611 						break;
612 					case I_BehaviourPredatorPlayer:
613 					case I_BehaviourPredator:
614 						blood_type=PARTICLE_PREDATOR_BLOOD;
615 						break;
616 					case I_BehaviourXenoborg:
617 					case I_BehaviourAutoGun:
618 						blood_type=PARTICLE_SPARK;
619 						break;
620 					case I_BehaviourNetCorpse:
621 						switch (corpseDataPtr->subtype) {
622 							default:
623 								blood_type=PARTICLE_NULL;
624 								break;
625 							case I_BehaviourMarinePlayer :
626 							case I_BehaviourMarine:
627 							case I_BehaviourSeal:
628 								/* Add an Android test here? */
629 								blood_type=PARTICLE_HUMAN_BLOOD;
630 								break;
631 							case I_BehaviourAlienPlayer :
632 							case I_BehaviourAlien:
633 							case I_BehaviourQueenAlien:
634 								blood_type=PARTICLE_ALIEN_BLOOD;
635 								break;
636 							case I_BehaviourPredatorPlayer:
637 							case I_BehaviourPredator:
638 								blood_type=PARTICLE_PREDATOR_BLOOD;
639 								break;
640 							case I_BehaviourXenoborg:
641 							case I_BehaviourAutoGun:
642 								blood_type=PARTICLE_SPARK;
643 								break;
644 						}
645 						break;
646 				}
647 			}
648 			break;
649 	}
650 
651 	return(blood_type);
652 }
653 
654 static int FirePrimaryLate,FireSecondaryLate;
655 
UpdateWeaponStateMachine(void)656 void UpdateWeaponStateMachine(void)
657 {
658 	PLAYER_WEAPON_DATA *weaponPtr;
659 	TEMPLATE_WEAPON_DATA *twPtr;
660     int justfiredp,justfireds,ps;
661 
662     /* access the extra data hanging off the strategy block */
663 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
664     GLOBALASSERT(playerStatusPtr);
665 
666 	/* player's current weapon */
667     GLOBALASSERT(playerStatusPtr->SelectedWeaponSlot<MAX_NO_OF_WEAPON_SLOTS);
668 
669 	if (playerStatusPtr->MyFaceHugger) {
670 		return;
671 	}
672 
673 	CurrentGameStats_UsingWeapon(playerStatusPtr->SelectedWeaponSlot);
674 
675     /* init a pointer to the weapon's data */
676     weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
677 
678 	justfiredp=0; // Has the player just fired...
679 	justfireds=0; // Has the player just fired...
680 	ps=0; // If so, primary or secondary?  For rapid fire recoil handling, in WeaponStateIdle.
681 
682 	FirePrimaryLate=0;
683 	FireSecondaryLate=0;
684 
685 	/* Hack for autoswap commmands. */
686 	if (AutoSwap!=-1) {
687         PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo=(AutoSwap+1);
688 		AutoSwap=-1;
689 	}
690 
691 	/* Player doesn't have a weapon! This will eventually be changed into an assertion
692 	that the player *does* have a weapon */
693 	if (weaponPtr->WeaponIDNumber == NULL_WEAPON)
694 		return;
695 
696 	/* Player is dead. Weapon goes idle */
697     if (!playerStatusPtr->IsAlive)
698 	{
699 		#if 0
700 		WeaponCreateStartFrame((void *)playerStatusPtr, weaponPtr);
701 		#endif
702 
703 		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
704     	weaponPtr->StateTimeOutCounter=0;
705 		return;
706 	}
707 
708     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
709 
710  	CalculatePlayersTarget(twPtr,weaponPtr);
711 
712 	playerStatusPtr->Encumberance=twPtr->Encum_Idle; //Default state
713 
714 	textprint("Weapon State %d\n",weaponPtr->CurrentState);
715 	textprint("Weapon_ThisBurst %d\n",Weapon_ThisBurst);
716 	textprint("Primary Mags %d\n",weaponPtr->PrimaryMagazinesRemaining);
717 	textprint("Primary Rounds %d\n",weaponPtr->PrimaryRoundsRemaining);
718 	textprint("Players Target Distance %d\n",PlayersTarget.Distance);
719 	#if 0
720 	textprint("Minigun_HeadJolt %d %d %d\n",Minigun_HeadJolt.EulerX,Minigun_HeadJolt.EulerY,Minigun_HeadJolt.EulerZ);
721 	textprint("HeadOrientation %d %d %d\n",HeadOrientation.EulerX,HeadOrientation.EulerY,HeadOrientation.EulerZ);
722 	textprint("ViewPanX %d\n",playerStatusPtr->ViewPanX);
723 	#endif
724 
725     /* if weapon is not idle, evaluate any state changes required */
726 	if (WEAPONSTATE_IDLE!=weaponPtr->CurrentState)
727 	{
728     	/* Time out current weapon state */
729     	{
730         	int timeOutRate = twPtr->TimeOutRateForState[weaponPtr->CurrentState];
731 
732 			if (WEAPONSTATE_INSTANTTIMEOUT==timeOutRate)
733             {
734             	weaponPtr->StateTimeOutCounter=0;
735             }
736             else
737            	{
738             	weaponPtr->StateTimeOutCounter-=MUL_FIXED(timeOutRate,NormalFrameTime);
739             }
740 
741         }
742         if(weaponPtr->StateTimeOutCounter<=0)
743         {
744 			WeaponFidgetPlaying=0;
745 			/* It's the only way to be sure. */
746         	switch(weaponPtr->CurrentState)
747 			{
748                 case WEAPONSTATE_FIRING_PRIMARY:
749                 {
750 				   	if (twPtr->PrimaryIsMeleeWeapon) {
751 						/* Melee weapons fire at the end of the 'firing' phase, in	 *
752 						 * addition to other special properties, like infinite ammo. */
753 						if (twPtr->FirePrimaryFunction!=NULL) {
754 							if ((*twPtr->FirePrimaryFunction)(weaponPtr)) {
755 								/* Er... well done. */
756 								/* It might be important to put something here, okay? */
757 								/* Till then, this will be compiled out. */
758 							}
759 						}
760 					}
761 
762 					if (twPtr->PrimaryIsRapidFire)
763 					{
764 						/* after shooting weapon goes straight to idle state */
765 						weaponPtr->CurrentState = WEAPONSTATE_IDLE;
766 						justfiredp=weaponPtr->StateTimeOutCounter+1;
767 						ps=1;
768 				    	weaponPtr->StateTimeOutCounter=0;
769 					}
770 					else
771 					{
772 						/* there is a 'recovery' time after shooting */
773 						weaponPtr->CurrentState = WEAPONSTATE_RECOIL_PRIMARY;
774 						weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
775 					}
776 
777 					playerStatusPtr->Encumberance=twPtr->Encum_FirePrime;
778 
779                 	break;
780 				}
781                 case WEAPONSTATE_FIRING_SECONDARY:
782                 {
783 
784 				   	if (twPtr->SecondaryIsMeleeWeapon) {
785 						/* Melee weapons fire at the end of the 'firing' phase, in	 *
786 						 * addition to other special properties, like infinite ammo. */
787 						if (twPtr->FireSecondaryFunction!=NULL) {
788 							if ((*twPtr->FireSecondaryFunction)(weaponPtr)) {
789 								/* Er... well done. */
790 								/* It might be important to put something here, okay? */
791 								/* Till then, this will be compiled out. */
792 							}
793 						}
794 					}
795 
796 					if (twPtr->SecondaryIsRapidFire)
797 					{
798 						/* after shooting weapon goes straight to idle state */
799 						weaponPtr->CurrentState = WEAPONSTATE_IDLE;
800 						justfireds=weaponPtr->StateTimeOutCounter+1;
801 						ps=2;
802 				    	weaponPtr->StateTimeOutCounter=0;
803 					}
804 					else
805 					{
806 						/* there is a 'recovery' time after shooting */
807 						weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY;
808 						weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
809 					}
810 
811 					playerStatusPtr->Encumberance=twPtr->Encum_FireSec;
812 
813                 	break;
814 				}
815 
816 			    case WEAPONSTATE_RELOAD_PRIMARY:
817 			    {
818 			    	/* load a new magazine */
819                     TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
820 					if (weaponPtr->PrimaryRoundsRemaining==0) {
821 						if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
822 							/* Two pistols reloads BOTH primary and secondary. */
823 							if (weaponPtr->PrimaryMagazinesRemaining) {
824 			                	weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
825 			                	weaponPtr->PrimaryMagazinesRemaining--;
826 							}
827 							if (weaponPtr->SecondaryMagazinesRemaining) {
828 			                	weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
829 			                	weaponPtr->SecondaryMagazinesRemaining--;
830 							}
831 						} else {
832 							/* Grenade launcher has already reloaded at this point. */
833 		                	weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
834 		                	weaponPtr->PrimaryMagazinesRemaining--;
835 						}
836 					}
837                		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
838 			    	weaponPtr->StateTimeOutCounter=0;
839 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
840 
841 		        	break;
842 		        }
843 			    case WEAPONSTATE_RELOAD_SECONDARY:
844 			    {
845 			    	/* load a new magazine */
846                     TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID];
847                 	weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
848                 	weaponPtr->SecondaryMagazinesRemaining--;
849                		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
850 			    	weaponPtr->StateTimeOutCounter=0;
851 
852 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
853 
854 		        	break;
855 		        }
856 
857                 case WEAPONSTATE_SWAPPING_IN:
858                 case WEAPONSTATE_SWAPPING_OUT:
859                 {
860                   	if (playerStatusPtr->SwapToWeaponSlot!=WEAPON_FINISHED_SWAPPING)
861                     {
862            		       	PLAYER_WEAPON_DATA *newWeaponPtr;
863            				PLAYER_WEAPON_DATA *nwp,*owp;
864 
865 						nwp=&(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
866 						owp=&(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]);
867 
868 						playerStatusPtr->PreviouslySelectedWeaponSlot = playerStatusPtr->SelectedWeaponSlot;
869                     	playerStatusPtr->SelectedWeaponSlot = playerStatusPtr->SwapToWeaponSlot;
870                     	newWeaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]);
871 
872                     	playerStatusPtr->SwapToWeaponSlot = WEAPON_FINISHED_SWAPPING;
873 
874 						if (SimilarPredWeapons(nwp,owp)	&& (weaponPtr->CurrentState==WEAPONSTATE_SWAPPING_IN)) {
875 
876 							/* Special case. */
877 	                    	newWeaponPtr->CurrentState = WEAPONSTATE_READYING;
878 							newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
879                     		weaponPtr = newWeaponPtr;
880     						twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
881 
882 						} else {
883 
884             		    	newWeaponPtr->CurrentState = WEAPONSTATE_SWAPPING_IN;
885                 			newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
886 
887                     		weaponPtr = newWeaponPtr;
888     						twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
889 
890 							GrabWeaponShape(weaponPtr);
891 
892 							if (!(twPtr->PrimaryIsMeleeWeapon)) {
893 								GrabMuzzleFlashShape(twPtr);
894 							}
895 							PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl;
896 							if (twPtr->HasShapeAnimation) {
897 								PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl;
898 							} else {
899 								PlayersWeapon.ShapeAnimControlBlock=NULL;
900 							}
901 						}
902                     }
903 					else
904                    	{
905                     	weaponPtr->CurrentState = WEAPONSTATE_READYING;
906 						weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
907                     }
908 
909 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
910 
911                 	break;
912                 }
913 
914 		        case WEAPONSTATE_RECOIL_PRIMARY:
915 				{
916 					if (!twPtr->PrimaryIsAutomatic && playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon)
917 					{
918 		        		weaponPtr->CurrentState = WEAPONSTATE_WAITING;
919 					}
920 					else
921 					{
922 		        		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
923 				    	weaponPtr->StateTimeOutCounter=0;
924 					}
925 
926 					playerStatusPtr->Encumberance=twPtr->Encum_FirePrime;
927 
928 					break;
929 				}
930 		        case WEAPONSTATE_RECOIL_SECONDARY:
931 				{
932 					if (!twPtr->SecondaryIsAutomatic && playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon)
933 					{
934 		        		weaponPtr->CurrentState = WEAPONSTATE_WAITING;
935 					}
936 					else
937 					{
938 		        		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
939 				    	weaponPtr->StateTimeOutCounter=0;
940 					}
941 					playerStatusPtr->Encumberance=twPtr->Encum_FireSec;
942 					break;
943 				}
944 
945 
946 				case WEAPONSTATE_WAITING:
947 				{
948 					/* wait for player to take his finger of fire */
949 					if( (!(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon
950 					     ||playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon))
951 					|| (/* Alien Claw! */
952 						(weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW)
953 						&&(twPtr->PrimaryIsAutomatic)
954 						&&(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon)
955 						) )
956 					{
957 		        		weaponPtr->CurrentState = WEAPONSTATE_IDLE;
958 				    	weaponPtr->StateTimeOutCounter=0;
959 					}
960 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
961 					break;
962 				}
963 
964 				case WEAPONSTATE_UNREADYING:
965 		        {
966 					if (SimilarPredWeapons(weaponPtr,&playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot])) {
967 
968            		       	PLAYER_WEAPON_DATA *newWeaponPtr;
969 						/* Special case. */
970 						playerStatusPtr->PreviouslySelectedWeaponSlot = playerStatusPtr->SelectedWeaponSlot;
971                     	playerStatusPtr->SelectedWeaponSlot = playerStatusPtr->SwapToWeaponSlot;
972                     	newWeaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]);
973                     	playerStatusPtr->SwapToWeaponSlot = WEAPON_FINISHED_SWAPPING;
974 
975 						newWeaponPtr->CurrentState = WEAPONSTATE_READYING;
976 						newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
977 
978                     	weaponPtr = newWeaponPtr;
979     					twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
980 						//GrabWeaponShape(weaponPtr);
981 
982 						if (!(twPtr->PrimaryIsMeleeWeapon)) GrabMuzzleFlashShape(twPtr);
983 						PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl;
984 						if (twPtr->HasShapeAnimation) {
985 							PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl;
986 						} else {
987 							PlayersWeapon.ShapeAnimControlBlock=NULL;
988 						}
989 
990 					} else {
991 						/* Change Me! */
992 						weaponPtr->CurrentState = WEAPONSTATE_SWAPPING_OUT;
993 						weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
994 						playerStatusPtr->Encumberance=twPtr->Encum_Idle;
995 					}
996 		        	break;
997 		        }
998 				case WEAPONSTATE_READYING:
999 		        {
1000 					//NewOnScreenMessage("WEAPON READY");
1001 					/* That's TEMPORARY!  For TESTING! */
1002 		        	weaponPtr->CurrentState = WEAPONSTATE_IDLE;
1003 			    	weaponPtr->StateTimeOutCounter=0;
1004 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
1005 		        	break;
1006 		        }
1007 
1008 		        default: /* applicable to many states, eg. WEAPONSTATE_JAMMED */
1009 		        {
1010                 	/* if timed-out return to idle state */
1011 		        	weaponPtr->CurrentState = WEAPONSTATE_IDLE;
1012 			    	weaponPtr->StateTimeOutCounter=0;
1013 					playerStatusPtr->Encumberance=twPtr->Encum_Idle;
1014 		        	break;
1015 		        }
1016 		    }
1017         }
1018 	}
1019     else {
1020        	int timeOutRate = twPtr->TimeOutRateForState[weaponPtr->CurrentState];
1021 
1022 		/* WEAPONSTATE_IDLE counts UP. */
1023 
1024         weaponPtr->StateTimeOutCounter+=MUL_FIXED(timeOutRate,NormalFrameTime);
1025 		textprint("WeaponstateIdle Time Counter = %d\n",weaponPtr->StateTimeOutCounter);
1026 
1027     	//weaponPtr->StateTimeOutCounter=0;
1028 	}
1029 
1030 	switch(weaponPtr->CurrentState)
1031 	{
1032 	    case WEAPONSTATE_JAMMED:
1033         {
1034     		if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon)
1035     		{
1036             	// MakeClickingNoise function goes here!
1037 				PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber);
1038             }
1039     		break;
1040         }
1041         case WEAPONSTATE_IDLE:
1042         {
1043 			WeaponStateIdle(playerStatusPtr,weaponPtr,twPtr,justfiredp,justfireds,ps);
1044 			break;
1045         }
1046 		case WEAPONSTATE_UNREADYING:
1047 		{
1048 			enum WEAPON_SLOT oldSlot=playerStatusPtr->SwapToWeaponSlot;
1049 		   	if(RequestChangeOfWeaponWhilstSwapping(playerStatusPtr,weaponPtr))
1050 			{
1051 				if (playerStatusPtr->SwappingIsDebounced)
1052 				{
1053 					//if (oldSlot==WEAPON_FINISHED_SWAPPING)
1054 					//	weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter;
1055 					//?
1056 
1057 					NewOnScreenMessage
1058 					(
1059 						GetTextString
1060 						(
1061 							TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name
1062 						)
1063 					);
1064 					playerStatusPtr->SwappingIsDebounced = 0;
1065 				}
1066 				else
1067 				{
1068 					playerStatusPtr->SwapToWeaponSlot = oldSlot;
1069 				}
1070 			}
1071 			else playerStatusPtr->SwappingIsDebounced = 1;
1072 			break;
1073 		}
1074 		case WEAPONSTATE_READYING:
1075        	case WEAPONSTATE_SWAPPING_IN:
1076         case WEAPONSTATE_SWAPPING_OUT:
1077 		{
1078 			enum WEAPON_SLOT oldSlot=playerStatusPtr->SwapToWeaponSlot;
1079 
1080 		   	if(RequestChangeOfWeaponWhilstSwapping(playerStatusPtr,weaponPtr))
1081 			{
1082 				if (playerStatusPtr->SwappingIsDebounced)
1083 				{
1084 
1085 					if (weaponPtr->CurrentState==WEAPONSTATE_READYING) {
1086 						/* Back outta here? */
1087 						weaponPtr->CurrentState=WEAPONSTATE_UNREADYING;
1088 						weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter;
1089 						if (twPtr->UseStateMovement==0) {
1090 							/* I guess it's hierarchical... */
1091 							PlayersWeaponHModelController.Reversed=1;
1092 						}
1093 					} else if (SimilarPredWeapons(&playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot],&playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot])) {
1094 
1095 						/* Very special case.. */
1096 
1097 					} else if (oldSlot==WEAPON_FINISHED_SWAPPING) {
1098 						weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter;
1099 						if (twPtr->UseStateMovement==0) {
1100 							/* I guess it's hierarchical... */
1101 							PlayersWeaponHModelController.Reversed=1;
1102 						}
1103 					}
1104 
1105 					NewOnScreenMessage
1106 					(
1107 						GetTextString
1108 						(
1109 							TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name
1110 						)
1111 					);
1112 					playerStatusPtr->SwappingIsDebounced = 0;
1113 				}
1114 				else
1115 				{
1116 					playerStatusPtr->SwapToWeaponSlot = oldSlot;
1117 				}
1118 			}
1119 			else playerStatusPtr->SwappingIsDebounced = 1;
1120 
1121 			break;
1122 		}
1123         default:
1124         {
1125         	break;
1126         }
1127 
1128 	}
1129 	StateDependentMovement(playerStatusPtr,weaponPtr);
1130 	PositionPlayersWeapon();
1131 
1132 }
1133 
WeaponStateIdle(PLAYER_STATUS * playerStatusPtr,PLAYER_WEAPON_DATA * weaponPtr,TEMPLATE_WEAPON_DATA * twPtr,int justfiredp,int justfireds,int ps)1134 static void WeaponStateIdle(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr,TEMPLATE_WEAPON_DATA *twPtr, int justfiredp, int justfireds, int ps)
1135 {
1136 	int CanFirePrimary, CanFireSecondary;
1137 	int WishToFirePrimary,PrimaryFired;
1138 
1139 	CanFirePrimary=1;
1140 	CanFireSecondary=1;
1141 	PrimaryFired=0;
1142 
1143 	if ( (twPtr->FireInChangeVision==0)&&(IsVisionChanging()) ) {
1144 		CanFirePrimary=0;
1145 		CanFireSecondary=0;
1146 	}
1147 
1148 	#if 0
1149 	if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1150 		CanFirePrimary=0;
1151 		CanFireSecondary=0;
1152 	}
1153 	#endif
1154 
1155 	WishToFirePrimary=playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon;
1156 
1157 	if (weaponPtr->WeaponIDNumber == WEAPON_MINIGUN) {
1158 		if ((Weapon_ThisBurst<MINIGUN_MINIMUM_BURST)&&(Weapon_ThisBurst>=0)
1159 			&&(weaponPtr->PrimaryRoundsRemaining)) {
1160 			WishToFirePrimary=1;
1161 			/* Retain CanFirePrimary. */
1162 		}
1163 		if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) {
1164 			CanFirePrimary=0;
1165 			Weapon_ThisBurst = -1;
1166 		}
1167 	} else if (weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE) {
1168 		if ((Weapon_ThisBurst<PULSERIFLE_MINIMUM_BURST)&&(Weapon_ThisBurst>=0)
1169 			&&(weaponPtr->PrimaryRoundsRemaining)) {
1170 			WishToFirePrimary=1;
1171 			/* Retain CanFirePrimary. */
1172 		}
1173 	} else if (weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN) {
1174 		if ((Weapon_ThisBurst<SMARTGUN_MINIMUM_BURST)&&(Weapon_ThisBurst>=0)
1175 			&&(weaponPtr->PrimaryRoundsRemaining)) {
1176 			WishToFirePrimary=1;
1177 			/* Retain CanFirePrimary. */
1178 		}
1179 	}
1180 
1181 	/* does the player wish to fire primary ammo*/
1182    	if ((WishToFirePrimary)&&(CanFirePrimary)) {
1183     	if (twPtr->PrimaryAmmoID != AMMO_NONE) {
1184        		if (twPtr->PrimaryIsMeleeWeapon) {
1185 
1186 				if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1187 					/* Force Decloak. */
1188 					playerStatusPtr->cloakOn=0;
1189 					Sound_Play(SID_PRED_CLOAKOFF,"h");
1190 					//playerNoise=1;
1191 				}
1192 
1193    	    		weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1194 				if (justfiredp) {
1195 					weaponPtr->StateTimeOutCounter = justfiredp-1;
1196 				} else {
1197 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1198 				}
1199 				/* KJL 11:46:42 03/04/97 - sound effects? */
1200 			} else if ((weaponPtr->PrimaryRoundsRemaining)
1201 				||( (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->SecondaryRoundsRemaining) )) {
1202 
1203        			/* consider probability of jamming */
1204    	  		   	if (twPtr->ProbabilityOfJamming > Random16BitNumber) {
1205 					weaponPtr->CurrentState = WEAPONSTATE_JAMMED;
1206 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1207        		  	} else { /* okay, the weapon is able to fire */
1208 
1209 					if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1210 						/* Force Decloak. */
1211 						playerStatusPtr->cloakOn=0;
1212 						Sound_Play(SID_PRED_CLOAKOFF,"h");
1213 						//playerNoise=1;
1214 					}
1215 
1216 					if (twPtr->FirePrimaryFunction!=NULL) {
1217 						/* FIRE!!! */
1218 						if (twPtr->FirePrimaryLate) {
1219 							if (weaponPtr->WeaponIDNumber == WEAPON_PRED_PISTOL) {
1220 								/* A little hackette, since I'm tired. */
1221 								if (playerStatusPtr->FieldCharge>0) {
1222 									FirePrimaryLate=1;
1223 		        	      			weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1224 									weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1225 								}
1226 							} else {
1227 								FirePrimaryLate=1;
1228 	        	      			weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1229 								weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1230 							}
1231 						} else if ((*twPtr->FirePrimaryFunction)(weaponPtr)) {
1232 							if (twPtr->PrimaryMuzzleFlash) {
1233 								if (twPtr->PrimaryAmmoID==AMMO_PARTICLE_BEAM) {
1234 									AddLightingEffectToObject(Player,LFX_PARTICLECANNON);
1235 								} else {
1236 									AddLightingEffectToObject(Player,LFX_MUZZLEFLASH);
1237 								}
1238 							}
1239         	      			weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1240 							weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1241 						}
1242 					}
1243 					PrimaryFired=1;
1244 				}
1245 			}
1246 			else
1247 			{
1248 				/* KJL 16:07:23 23/11/98 - trying to fire a weapon with no ammo */
1249 				PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber);
1250 				if (weaponPtr->WeaponIDNumber == WEAPON_MINIGUN) {
1251 					FireEmptyMinigun(weaponPtr);
1252 				}
1253         	}
1254 		} else if (twPtr->FirePrimaryFunction!=NULL) {
1255 
1256         	int timeOutRate = twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY];
1257 
1258 			if (timeOutRate!=WEAPONSTATE_INSTANTTIMEOUT) {
1259 				if ((*twPtr->FirePrimaryFunction)(weaponPtr)) {
1260 	        		weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1261 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1262 				}
1263 			} else {
1264 				/* Do something special anyway... */
1265 				(*twPtr->FirePrimaryFunction)(weaponPtr);
1266         		weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
1267 				weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1268 			}
1269 		}
1270     } else if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon)&&(CanFireSecondary)) {
1271 		/* or the secondary ammo */
1272     	if (twPtr->SecondaryAmmoID != AMMO_NONE) {
1273            	if (twPtr->SecondaryIsMeleeWeapon) {
1274 				if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1275 					/* Force Decloak. */
1276 					playerStatusPtr->cloakOn=0;
1277 					Sound_Play(SID_PRED_CLOAKOFF,"h");
1278 					//playerNoise=1;
1279 				}
1280        	    	weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
1281 				if (justfireds) {
1282 					weaponPtr->StateTimeOutCounter = justfireds-1;
1283 				} else {
1284 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1285 				}
1286 				/* KJL 11:46:42 03/04/97 - sound effects? */
1287 			} else if ( (weaponPtr->SecondaryRoundsRemaining)
1288 				||( (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)&&(weaponPtr->PrimaryRoundsRemaining) )
1289 				||( (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->PrimaryRoundsRemaining) )) {
1290            		/* consider probability of jamming */
1291        	  	   	if (twPtr->ProbabilityOfJamming > Random16BitNumber) {
1292 					weaponPtr->CurrentState = WEAPONSTATE_JAMMED;
1293 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1294        	  	   	} else {
1295 					/* okay, the weapon is able to fire */
1296 					if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1297 						/* Force Decloak. */
1298 						playerStatusPtr->cloakOn=0;
1299 						Sound_Play(SID_PRED_CLOAKOFF,"h");
1300 						//playerNoise=1;
1301 					}
1302 					if (twPtr->FireSecondaryFunction!=NULL) {
1303 						/* FIRE!!! */
1304 						if (twPtr->FireSecondaryLate) {
1305 							FireSecondaryLate=1;
1306 	              	    	weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
1307 							weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1308 						} else if ((*twPtr->FireSecondaryFunction)(weaponPtr)) {
1309 							if (twPtr->SecondaryMuzzleFlash) {
1310 								AddLightingEffectToObject(Player,LFX_MUZZLEFLASH);
1311 		              	    	weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
1312 								weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1313 							}
1314 						}
1315 					}
1316 				}
1317 			} else {
1318             	// MakeClickingNoise function goes here!
1319 				PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber);
1320             }
1321 		} else if (twPtr->FireSecondaryFunction!=NULL) {
1322 
1323         	int timeOutRate = twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_SECONDARY];
1324 
1325 			if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
1326 				/* Force Decloak. */
1327 				playerStatusPtr->cloakOn=0;
1328 				Sound_Play(SID_PRED_CLOAKOFF,"h");
1329 				//playerNoise=1;
1330 			}
1331 
1332 			if (timeOutRate!=WEAPONSTATE_INSTANTTIMEOUT) {
1333 				if ((*twPtr->FireSecondaryFunction)(weaponPtr)) {
1334 	        		weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
1335 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1336 				}
1337 			} else {
1338 				/* Do something special anyway... */
1339 				(*twPtr->FireSecondaryFunction)(weaponPtr);
1340         		weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
1341 				weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1342 			}
1343 		}
1344     } else if (ps) {
1345 		/* Not firing now, for some reason.  But you were. *
1346 		 * Not only that, but your're also rapid fire.     *
1347 		 * For example, Doom Plasma Gun has rapid fire and *
1348 		 * recoil: also anything that 'charges', like tail.*/
1349 		if (ps==1) {
1350 			if (twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]!=WEAPONSTATE_INSTANTTIMEOUT) {
1351 				/* there is a 'recovery' time after shooting */
1352 				weaponPtr->CurrentState = WEAPONSTATE_RECOIL_PRIMARY;
1353 				weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1354 			}
1355 		} else {
1356 			if (twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_SECONDARY]!=WEAPONSTATE_INSTANTTIMEOUT) {
1357 				/* there is a 'recovery' time after shooting */
1358 				weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY;
1359 				weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1360 			}
1361 		}
1362     } else if ((RequestChangeOfWeapon(playerStatusPtr,weaponPtr))
1363     	||((playerStatusPtr->SelectedWeaponSlot!=playerStatusPtr->SwapToWeaponSlot)
1364     		&&(playerStatusPtr->SwapToWeaponSlot!=WEAPON_FINISHED_SWAPPING))) {
1365 		weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1366 	    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1367 		NewOnScreenMessage
1368 		(
1369 			GetTextString
1370 			(
1371 				TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name
1372 			)
1373 		);
1374 	} else if (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining!=0)	{
1375     	/* if you've ran out of ammo, but you've got some magazines, reload. */
1376     	if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
1377 			/* Two pistols ammo handling! */
1378 			if (weaponPtr->SecondaryRoundsRemaining==0) {
1379 				if (weaponPtr->SecondaryMagazinesRemaining!=0) {
1380 			       	weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY;
1381 			   		weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1382 				} else {
1383 					/* Change to one pistol if you can! */
1384 					int pistol_slot;
1385 
1386 					pistol_slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL);
1387 					if (pistol_slot!=-1) {
1388 						playerStatusPtr->SwapToWeaponSlot = pistol_slot;
1389 						weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1390 						weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1391 					} else {
1392 						/* Utterly fubared. */
1393 						weaponPtr->SecondaryMagazinesRemaining=0;
1394 						return;
1395 					}
1396 				}
1397 			}
1398 	    } else {
1399 	       	weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY;
1400 	   		weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1401 		}
1402 	#if 0
1403 	} else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)
1404 		&& (AvP.PlayerType==I_Marine)
1405 		&& (weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER)
1406 		&& (
1407 				(GrenadeLauncherData.ProximityRoundsRemaining!=0)
1408 			  	||(GrenadeLauncherData.FragmentationRoundsRemaining!=0)
1409 			 	||(GrenadeLauncherData.StandardRoundsRemaining!=0)
1410 				||(GrenadeLauncherData.ProximityMagazinesRemaining!=0)
1411 			  	||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0)
1412 			 	||(GrenadeLauncherData.StandardMagazinesRemaining!=0)
1413 			)
1414 		) {
1415 		/* Deal with Al's 'grenade launcher change ammo' case... */
1416 		GrenadeLauncher_EmergencyChangeAmmo(weaponPtr);
1417 	} else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)
1418 		&& (AvP.PlayerType==I_Marine)
1419 		&& ( (weaponPtr->WeaponIDNumber!=WEAPON_GRENADELAUNCHER)
1420 			|| (
1421 				(GrenadeLauncherData.ProximityRoundsRemaining==0)
1422 			  	&&(GrenadeLauncherData.FragmentationRoundsRemaining==0)
1423 			 	&&(GrenadeLauncherData.StandardRoundsRemaining==0)
1424 				&&(GrenadeLauncherData.ProximityMagazinesRemaining==0)
1425 			  	&&(GrenadeLauncherData.FragmentationMagazinesRemaining==0)
1426 			 	&&(GrenadeLauncherData.StandardMagazinesRemaining==0)
1427 			))
1428 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PULSERIFLE)
1429 		&& (weaponPtr->WeaponIDNumber!=WEAPON_CUDGEL)
1430 		) {
1431 		/* Auto change to pulserifle. */
1432 		int slot;
1433 
1434 		/*Don't swap weapons if the marine is a specialist marine*/
1435 		if(AvP.Network == I_No_Network || netGameData.myCharacterSubType==NGSCT_General)
1436 		{
1437 			slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1438 			if (slot==-1) {
1439 				/* Argh! Whadda ya mean, you've got no pulse rifle? */
1440 			} else {
1441 	    		playerStatusPtr->SwapToWeaponSlot = slot;
1442 				weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1443 			    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1444 			}
1445 		}
1446 	} else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)
1447 		&& (AvP.PlayerType==I_Marine)
1448 		&& (weaponPtr->WeaponIDNumber==WEAPON_PULSERIFLE)
1449 		&& (weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining==0)
1450 		) {
1451 		/* If you _are_ the pulserifle, and you have no rounds left, try to get the cudgel. */
1452 		if(AvP.Network == I_No_Network || netGameData.myCharacterSubType==NGSCT_General)
1453 		{
1454 			int slot;
1455 			/* Might want to check for any other weapons with ammo here? */
1456 			slot=SlotForThisWeapon(WEAPON_CUDGEL);
1457 			if (slot!=-1) {
1458 	    		playerStatusPtr->SwapToWeaponSlot = slot;
1459 				weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1460 			    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1461 			}
1462 		}
1463 	} else if ((AvP.PlayerType==I_Marine)
1464 		&& (weaponPtr->WeaponIDNumber==WEAPON_CUDGEL)
1465 		) {
1466 		/* If cudgel is selected, and the pulserifle has ammo, change to _it_. */
1467 		int pulserifle_slot;
1468 
1469 		pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1470 		if (pulserifle_slot!=-1) {
1471 			if (WeaponHasAmmo(pulserifle_slot)) {
1472 	    		playerStatusPtr->SwapToWeaponSlot = pulserifle_slot;
1473 				weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1474 			    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1475 			}
1476 		}
1477 	#else
1478 	} else if ((AvP.PlayerType==I_Marine)
1479 		&&(Marine_WantToChangeWeapon(weaponPtr))) {
1480 		MarineZeroAmmoFunctionality(playerStatusPtr,weaponPtr);
1481 	#endif
1482 
1483 	#if 0
1484 	} else if ((
1485 		(weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)
1486 		&& (AvP.PlayerType==I_Predator)
1487 		#if 0
1488 		/* Why is this line here? */
1489 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_RIFLE)
1490 		/* I find this VERY scary.  The Phantom Code Changer is at work. */
1491 		#endif
1492 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_WRISTBLADE)
1493 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_STAFF)
1494 		&& (weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP)
1495 		)||(
1496 		(AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON)
1497 		&&(playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart)
1498 		&&(playerStatusPtr->FieldCharge<MUL_FIXED((Caster_Jumpstart-playerStatusPtr->PlasmaCasterCharge),Caster_ChargeRatio))
1499 		)||(
1500 		(AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL)
1501 		&&(playerStatusPtr->FieldCharge<PredPistol_ShotCost)
1502 		)) {
1503 		/* Auto change to wristblade. */
1504 		int slot;
1505 
1506 		slot=SlotForThisWeapon(WEAPON_PRED_WRISTBLADE);
1507 		if (slot==-1) {
1508 			/* Argh! Whadda ya mean, you've got no wristblade? */
1509 			GLOBALASSERT(0);
1510 		} else {
1511 	    	playerStatusPtr->SwapToWeaponSlot = slot;
1512 			weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1513 		    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1514 		}
1515 	#else
1516 	} else if ((AvP.PlayerType==I_Predator)
1517 		&& (Predator_WantToChangeWeapon(playerStatusPtr,weaponPtr))) {
1518 		PredatorZeroAmmoFunctionality(playerStatusPtr,weaponPtr);
1519 	#endif
1520     } else if (twPtr->SecondaryAmmoID != AMMO_NONE) {
1521     	/* if you've ran out of ammo, but you've got some magazines, reload. */
1522 		if (weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining!=0) {
1523 	    	if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
1524 				/* Two pistols ammo handling! */
1525 				if (weaponPtr->PrimaryRoundsRemaining==0) {
1526 					if (weaponPtr->PrimaryMagazinesRemaining!=0) {
1527 				       	weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY;
1528 				   		weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1529 					} else {
1530 						/* Change to one pistol if you can! */
1531 						int pistol_slot;
1532 
1533 						pistol_slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL);
1534 						if (pistol_slot!=-1) {
1535 							playerStatusPtr->SwapToWeaponSlot = pistol_slot;
1536 							weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
1537 							weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1538 						} else {
1539 							/* Utterly fubared. */
1540 							weaponPtr->PrimaryMagazinesRemaining=0;
1541 							return;
1542 						}
1543 					}
1544 				}
1545 		    } else {
1546 	          	weaponPtr->CurrentState = WEAPONSTATE_RELOAD_SECONDARY;
1547 		   		weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
1548 			}
1549     	}
1550 	} else if ((AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_DISC)) {
1551 		SECTION_DATA *disc_section;
1552 
1553 		/* You should have a disc. */
1554 		disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk");
1555 		GLOBALASSERT(disc_section);
1556 		/* Force Appear Disc. */
1557 		disc_section->flags&=~section_data_notreal;
1558 
1559 	} else {
1560 		/* Wow, genuinely idle! */
1561 	}
1562 
1563 	if ((weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE)
1564 		||(weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN)) {
1565 		if (!PrimaryFired) {
1566 			/* Maybe Reset? */
1567 			Weapon_ThisBurst=-1;
1568 		}
1569 	}
1570 }
1571 
RequestChangeOfWeapon(PLAYER_STATUS * playerStatusPtr,PLAYER_WEAPON_DATA * weaponPtr)1572 static int RequestChangeOfWeapon(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr)
1573 {
1574 	playerStatusPtr->SwappingIsDebounced = 0;
1575 
1576 	if (playerStatusPtr->MyFaceHugger) {
1577 		return(0);
1578 	}
1579 
1580     /* else if you wish to change to the previous weapon */
1581     if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon)
1582    	{
1583     	enum WEAPON_SLOT newSlot = playerStatusPtr->SelectedWeaponSlot;
1584 		int slotValidity;
1585 
1586 		slotValidity=0;
1587 
1588         do {
1589 	   		if(newSlot-- == WEAPON_SLOT_1) {
1590      			newSlot=MAX_NO_OF_WEAPON_SLOTS-1;
1591 			}
1592 
1593 			if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) {
1594 				slotValidity=1;
1595 			}
1596 			/* But not if you're a disk launcher with no disks. */
1597 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1598 				if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0
1599 					&& playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) {
1600 					slotValidity=0;
1601 				}
1602 			}
1603 			/* And not if you're the cudgel. */
1604 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1605 				if (playerStatusPtr->SelectedWeaponSlot!=newSlot) {
1606 					slotValidity=0;
1607 				}
1608 			}
1609 			/* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */
1610 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1611 				if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1612 					if (!WeaponHasAmmo(newSlot)) {
1613 						slotValidity=0;
1614 					}
1615 				}
1616 			} else {
1617 				/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
1618 				int pulserifle_slot;
1619 				int cudgel_slot;
1620 
1621 				cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
1622 
1623 				if (cudgel_slot!=-1) {
1624 					if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) {
1625 						cudgel_slot=-1;
1626 					}
1627 				}
1628 
1629 				if (cudgel_slot!=-1) {
1630 					pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1631 
1632 					if (pulserifle_slot!=-1) {
1633 						if (!WeaponHasAmmo(pulserifle_slot)) {
1634 							newSlot=cudgel_slot;
1635 							slotValidity=1;
1636 						}
1637 					}
1638 				}
1639 			}
1640             // Disallow Gold version weapons with regular version
1641 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1642 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1643 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1644                 slotValidity=0;
1645             }
1646 		} while(slotValidity==0);
1647 
1648 		if(newSlot != playerStatusPtr->SelectedWeaponSlot)
1649 		{
1650 		    playerStatusPtr->SwapToWeaponSlot = newSlot;
1651 		  	return 1;
1652 		}
1653     }
1654     /* else if you wish to change to the next weapon */
1655     else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon)
1656     {
1657 		enum WEAPON_SLOT newSlot = playerStatusPtr->SelectedWeaponSlot;
1658 		int slotValidity;
1659 
1660 		slotValidity=0;
1661 
1662         do {
1663 	   		if(++newSlot == MAX_NO_OF_WEAPON_SLOTS) {
1664      			newSlot=WEAPON_SLOT_1;
1665 			}
1666 			if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) {
1667 				slotValidity=1;
1668 			}
1669 			/* But not if you're a disk launcher with no disks. */
1670 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1671 				if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0
1672 					&& playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) {
1673 					slotValidity=0;
1674 				}
1675 			}
1676 			/* And not if you're the cudgel. */
1677 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1678 				if (playerStatusPtr->SelectedWeaponSlot!=newSlot) {
1679 					slotValidity=0;
1680 				}
1681 			}
1682 			/* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */
1683 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1684 				if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1685 					if (!WeaponHasAmmo(newSlot)) {
1686 						slotValidity=0;
1687 					}
1688 				}
1689 			} else {
1690 				/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
1691 				int pulserifle_slot;
1692 				int cudgel_slot;
1693 
1694 				cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
1695 
1696 				if (cudgel_slot!=-1) {
1697 					if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) {
1698 						cudgel_slot=-1;
1699 					}
1700 				}
1701 
1702 				if (cudgel_slot!=-1) {
1703 					pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1704 
1705 					if (pulserifle_slot!=-1) {
1706 						if (!WeaponHasAmmo(pulserifle_slot)) {
1707 							newSlot=cudgel_slot;
1708 							slotValidity=1;
1709 						}
1710 					}
1711 				}
1712 			}
1713             // Disallow Gold version weapons with regular version
1714 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1715 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1716 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1717                 slotValidity=0;
1718             }
1719 		} while(slotValidity==0);
1720 
1721 		if(newSlot != playerStatusPtr->SelectedWeaponSlot)
1722 		{
1723 		    playerStatusPtr->SwapToWeaponSlot = newSlot;
1724 		  	return 1;
1725 		}
1726     }
1727 	/* else pick a weapon, any weapon */
1728 	else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo)
1729     {
1730         enum WEAPON_SLOT requestedSlot = (enum WEAPON_SLOT)(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo - 1);
1731 
1732         LOCALASSERT(requestedSlot < MAX_NO_OF_WEAPON_SLOTS);
1733         LOCALASSERT(requestedSlot >= 0);
1734 
1735         if( (requestedSlot != playerStatusPtr->SelectedWeaponSlot)
1736           &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == 1) )
1737         {
1738             // Disallow Gold version weapons with regular version
1739 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1740 			   (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1741 			   (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1742                 return 0;
1743             }
1744 			if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1745 				if (playerStatusPtr->WeaponSlot[requestedSlot].PrimaryRoundsRemaining==0
1746 					&& playerStatusPtr->WeaponSlot[requestedSlot].PrimaryMagazinesRemaining==0) {
1747 					#if 0
1748 					sprintf(tempstring,"NO AMMO FOR %s\n",GetTextString(
1749 						TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name)
1750 					);
1751 					NewOnScreenMessage(tempstring);
1752 					#else
1753 					//NewOnScreenMessage(GetTextString(TEXTSTRING_NOAMMOFORWEAPON));
1754 					#endif
1755 					return 0;
1756 				}
1757 			}
1758 			/* Look, I said you can't select the cudgel! */
1759 			if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1760 				return 0;
1761 			}
1762 	    	/* Of course, if you are the cudgel and the the pulserifle has no ammo... */
1763 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1764 				if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1765 					if (!WeaponHasAmmo(requestedSlot)) {
1766 						return(0);
1767 					}
1768 				}
1769 			} else {
1770 				if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1771 					/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
1772 					int pulserifle_slot;
1773 					int cudgel_slot;
1774 
1775 					cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
1776 					if (cudgel_slot!=-1) {
1777 						pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1778 
1779 						if (pulserifle_slot!=-1) {
1780 							if (!WeaponHasAmmo(pulserifle_slot)) {
1781 								requestedSlot=cudgel_slot;
1782 							}
1783 						}
1784 					}
1785 				}
1786 			}
1787 
1788 	    	playerStatusPtr->SwapToWeaponSlot = requestedSlot;
1789 		  	return 1;
1790     	} else if( (requestedSlot != playerStatusPtr->SelectedWeaponSlot)
1791           &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == -1) )
1792 		{
1793 			#if 0
1794 			sprintf(tempstring,"%s NOT AVAILABLE IN DEMO\n",GetTextString(
1795 				TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name)
1796 			);
1797 			NewOnScreenMessage(tempstring);
1798 			#endif
1799 		}
1800     }
1801 
1802    	return 0;
1803 }
RequestChangeOfWeaponWhilstSwapping(PLAYER_STATUS * playerStatusPtr,PLAYER_WEAPON_DATA * weaponPtr)1804 static int RequestChangeOfWeaponWhilstSwapping(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr)
1805 {
1806     enum WEAPON_SLOT currentSlot;
1807 
1808 	if (playerStatusPtr->MyFaceHugger) {
1809 		return(0);
1810 	}
1811 
1812 	if (playerStatusPtr->SwapToWeaponSlot == WEAPON_FINISHED_SWAPPING)
1813 	{
1814 		currentSlot = playerStatusPtr->SelectedWeaponSlot;
1815 	}
1816 	else
1817 	{
1818 		currentSlot = playerStatusPtr->SwapToWeaponSlot;
1819 	}
1820 
1821 
1822     /* else if you wish to change to the previous weapon */
1823     if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon)
1824    	{
1825     	enum WEAPON_SLOT newSlot = currentSlot;
1826        	int slotValidity=0;
1827 
1828         do
1829 		{
1830 	   		if(newSlot-- == WEAPON_SLOT_1) {
1831      			newSlot=MAX_NO_OF_WEAPON_SLOTS-1;
1832 			}
1833 			if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) {
1834 				slotValidity=1;
1835 			}
1836 			/* But not if you're a disk launcher with no disks. */
1837 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1838 				if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0
1839 					&& playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) {
1840 					slotValidity=0;
1841 				}
1842 			}
1843 			/* And not if you're the cudgel. */
1844 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1845 				if (playerStatusPtr->SelectedWeaponSlot!=newSlot) {
1846 					slotValidity=0;
1847 				}
1848 			}
1849 			/* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */
1850 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1851 				if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1852 					if (!WeaponHasAmmo(newSlot)) {
1853 						slotValidity=0;
1854 					}
1855 				}
1856 			} else {
1857 				/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
1858 				int pulserifle_slot;
1859 				int cudgel_slot;
1860 
1861 				cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
1862 
1863 				if (cudgel_slot!=-1) {
1864 					if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) {
1865 						cudgel_slot=-1;
1866 					}
1867 				}
1868 
1869 				if (cudgel_slot!=-1) {
1870 					pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1871 
1872 					if (pulserifle_slot!=-1) {
1873 						if (!WeaponHasAmmo(pulserifle_slot)) {
1874 							newSlot=cudgel_slot;
1875 							slotValidity=1;
1876 						}
1877 					}
1878 				}
1879 			}
1880             // Disallow Gold version weapons with regular version
1881 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1882 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1883 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1884                 slotValidity=0;
1885             }
1886 		}
1887 		while(slotValidity==0);
1888 
1889 		playerStatusPtr->SwapToWeaponSlot = newSlot;
1890 		return 1;
1891 	}
1892     /* else if you wish to change to the next weapon */
1893     else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon)
1894     {
1895 		enum WEAPON_SLOT newSlot = currentSlot;
1896 		int slotValidity=0;
1897 
1898         do
1899 		{
1900 	   		if(++newSlot == MAX_NO_OF_WEAPON_SLOTS) {
1901      			newSlot=WEAPON_SLOT_1;
1902 			}
1903 			if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) {
1904 				slotValidity=1;
1905 			}
1906 			/* But not if you're a disk launcher with no disks. */
1907 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1908 				if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0
1909 					&& playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) {
1910 					slotValidity=0;
1911 				}
1912 			}
1913 			/* And not if you're the cudgel. */
1914 			if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1915 				if (playerStatusPtr->SelectedWeaponSlot!=newSlot) {
1916 					slotValidity=0;
1917 				}
1918 			}
1919 			/* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */
1920 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1921 				if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
1922 					if (!WeaponHasAmmo(newSlot)) {
1923 						slotValidity=0;
1924 					}
1925 				}
1926 			} else {
1927 				/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
1928 				int pulserifle_slot;
1929 				int cudgel_slot;
1930 
1931 				cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
1932 
1933 				if (cudgel_slot!=-1) {
1934 					if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) {
1935 						cudgel_slot=-1;
1936 					}
1937 				}
1938 
1939 				if (cudgel_slot!=-1) {
1940 					pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1941 
1942 					if (pulserifle_slot!=-1) {
1943 						if (!WeaponHasAmmo(pulserifle_slot)) {
1944 							newSlot=cudgel_slot;
1945 							slotValidity=1;
1946 						}
1947 					}
1948 				}
1949 			}
1950             // Disallow Gold version weapons with regular version
1951 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1952 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1953 			   (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1954                 slotValidity=0;
1955             }
1956 		}
1957 		while(slotValidity==0);
1958 
1959 	    playerStatusPtr->SwapToWeaponSlot = newSlot;
1960 		return 1;
1961     }
1962 	/* else pick a weapon, any weapon */
1963 	else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo)
1964     {
1965         enum WEAPON_SLOT requestedSlot = (enum WEAPON_SLOT)(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo - 1);
1966 
1967         LOCALASSERT(requestedSlot < MAX_NO_OF_WEAPON_SLOTS);
1968         LOCALASSERT(requestedSlot >= 0);
1969 
1970         if( (requestedSlot != currentSlot)
1971           &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == 1) )
1972         {
1973             // Disallow Gold version weapons with regular version
1974 			if (!AllowGoldWeapons && ((playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) ||
1975 			   (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) ||
1976 			   (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS))) {
1977                 return 0;
1978             }
1979 			if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PRED_DISC) {
1980 				if (playerStatusPtr->WeaponSlot[requestedSlot].PrimaryRoundsRemaining==0
1981 					&& playerStatusPtr->WeaponSlot[requestedSlot].PrimaryMagazinesRemaining==0) {
1982 					#if 0
1983 					sprintf(tempstring,"NO AMMO FOR %s\n",GetTextString(
1984 						TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name)
1985 					);
1986 					NewOnScreenMessage(tempstring);
1987 					#else
1988 					//NewOnScreenMessage(GetTextString(TEXTSTRING_NOAMMOFORWEAPON));
1989 					#endif
1990 					return 0;
1991 				}
1992 			}
1993 			/* Look, I said you can't select the cudgel! */
1994 			if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1995 				return 0;
1996 			}
1997 	    	/* Of course, if you are the cudgel and the the pulserifle has no ammo... */
1998 			if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) {
1999 				if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
2000 					if (!WeaponHasAmmo(requestedSlot)) {
2001 						return(0);
2002 					}
2003 				}
2004 			} else {
2005 				if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) {
2006 					/* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */
2007 					int pulserifle_slot;
2008 					int cudgel_slot;
2009 
2010 					cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL);
2011 					if (cudgel_slot!=-1) {
2012 						pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
2013 
2014 						if (pulserifle_slot!=-1) {
2015 							if (!WeaponHasAmmo(pulserifle_slot)) {
2016 								requestedSlot=cudgel_slot;
2017 							}
2018 						}
2019 					}
2020 				}
2021 			}
2022 
2023 	    	playerStatusPtr->SwapToWeaponSlot = requestedSlot;
2024 			return 1;
2025     	} else if( (requestedSlot != currentSlot)
2026           &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == -1) )
2027         {
2028 			#if 0
2029 			sprintf(tempstring,"%s NOT AVAILABLE IN DEMO\n",GetTextString(
2030 				TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name)
2031 			);
2032 			NewOnScreenMessage(tempstring);
2033 			#endif
2034 		}
2035     }
2036 
2037    	return 0;
2038 }
2039 
2040 /*KJL********************************************************************************************
2041 * Function to handle weapons whose firing rates are >= the frame rate, and therefore need to be *
2042 * handled in a FRI manner.                                                                      *
2043 ********************************************************************************************KJL*/
FireBurstWeapon(PLAYER_WEAPON_DATA * weaponPtr)2044 int FireBurstWeapon(PLAYER_WEAPON_DATA *weaponPtr) {
2045 
2046 	if (Weapon_ThisBurst==-1) {
2047 		Weapon_ThisBurst=0;
2048 	}
2049 
2050 	Weapon_ThisBurst+=FireAutomaticWeapon(weaponPtr);
2051 
2052 	return(1);
2053 }
2054 
FireAutomaticWeapon(PLAYER_WEAPON_DATA * weaponPtr)2055 int FireAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr)
2056 {
2057 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
2058   	TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
2059    	int oldAmmoCount;
2060 
2061     {
2062     	oldAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16;
2063 		/* ammo is in 16.16. we want the integer part, rounded up */
2064 		if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) oldAmmoCount+=1;
2065 	}
2066 
2067 
2068    	{
2069    	   	/* theoretical number of bullets fired each frame, as a 16.16 number */
2070    	   	int bulletsToFire=MUL_FIXED(twPtr->FiringRate,NormalFrameTime);
2071 
2072     	if (bulletsToFire<weaponPtr->PrimaryRoundsRemaining)
2073     	{
2074     		weaponPtr->PrimaryRoundsRemaining -= bulletsToFire;
2075        	}
2076         else /* end of magazine */
2077         {
2078            	weaponPtr->PrimaryRoundsRemaining=0;
2079         }
2080     }
2081 
2082     {
2083     	int bulletsFired;
2084     	int newAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16;
2085 			/* ammo is in 16.16. we want the integer part, rounded up */
2086 			if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) newAmmoCount+=1;
2087 
2088         bulletsFired = oldAmmoCount-newAmmoCount;
2089 
2090 	    /* Changed to create projectiles for the flamethrower */
2091 
2092 	    if (templateAmmoPtr->CreatesProjectile)
2093 	    {
2094 	      if (bulletsFired)
2095 	      {
2096 	        ProjectilesFired=bulletsFired;
2097 	        FireProjectileAmmo(twPtr->PrimaryAmmoID);
2098 	      }
2099 	    }
2100 	    else /* instantaneous line of sight */
2101 	    {
2102 	      if (bulletsFired)
2103 			  {
2104 				  PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,bulletsFired);
2105 				CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,bulletsFired);
2106 			  }
2107 	    }
2108 		return(bulletsFired);
2109 	}
2110 }
2111 
FireNonAutomaticWeapon(PLAYER_WEAPON_DATA * weaponPtr)2112 int FireNonAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr)
2113 {
2114 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
2115    	TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
2116   	weaponPtr->PrimaryRoundsRemaining -= 65536;
2117 
2118     /* does ammo create an actual object? */
2119     if (templateAmmoPtr->CreatesProjectile)
2120     {
2121 		FireProjectileAmmo(twPtr->PrimaryAmmoID);
2122 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
2123     }
2124     else /* instantaneous line of sight */
2125     {
2126 		PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,1);
2127 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
2128 	}
2129 	return(1);
2130 }
2131 
FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA * weaponPtr)2132 int FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA *weaponPtr)
2133 {
2134 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
2135    	TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID];
2136   	weaponPtr->SecondaryRoundsRemaining -= 65536;
2137 
2138     /* does ammo create an actual object? */
2139     if (templateAmmoPtr->CreatesProjectile)
2140     {
2141 		FireProjectileAmmo(twPtr->SecondaryAmmoID);
2142 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
2143     }
2144     else /* instantaneous line of sight */
2145     {
2146 		PlayerFireLineOfSightAmmo(twPtr->SecondaryAmmoID,1);
2147 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
2148 	}
2149 	return(1);
2150 }
2151 
2152 
2153 #define WEAPON_RANGE 1000000  /* link this to weapon/ammo type perhaps */
2154 
2155 /* instantaneous line of sight firing */
PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID,int multiple)2156 static void PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID, int multiple)
2157 {
2158 
2159 	if (PlayersTarget.DispPtr)
2160 	{
2161 		if (PlayersTarget.HModelSection!=NULL) {
2162 			textprint("Hitting a hierarchical section.\n");
2163 			GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller);
2164 		}
2165 
2166 		HandleWeaponImpact(&(PlayersTarget.Position),PlayersTarget.DispPtr->ObStrategyBlock,AmmoID,&GunMuzzleDirectionInWS, multiple*ONE_FIXED, PlayersTarget.HModelSection);
2167 
2168 		/* Put in a target filter here? */
2169 		if (AccuracyStats_TargetFilter(PlayersTarget.DispPtr->ObStrategyBlock)) {
2170 			CurrentGameStats_WeaponHit(PlayerStatusPtr->SelectedWeaponSlot,multiple);
2171 		}
2172 	}
2173 
2174 }
2175 
HandleWeaponImpact(VECTORCH * positionPtr,STRATEGYBLOCK * sbPtr,enum AMMO_ID AmmoID,VECTORCH * directionPtr,int multiple,SECTION_DATA * this_section_data)2176 void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data)
2177 {
2178 	VECTORCH incoming,*invec;
2179 
2180 	/* 'multiple' is now in FIXED POINT!  */
2181 
2182 	#if 0
2183 	if ((GRENADE_MODE)&&(positionPtr)) {
2184 		switch (AmmoID) {
2185 			case AMMO_10MM_CULW:
2186 			case AMMO_SMARTGUN:
2187 			case AMMO_MINIGUN:
2188 				{
2189 					HandleEffectsOfExplosion
2190 					(
2191 						sbPtr,
2192 						positionPtr,
2193 						TemplateAmmo[AMMO_PULSE_GRENADE].MaxRange,
2194 						&TemplateAmmo[AMMO_PULSE_GRENADE].MaxDamage[AvP.Difficulty],
2195 						TemplateAmmo[AMMO_PULSE_GRENADE].ExplosionIsFlat
2196 					);
2197 					{
2198 						Explosion_SoundData.position=*positionPtr;
2199 					    Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
2200 			    	}
2201 				}
2202 				break;
2203 			default:
2204 				break;
2205 		}
2206 	}
2207 	#endif
2208 
2209 	if(sbPtr)
2210 	{
2211 		if (sbPtr->DynPtr) {
2212 			MATRIXCH WtoLMat;
2213 			/* Consider incoming hit direction. */
2214 			WtoLMat=sbPtr->DynPtr->OrientMat;
2215 			TransposeMatrixCH(&WtoLMat);
2216 			RotateAndCopyVector(directionPtr,&incoming,&WtoLMat);
2217 			invec=&incoming;
2218 		} else {
2219 			invec=NULL;
2220 		}
2221 
2222 		if (this_section_data)
2223 		{
2224 			if (sbPtr->SBdptr)
2225 			{
2226 				//if (sbPtr->SBdptr->HModelControlBlock && (sbPtr->I_SBtype != I_BehaviourNetGhost))
2227 				if (sbPtr->SBdptr->HModelControlBlock)
2228 				{
2229 					/* Netghost case now handled properly. */
2230 					AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point,this_section_data);
2231 
2232 					GLOBALASSERT(sbPtr->SBdptr->HModelControlBlock==this_section_data->my_controller);
2233 					CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple, this_section_data,invec,positionPtr,0);
2234 					/* No longer return: do knockback. */
2235 					//return;
2236 				}
2237 				else
2238 				{
2239 		  			CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec);
2240 				}
2241 			}
2242 			else
2243 			{
2244 		  		CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec);
2245 			}
2246 		}
2247 		else
2248 		{
2249 		  	CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec);
2250 		}
2251 
2252 		if (sbPtr->DynPtr)
2253 		{
2254 			DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2255 			EULER rotation;
2256 			#if 0
2257 			int magnitudeOfForce = (5000*TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty].Impact) / dynPtr->Mass;
2258 			#else
2259 			int magnitudeOfForce = (5000*TotalKineticDamage(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty])) / dynPtr->Mass;
2260 			#endif
2261 			/* okay, not too sure yet what this should do */
2262 	  	  	dynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx,magnitudeOfForce);
2263 			dynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy,magnitudeOfForce);
2264 	  	  	dynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz,magnitudeOfForce);
2265 
2266 		  //CalculateTorque(&rotation, directionPtr, sbPtr);
2267 			CalculateTorqueAtPoint(&rotation,positionPtr,sbPtr);
2268 			/* okay, not too sure yet what this should do */
2269 		    // magnitudeOfForce /= 100;
2270 
2271 	  		dynPtr->AngImpulse.EulerX += MUL_FIXED(rotation.EulerX,magnitudeOfForce);
2272 	  		dynPtr->AngImpulse.EulerY += MUL_FIXED(rotation.EulerY,magnitudeOfForce);
2273 	  		dynPtr->AngImpulse.EulerZ += MUL_FIXED(rotation.EulerZ,magnitudeOfForce);
2274 
2275 		}
2276 
2277 
2278 	}
2279 
2280 	/* KJL 10:44:49 02/03/98 - add bullet hole to world */
2281 	if (LOS_ObjectHitPtr) {
2282 		/* only add to the landscape, ie. modules */
2283 		if (LOS_ObjectHitPtr->ObMyModule)
2284 		{
2285 			/* bad idea to put bullethole on a morphing object */
2286 			if(!LOS_ObjectHitPtr->ObMorphCtrl)
2287 			{
2288 				MakeDecal
2289 				(
2290 					DECAL_BULLETHOLE,
2291 					&LOS_ObjectNormal,
2292 					positionPtr,
2293 					LOS_ObjectHitPtr->ObMyModule->m_index
2294 				);
2295 			}
2296 			/* cause a ricochet 1 in 8 times */
2297 			if (((FastRandom()&65535) < 8192)&&(AmmoID!=AMMO_XENOBORG))
2298 			{
2299 				MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr);
2300 			}
2301 		}
2302 
2303 		/*also do ricochets on the queen*/
2304 		if(sbPtr && sbPtr->I_SBtype==I_BehaviourQueenAlien)
2305 		{
2306 			/* cause a ricochet 1 in 8 times */
2307 			if (((FastRandom()&65535) < 8192)&&(AmmoID!=AMMO_XENOBORG))
2308 			{
2309 				MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr);
2310 			}
2311 		}
2312 	}
2313 
2314 
2315 
2316 	#if 0
2317 	switch (AmmoID)
2318 	{
2319 		case AMMO_PLASMA:
2320 		{
2321 			DISPLAYBLOCK *dispPtr = MakeDebris(I_BehaviourPlasmaImpact,positionPtr);
2322 			if (dispPtr)
2323 			{
2324  				if(AvP.Network!=I_No_Network)
2325   					AddNetMsg_LocalRicochet(I_BehaviourPlasmaImpact,positionPtr,&LOS_ObjectNormal);
2326 
2327 				MakeMatrixFromDirection(&LOS_ObjectNormal,&dispPtr->ObMat);
2328 			}
2329 			break;
2330 		}
2331 		case AMMO_PARTICLE_BEAM:
2332 		{
2333 			{
2334 				VECTORCH velocity={0,0,0};
2335 				MakeParticle(positionPtr,&(velocity),PARTICLE_BLACKSMOKE);
2336 			}
2337 			break;
2338 		}
2339 		default:
2340 		{
2341 			DISPLAYBLOCK *dispPtr = MakeDebris(I_BehaviourBulletRicochet,positionPtr);
2342 			if (dispPtr)
2343 			{
2344  				if(AvP.Network!=I_No_Network)
2345  					AddNetMsg_LocalRicochet(I_BehaviourBulletRicochet,positionPtr,&LOS_ObjectNormal);
2346 
2347 				MakeMatrixFromDirection(&LOS_ObjectNormal,&dispPtr->ObMat);
2348 			}
2349 			break;
2350 		}
2351 	}
2352 	#endif
2353 
2354 
2355 }
2356 
TotalKineticDamage(DAMAGE_PROFILE * damage)2357 int TotalKineticDamage(DAMAGE_PROFILE *damage) {
2358 
2359 	int tkd;
2360 
2361 
2362 	tkd=(damage->Impact+damage->Penetrative+damage->Cutting);
2363 
2364 
2365 	return(tkd);
2366 }
2367 
GetDirectionOfAttack(STRATEGYBLOCK * sbPtr,VECTORCH * WorldVector,VECTORCH * Output)2368 void GetDirectionOfAttack(STRATEGYBLOCK *sbPtr,VECTORCH *WorldVector,VECTORCH *Output) {
2369 
2370 	MATRIXCH WtoLMat;
2371 
2372 	GLOBALASSERT(sbPtr);
2373 
2374 	if (sbPtr->DynPtr==NULL) {
2375 		/* Handle as best we can. */
2376 		Output->vx=0;
2377 		Output->vy=0;
2378 		Output->vz=0;
2379 		return;
2380 	}
2381 
2382 	/* Consider incoming hit direction. */
2383 	WtoLMat=sbPtr->DynPtr->OrientMat;
2384 	TransposeMatrixCH(&WtoLMat);
2385 	RotateAndCopyVector(WorldVector,Output,&WtoLMat);
2386 	Normalise(Output);
2387 
2388 }
2389 
CauseDamageToObject(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,VECTORCH * incoming)2390 void CauseDamageToObject(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming)
2391 {
2392 	int use_multiple;
2393 
2394 	GLOBALASSERT(sbPtr);
2395 	GLOBALASSERT(damage);
2396 
2397 	use_multiple=multiple;
2398 
2399 	if (sbPtr->I_SBtype==I_BehaviourNetGhost) {
2400 		DamageNetworkGhost(sbPtr, damage, use_multiple,NULL,incoming);
2401 		return;
2402 	}
2403 
2404 	if (sbPtr->I_SBtype==I_BehaviourDummy) {
2405 		/* Dummys are INDESTRUCTIBLE. */
2406 		return;
2407 	}
2408 
2409 	if (sbPtr->I_SBtype==I_BehaviourPredator) {
2410 		if (damage->Id==AMMO_PRED_ENERGY_BOLT) {
2411 			/* Make NPC Preds immune to splash damage? */
2412 			return;
2413 		}
2414 	}
2415 
2416 	if (damage->Id==AMMO_NPC_OBSTACLE_CLEAR) {
2417 		if (sbPtr->I_SBtype==I_BehaviourInanimateObject) {
2418 			INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr;
2419 
2420 			if (objStatPtr->explosionType!=0) {
2421 				/* Try not to blunder through fatal things... */
2422 				return;
2423 			}
2424 		}
2425 	}
2426 
2427 	if(sbPtr->I_SBtype==I_BehaviourMarinePlayer ||
2428 	   sbPtr->I_SBtype==I_BehaviourAlienPlayer ||
2429 	   sbPtr->I_SBtype==I_BehaviourPredatorPlayer)
2430 	{
2431 		//check for player invulnerability
2432 		PLAYER_STATUS *psPtr=(PLAYER_STATUS*)sbPtr->SBdataptr;
2433 		GLOBALASSERT(psPtr);
2434 		if(psPtr->invulnerabilityTimer>0)
2435 		{
2436 			//player is still invulnerable
2437 			return;
2438 		}
2439 
2440 		#if 0
2441 		/* And check for warpspeed cheatmode. */
2442 		if (WARPSPEED_CHEATMODE) {
2443 			use_multiple>>=1;
2444 		}
2445 		#endif
2446 	}
2447 
2448 	/* Friendly Fire? */
2449 	if(AvP.Network != I_No_Network)
2450 	{
2451 		if (netGameData.disableFriendlyFire && (netGameData.gameType==NGT_CoopDeathmatch || netGameData.gameType==NGT_Coop)) {
2452 			if (sbPtr->I_SBtype==I_BehaviourMarinePlayer) {
2453 				if ((FriendlyFireDamageFilter(damage))==0) {
2454 					return;
2455 				}
2456 			}
2457 		}
2458 	}
2459 
2460 	DamageDamageBlock(&sbPtr->SBDamageBlock,damage,use_multiple);
2461 
2462 	/* This bit will still need to exist: but differently. */
2463 
2464 	/* Andy 13/10/97 -
2465 		 Sound calls now placed in object specific damage functions ...IsDamaged */
2466 
2467  	switch(sbPtr->I_SBtype)
2468 	{
2469 		case I_BehaviourAlien:
2470 		{
2471    	 	/* reduce alien health */
2472 			AlienIsDamaged(sbPtr, damage, use_multiple, 0,NULL,incoming,NULL);
2473 			break;
2474 		}
2475 		case I_BehaviourMarinePlayer:
2476 		case I_BehaviourAlienPlayer:
2477 		case I_BehaviourPredatorPlayer:
2478 		{
2479 			PlayerIsDamaged(sbPtr,damage,use_multiple,incoming);
2480 			break;
2481 		}
2482 		case I_BehaviourInanimateObject:
2483 		{
2484 			InanimateObjectIsDamaged(sbPtr,damage,use_multiple);
2485 			break;
2486 		}
2487 		case I_BehaviourVideoScreen:
2488 		{
2489 			VideoScreenIsDamaged(sbPtr,damage,use_multiple);
2490 			break;
2491 		}
2492 		case I_BehaviourPlacedLight:
2493 		{
2494 			PlacedLightIsDamaged(sbPtr,damage,use_multiple);
2495 			break;
2496 		}
2497 		case I_BehaviourTrackObject:
2498 		{
2499 			TrackObjectIsDamaged(sbPtr,damage,use_multiple);
2500 			break;
2501 		}
2502 		case I_BehaviourPredator:
2503 		{
2504 			PredatorIsDamaged(sbPtr,damage,use_multiple,NULL,incoming);
2505 			break;
2506 		}
2507 		case I_BehaviourXenoborg:
2508 		{
2509 			XenoborgIsDamaged(sbPtr, damage, use_multiple, 0,incoming);
2510 			break;
2511 		}
2512 		case I_BehaviourSeal:
2513 		case I_BehaviourMarine:
2514 		{
2515 			MarineIsDamaged(sbPtr,damage,use_multiple,0,NULL,incoming);
2516 			break;
2517 		}
2518 		case I_BehaviourQueenAlien:
2519 		{
2520 			QueenIsDamaged(sbPtr,damage,use_multiple,NULL,incoming,NULL);
2521 			break;
2522 		}
2523 		case I_BehaviourPredatorAlien:
2524 		{
2525 			GLOBALASSERT(0);
2526 			//PAQIsDamaged(sbPtr,damage,use_multiple);
2527 			break;
2528 		}
2529 		case I_BehaviourFaceHugger:
2530 		{
2531 			FacehuggerIsDamaged(sbPtr,damage,use_multiple);
2532 			break;
2533 		}
2534 	  case I_BehaviourGrenade:
2535 		case I_BehaviourFlareGrenade:
2536 		case I_BehaviourFragmentationGrenade:
2537 		case I_BehaviourProximityGrenade:
2538 	  case I_BehaviourRocket:
2539 	  case I_BehaviourPulseGrenade:
2540 	  case I_BehaviourPredatorEnergyBolt:
2541 	  case I_BehaviourXenoborgEnergyBolt:
2542 		{
2543 			/* make it explode! */
2544 			((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 0;
2545 			break;
2546 		}
2547 		case I_BehaviourFrisbee:
2548 		{
2549 			/* make it explode! */
2550 			((FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 0;
2551 			break;
2552 		}
2553 		case I_BehaviourNetGhost:
2554 		{
2555 			DamageNetworkGhost(sbPtr, damage, use_multiple,NULL,incoming);
2556 			break;
2557 		}
2558 		case I_BehaviourAutoGun:
2559 		{
2560 			AGunIsDamaged(sbPtr, damage, use_multiple, 0,incoming);
2561 			break;
2562 		}
2563 		case I_BehaviourNetCorpse:
2564 		{
2565 			CorpseIsDamaged(sbPtr,damage,use_multiple,0,NULL,incoming);
2566 			break;
2567 		}
2568 		default:
2569 			break;
2570 	}
2571 }
2572 
2573 
HandleEffectsOfExplosion(STRATEGYBLOCK * objectToIgnorePtr,VECTORCH * centrePtr,int maxRange,DAMAGE_PROFILE * maxDamage,int flat)2574 void HandleEffectsOfExplosion(STRATEGYBLOCK *objectToIgnorePtr, VECTORCH *centrePtr, int maxRange, DAMAGE_PROFILE *maxDamage, int flat)
2575 {
2576 	DISPLAYBLOCK *ignoreDispPtr;
2577 	int i = NumActiveStBlocks;
2578 
2579 	if (objectToIgnorePtr)
2580 	{
2581 		ignoreDispPtr = objectToIgnorePtr->SBdptr;
2582 	}
2583 	else
2584 	{
2585 		ignoreDispPtr = 0;
2586 	}
2587 
2588 	/* The damage done by an explosions varies linearly with range from the explosion's
2589 	centre so that no damage is done to an object which is 'maxRange' away. */
2590 
2591 	while(i)
2592 	{
2593 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[--i];
2594 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2595 		DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
2596 
2597 		if (sbPtr == objectToIgnorePtr) continue;
2598 
2599 		if (dynPtr && dispPtr)
2600 		{
2601 			int range;
2602 			VECTORCH displacement;
2603 
2604 			displacement.vx = dynPtr->Position.vx - centrePtr->vx;
2605 			displacement.vy = dynPtr->Position.vy - centrePtr->vy;
2606 			displacement.vz = dynPtr->Position.vz - centrePtr->vz;
2607 			range = Approximate3dMagnitude(&displacement);
2608 
2609 			/* find if object is in explosion radius */
2610 			if (range && range < maxRange)
2611 			{
2612 				/* now check line of sight */
2613 				BOOL visible=IsThisObjectVisibleFromThisPosition_WithIgnore(dispPtr,ignoreDispPtr,centrePtr,maxRange);
2614 				if(LOS_Lambda>range)
2615 				{
2616 					//seen past the object , so it probably is visible , but has a hole in it
2617 					visible=TRUE;
2618 				}
2619 
2620 				if(visible)
2621 				{
2622 					int mult,damage;
2623 					enum PARTICLE_ID blood_type;
2624 
2625 					if (flat) mult=ONE_FIXED;
2626 					else mult=DIV_FIXED((maxRange-range),maxRange);
2627 
2628 					damage=MUL_FIXED(TotalKineticDamage(maxDamage),mult);
2629 
2630 					/* Identify blood type now! */
2631 					blood_type=GetBloodType(sbPtr);
2632 					{
2633 						VECTORCH attack_dir;
2634 						GetDirectionOfAttack(sbPtr,&displacement,&attack_dir);
2635 
2636 						CauseDamageToObject(sbPtr,maxDamage,mult,&attack_dir);
2637 				 	}
2638 					if (NPC_IsDead(sbPtr)) {
2639 						/* Blood! */
2640 						VECTORCH position;
2641 
2642 						GetTargetingPointOfObject_Far(sbPtr,&position);
2643 
2644 						if ((damage)&&(blood_type!=PARTICLE_NULL)) {
2645 							/* Let's just use ObMaxX for now... */
2646 							MakeBloodExplosion(&position, dispPtr->ObRadius, centrePtr, damage, blood_type);
2647 						}
2648 					}
2649 				 	/* effect of explosion on object's dynamics */
2650 					{
2651 						EULER rotation;
2652 	 					int magnitudeOfForce = 5000*damage/dynPtr->Mass;
2653 
2654 						Normalise(&displacement);
2655 
2656 						/* okay, not too sure yet what this should do */
2657 				  		dynPtr->LinImpulse.vx += MUL_FIXED(displacement.vx,magnitudeOfForce);
2658 						dynPtr->LinImpulse.vy += MUL_FIXED(displacement.vy,magnitudeOfForce);
2659 					  	dynPtr->LinImpulse.vz += MUL_FIXED(displacement.vz,magnitudeOfForce);
2660 
2661 						CalculateTorque(&rotation, &displacement, sbPtr);
2662 
2663 						/* okay, not too sure yet what this should do */
2664 						 //	magnitudeOfForce /= 100;
2665 				  		dynPtr->AngImpulse.EulerX += MUL_FIXED(rotation.EulerX,magnitudeOfForce);
2666 				  		dynPtr->AngImpulse.EulerY += MUL_FIXED(rotation.EulerY,magnitudeOfForce);
2667 				  		dynPtr->AngImpulse.EulerZ += MUL_FIXED(rotation.EulerZ,magnitudeOfForce);
2668 					}
2669 				}
2670 			}
2671 		}
2672    	}
2673 
2674 	switch (maxDamage->ExplosivePower)
2675 	{
2676 		case 6:
2677 		{
2678 
2679 			MakeVolumetricExplosionAt(centrePtr,EXPLOSION_SMALL_NOCOLLISIONS);
2680 
2681 			if(AvP.Network!=I_No_Network)
2682 			{
2683 				AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_SMALL_NOCOLLISIONS);
2684 			}
2685 			break;
2686 		}
2687 		case 5:
2688 		{
2689 			MakeVolumetricExplosionAt(centrePtr,EXPLOSION_MOLOTOV);
2690 			break;
2691 		}
2692 		case 4:
2693 		{
2694 			/* Must be the plasmacaster.  SFX? */
2695 			break;
2696 		}
2697 		case 3:
2698 		{
2699 			MakeElectricalExplosion(centrePtr);
2700 
2701 			if(AvP.Network!=I_No_Network)
2702 			{
2703 				AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_PREDATORPISTOL);
2704 			}
2705 			break;
2706 		}
2707 		case 2:
2708 		{
2709 
2710 			MakeVolumetricExplosionAt(centrePtr,EXPLOSION_HUGE);
2711 
2712 			if(AvP.Network!=I_No_Network)
2713 			{
2714 				AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_HUGE);
2715 			}
2716 			break;
2717 		}
2718 		case 1:
2719 		{
2720 
2721 			MakeVolumetricExplosionAt(centrePtr,EXPLOSION_PULSEGRENADE);
2722 
2723 			if(AvP.Network!=I_No_Network)
2724 			{
2725 				AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_PULSEGRENADE);
2726 			}
2727 			break;
2728 		}
2729 		default:
2730 			break;
2731 	}
2732 
2733 }
2734 
2735 
FireAutoGun(STRATEGYBLOCK * sbPtr)2736 void FireAutoGun(STRATEGYBLOCK *sbPtr)
2737 {
2738 	#if 0
2739 	AUTOGUN_BEHAV_BLOCK *ag_bhv;
2740 	ag_bhv = (AUTOGUN_BEHAV_BLOCK*)(sbPtr->SBdataptr);
2741 
2742 	FireLineOfSightAmmo(AMMO_AUTOGUN, &(ag_bhv->global_muzz_pos), &(ag_bhv->tgt_direction),1);
2743 	#endif
2744 }
2745 
2746 
MakeMatrixFromDirection(VECTORCH * directionPtr,MATRIXCH * matrixPtr)2747 void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr)
2748 {
2749 	VECTORCH XVector;
2750 	VECTORCH YVector;
2751 
2752    	if (directionPtr->vx==0)
2753 	{
2754 		XVector.vx = 65536;
2755 		XVector.vy = 0;
2756 		XVector.vz = 0;
2757 	}
2758 	else if (directionPtr->vy==0)
2759 	{
2760 		XVector.vx = 0;
2761 		XVector.vy = 65536;
2762 		XVector.vz = 0;
2763 	}
2764 	else if (directionPtr->vz==0)
2765 	{
2766 		XVector.vx = 0;
2767 		XVector.vy = 0;
2768 		XVector.vz = 65536;
2769 	}
2770 	else
2771 	{
2772 		XVector.vx = directionPtr->vz;
2773 		XVector.vy = 0;
2774 		XVector.vz = -directionPtr->vx;
2775 		Normalise(&XVector);
2776 	}
2777 
2778 	CrossProduct(directionPtr, &XVector, &YVector);
2779 
2780 	matrixPtr->mat11 = XVector.vx;
2781 	matrixPtr->mat12 = XVector.vy;
2782 	matrixPtr->mat13 = XVector.vz;
2783 
2784 	matrixPtr->mat21 = YVector.vx;
2785 	matrixPtr->mat22 = YVector.vy;
2786 	matrixPtr->mat23 = YVector.vz;
2787 
2788 	matrixPtr->mat31 = directionPtr->vx;
2789 	matrixPtr->mat32 = directionPtr->vy;
2790 	matrixPtr->mat33 = directionPtr->vz;
2791 }
2792 
2793 
2794 
2795 /*KJL*************
2796 * 3D Weapon Code *
2797 *************KJL*/
2798 /* values which are evaluated at runtime */
2799 VECTORCH CentreOfMuzzleOffset;
2800 int MuzzleFlashLength;
2801 
PositionPlayersWeapon(void)2802 void PositionPlayersWeapon(void)
2803 {
2804 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
2805 	PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2806 	TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
2807 
2808 	VECTORCH gunDirection;
2809 	//VECTORCH gunOffset = twPtr->RestPosition;
2810 	VECTORCH gunOffset = PlayersWeaponCameraOffset;
2811 	gunOffset.vx += twPtr->RestPosition.vx;
2812 	gunOffset.vy += twPtr->RestPosition.vy;
2813 	gunOffset.vz += twPtr->RestPosition.vz;
2814 
2815 	gunOffset.vx += weaponPtr->PositionOffset.vx;
2816 	gunOffset.vy += weaponPtr->PositionOffset.vy;
2817 	gunOffset.vz += weaponPtr->PositionOffset.vz;
2818 
2819    	if ( (!(twPtr->PrimaryIsMeleeWeapon || (weaponPtr->WeaponIDNumber == WEAPON_PRED_DISC)
2820 		||(weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON)
2821 		||(weaponPtr->WeaponIDNumber == WEAPON_PRED_MEDICOMP)
2822 		)) ) {
2823 		{
2824 			gunDirection = PlayersTarget.Position;
2825 
2826 			{
2827 				VECTORCH offset;
2828 				offset.vx = gunOffset.vx/4;
2829 				offset.vy = gunOffset.vy/4;
2830 				offset.vz = gunOffset.vz/4;
2831 
2832 				{
2833 					MATRIXCH mat = Global_VDB_Ptr->VDB_Mat;
2834 					TransposeMatrixCH(&mat);
2835 					RotateVector(&offset, &mat);
2836 		 		}
2837 			 	gunDirection.vx -= Global_VDB_Ptr->VDB_World.vx-offset.vx;
2838 			  	gunDirection.vy -= Global_VDB_Ptr->VDB_World.vy-offset.vy;
2839 			  	gunDirection.vz -= Global_VDB_Ptr->VDB_World.vz-offset.vz;
2840 			}
2841 			Normalise(&gunDirection);
2842 		}
2843 		{
2844 			MATRIXCH mat;
2845 			EULER dir = weaponPtr->DirectionOffset;
2846 			VECTORCH XVector;
2847 			VECTORCH YVector;
2848 		    VECTORCH ZVector;
2849 
2850 			ZVector = gunDirection;
2851 			#if 0
2852 			/* KJL 13:13:34 04/05/97 - allow weapon to rotate about z axis */
2853 			XVector.vx = ZVector.vz;
2854 			XVector.vy = 0;
2855 			XVector.vz = -ZVector.vx;
2856 
2857 			Normalise(&XVector);
2858 
2859 			CrossProduct(&ZVector,&XVector, &YVector);
2860 			#else
2861 			/* keep weapon stable about z axis - definitely needed for alien */
2862 			YVector.vx = Global_VDB_Ptr->VDB_Mat.mat12;
2863 			YVector.vy = Global_VDB_Ptr->VDB_Mat.mat22;
2864 			YVector.vz = Global_VDB_Ptr->VDB_Mat.mat32;
2865 			CrossProduct(&YVector,&ZVector, &XVector);
2866 			Normalise(&XVector);
2867 			#endif
2868 
2869 			PlayersWeapon.ObMat.mat11 = XVector.vx;
2870 			PlayersWeapon.ObMat.mat12 = XVector.vy;
2871 			PlayersWeapon.ObMat.mat13 = XVector.vz;
2872 
2873 			PlayersWeapon.ObMat.mat21 = YVector.vx;
2874 			PlayersWeapon.ObMat.mat22 = YVector.vy;
2875 			PlayersWeapon.ObMat.mat23 = YVector.vz;
2876 
2877 			PlayersWeapon.ObMat.mat31 = ZVector.vx;
2878 			PlayersWeapon.ObMat.mat32 = ZVector.vy;
2879 			PlayersWeapon.ObMat.mat33 = ZVector.vz;
2880 
2881 			if (dir.EulerX != 0 || dir.EulerY !=0 || dir.EulerZ != 0)
2882 		 	{
2883 				if (dir.EulerX<0) dir.EulerX = 4096 + dir.EulerX;
2884 				if (dir.EulerY<0) dir.EulerY = 4096 + dir.EulerY;
2885 				if (dir.EulerZ<0) dir.EulerZ = 4096 + dir.EulerZ;
2886 
2887 				CreateEulerMatrix(&dir, &mat);
2888 				TransposeMatrixCH(&mat);
2889 				MatrixMultiply(&PlayersWeapon.ObMat,&mat,&PlayersWeapon.ObMat);
2890 
2891 		 	}
2892 		}
2893 	} else {
2894 		/* Pred Weapons. */
2895 		PlayersWeapon.ObMat=Global_VDB_Ptr->VDB_Mat;
2896 		TransposeMatrixCH(&PlayersWeapon.ObMat);
2897 	}
2898 
2899 	PlayersWeapon.ObView = gunOffset;
2900 
2901 	{
2902 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
2903 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
2904 
2905 		VECTORCH offset = PlayersWeapon.ObView;
2906 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
2907 
2908 		TransposeMatrixCH(&matrix);
2909 
2910 	   	RotateVector(&offset, &matrix);
2911 
2912 		PlayersWeapon.ObWorld.vx = (VDBPtr->VDB_World.vx + offset.vx);
2913 		PlayersWeapon.ObWorld.vy = (VDBPtr->VDB_World.vy + offset.vy);
2914 		PlayersWeapon.ObWorld.vz = (VDBPtr->VDB_World.vz + offset.vz);
2915 	}
2916 
2917 	/* Late firing.  Note that this is a horrible hack. */
2918 	if (FirePrimaryLate) {
2919 		if ((*twPtr->FirePrimaryFunction)(weaponPtr)) {
2920 			if (twPtr->PrimaryMuzzleFlash) {
2921 				if (twPtr->PrimaryAmmoID==AMMO_PARTICLE_BEAM) {
2922 					AddLightingEffectToObject(Player,LFX_PARTICLECANNON);
2923 				} else {
2924 					AddLightingEffectToObject(Player,LFX_MUZZLEFLASH);
2925 				}
2926 			}
2927 		}
2928 	} else if (FireSecondaryLate) {
2929 		if (twPtr->SecondaryMuzzleFlash) {
2930 			if ((*twPtr->FireSecondaryFunction)(weaponPtr)) {
2931 				AddLightingEffectToObject(Player,LFX_MUZZLEFLASH);
2932 			}
2933 		}
2934 	}
2935 	/* It ignores all the things that are pipeline specific, like the return *
2936 	 * condition of the fire function, and won't work for melee weapons. */
2937 
2938 }
2939 
PositionPlayersWeaponMuzzleFlash(void)2940 void PositionPlayersWeaponMuzzleFlash(void)
2941 {
2942 	int size = 65536*3/4 - (FastRandom()&16383);
2943 	int length = size;
2944 
2945 	if (PWMFSDP) {
2946 //		textprint("Hierarchical Muzzle Flash.\n");
2947 
2948 		PlayersWeaponMuzzleFlash.ObWorld=PWMFSDP->World_Offset;
2949 		PlayersWeaponMuzzleFlash.ObMat=PWMFSDP->SecMat;
2950 		return;
2951 
2952 	}
2953 
2954 	{
2955 
2956 		PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
2957 		PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2958 		if (weaponPtr->WeaponIDNumber==WEAPON_SMARTGUN) length*=2;
2959 
2960 	}
2961 
2962 	{
2963 		VECTORCH v = CentreOfMuzzleOffset;
2964  //		int disp = MUL_FIXED(MuzzleFlashLength,length);
2965 
2966 		RotateVector(&v,&PlayersWeapon.ObMat);
2967 
2968 		v.vx+=PlayersWeapon.ObWorld.vx;
2969 		v.vy+=PlayersWeapon.ObWorld.vy;
2970 		v.vz+=PlayersWeapon.ObWorld.vz;
2971 		/* position the muzzle flash in world space */
2972 		PlayersWeaponMuzzleFlash.ObWorld.vx = v.vx+MUL_FIXED(200,PlayersWeapon.ObMat.mat31);
2973 		PlayersWeaponMuzzleFlash.ObWorld.vy = v.vy+MUL_FIXED(200,PlayersWeapon.ObMat.mat32);
2974 		PlayersWeaponMuzzleFlash.ObWorld.vz = v.vz+MUL_FIXED(200,PlayersWeapon.ObMat.mat33);
2975  //		PlayersWeaponMuzzleFlash.ObWorld.vx = v.vx+MUL_FIXED(disp,PlayersWeapon.ObMat.mat31);
2976  //		PlayersWeaponMuzzleFlash.ObWorld.vy = v.vy+MUL_FIXED(disp,PlayersWeapon.ObMat.mat32);
2977  //		PlayersWeaponMuzzleFlash.ObWorld.vz = v.vz+MUL_FIXED(disp,PlayersWeapon.ObMat.mat33);
2978 	}
2979 
2980 	/* calculate it's view space position */
2981 	{
2982 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
2983 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
2984 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
2985 
2986 		PlayersWeaponMuzzleFlash.ObView.vx = PlayersWeaponMuzzleFlash.ObWorld.vx - VDBPtr->VDB_World.vx;
2987 		PlayersWeaponMuzzleFlash.ObView.vy = PlayersWeaponMuzzleFlash.ObWorld.vy - VDBPtr->VDB_World.vy;
2988 		PlayersWeaponMuzzleFlash.ObView.vz = PlayersWeaponMuzzleFlash.ObWorld.vz - VDBPtr->VDB_World.vz;
2989 		RotateVector(&PlayersWeaponMuzzleFlash.ObView, &matrix);
2990 	}
2991 
2992 	/* align the muzzle flash with the gun */
2993 	PlayersWeaponMuzzleFlash.ObMat.mat11 = MUL_FIXED(size,PlayersWeapon.ObMat.mat11);
2994 	PlayersWeaponMuzzleFlash.ObMat.mat12 = MUL_FIXED(size,PlayersWeapon.ObMat.mat12);
2995 	PlayersWeaponMuzzleFlash.ObMat.mat13 = MUL_FIXED(size,PlayersWeapon.ObMat.mat13);
2996 
2997 	PlayersWeaponMuzzleFlash.ObMat.mat21 = MUL_FIXED(size,PlayersWeapon.ObMat.mat21);
2998 	PlayersWeaponMuzzleFlash.ObMat.mat22 = MUL_FIXED(size,PlayersWeapon.ObMat.mat22);
2999 	PlayersWeaponMuzzleFlash.ObMat.mat23 = MUL_FIXED(size,PlayersWeapon.ObMat.mat23);
3000 
3001 	PlayersWeaponMuzzleFlash.ObMat.mat31 = MUL_FIXED(length,PlayersWeapon.ObMat.mat31);
3002 	PlayersWeaponMuzzleFlash.ObMat.mat32 = MUL_FIXED(length,PlayersWeapon.ObMat.mat32);
3003 	PlayersWeaponMuzzleFlash.ObMat.mat33 = MUL_FIXED(length,PlayersWeapon.ObMat.mat33);
3004 
3005 	/* rotate flash around in random multiples of 60 degrees */
3006 	{
3007 		MATRIXCH mat;
3008    		int angle = (FastRandom()%6)*683;
3009  	  	int cos = GetCos(angle);
3010  	  	int sin = GetSin(angle);
3011  	  	mat.mat11 = cos;
3012  	  	mat.mat12 = sin;
3013  	  	mat.mat13 = 0;
3014  	  	mat.mat21 = -sin;
3015  	  	mat.mat22 = cos;
3016  	  	mat.mat23 = 0;
3017  	  	mat.mat31 = 0;
3018  	  	mat.mat32 = 0;
3019  	  	mat.mat33 = 65536;
3020 		 	MatrixMultiply(&PlayersWeaponMuzzleFlash.ObMat,&mat,&PlayersWeaponMuzzleFlash.ObMat);
3021 	}
3022 
3023 }
3024 
3025 
3026 
StateDependentMovement(PLAYER_STATUS * playerStatusPtr,PLAYER_WEAPON_DATA * weaponPtr)3027 static void StateDependentMovement(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr)
3028 {
3029 	TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3030 
3031 	if (twPtr->WeaponStateFunction[weaponPtr->CurrentState]!=NULL) {
3032 		(*twPtr->WeaponStateFunction[weaponPtr->CurrentState])((void *)playerStatusPtr,weaponPtr);
3033 	}
3034 
3035  	if (twPtr->UseStateMovement==0) {
3036 
3037 		/* Judder is now in targeting.c! */
3038 		return;
3039 	}
3040 
3041  	/* Handle on-screen movement of gun */
3042     switch(weaponPtr->CurrentState)
3043 	{
3044 		case WEAPONSTATE_SWAPPING_IN:
3045         case WEAPONSTATE_SWAPPING_OUT:
3046 		{
3047 			//VECTORCH gunOffset = twPtr->RestPosition;
3048         	VECTORCH gunOffset = PlayersWeaponCameraOffset;
3049         	int offset;
3050 
3051         	/* scroll old weapon down screen & new weapon up */
3052         	if (playerStatusPtr->SwapToWeaponSlot != WEAPON_FINISHED_SWAPPING)
3053             {
3054 				offset = 65536-weaponPtr->StateTimeOutCounter;
3055            	}
3056             else
3057             {
3058 				offset = weaponPtr->StateTimeOutCounter;
3059             }
3060 
3061           	/* slide a bit to the right when swapping */
3062 			weaponPtr->DirectionOffset.EulerX =(offset>>7);
3063 			weaponPtr->PositionOffset.vx = MUL_FIXED(offset,gunOffset.vx);
3064             weaponPtr->PositionOffset.vy = MUL_FIXED(offset,gunOffset.vy);
3065 			weaponPtr->PositionOffset.vz = MUL_FIXED(-offset,gunOffset.vz);
3066 
3067 			break;
3068 
3069 		}
3070         case WEAPONSTATE_FIRING_PRIMARY:
3071         {
3072 	        if (twPtr->PrimaryIsRapidFire)
3073         	{
3074 	        	/* jiggle the weapon around when you shoot */
3075 			   	weaponPtr->PositionOffset.vz = (FastRandom()&twPtr->RecoilMaxRandomZ) - twPtr->RecoilMaxZ;
3076   	 			weaponPtr->DirectionOffset.EulerX =	(FastRandom()&twPtr->RecoilMaxXTilt)-twPtr->RecoilMaxXTilt/2;
3077   	 			weaponPtr->DirectionOffset.EulerY =	(FastRandom()&twPtr->RecoilMaxYTilt)-twPtr->RecoilMaxYTilt/2;
3078 
3079 				HeadOrientation.EulerX = ((FastRandom()&31)-16)&4095;
3080 			}
3081 			else
3082 			{
3083 				HeadOrientation.EulerX = 4095-32;
3084 			}
3085 			break;
3086         }
3087         case WEAPONSTATE_RECOIL_PRIMARY:
3088         {
3089 			int offset = 65536-weaponPtr->StateTimeOutCounter;
3090 
3091 		   	weaponPtr->PositionOffset.vz = -MUL_FIXED(offset,twPtr->RecoilMaxZ);
3092  			weaponPtr->DirectionOffset.EulerX =-MUL_FIXED(offset,twPtr->RecoilMaxXTilt);
3093             break;
3094         }
3095         case WEAPONSTATE_RECOIL_SECONDARY:
3096         {
3097 			int offset = 65536-weaponPtr->StateTimeOutCounter;
3098 
3099 		   	weaponPtr->PositionOffset.vz = -MUL_FIXED(offset,twPtr->RecoilMaxZ);
3100  			weaponPtr->DirectionOffset.EulerX =-MUL_FIXED(offset,twPtr->RecoilMaxXTilt);
3101             break;
3102         }
3103 
3104 
3105 		default:
3106         {
3107 			/* recentre offsets */
3108 			int linearCenteringSpeed = MUL_FIXED(300,NormalFrameTime);
3109 			int rotationalCenteringSpeed = MUL_FIXED(1500,NormalFrameTime);
3110     		if (weaponPtr->PositionOffset.vx > 0 )
3111 			{
3112 				weaponPtr->PositionOffset.vx -= linearCenteringSpeed;
3113 				if (weaponPtr->PositionOffset.vx < 0) weaponPtr->PositionOffset.vx = 0;
3114 			}
3115 			else if (weaponPtr->PositionOffset.vx < 0 )
3116 			{
3117 				weaponPtr->PositionOffset.vx += linearCenteringSpeed;
3118 				if (weaponPtr->PositionOffset.vx > 0) weaponPtr->PositionOffset.vx = 0;
3119 			}
3120 
3121 			if (weaponPtr->PositionOffset.vy > 0 )
3122 			{
3123 				weaponPtr->PositionOffset.vy -= linearCenteringSpeed;
3124 				if (weaponPtr->PositionOffset.vy < 0) weaponPtr->PositionOffset.vy = 0;
3125 			}
3126 			else if (weaponPtr->PositionOffset.vy < 0 )
3127 			{
3128 				weaponPtr->PositionOffset.vy += linearCenteringSpeed;
3129 				if (weaponPtr->PositionOffset.vy > 0) weaponPtr->PositionOffset.vy = 0;
3130 			}
3131 
3132 			if (weaponPtr->PositionOffset.vz > 0 )
3133 			{
3134 				weaponPtr->PositionOffset.vz -= linearCenteringSpeed;
3135 				if (weaponPtr->PositionOffset.vz < 0) weaponPtr->PositionOffset.vz = 0;
3136 			}
3137 			else if (weaponPtr->PositionOffset.vz < 0 )
3138 			{
3139 				weaponPtr->PositionOffset.vz += linearCenteringSpeed;
3140 				if (weaponPtr->PositionOffset.vz > 0) weaponPtr->PositionOffset.vz = 0;
3141 			}
3142 
3143 			if (weaponPtr->DirectionOffset.EulerX > 0 )
3144 			{
3145 				weaponPtr->DirectionOffset.EulerX -= rotationalCenteringSpeed;
3146 				if (weaponPtr->DirectionOffset.EulerX < 0) weaponPtr->DirectionOffset.EulerX = 0;
3147 			}
3148 			else if (weaponPtr->DirectionOffset.EulerX < 0 )
3149 			{
3150 				weaponPtr->DirectionOffset.EulerX += rotationalCenteringSpeed;
3151 				if (weaponPtr->DirectionOffset.EulerX > 0) weaponPtr->DirectionOffset.EulerX = 0;
3152 			}
3153 
3154 			if (weaponPtr->DirectionOffset.EulerY > 0 )
3155 			{
3156 				weaponPtr->DirectionOffset.EulerY -= rotationalCenteringSpeed;
3157 				if (weaponPtr->DirectionOffset.EulerY < 0) weaponPtr->DirectionOffset.EulerY = 0;
3158 			}
3159 			else if (weaponPtr->DirectionOffset.EulerY < 0 )
3160 			{
3161 				weaponPtr->DirectionOffset.EulerY += rotationalCenteringSpeed;
3162 				if (weaponPtr->DirectionOffset.EulerY > 0) weaponPtr->DirectionOffset.EulerY = 0;
3163 			}
3164 
3165 			if (weaponPtr->DirectionOffset.EulerZ > 0 )
3166 			{
3167 				weaponPtr->DirectionOffset.EulerZ -= rotationalCenteringSpeed;
3168 				if (weaponPtr->DirectionOffset.EulerZ < 0) weaponPtr->DirectionOffset.EulerZ = 0;
3169 			}
3170 			else if (weaponPtr->DirectionOffset.EulerZ < 0 )
3171 			{
3172 				weaponPtr->DirectionOffset.EulerZ += rotationalCenteringSpeed;
3173 				if (weaponPtr->DirectionOffset.EulerZ > 0) weaponPtr->DirectionOffset.EulerZ = 0;
3174 			}
3175 
3176         	break;
3177         }
3178 
3179 
3180 	}
3181 
3182 }
3183 
3184 
3185 
UpdateWeaponShape(void)3186 extern void UpdateWeaponShape(void)
3187 {
3188 	PLAYER_WEAPON_DATA *weaponPtr;
3189 	TEMPLATE_WEAPON_DATA *twPtr;
3190 
3191     /* access the extra data hanging off the strategy block */
3192 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
3193     GLOBALASSERT(playerStatusPtr);
3194 
3195 	/* player's current weapon */
3196     GLOBALASSERT(playerStatusPtr->SelectedWeaponSlot<MAX_NO_OF_WEAPON_SLOTS);
3197 
3198     /* init a pointer to the weapon's data */
3199     weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
3200 
3201 	/* Player doesn't have a weapon! This will eventually be changed into an assertion
3202 	that the player *does* have a weapon */
3203 	if (weaponPtr->WeaponIDNumber == NULL_WEAPON)
3204 		return;
3205 
3206     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3207 
3208 	GrabWeaponShape(weaponPtr);
3209 
3210 	if (!(twPtr->PrimaryIsMeleeWeapon)) GrabMuzzleFlashShape(twPtr);
3211 
3212 	PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl;
3213 	if (twPtr->HasShapeAnimation) {
3214 		PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl;
3215 	} else {
3216 		PlayersWeapon.ShapeAnimControlBlock=NULL;
3217 	}
3218 
3219 }
3220 
GetHierarchicalWeapon(char * riffname,char * hierarchyname,int sequence_type,int sub_sequence)3221 void GetHierarchicalWeapon(char *riffname, char *hierarchyname, int sequence_type, int sub_sequence) {
3222 
3223 	extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
3224 	SECTION *root_section;
3225 	SECTION_DATA *camera_section;
3226 
3227 	root_section=GetNamedHierarchyFromLibrary(riffname,hierarchyname);
3228 
3229 	GLOBALASSERT(root_section);
3230 
3231 	Dispel_HModel(&PlayersWeaponHModelController);
3232 	Create_HModel(&PlayersWeaponHModelController,root_section);
3233 	InitHModelSequence(&PlayersWeaponHModelController,sequence_type,sub_sequence,ONE_FIXED); // Was >>3
3234 
3235 	/* Causes that 'one frame' flicker? */
3236 	//ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon);
3237 
3238 	PlayersWeapon.HModelControlBlock=&PlayersWeaponHModelController;
3239 	PlayersWeapon.HModelControlBlock->Playing=1;
3240 	PlayersWeapon.HModelControlBlock->Looped=1;
3241 
3242 	PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"dum flash");
3243 	if (PWMFSDP==NULL) {
3244 		PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum flash");
3245 		/* ?&$(*"*&^ pred pistol!!! */
3246 		if (PWMFSDP==NULL) {
3247 			PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash");
3248 		}
3249 	}
3250 	/* Could be NULL though, I don't care at this stage. */
3251 
3252 	camera_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"Camera Root");
3253 
3254 	if (camera_section) {
3255 		//PlayersWeaponCameraOffset=camera_section->sempai->sequence_array->first_frame->Offset;
3256 		GetKeyFrameOffset(camera_section->sempai->sequence_array->first_frame,&PlayersWeaponCameraOffset);
3257 		PlayersWeaponCameraOffset.vx=-PlayersWeaponCameraOffset.vx;
3258 		PlayersWeaponCameraOffset.vy=-PlayersWeaponCameraOffset.vy;
3259 		PlayersWeaponCameraOffset.vz=-PlayersWeaponCameraOffset.vz;
3260 	} else {
3261 		GLOBALASSERT(0);
3262 		/* If you really want, you could do something like... *
3263 		PlayersWeaponCameraOffset=twPtr->RestPosition;
3264 		 * But that would cause a compiler error.             */
3265 	}
3266 
3267 
3268 }
3269 
GrabWeaponShape(PLAYER_WEAPON_DATA * weaponPtr)3270 void GrabWeaponShape(PLAYER_WEAPON_DATA *weaponPtr)
3271 {
3272 
3273 	TEMPLATE_WEAPON_DATA *twPtr;
3274 
3275     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3276 
3277 	/* if there is no shape name then return */
3278 	if (twPtr->WeaponShapeName == NULL) return;
3279 
3280 	PlayersWeapon.ObShape = GetLoadedShapeMSL(twPtr->WeaponShapeName);
3281 	LOCALASSERT(PlayersWeapon.ObShape>0);
3282 
3283    	PlayersWeapon.ObFlags  = ObFlag_VertexHazing|ObFlag_MultLSrc;
3284 	PlayersWeapon.ObFlags2 = 0;
3285 	PlayersWeapon.ObFlags3 = 0;
3286 
3287   	PlayersWeapon.ObLightType = LightType_PerVertex;
3288 
3289 	PlayersWeapon.HModelControlBlock=NULL;
3290 
3291 	//WeaponSetStartFrame(NULL,NULL);
3292 	FindEndOfShape(&CentreOfMuzzleOffset,PlayersWeapon.ObShape);
3293 
3294 	if (twPtr->HierarchyName) {
3295 
3296 		/* Bit of a cheap test, I know. */
3297 		GetHierarchicalWeapon(twPtr->RiffName,twPtr->HierarchyName,twPtr->InitialSequenceType,twPtr->InitialSubSequence);
3298 
3299 	} else {
3300 		Dispel_HModel(&PlayersWeaponHModelController);
3301 		PWMFSDP=NULL;
3302 		PlayersWeaponCameraOffset=twPtr->RestPosition;
3303 	}
3304 
3305 	if (twPtr->WeaponInitFunction!=NULL) {
3306 		(*twPtr->WeaponInitFunction)(weaponPtr);
3307 	}
3308 
3309 }
3310 
GrabMuzzleFlashShape(TEMPLATE_WEAPON_DATA * twPtr)3311 void GrabMuzzleFlashShape(TEMPLATE_WEAPON_DATA *twPtr)
3312 {
3313 	#if 0
3314 	/* if there is no shape name then return */
3315 	if (twPtr->MuzzleFlashShapeName == NULL) return;
3316 
3317 	/* otherwise setup displayblock */
3318 	PlayersWeaponMuzzleFlash.ObShape = GetLoadedShapeMSL(twPtr->MuzzleFlashShapeName);
3319 	LOCALASSERT(PlayersWeaponMuzzleFlash.ObShape>0);
3320 
3321    	PlayersWeaponMuzzleFlash.ObFlags  = ObFlag_NoInfLSrc|ObFlag_MultLSrc;
3322 	PlayersWeaponMuzzleFlash.ObFlags2 = 0;
3323 	PlayersWeaponMuzzleFlash.ObFlags3 = ObFlag3_NoLightDot;
3324 
3325   	PlayersWeaponMuzzleFlash.ObLightType = LightType_PerVertex;
3326 
3327   	{
3328   		SHAPEHEADER *shapePtr = GetShapeData(PlayersWeaponMuzzleFlash.ObShape);
3329 	   	MuzzleFlashLength = -shapePtr->shapeminz;
3330 	}
3331 	#endif
3332 }
3333 
3334 
FindEndOfShape(VECTORCH * endPositionPtr,int shapeIndex)3335 void FindEndOfShape(VECTORCH* endPositionPtr, int shapeIndex)
3336 {
3337 	extern int SetupPolygonAccessFromShapeIndex(int shapeIndex);
3338 	int max_z = 0;
3339    	int pointsFound = 0;
3340 	int numberOfItems;
3341 
3342 	{
3343 		SHAPEHEADER *shapePtr = GetShapeData(shapeIndex);
3344 		LOCALASSERT(shapePtr);
3345 		max_z = shapePtr->shapemaxz;
3346 	}
3347 	endPositionPtr->vx = 0;
3348 	endPositionPtr->vy = 0;
3349 	endPositionPtr->vz = max_z;
3350 
3351 	numberOfItems = SetupPolygonAccessFromShapeIndex(shapeIndex);
3352 
3353 	/* go through polys and get the average position of all the
3354 	points whose z value is near the max z of the shape */
3355 	while(numberOfItems)
3356 	{
3357 		AccessNextPolygon();
3358 		{
3359 			struct ColPolyTag polyData;
3360 	        GetPolygonVertices(&polyData);
3361 
3362 		   	{
3363 		 		VECTORCH *vertexPtr = &polyData.PolyPoint[0];
3364 			 	int noOfVertices = polyData.NumberOfVertices;
3365 				do
3366 		 		{
3367 					int z = vertexPtr->vz;
3368 
3369 					if (z >= max_z-5)
3370 					{
3371 						endPositionPtr->vx += vertexPtr->vx;
3372 						endPositionPtr->vy += vertexPtr->vy;
3373 						pointsFound++;
3374 					}
3375 
3376 					vertexPtr++;
3377 		 			noOfVertices--;
3378 		 		}
3379 				while(noOfVertices);
3380 		 	}
3381 		}
3382 		numberOfItems--;
3383 	}
3384 	LOCALASSERT(pointsFound!=0);
3385 	endPositionPtr->vx /= pointsFound;
3386 	endPositionPtr->vy /= pointsFound;
3387 
3388     return;
3389 }
3390 
3391 
3392 #if 0
3393 static void FireLineOfSightAmmo(enum AMMO_ID AmmoID, VECTORCH* sourcePtr, VECTORCH* directionPtr, int multiple)
3394 {
3395 	#if 0
3396 	LOS_Lambda = 10000000;
3397 	LOS_ObjectHitPtr = 0;
3398 	LOS_HModel_Section=NULL;
3399 	{
3400 	   	extern int NumActiveBlocks;
3401 		extern DISPLAYBLOCK* ActiveBlockList[];
3402 	   	int numberOfObjects = NumActiveBlocks;
3403 
3404 	   	while (numberOfObjects--)
3405 		{
3406 			DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects];
3407 			VECTORCH alpha = *sourcePtr;
3408 			VECTORCH beta = *directionPtr;
3409 			GLOBALASSERT(objectPtr);
3410 
3411 			CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1);
3412 		}
3413 	}
3414   	#else
3415 	FindPolygonInLineOfSight(directionPtr,sourcePtr,0,NULL);
3416 	#endif
3417 
3418 	if (LOS_ObjectHitPtr)
3419 	{
3420 		/* this fn needs updating to take amount of damage into account etc. */
3421 		if (LOS_ObjectHitPtr->ObStrategyBlock) {
3422 			if ((LOS_ObjectHitPtr->ObStrategyBlock->SBdptr)&&(LOS_HModel_Section)) {
3423 				GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller);
3424 			}
3425 		}
3426 
3427 		HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,directionPtr, multiple*ONE_FIXED, LOS_HModel_Section);
3428 	}
3429 }
3430 #endif
3431 
3432 
CalculateTorque(EULER * rotationPtr,VECTORCH * directionPtr,STRATEGYBLOCK * sbPtr)3433 static void CalculateTorque(EULER *rotationPtr, VECTORCH *directionPtr, STRATEGYBLOCK *sbPtr)
3434 {
3435 	VECTORCH point,absPoint;
3436 	int intersectionPlane;
3437 	DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3438 
3439 	{
3440 		MATRIXCH mat=dynPtr->OrientMat;
3441 		TransposeMatrixCH(&mat);
3442 
3443 		point.vx = directionPtr->vx - dynPtr->Position.vx;
3444 		point.vy = directionPtr->vy - dynPtr->Position.vy;
3445 		point.vz = directionPtr->vz - dynPtr->Position.vz;
3446 
3447 		RotateVector(&point,&mat);
3448 	}
3449 
3450 	absPoint=point;
3451 	if (absPoint.vx<0) absPoint.vx = -absPoint.vx;
3452 	if (absPoint.vy<0) absPoint.vy = -absPoint.vy;
3453 	if (absPoint.vz<0) absPoint.vz = -absPoint.vz;
3454 
3455 	/* KJL 16:59:03 03/06/97 - paranoia check */
3456 	LOCALASSERT(absPoint.vx>=0);
3457 	LOCALASSERT(absPoint.vy>=0);
3458 	LOCALASSERT(absPoint.vz>=0);
3459 
3460 	if (absPoint.vx > absPoint.vz)
3461 	{
3462 		if (absPoint.vx > absPoint.vy)
3463 		{
3464 			intersectionPlane = ix;
3465 		}
3466 		else
3467 		{
3468 			intersectionPlane = iy;
3469 		}
3470 	}
3471 	else
3472 	{
3473 		if (absPoint.vz > absPoint.vy)
3474 		{
3475 			intersectionPlane = iz;
3476 		}
3477 		else
3478 		{
3479 			intersectionPlane = iy;
3480 		}
3481 	}
3482 
3483 	switch (intersectionPlane)
3484 	{
3485 		case ix:
3486 		{
3487 
3488 			rotationPtr->EulerX = 0;
3489 			rotationPtr->EulerY = -DIV_FIXED(point.vz,point.vx);
3490 			rotationPtr->EulerZ = DIV_FIXED(point.vy,point.vx);
3491 
3492 			break;
3493 		}
3494 		case iy:
3495 		{
3496 			rotationPtr->EulerX = DIV_FIXED(point.vz,point.vy);
3497 			rotationPtr->EulerY = 0;
3498 			rotationPtr->EulerZ = -DIV_FIXED(point.vx,point.vy);
3499 
3500 			break;
3501 		}
3502 		case iz:
3503 		{
3504 			rotationPtr->EulerX = -DIV_FIXED(point.vy,point.vz);
3505 			rotationPtr->EulerY = DIV_FIXED(point.vx,point.vz);
3506 			rotationPtr->EulerZ = 0;
3507 
3508 			break;
3509 		}
3510 		default:
3511 			break;
3512 	}
3513 
3514 }
3515 
3516 
CalculateTorqueAtPoint(EULER * rotationPtr,VECTORCH * pointPtr,STRATEGYBLOCK * sbPtr)3517 static void CalculateTorqueAtPoint(EULER *rotationPtr, VECTORCH *pointPtr, STRATEGYBLOCK *sbPtr)
3518 {
3519 	#if 0
3520 	DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3521 	VECTORCH point;
3522 	VECTORCH rotationDirection;
3523 	int rotationMagnitude;
3524 
3525 	point.vx = pointPtr->vx - dynPtr->Position.vx;
3526 	point.vy = pointPtr->vy - dynPtr->Position.vy;
3527 	point.vz = pointPtr->vz - dynPtr->Position.vz;
3528 
3529 	CrossProduct(pointPtr, directionPtr, &rotationDirection);
3530 
3531 	rotationMagnitude = Magnitude(&rotationDirection);
3532 
3533 	/* normalise direction */
3534 	rotationDirection.vx = DIV_FIXED(rotationDirection.vx,rotationMagnitude);
3535 	rotationDirection.vy = DIV_FIXED(rotationDirection.vy,rotationMagnitude);
3536 	rotationDirection.vz = DIV_FIXED(rotationDirection.vz,rotationMagnitude);
3537 
3538 	{
3539 	//	MATRIXCH matrix,mat;
3540 	//	MakeMatrixFromDirection(directionPtr, &matrix);
3541 
3542 	//	MatrixMultiply(&mat,&matrix,&mat);
3543 	//	MatrixToEuler(&mat,rotationPtr);
3544 	}
3545 
3546 	#else
3547 	VECTORCH normal,point;
3548 	int intersectionPlane;
3549 	DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3550 
3551 	/* if the strategy block doesn't have a dynamics or display block, skip it */
3552 	if (!(dynPtr) || !(sbPtr->SBdptr)) return;
3553 	{
3554 		MATRIXCH mat=dynPtr->OrientMat;
3555 		TransposeMatrixCH(&mat);
3556 
3557 		point.vx = pointPtr->vx - dynPtr->Position.vx;
3558 		point.vy = pointPtr->vy - dynPtr->Position.vy;
3559 		point.vz = pointPtr->vz - dynPtr->Position.vz;
3560 
3561 		RotateVector(&point,&mat);
3562 
3563  //		normal = *normalPtr;
3564  //		RotateVector(&normal,&mat);
3565 		normal = point;
3566 	}
3567 
3568 	{
3569 		VECTORCH absNormal = normal;
3570 		if (absNormal.vx<0) absNormal.vx=-absNormal.vx;
3571 		if (absNormal.vy<0) absNormal.vy=-absNormal.vy;
3572 		if (absNormal.vz<0) absNormal.vz=-absNormal.vz;
3573 
3574 		if (absNormal.vx > absNormal.vy)
3575 		{
3576 			if (absNormal.vx > absNormal.vz)
3577 			{
3578 				intersectionPlane = ix;
3579 			}
3580 			else
3581 			{
3582 				intersectionPlane = iz;
3583 	 		}
3584 		}
3585 		else
3586 		{
3587 			if (absNormal.vy > absNormal.vz)
3588 			{
3589 				intersectionPlane = iy;
3590 			}
3591 			else
3592 			{
3593 				intersectionPlane = iz;
3594 			}
3595 		}
3596 	}
3597 
3598 
3599 
3600 	switch (intersectionPlane)
3601 	{
3602 		case ix:
3603 		{
3604 
3605 			rotationPtr->EulerX = 0;
3606 			if (point.vx>0)
3607 			{
3608 				rotationPtr->EulerY = -point.vz;
3609 	   			rotationPtr->EulerZ = point.vy;
3610 			}
3611 			else
3612 			{
3613 		 		rotationPtr->EulerY = point.vz;
3614 		   		rotationPtr->EulerZ = -point.vy;
3615 			}
3616 			break;
3617 		}
3618 		case iy:
3619 		{
3620 			rotationPtr->EulerY = 0;
3621 
3622 			if (point.vy>0)
3623 			{
3624 	   			rotationPtr->EulerX = point.vz;
3625 		 		rotationPtr->EulerZ = -point.vx;
3626 			}
3627 			else
3628 			{
3629 			 	rotationPtr->EulerX = -point.vz;
3630 		   		rotationPtr->EulerZ = point.vx;
3631 			}
3632 			break;
3633 		}
3634 		case iz:
3635 		{
3636 			rotationPtr->EulerZ = 0;
3637 			if (point.vz>0)
3638 			{
3639 		  		rotationPtr->EulerX = -point.vy;
3640 				rotationPtr->EulerY = point.vx;
3641 			}
3642 			else
3643 			{
3644 				rotationPtr->EulerX = point.vy;
3645 				rotationPtr->EulerY = -point.vx;
3646 			}
3647 			break;
3648 		}
3649 		default:
3650 			break;
3651 	}
3652 	{
3653 		SHAPEHEADER	*shapePtr = GetShapeData(sbPtr->SBdptr->ObShape);
3654 		rotationPtr->EulerX=DIV_FIXED(rotationPtr->EulerX, shapePtr->shaperadius);
3655 		rotationPtr->EulerY=DIV_FIXED(rotationPtr->EulerY, shapePtr->shaperadius);
3656 		rotationPtr->EulerZ=DIV_FIXED(rotationPtr->EulerZ, shapePtr->shaperadius);
3657 	}
3658 	#if 0
3659 	{
3660 		MATRIXCH mat;
3661 		CreateEulerMatrix(rotationPtr, &mat);
3662    		TransposeMatrixCH(&mat);
3663 
3664 		MatrixMultiply(&mat,&(dynPtr->OrientMat),&mat);
3665 		MatrixToEuler(&mat,rotationPtr);
3666 
3667 	}
3668 	#else
3669 	{
3670 //		RotateVector((VECTORCH *)(rotationPtr),&(dynPtr->OrientMat));
3671  	}
3672 	#endif
3673 	#endif
3674 }
3675 
3676 
3677 
AlienTailTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3678 void AlienTailTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3679 {
3680 //    TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3681 	VECTORCH startDir = {0,-65536,0};
3682 	VECTORCH endDir = {37837,37837,37837};
3683 	VECTORCH direction;
3684 	int timeLeft = (weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)? weaponPtr->StateTimeOutCounter:65536-weaponPtr->StateTimeOutCounter;
3685 	int timeDone = 65536-timeLeft;
3686 
3687 	weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,300);
3688 	weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,0);
3689 	weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,500);
3690 
3691 	direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED);
3692 	direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED);
3693 	direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED);
3694 	Normalise(&direction);
3695 
3696 	MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat));
3697 	{
3698 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3699 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3700 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
3701 
3702 		TransposeMatrixCH(&matrix);
3703 		MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat);
3704 	}
3705 }
3706 
MeleeWeaponNullTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3707 void MeleeWeaponNullTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3708 {
3709 	weaponPtr->PositionOffset.vz = -100000;
3710 }
3711 
AlienClawTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3712 void AlienClawTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3713 {
3714 //    TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3715 	VECTORCH startDir = {-65536,0,0};
3716 	VECTORCH endDir = {-2,0,65535};
3717 	VECTORCH direction;
3718 	int timeLeft = weaponPtr->StateTimeOutCounter;
3719 	int timeDone = 65536-timeLeft;
3720 
3721 	weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,600);
3722 	weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,-200);
3723 	weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,400);
3724 
3725 	direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED);
3726 	direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED);
3727 	direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED);
3728 	Normalise(&direction);
3729 //	direction = endDir;
3730 
3731 	MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat));
3732 	{
3733 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3734 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3735 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
3736 
3737 		TransposeMatrixCH(&matrix);
3738 		MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat);
3739 	}
3740 	PlayersWeapon.ObMat.mat21 = -PlayersWeapon.ObMat.mat21;
3741 	PlayersWeapon.ObMat.mat22 = -PlayersWeapon.ObMat.mat22;
3742 	PlayersWeapon.ObMat.mat23 = -PlayersWeapon.ObMat.mat23;
3743 	PlayersWeapon.ObMat.mat11 = -PlayersWeapon.ObMat.mat11;
3744 	PlayersWeapon.ObMat.mat12 = -PlayersWeapon.ObMat.mat12;
3745 	PlayersWeapon.ObMat.mat13 = -PlayersWeapon.ObMat.mat13;
3746 }
AlienClawEndTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3747 void AlienClawEndTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3748 {
3749 //    TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3750 	VECTORCH startDir = {-2,0,65535};
3751 	VECTORCH endDir = {-2,0,65535};
3752 	VECTORCH direction;
3753 	int timeLeft = weaponPtr->StateTimeOutCounter;
3754 	int timeDone = 65536-timeLeft;
3755 
3756 	weaponPtr->PositionOffset.vx = 600+MUL_FIXED(timeDone,200);
3757 	weaponPtr->PositionOffset.vy = -200+MUL_FIXED(timeDone,300);
3758 	weaponPtr->PositionOffset.vz = 400+MUL_FIXED(timeDone,-400);
3759 
3760 	direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED);
3761 	direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED);
3762 	direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED);
3763 	Normalise(&direction);
3764 
3765 	MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat));
3766 	{
3767 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3768 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3769 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
3770 
3771 		TransposeMatrixCH(&matrix);
3772 		MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat);
3773 	}
3774 	PlayersWeapon.ObMat.mat21 = -PlayersWeapon.ObMat.mat21;
3775 	PlayersWeapon.ObMat.mat22 = -PlayersWeapon.ObMat.mat22;
3776 	PlayersWeapon.ObMat.mat23 = -PlayersWeapon.ObMat.mat23;
3777 	PlayersWeapon.ObMat.mat11 = -PlayersWeapon.ObMat.mat11;
3778 	PlayersWeapon.ObMat.mat12 = -PlayersWeapon.ObMat.mat12;
3779 	PlayersWeapon.ObMat.mat13 = -PlayersWeapon.ObMat.mat13;
3780 }
3781 
PredWristbladeTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3782 void PredWristbladeTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3783 {
3784 //    TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3785 	VECTORCH startDir = {0,0,65536};
3786 	VECTORCH endDir = {-37837,-37837,37837};
3787 	VECTORCH direction;
3788 	int timeLeft = ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))? weaponPtr->StateTimeOutCounter:65536-weaponPtr->StateTimeOutCounter;
3789 	int timeDone = 65536-timeLeft;
3790 
3791 	weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,-200);
3792 	weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,-50);
3793 	weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,900);
3794 
3795 	direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED);
3796 	direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED);
3797 	direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED);
3798 	Normalise(&direction);
3799 
3800 	MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat));
3801 	{
3802 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3803 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3804 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
3805 
3806 		TransposeMatrixCH(&matrix);
3807 		MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat);
3808 	}
3809 }
3810 
3811 
3812 
3813 
3814 
3815 /* in mm */
3816 //#define ACTIVATION_Z_RANGE 3000
3817 //#define ACTIVATION_X_RANGE 500
3818 //#define ACTIVATION_Y_RANGE 500
3819 
3820 #define ACTIVATION_Z_RANGE 4000
3821 #define ACTIVATION_X_RANGE 2000
3822 #define ACTIVATION_Y_RANGE 2000
3823 
DamageObjectInLineOfSight(PLAYER_WEAPON_DATA * weaponPtr)3824 int DamageObjectInLineOfSight(PLAYER_WEAPON_DATA *weaponPtr)
3825 {
3826 	int numberOfObjects = NumOnScreenBlocks;
3827 	enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
3828 
3829 	while (numberOfObjects)
3830 	{
3831 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
3832 		STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
3833 		GLOBALASSERT(objectPtr);
3834 
3835 		/* does object have a strategy block? */
3836 		if (sbPtr)
3837 		{
3838 			/* is it in range? */
3839 			if (objectPtr->ObView.vz > 0 && objectPtr->ObView.vz < ACTIVATION_Z_RANGE)
3840 			{
3841 				int screenX = objectPtr->ObView.vx;
3842 			   	int screenY = objectPtr->ObView.vy;
3843 
3844 				if (screenX<0) screenX=-screenX;
3845 				if (screenY<0) screenY=-screenY;
3846 				screenX-=objectPtr->ObMaxX;
3847 				screenY-=objectPtr->ObMaxY;
3848 
3849 				if (screenX < ACTIVATION_X_RANGE && screenY < ACTIVATION_Y_RANGE)
3850 				{
3851 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3852 			  	  	if (dynPtr)
3853 					{
3854 						int magnitudeOfForce = (5000*TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty].Cutting) / dynPtr->Mass;
3855 				  	  	dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce);
3856 						dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce);
3857 				  	  	dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce);
3858 			  			CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3859 					}
3860 			  	}
3861 			}
3862 		}
3863 	}
3864 
3865 
3866 	return(1);
3867 }
3868 
3869 
PredDiscThrowTrajectory(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)3870 void PredDiscThrowTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr)
3871 {
3872 //  TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
3873 	EULER startorient = {0,0,1024};
3874 	EULER endorient = {-1024,0,1024};
3875 	EULER orient;
3876 	VECTORCH startpoint= {400,-50,900};
3877 	VECTORCH endpoint= {-800,-50,200};
3878 	int timeLeft = weaponPtr->StateTimeOutCounter;
3879 	int timeDone = 65536-timeLeft;
3880 
3881 	weaponPtr->PositionOffset.vx = WideMul2NarrowDiv(startpoint.vx, timeLeft, endpoint.vx, timeDone, ONE_FIXED);
3882 	weaponPtr->PositionOffset.vy = WideMul2NarrowDiv(startpoint.vy, timeLeft, endpoint.vy, timeDone, ONE_FIXED);
3883 	weaponPtr->PositionOffset.vz = WideMul2NarrowDiv(startpoint.vz, timeLeft, endpoint.vz, timeDone, ONE_FIXED);
3884 
3885 	orient.EulerX = WideMul2NarrowDiv(startorient.EulerX, timeLeft, endorient.EulerX, timeDone, ONE_FIXED);
3886 	orient.EulerY = WideMul2NarrowDiv(startorient.EulerY, timeLeft, endorient.EulerY, timeDone, ONE_FIXED);
3887 	orient.EulerZ = WideMul2NarrowDiv(startorient.EulerZ, timeLeft, endorient.EulerZ, timeDone, ONE_FIXED);
3888 
3889 	CreateEulerMatrix(&orient,&(PlayersWeapon.ObMat));
3890 
3891 	{
3892 		extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3893 		VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3894 		MATRIXCH matrix	= VDBPtr->VDB_Mat;
3895 
3896 		TransposeMatrixCH(&matrix);
3897 		MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat);
3898 	}
3899 }
3900 
DamageDamageBlock(DAMAGEBLOCK * DBPtr,DAMAGE_PROFILE * damage,int multiple)3901 static void DamageDamageBlock(DAMAGEBLOCK *DBPtr, DAMAGE_PROFILE *damage, int multiple) {
3902 
3903 	/* Separate function to ease writing clarity. */
3904 
3905 	int ArmourDamage;
3906 	int HealthDamage;
3907 	int Fraction;
3908 	int Integer;
3909 
3910 	Fraction=multiple&(ONE_FIXED-1);
3911 	Integer=multiple>>ONE_FIXED_SHIFT;
3912 
3913 	/* We must apply damage sequentially. Fraction first, then each 'multiple'.
3914 	Otherwise, an armour damaging attack hitting multiple times in one frame
3915 	would behave differently depending on the framerate.  Sure, that case might
3916 	never arise, but that's not the point!
3917 	*/
3918 
3919 	if (DBPtr->SB_H_flags.Indestructable) {
3920 		return;
3921 	}
3922 
3923 	if (Fraction) {
3924 
3925 		ArmourDamage=0;
3926 		HealthDamage=0;
3927 
3928 		if (damage->Impact) {
3929 			int unblocked,tempdamage;
3930 			/* Impact damage. */
3931 			tempdamage=damage->Impact*Fraction;
3932 			HealthDamage+=tempdamage/10;
3933 
3934 			//unblocked=tempdamage-DBPtr->Armour;
3935 			unblocked=MUL_FIXED(((damage->Impact*ONE_FIXED)-DBPtr->Armour),Fraction);
3936 			if (unblocked>0) {
3937 				HealthDamage+=unblocked;
3938 			}
3939 			tempdamage>>=4;
3940 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
3941 				ArmourDamage+=tempdamage;
3942 			}
3943 		}
3944 
3945 		if (damage->Cutting) {
3946 			int unblocked,tempdamage;
3947 			/* Cutting damage. */
3948 			tempdamage=damage->Cutting*Fraction;
3949 			HealthDamage+=tempdamage>>2;
3950 
3951 			//unblocked=tempdamage-DBPtr->Armour;
3952 			unblocked=MUL_FIXED(((damage->Cutting*ONE_FIXED)-DBPtr->Armour),Fraction);
3953 
3954 			if (unblocked>0) {
3955 				HealthDamage+=unblocked;
3956 			}
3957 			tempdamage>>=3;
3958 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
3959 				ArmourDamage+=tempdamage;
3960 			}
3961 		}
3962 
3963 		if (damage->Penetrative) {
3964 			int unblocked,tempdamage;
3965 			/* Penetrative damage. */
3966 			tempdamage=damage->Penetrative*Fraction;
3967 			HealthDamage+=tempdamage/10;
3968 
3969 			//unblocked=tempdamage-(DBPtr->Armour>>6);
3970 			unblocked=MUL_FIXED(((damage->Penetrative*ONE_FIXED)-(DBPtr->Armour>>6)),Fraction);
3971 
3972 			if (unblocked>0) {
3973 				HealthDamage+=unblocked;
3974 			}
3975 			tempdamage>>=4;
3976 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
3977 				ArmourDamage+=tempdamage;
3978 			}
3979 		}
3980 
3981 		if ((damage->Fire)&&(DBPtr->SB_H_flags.FireResistant==0)) {
3982 			int tempdamage;
3983 			/* Fire damage. */
3984 			tempdamage=damage->Fire*Fraction;
3985 			if (DBPtr->SB_H_flags.Combustability==2) {
3986 				tempdamage<<=1;
3987 			} else if (DBPtr->SB_H_flags.Combustability==3) {
3988 				tempdamage>>=2;
3989 			}
3990 			HealthDamage+=tempdamage;
3991 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
3992 				ArmourDamage+=tempdamage>>3;
3993 			}
3994 		}
3995 
3996 		if ((damage->Electrical)&&(DBPtr->SB_H_flags.ElectricResistant==0)) {
3997 			int tempdamage;
3998 			/* Electrical damage. */
3999 			tempdamage=damage->Electrical*Fraction;
4000 			if (DBPtr->SB_H_flags.ElectricSensitive) {
4001 				tempdamage<<=2;
4002 			}
4003 			HealthDamage+=tempdamage;
4004 		}
4005 
4006 		if ((damage->Acid)&&(DBPtr->SB_H_flags.AcidResistant==0)) {
4007 			int unblocked,tempdamage;
4008 			/* Acid damage. */
4009 			tempdamage=damage->Acid*Fraction;
4010 			unblocked=0;
4011 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4012 				if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
4013 					ArmourDamage+=tempdamage;
4014 					if (ArmourDamage>DBPtr->Armour) {
4015 						/* Now we're through. */
4016 						unblocked=tempdamage-DBPtr->Armour;
4017 					}
4018 				} else {
4019 					ArmourDamage+=(tempdamage>>1);
4020 					if (ArmourDamage>DBPtr->Armour) {
4021 						/* Now we're through. */
4022 						unblocked=tempdamage-(DBPtr->Armour<<1);
4023 					}
4024 				}
4025 			}
4026 			if (unblocked>0) {
4027 				HealthDamage+=unblocked;
4028 			}
4029 		}
4030 
4031 		/* Apply Damage. */
4032 
4033 		if (ArmourDamage>0) {
4034 			if (DBPtr->Armour<ArmourDamage) DBPtr->Armour=0;
4035 			else DBPtr->Armour-=ArmourDamage;
4036 		}
4037 
4038 		if (HealthDamage>0) {
4039 			if (DBPtr->Health<HealthDamage) DBPtr->Health=0;
4040 			else DBPtr->Health-=HealthDamage;
4041 		}
4042 
4043 	}
4044 
4045 	/* Now, the integer. */
4046 
4047 	while (Integer) {
4048 
4049 		ArmourDamage=0;
4050 		HealthDamage=0;
4051 
4052 		if (damage->Impact) {
4053 			int unblocked,tempdamage;
4054 			/* Impact damage. */
4055 			tempdamage=damage->Impact*ONE_FIXED;
4056 			HealthDamage+=tempdamage/10;
4057 			unblocked=tempdamage-DBPtr->Armour;
4058 			if (unblocked>0) {
4059 				HealthDamage+=unblocked;
4060 			}
4061 			tempdamage>>=4;
4062 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4063 				ArmourDamage+=tempdamage;
4064 			}
4065 		}
4066 
4067 		if (damage->Cutting) {
4068 			int unblocked,tempdamage;
4069 			/* Cutting damage. */
4070 			tempdamage=damage->Cutting*ONE_FIXED;
4071 			HealthDamage+=tempdamage>>2;
4072 			unblocked=tempdamage-DBPtr->Armour;
4073 			if (unblocked>0) HealthDamage+=unblocked;
4074 			tempdamage>>=3;
4075 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4076 				ArmourDamage+=tempdamage;
4077 			}
4078 		}
4079 
4080 		if (damage->Penetrative) {
4081 			int unblocked,tempdamage;
4082 			/* Penetrative damage. */
4083 			tempdamage=damage->Penetrative*ONE_FIXED;
4084 			HealthDamage+=tempdamage/10;
4085 			unblocked=tempdamage-(DBPtr->Armour>>6);
4086 			if (unblocked>0) {
4087 				HealthDamage+=unblocked;
4088 			}
4089 			tempdamage>>=4;
4090 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4091 				ArmourDamage+=tempdamage;
4092 			}
4093 		}
4094 
4095 		if ((damage->Fire)&&(DBPtr->SB_H_flags.FireResistant==0)) {
4096 			int tempdamage;
4097 			/* Fire damage. */
4098 			tempdamage=damage->Fire*ONE_FIXED;
4099 			if (DBPtr->SB_H_flags.Combustability==2) {
4100 				tempdamage<<=1;
4101 			} else if (DBPtr->SB_H_flags.Combustability==3) {
4102 				tempdamage>>=2;
4103 			}
4104 			HealthDamage+=tempdamage;
4105 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4106 				ArmourDamage+=tempdamage>>3;
4107 			}
4108 		}
4109 
4110 		if ((damage->Electrical)&&(DBPtr->SB_H_flags.ElectricResistant==0)) {
4111 			int tempdamage;
4112 			/* Electrical damage. */
4113 			tempdamage=damage->Electrical*ONE_FIXED;
4114 			if (DBPtr->SB_H_flags.ElectricSensitive) {
4115 				tempdamage<<=2;
4116 			}
4117 			HealthDamage+=tempdamage;
4118 		}
4119 
4120 		if ((damage->Acid)&&(DBPtr->SB_H_flags.AcidResistant==0)) {
4121 			int unblocked,tempdamage;
4122 			/* Acid damage. */
4123 			tempdamage=damage->Acid*ONE_FIXED;
4124 			unblocked=0;
4125 			if (DBPtr->SB_H_flags.PerfectArmour==0) {
4126 				if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
4127 					ArmourDamage+=tempdamage;
4128 					if (ArmourDamage>DBPtr->Armour) {
4129 						/* Now we're through. */
4130 						unblocked=tempdamage-DBPtr->Armour;
4131 					}
4132 				} else {
4133 					ArmourDamage+=(tempdamage>>1);
4134 					if (ArmourDamage>DBPtr->Armour) {
4135 						/* Now we're through. */
4136 						unblocked=tempdamage-(DBPtr->Armour<<1);
4137 					}
4138 				}
4139 			}
4140 			if (unblocked>0) {
4141 				HealthDamage+=unblocked;
4142 			}
4143 		}
4144 
4145 		/* Apply Damage. */
4146 
4147 		if (ArmourDamage>0) {
4148 			if (DBPtr->Armour<ArmourDamage) DBPtr->Armour=0;
4149 			else DBPtr->Armour-=ArmourDamage;
4150 		}
4151 
4152 		if (HealthDamage>0) {
4153 			if (DBPtr->Health<HealthDamage) DBPtr->Health=0;
4154 			else DBPtr->Health-=HealthDamage;
4155 		}
4156 
4157 		Integer--;
4158 
4159 	}
4160 
4161 }
4162 
InitThisWeapon(PLAYER_WEAPON_DATA * pwPtr)4163 void InitThisWeapon(PLAYER_WEAPON_DATA *pwPtr) {
4164 
4165 	TEMPLATE_WEAPON_DATA *twPtr;
4166 	int shapenum;
4167 	SHAPEHEADER *shptr;
4168 
4169 	if (pwPtr->WeaponIDNumber==NULL_WEAPON) {
4170 		/* D'oh! */
4171 		pwPtr->TxAnimCtrl=NULL;
4172 		pwPtr->ShpAnimCtrl.current.seconds_per_frame=0;
4173 		pwPtr->ShpAnimCtrl.current.sequence_no=0;
4174 		pwPtr->ShpAnimCtrl.current.start_frame=0;
4175 		pwPtr->ShpAnimCtrl.current.end_frame=0;
4176 		pwPtr->ShpAnimCtrl.current.default_start_and_end_frames=0;
4177 		pwPtr->ShpAnimCtrl.current.reversed=0;
4178 		pwPtr->ShpAnimCtrl.current.stop_at_end=0;
4179 		pwPtr->ShpAnimCtrl.current.empty=0;
4180 		pwPtr->ShpAnimCtrl.current.stop_now=0;
4181 		pwPtr->ShpAnimCtrl.current.pause_at_end=0;
4182 		pwPtr->ShpAnimCtrl.current.done_a_frame=0;
4183 		pwPtr->ShpAnimCtrl.current.sequence=NULL;
4184 		pwPtr->ShpAnimCtrl.current.current_frame=0;
4185 		pwPtr->ShpAnimCtrl.current.time_to_next_frame=0;
4186 
4187 		pwPtr->ShpAnimCtrl.next.seconds_per_frame=0;
4188 		pwPtr->ShpAnimCtrl.next.sequence_no=0;
4189 		pwPtr->ShpAnimCtrl.next.start_frame=0;
4190 		pwPtr->ShpAnimCtrl.next.end_frame=0;
4191 		pwPtr->ShpAnimCtrl.next.default_start_and_end_frames=0;
4192 		pwPtr->ShpAnimCtrl.next.reversed=0;
4193 		pwPtr->ShpAnimCtrl.next.stop_at_end=0;
4194 		pwPtr->ShpAnimCtrl.next.empty=0;
4195 		pwPtr->ShpAnimCtrl.next.stop_now=0;
4196 		pwPtr->ShpAnimCtrl.next.pause_at_end=0;
4197 		pwPtr->ShpAnimCtrl.next.done_a_frame=0;
4198 		pwPtr->ShpAnimCtrl.next.sequence=NULL;
4199 		pwPtr->ShpAnimCtrl.next.current_frame=0;
4200 		pwPtr->ShpAnimCtrl.next.time_to_next_frame=0;
4201 
4202 		pwPtr->ShpAnimCtrl.finished=0;
4203 		pwPtr->ShpAnimCtrl.playing=0;
4204 		pwPtr->ShpAnimCtrl.anim_header=NULL;
4205 		return;
4206 	}
4207 
4208 	twPtr=&TemplateWeapon[pwPtr->WeaponIDNumber];
4209 
4210 	if (twPtr->WeaponShapeName==NULL) return;
4211 	/* Got to allow for GetLoadedShapeMSL not being bomb-proof. */
4212 
4213 	shapenum = GetLoadedShapeMSL(twPtr->WeaponShapeName);
4214 	shptr=GetShapeData(shapenum);
4215 
4216 	if (twPtr->HasTextureAnimation) {
4217 		int item_num;
4218 		TXACTRLBLK **pptxactrlblk;
4219 
4220 		pptxactrlblk = &pwPtr->TxAnimCtrl;
4221 
4222 		SetupPolygonFlagAccessForShape(shptr);
4223 
4224 		for(item_num = 0; item_num < shptr->numitems; item_num ++)
4225 		{
4226 			POLYHEADER *poly =  (POLYHEADER*)(shptr->items[item_num]);
4227 			LOCALASSERT(poly);
4228 
4229 			if((Request_PolyFlags((void *)poly)) & iflag_txanim)
4230 			{
4231 				TXACTRLBLK *pnew_txactrlblk;
4232 
4233 				pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK));
4234 
4235 				if (pnew_txactrlblk)
4236 				{
4237 					// We have allocated the new tx anim control block so initialise it
4238 
4239 					pnew_txactrlblk->tac_flags = 0;
4240 					pnew_txactrlblk->tac_item = item_num;
4241 					pnew_txactrlblk->tac_sequence = 0;
4242 					pnew_txactrlblk->tac_node = 0;
4243 					pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shapenum, item_num);
4244 					pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shapenum);
4245 
4246 					pnew_txactrlblk->tac_txah.txa_currentframe = 0;
4247 					pnew_txactrlblk->tac_txah.txa_flags |= txa_flag_play;
4248 
4249 					/* change the value held in pptxactrlblk
4250 					 which point to the previous structures "next"
4251 				 	pointer*/
4252 
4253 					*pptxactrlblk = pnew_txactrlblk;
4254 					pptxactrlblk = &pnew_txactrlblk->tac_next;
4255 				}
4256 
4257 			}
4258 		}
4259 		*pptxactrlblk=0;
4260 
4261 	} else {
4262 		pwPtr->TxAnimCtrl=NULL;
4263 	}
4264 
4265 	/* Now the shape animation... */
4266 
4267 	if (twPtr->HasShapeAnimation) {
4268 		InitShapeAnimationController(&pwPtr->ShpAnimCtrl,shptr);
4269 	} else {
4270 		pwPtr->ShpAnimCtrl.current.seconds_per_frame=0;
4271 		pwPtr->ShpAnimCtrl.current.sequence_no=0;
4272 		pwPtr->ShpAnimCtrl.current.start_frame=0;
4273 		pwPtr->ShpAnimCtrl.current.end_frame=0;
4274 		pwPtr->ShpAnimCtrl.current.default_start_and_end_frames=0;
4275 		pwPtr->ShpAnimCtrl.current.reversed=0;
4276 		pwPtr->ShpAnimCtrl.current.stop_at_end=0;
4277 		pwPtr->ShpAnimCtrl.current.empty=0;
4278 		pwPtr->ShpAnimCtrl.current.stop_now=0;
4279 		pwPtr->ShpAnimCtrl.current.pause_at_end=0;
4280 		pwPtr->ShpAnimCtrl.current.done_a_frame=0;
4281 		pwPtr->ShpAnimCtrl.current.sequence=NULL;
4282 		pwPtr->ShpAnimCtrl.current.current_frame=0;
4283 		pwPtr->ShpAnimCtrl.current.time_to_next_frame=0;
4284 
4285 		pwPtr->ShpAnimCtrl.next.seconds_per_frame=0;
4286 		pwPtr->ShpAnimCtrl.next.sequence_no=0;
4287 		pwPtr->ShpAnimCtrl.next.start_frame=0;
4288 		pwPtr->ShpAnimCtrl.next.end_frame=0;
4289 		pwPtr->ShpAnimCtrl.next.default_start_and_end_frames=0;
4290 		pwPtr->ShpAnimCtrl.next.reversed=0;
4291 		pwPtr->ShpAnimCtrl.next.stop_at_end=0;
4292 		pwPtr->ShpAnimCtrl.next.empty=0;
4293 		pwPtr->ShpAnimCtrl.next.stop_now=0;
4294 		pwPtr->ShpAnimCtrl.next.pause_at_end=0;
4295 		pwPtr->ShpAnimCtrl.next.done_a_frame=0;
4296 		pwPtr->ShpAnimCtrl.next.sequence=NULL;
4297 		pwPtr->ShpAnimCtrl.next.current_frame=0;
4298 		pwPtr->ShpAnimCtrl.next.time_to_next_frame=0;
4299 
4300 		pwPtr->ShpAnimCtrl.finished=0;
4301 		pwPtr->ShpAnimCtrl.playing=0;
4302 		pwPtr->ShpAnimCtrl.anim_header=NULL;
4303 	}
4304 }
4305 
ParticleBeamSwapping(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)4306 void ParticleBeamSwapping(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
4307 
4308 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
4309 		/* Setup animation. */
4310 		SHAPEANIMATIONCONTROLDATA sacd;
4311 		InitShapeAnimationControlData(&sacd);
4312 		sacd.seconds_per_frame = ONE_FIXED/36;
4313 		sacd.sequence_no = 0;
4314 		sacd.default_start_and_end_frames = 1;
4315 		sacd.reversed = 0;
4316 		sacd.stop_at_end = 1;
4317 		SetShapeAnimationSequence(&PlayersWeapon, &sacd);
4318 	}
4319 }
4320 
ParticleBeamReadying(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)4321 void ParticleBeamReadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
4322 
4323 	DoShapeAnimation(&PlayersWeapon);
4324 
4325 }
4326 
ParticleBeamUnreadying(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)4327 void ParticleBeamUnreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
4328 
4329 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
4330 		/* Start animation. */
4331 		SHAPEANIMATIONCONTROLDATA sacd;
4332 		InitShapeAnimationControlData(&sacd);
4333 		sacd.seconds_per_frame = ONE_FIXED/36;
4334 		sacd.sequence_no = 0;
4335 		sacd.default_start_and_end_frames = 1;
4336 		sacd.reversed = 1;
4337 		sacd.stop_at_end = 1;
4338 		SetShapeAnimationSequence(&PlayersWeapon, &sacd);
4339 
4340 	} else {
4341 		DoShapeAnimation(&PlayersWeapon);
4342 	}
4343 
4344 }
4345 
GrenadeLauncher_UpdateBullets(PLAYER_WEAPON_DATA * weaponPtr)4346 void GrenadeLauncher_UpdateBullets(PLAYER_WEAPON_DATA *weaponPtr) {
4347 
4348 	int a;
4349 	/* Flags the correct number of bullets as visible... */
4350 
4351 	for (a=0; a<6; a++) {
4352 		if (a>(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT)) {
4353 			/* Not vis. */
4354 			GrenadeLauncherSectionPointers[a]->flags|=section_data_notreal;
4355 		} else {
4356 			/* Vis. */
4357 			GrenadeLauncherSectionPointers[a]->flags&=~section_data_notreal;
4358 		}
4359 	}
4360 
4361 	switch (GrenadeLauncherData.SelectedAmmo) {
4362 		case AMMO_FLARE_GRENADE:
4363 		{
4364 			GrenadeLauncherData.FlareRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4365 			GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4366 			ChangeHUDToAlternateShapeSet("MarineWeapons","Flare");
4367 			break;
4368 		}
4369 		case AMMO_FRAGMENTATION_GRENADE:
4370 		{
4371 			GrenadeLauncherData.FragmentationRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4372 			GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4373 			ChangeHUDToAlternateShapeSet("MarineWeapons","Frag");
4374 			break;
4375 		}
4376 		case AMMO_PROXIMITY_GRENADE:
4377 		{
4378 			GrenadeLauncherData.ProximityRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4379 			GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4380 			ChangeHUDToAlternateShapeSet("MarineWeapons","Proxmine");
4381 			break;
4382 		}
4383 		case AMMO_GRENADE:
4384 		{
4385 			GrenadeLauncherData.StandardRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4386 			GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4387 			ChangeHUDToAlternateShapeSet("MarineWeapons","Grenade");
4388 			break;
4389 		}
4390 		default:
4391 		{
4392 			GLOBALASSERT(0);
4393 			break;
4394 		}
4395 	}
4396 
4397 
4398 }
4399 
GrenadeLauncherFire(PLAYER_WEAPON_DATA * weaponPtr)4400 int GrenadeLauncherFire(PLAYER_WEAPON_DATA *weaponPtr) {
4401 
4402 	int a;
4403 
4404 	a=FireNonAutomaticWeapon(weaponPtr);
4405 
4406 	//GrenadeLauncher_UpdateBullets(weaponPtr);
4407 
4408 	return(a);
4409 
4410 }
4411 
GrenadeLauncher_EmergencyChangeAmmo(PLAYER_WEAPON_DATA * weaponPtr)4412 void GrenadeLauncher_EmergencyChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr) {
4413 
4414 	enum AMMO_ID change_to_ammo,original_ammo;
4415 
4416 	/* CDF 11/3/99: different priorities here.  And only three ammo types. */
4417 
4418 	original_ammo=GrenadeLauncherData.SelectedAmmo;
4419 	change_to_ammo=AMMO_NONE;
4420 
4421 
4422 	switch(original_ammo) {
4423 		case AMMO_GRENADE:
4424 		{
4425 			if ((GrenadeLauncherData.FragmentationRoundsRemaining>0)
4426 				||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) {
4427 				/* Valid. */
4428 				change_to_ammo=AMMO_FRAGMENTATION_GRENADE;
4429 			} else if ((GrenadeLauncherData.ProximityRoundsRemaining>0)
4430 				||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) {
4431 				/* Valid. */
4432 				change_to_ammo=AMMO_PROXIMITY_GRENADE;
4433 			}
4434 			break;
4435 		}
4436 		case AMMO_FLARE_GRENADE:
4437 		{
4438 			GLOBALASSERT(0);
4439 			break;
4440 		}
4441 		case AMMO_FRAGMENTATION_GRENADE:
4442 		{
4443 			if ((GrenadeLauncherData.StandardRoundsRemaining>0)
4444 				||(GrenadeLauncherData.StandardMagazinesRemaining>0)) {
4445 				/* Valid. */
4446 				change_to_ammo=AMMO_GRENADE;
4447 			} else if ((GrenadeLauncherData.ProximityRoundsRemaining>0)
4448 				||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) {
4449 				/* Valid. */
4450 				change_to_ammo=AMMO_PROXIMITY_GRENADE;
4451 			}
4452 			break;
4453 		}
4454 		case AMMO_PROXIMITY_GRENADE:
4455 		{
4456 			if ((GrenadeLauncherData.StandardRoundsRemaining>0)
4457 				||(GrenadeLauncherData.StandardMagazinesRemaining>0)) {
4458 				/* Valid. */
4459 				change_to_ammo=AMMO_GRENADE;
4460 			} else if ((GrenadeLauncherData.FragmentationRoundsRemaining>0)
4461 				||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) {
4462 				/* Valid. */
4463 				change_to_ammo=AMMO_FRAGMENTATION_GRENADE;
4464 			}
4465 			break;
4466 		}
4467 		default:
4468 		{
4469 			GLOBALASSERT(0);
4470 			break;
4471 		}
4472 	}
4473 
4474 
4475 	if ((change_to_ammo==original_ammo)||(change_to_ammo==AMMO_NONE)) {
4476 		/* No other ammo types! */
4477 		return;
4478 	}
4479 
4480 	switch (original_ammo) {
4481 		case AMMO_FLARE_GRENADE:
4482 		{
4483 			GrenadeLauncherData.FlareRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4484 			GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4485 			break;
4486 		}
4487 		case AMMO_FRAGMENTATION_GRENADE:
4488 		{
4489 			GrenadeLauncherData.FragmentationRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4490 			GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4491 			break;
4492 		}
4493 		case AMMO_PROXIMITY_GRENADE:
4494 		{
4495 			GrenadeLauncherData.ProximityRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4496 			GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4497 			break;
4498 		}
4499 		case AMMO_GRENADE:
4500 		{
4501 			GrenadeLauncherData.StandardRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4502 			GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4503 			break;
4504 		}
4505 		default:
4506 		{
4507 			GLOBALASSERT(0);
4508 			break;
4509 		}
4510 	}
4511 
4512 	/* KJL 11:31:44 04/09/97 - when you press secondary fire, you change ammo type */
4513 	switch(change_to_ammo)
4514 	{
4515 		case AMMO_FLARE_GRENADE:
4516 		{
4517 			GrenadeLauncherData.SelectedAmmo = AMMO_FLARE_GRENADE;
4518 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.FlareRoundsRemaining;
4519 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FlareMagazinesRemaining;
4520 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE));
4521 			break;
4522 		}
4523 		case AMMO_FRAGMENTATION_GRENADE:
4524 		{
4525 
4526 			GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE;
4527 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.FragmentationRoundsRemaining;
4528 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining;
4529 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE));
4530 			break;
4531 		}
4532 		case AMMO_PROXIMITY_GRENADE:
4533 		{
4534 			GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE;
4535 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.ProximityRoundsRemaining;
4536 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining;
4537 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE));
4538 			break;
4539 		}
4540 		case AMMO_GRENADE:
4541 		{
4542 			GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE;
4543 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.StandardRoundsRemaining;
4544 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining;
4545 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_GRENADE));
4546 			break;
4547 		}
4548 		default:
4549 			break;
4550 	}
4551 
4552 	weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY;
4553 	weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
4554 
4555 	return;
4556 
4557 }
4558 
GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA * weaponPtr)4559 int GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr) {
4560 
4561 	enum AMMO_ID change_to_ammo,original_ammo,temp_ammo;
4562 
4563 	/* CDF 1/5/98: only change to ammo that you have! */
4564 
4565 	original_ammo=GrenadeLauncherData.SelectedAmmo;
4566 	change_to_ammo=AMMO_NONE;
4567 	temp_ammo=original_ammo;
4568 
4569 	while (change_to_ammo==AMMO_NONE) {
4570 		switch(temp_ammo) {
4571 			case AMMO_GRENADE:
4572 			{
4573 //				temp_ammo=AMMO_FLARE_GRENADE;
4574 				temp_ammo=AMMO_FRAGMENTATION_GRENADE;
4575 				if (temp_ammo==original_ammo) {
4576 					/* Gone all the way round.  Doh! */
4577 					change_to_ammo=temp_ammo;
4578 					break;
4579 				}
4580 				//if ((GrenadeLauncherData.FlareRoundsRemaining>0)
4581 				//	||(GrenadeLauncherData.FlareMagazinesRemaining>0)) {
4582 				if ((GrenadeLauncherData.FragmentationRoundsRemaining>0)
4583 					||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) {
4584 					/* Valid. */
4585 					change_to_ammo=temp_ammo;
4586 				}
4587 				break;
4588 			}
4589 			case AMMO_FLARE_GRENADE:
4590 			{
4591 				temp_ammo=AMMO_FRAGMENTATION_GRENADE;
4592 				if (temp_ammo==original_ammo) {
4593 					/* Gone all the way round.  Doh! */
4594 					change_to_ammo=temp_ammo;
4595 					break;
4596 				}
4597 				if ((GrenadeLauncherData.FragmentationRoundsRemaining>0)
4598 					||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) {
4599 					/* Valid. */
4600 					change_to_ammo=temp_ammo;
4601 				}
4602 				break;
4603 			}
4604 			case AMMO_FRAGMENTATION_GRENADE:
4605 			{
4606 				temp_ammo=AMMO_PROXIMITY_GRENADE;
4607 //				temp_ammo=AMMO_GRENADE;
4608 				if (temp_ammo==original_ammo) {
4609 					/* Gone all the way round.  Doh! */
4610 					change_to_ammo=temp_ammo;
4611 					break;
4612 				}
4613 				if ((GrenadeLauncherData.ProximityRoundsRemaining>0)
4614 					||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) {
4615 				//if ((GrenadeLauncherData.StandardRoundsRemaining>0)
4616 				//	||(GrenadeLauncherData.StandardMagazinesRemaining>0)) {
4617 					/* Valid. */
4618 					change_to_ammo=temp_ammo;
4619 				}
4620 				break;
4621 			}
4622 			case AMMO_PROXIMITY_GRENADE:
4623 			{
4624 				temp_ammo=AMMO_GRENADE;
4625 				if (temp_ammo==original_ammo) {
4626 					/* Gone all the way round.  Doh! */
4627 					change_to_ammo=temp_ammo;
4628 					break;
4629 				}
4630 				if ((GrenadeLauncherData.StandardRoundsRemaining>0)
4631 					||(GrenadeLauncherData.StandardMagazinesRemaining>0)) {
4632 					/* Valid. */
4633 					change_to_ammo=temp_ammo;
4634 				}
4635 				break;
4636 			}
4637 			default:
4638 			{
4639 				GLOBALASSERT(0);
4640 				break;
4641 			}
4642 		}
4643 	}
4644 
4645 	if (change_to_ammo==original_ammo) {
4646 		/* No other ammo types! */
4647 		return(0);
4648 	}
4649 
4650 	switch (original_ammo) {
4651 		case AMMO_FLARE_GRENADE:
4652 		{
4653 			GrenadeLauncherData.FlareRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4654 			GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4655 			break;
4656 		}
4657 		case AMMO_FRAGMENTATION_GRENADE:
4658 		{
4659 			GrenadeLauncherData.FragmentationRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4660 			GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4661 			break;
4662 		}
4663 		case AMMO_PROXIMITY_GRENADE:
4664 		{
4665 			GrenadeLauncherData.ProximityRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4666 			GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4667 			break;
4668 		}
4669 		case AMMO_GRENADE:
4670 		{
4671 			GrenadeLauncherData.StandardRoundsRemaining    = weaponPtr->PrimaryRoundsRemaining;
4672 			GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining;
4673 			break;
4674 		}
4675 		default:
4676 		{
4677 			GLOBALASSERT(0);
4678 			break;
4679 		}
4680 	}
4681 
4682 	/* KJL 11:31:44 04/09/97 - when you press secondary fire, you change ammo type */
4683 	switch(change_to_ammo)
4684 	{
4685 		case AMMO_FLARE_GRENADE:
4686 		{
4687 			GrenadeLauncherData.SelectedAmmo = AMMO_FLARE_GRENADE;
4688 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.FlareRoundsRemaining;
4689 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FlareMagazinesRemaining;
4690 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE));
4691 			break;
4692 		}
4693 		case AMMO_FRAGMENTATION_GRENADE:
4694 		{
4695 
4696 			GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE;
4697 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.FragmentationRoundsRemaining;
4698 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining;
4699 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE));
4700 			break;
4701 		}
4702 		case AMMO_PROXIMITY_GRENADE:
4703 		{
4704 			GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE;
4705 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.ProximityRoundsRemaining;
4706 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining;
4707 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE));
4708 			break;
4709 		}
4710 		case AMMO_GRENADE:
4711 		{
4712 			GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE;
4713 			weaponPtr->PrimaryRoundsRemaining =	GrenadeLauncherData.StandardRoundsRemaining;
4714 			weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining;
4715 			NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_GRENADE));
4716 			break;
4717 		}
4718 		default:
4719 			break;
4720 	}
4721 
4722 	//GrenadeLauncher_UpdateBullets(weaponPtr);
4723     //weaponPtr->CurrentState = WEAPONSTATE_WAITING;
4724 
4725 	weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY;
4726 	weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
4727 
4728 	return(1);
4729 
4730 }
4731 
SmartgunSecondaryFire(PLAYER_WEAPON_DATA * weaponPtr)4732 int SmartgunSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr) {
4733 
4734 	switch (SmartgunMode) {
4735 		case I_Track:
4736 			/* Language Localise */
4737 			NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_FREEMODE));
4738 			SmartgunMode=I_Free;
4739 			break;
4740 		case I_Free:
4741 			/* Language Localise */
4742 			NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_TRACKMODE));
4743 			SmartgunMode=I_Track;
4744 			break;
4745 		default:
4746 			GLOBALASSERT(0);
4747 			break;
4748 	}
4749 	Sound_Play(SID_SMART_MODESWITCH,NULL);
4750 
4751     weaponPtr->CurrentState = WEAPONSTATE_WAITING;
4752 
4753 	return(0);
4754 
4755 }
4756 
PredDiscChangeMode(PLAYER_WEAPON_DATA * weaponPtr)4757 int PredDiscChangeMode(PLAYER_WEAPON_DATA *weaponPtr) {
4758 
4759 	#if 0
4760 	switch (ThisDiscMode) {
4761 		case I_Seek_Track:
4762 			ThisDiscMode=I_Search_Destroy;
4763 			/* Language Localise */
4764 			NewOnScreenMessage("SEARCH AND DESTROY");
4765 			break;
4766 		case I_Search_Destroy:
4767 			ThisDiscMode=I_Proximity_Mine;
4768 			/* Language Localise */
4769 			NewOnScreenMessage("PROXIMITY MINE");
4770 			break;
4771 		case I_Proximity_Mine:
4772 			ThisDiscMode=I_Seek_Track;
4773 			/* Language Localise */
4774 			NewOnScreenMessage("SEEK AND TRACK");
4775 			break;
4776 	}
4777     weaponPtr->CurrentState = WEAPONSTATE_WAITING;
4778 	#endif
4779 
4780 	return(0);
4781 }
4782 
4783 
MeleeWeapon_180Degree_Front_Core(DAMAGE_PROFILE * damage,int multiple,int range)4784 int MeleeWeapon_180Degree_Front_Core(DAMAGE_PROFILE *damage,int multiple,int range)
4785 {
4786 	int numberOfObjects = NumOnScreenBlocks;
4787 	int numhits=0;
4788 	STRATEGYBLOCK *objectToHit=0;
4789 
4790 	int hurt_people;
4791 
4792 	hurt_people=1;
4793 
4794 	while (numberOfObjects)
4795 	{
4796 		VECTORCH targetpos,targetposW;
4797 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
4798 		STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
4799 		GLOBALASSERT(objectPtr);
4800 
4801 		/* does object have a strategy block? */
4802 		if (sbPtr)
4803 		{
4804 
4805 			GetTargetingPointOfObject(objectPtr,&targetpos);
4806 			targetposW=targetpos;
4807 			targetpos.vx-=Global_VDB_Ptr->VDB_World.vx;
4808 			targetpos.vy-=Global_VDB_Ptr->VDB_World.vy;
4809 			targetpos.vz-=Global_VDB_Ptr->VDB_World.vz;
4810 			RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat);
4811 
4812 			/* is it in range? */
4813 			if (targetpos.vz > 0) {
4814 
4815 				int dist=Approximate3dMagnitude(&targetpos);
4816 
4817 				if (dist<range)	{
4818 
4819 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
4820 			  	  	if (dynPtr)
4821 					{
4822 						#if 1
4823 						/* KJL 19:10:49 25/01/99 - I'm going to try changing this to
4824 						see if I can have an Alien that doesn't kill multiple things in one frame */
4825 
4826 						/* CDF 30/3/99 - I'm going to change it back with modifications,
4827 						since people evidently can't make up their minds. */
4828 
4829 						//if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range))
4830 						if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&targetposW))
4831 						{
4832 
4833 							int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
4834 					  	  	dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce);
4835 							dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce);
4836 					  	  	dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce);
4837 							/* Consider target aspect. */
4838 							{
4839 								VECTORCH attack_dir,displacement;
4840 								int real_multiple;
4841 								int do_attack;
4842 
4843 								displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx;
4844 								displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy;
4845 								displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz;
4846 
4847 								GetDirectionOfAttack(sbPtr,&displacement,&attack_dir);
4848 
4849 								if (attack_dir.vz>0) {
4850 									real_multiple=multiple<<1;
4851 								} else {
4852 									real_multiple=multiple;
4853 								}
4854 
4855 					  			/* Consider player's target. */
4856 
4857 								/* Here's the mod. */
4858 								switch (sbPtr->I_SBtype) {
4859 									case I_BehaviourMarine:
4860 									case I_BehaviourMarinePlayer:
4861 									case I_BehaviourPredator:
4862 									case I_BehaviourAutoGun:
4863 									case I_BehaviourAlien:
4864 										if (hurt_people) {
4865 											do_attack=1;
4866 											hurt_people=0;
4867 										} else {
4868 											do_attack=0;
4869 										}
4870 										break;
4871 									default:
4872 										do_attack=1;
4873 										break;
4874 								}
4875 
4876 								if (do_attack) {
4877 									if (sbPtr->SBdptr->HModelControlBlock) {
4878 										DISPLAYBLOCK *frag;
4879 
4880 										frag=HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir);
4881 										/* If you're an alien, consider limb rip damage. */
4882 										if (AvP.PlayerType==I_Alien) {
4883 											if (sbPtr->I_SBtype==I_BehaviourMarine) {
4884 												MARINE_STATUS_BLOCK *marineStatusPointer;
4885 
4886 												marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
4887 											    LOCALASSERT(marineStatusPointer);
4888 
4889 												if (marineStatusPointer->Android==0) {
4890 													if (frag) {
4891 														/* Took off a limb! */
4892 														LimbRip_AwardHealth();
4893 													}
4894 												}
4895 											} else if (sbPtr->I_SBtype==I_BehaviourNetCorpse) {
4896 												NETCORPSEDATABLOCK *corpseDataPtr;
4897 
4898 												corpseDataPtr = (NETCORPSEDATABLOCK *)(sbPtr->SBdataptr);
4899 												LOCALASSERT(corpseDataPtr);
4900 
4901 												if (corpseDataPtr->Android==0) {
4902 													if (frag) {
4903 														/* Took off a limb! */
4904 														LimbRip_AwardHealth();
4905 													}
4906 												}
4907 											}
4908 										}
4909 									} else {
4910 						  				CauseDamageToObject(sbPtr, damage, real_multiple,&attack_dir);
4911 									}
4912 								}
4913 							}
4914 							numhits++;
4915 						}
4916 						#else
4917 						//if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range))
4918 						if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&targetposW)) {
4919 							objectToHit = sbPtr;
4920 							range = dist;
4921 						}
4922 						#endif
4923 					}
4924 			  	}
4925 			}
4926 		}
4927 	}
4928 
4929 	/* Here's a new modification... */
4930 	if (numhits==0) {
4931 		/* Let's see if we've missed something obvious. */
4932 		if (PlayersTarget.DispPtr) {
4933 			if (PlayersTarget.Distance<range) {
4934 				if (PlayersTarget.DispPtr->ObStrategyBlock) {
4935 					/* May as well hit this, then. */
4936 					objectToHit=PlayersTarget.DispPtr->ObStrategyBlock;
4937 					if (objectToHit->DynPtr) {
4938 						DYNAMICSBLOCK *dynPtr = objectToHit->DynPtr;
4939 						int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
4940 				  	  	dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce);
4941 						dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce);
4942 				  	  	dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce);
4943 						/* Consider target aspect. */
4944 						{
4945 							VECTORCH attack_dir,displacement;
4946 							int real_multiple;
4947 
4948 							displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx;
4949 							displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy;
4950 							displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz;
4951 
4952 							GetDirectionOfAttack(objectToHit,&displacement,&attack_dir);
4953 
4954 							if (attack_dir.vz>0) {
4955 								real_multiple=multiple<<1;
4956 							} else {
4957 								real_multiple=multiple;
4958 							}
4959 
4960 				  			/* Consider player's target. */
4961 
4962 							if (objectToHit->SBdptr->HModelControlBlock) {
4963 								DISPLAYBLOCK *frag;
4964 
4965 								frag=HtoHDamageToHModel(objectToHit, damage, real_multiple, NULL, &attack_dir);
4966 								/* If you're an alien, consider limb rip damage. */
4967 								if (AvP.PlayerType==I_Alien) {
4968 									if (objectToHit->I_SBtype==I_BehaviourMarine) {
4969 										MARINE_STATUS_BLOCK *marineStatusPointer;
4970 
4971 										marineStatusPointer = (MARINE_STATUS_BLOCK *)(objectToHit->SBdataptr);
4972 									    LOCALASSERT(marineStatusPointer);
4973 
4974 										if (marineStatusPointer->Android==0) {
4975 											if (frag) {
4976 												/* Took off a limb! */
4977 												LimbRip_AwardHealth();
4978 											}
4979 										}
4980 									} else if (objectToHit->I_SBtype==I_BehaviourNetCorpse) {
4981 										NETCORPSEDATABLOCK *corpseDataPtr;
4982 
4983 										corpseDataPtr = (NETCORPSEDATABLOCK *)(objectToHit->SBdataptr);
4984 										LOCALASSERT(corpseDataPtr);
4985 
4986 										if (corpseDataPtr->Android==0) {
4987 											if (frag) {
4988 												/* Took off a limb! */
4989 												LimbRip_AwardHealth();
4990 											}
4991 										}
4992 									}
4993 								}
4994 							} else {
4995 				  				CauseDamageToObject(objectToHit, damage, real_multiple,&attack_dir);
4996 							}
4997 						}
4998 						numhits++;
4999 					}
5000 				}
5001 			}
5002 		}
5003 	}
5004 
5005 	return(numhits);
5006 }
5007 
MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA * weaponPtr)5008 int MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA *weaponPtr)
5009 {
5010 	enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
5011 	int hits;
5012 
5013 	hits=MeleeWeapon_180Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
5014 
5015 	return(hits);
5016 }
5017 
MeleeWeapon_90Degree_Front_Core(DAMAGE_PROFILE * damage,int multiple,int range)5018 int MeleeWeapon_90Degree_Front_Core(DAMAGE_PROFILE *damage,int multiple,int range)
5019 {
5020 	int numberOfObjects = NumOnScreenBlocks;
5021 	int numhits=0;
5022 	STRATEGYBLOCK *objectToHit=NULL;
5023 
5024 	int hurt_people;
5025 
5026 	hurt_people=1;
5027 
5028 	while (numberOfObjects)
5029 	{
5030 		STRATEGYBLOCK *sbPtr;
5031 		VECTORCH targetpos,targetposW;
5032 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
5033 
5034 		GLOBALASSERT(objectPtr);
5035 		sbPtr = objectPtr->ObStrategyBlock;
5036 
5037 		/* does object have a strategy block? */
5038 		if (sbPtr)
5039 		{
5040 			GetTargetingPointOfObject(objectPtr,&targetpos);
5041 			targetposW=targetpos;
5042 			targetpos.vx-=Global_VDB_Ptr->VDB_World.vx;
5043 			targetpos.vy-=Global_VDB_Ptr->VDB_World.vy;
5044 			targetpos.vz-=Global_VDB_Ptr->VDB_World.vz;
5045 			RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat);
5046 
5047 			/* is it in the frustrum? */
5048 			if ( (targetpos.vz >0)
5049 				&& (targetpos.vz >  targetpos.vx)
5050 				&& (targetpos.vz > -targetpos.vx)
5051 				&& (targetpos.vz >  targetpos.vy)
5052 				&& (targetpos.vz > -targetpos.vy) ) {
5053 
5054 				int dist=Approximate3dMagnitude(&targetpos);
5055 
5056 				/* HACKAHACKAHACKA */
5057 
5058 				if (objectPtr->HModelControlBlock==NULL) {
5059 					if (objectPtr->ObShapeData) {
5060 						dist-=(objectPtr->ObShapeData->shaperadius)>>1;
5061 					}
5062 				}
5063 
5064 				if (dist<range)	{
5065 
5066 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
5067 			  	  	if (dynPtr)
5068 					{
5069 
5070 						if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range)) {
5071 
5072 							int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
5073 				  		  	dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce);
5074 							dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce);
5075 				  		  	dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce);
5076 			  				/* Consider player's target. */
5077 
5078 							/* Consider target aspect. */
5079 							{
5080 								VECTORCH attack_dir,displacement;
5081 								int real_multiple;
5082 								int do_attack;
5083 
5084 								displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx;
5085 								displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy;
5086 								displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz;
5087 
5088 								GetDirectionOfAttack(sbPtr,&displacement,&attack_dir);
5089 
5090 								if (attack_dir.vz>0) {
5091 									real_multiple=multiple<<1;
5092 								} else {
5093 									real_multiple=multiple;
5094 								}
5095 
5096 					  			/* Consider player's target. */
5097 
5098 								switch (sbPtr->I_SBtype) {
5099 									case I_BehaviourMarine:
5100 									case I_BehaviourMarinePlayer:
5101 									case I_BehaviourPredator:
5102 									case I_BehaviourAutoGun:
5103 									case I_BehaviourAlien:
5104 										if (hurt_people) {
5105 											do_attack=1;
5106 											hurt_people=0;
5107 										} else {
5108 											do_attack=0;
5109 										}
5110 										break;
5111 									default:
5112 										do_attack=1;
5113 										break;
5114 								}
5115 
5116 								if (do_attack) {
5117 									if (sbPtr->SBdptr->HModelControlBlock) {
5118 										if (damage->Special) {
5119 											/* Target an alien's chest. */
5120 											if (sbPtr->I_SBtype==I_BehaviourAlien) {
5121 												SECTION_DATA *chest;
5122 												chest=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,"chest");
5123 												GLOBALASSERT(chest);
5124 												CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr,damage,real_multiple,chest,&attack_dir,NULL,0);
5125 											} else {
5126 												HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir);
5127 											}
5128 										} else {
5129 											HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir);
5130 										}
5131 									} else {
5132 					  					CauseDamageToObject(sbPtr, damage, real_multiple,&attack_dir);
5133 									}
5134 								}
5135 							}
5136 							numhits++;
5137 						}
5138 					}
5139 			  	}
5140 			}
5141 		}
5142 	}
5143 
5144 	/* Here's a new modification... */
5145 	if (numhits==0) {
5146 		/* Let's see if we've missed something obvious. */
5147 		if (PlayersTarget.DispPtr) {
5148 			if (PlayersTarget.Distance<range) {
5149 				if (PlayersTarget.DispPtr->ObStrategyBlock) {
5150 					/* May as well hit this, then. */
5151 					objectToHit=PlayersTarget.DispPtr->ObStrategyBlock;
5152 					if (objectToHit->DynPtr) {
5153 						DYNAMICSBLOCK *dynPtr = objectToHit->DynPtr;
5154 						int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
5155 				  	  	dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce);
5156 						dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce);
5157 				  	  	dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce);
5158 						/* Consider target aspect. */
5159 						{
5160 							VECTORCH attack_dir,displacement;
5161 							int real_multiple;
5162 
5163 							displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx;
5164 							displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy;
5165 							displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz;
5166 
5167 							GetDirectionOfAttack(objectToHit,&displacement,&attack_dir);
5168 
5169 							if (attack_dir.vz>0) {
5170 								real_multiple=multiple<<1;
5171 							} else {
5172 								real_multiple=multiple;
5173 							}
5174 
5175 				  			/* Consider player's target. */
5176 
5177 							if (objectToHit->SBdptr->HModelControlBlock) {
5178 								DISPLAYBLOCK *frag;
5179 
5180 								frag=HtoHDamageToHModel(objectToHit, damage, real_multiple, NULL, &attack_dir);
5181 								/* If you're an alien, consider limb rip damage. */
5182 								if (AvP.PlayerType==I_Alien) {
5183 									if (objectToHit->I_SBtype==I_BehaviourMarine) {
5184 										MARINE_STATUS_BLOCK *marineStatusPointer;
5185 
5186 										marineStatusPointer = (MARINE_STATUS_BLOCK *)(objectToHit->SBdataptr);
5187 									    LOCALASSERT(marineStatusPointer);
5188 
5189 										if (marineStatusPointer->Android==0) {
5190 											if (frag) {
5191 												/* Took off a limb! */
5192 												LimbRip_AwardHealth();
5193 											}
5194 										}
5195 									} else if (objectToHit->I_SBtype==I_BehaviourNetCorpse) {
5196 										NETCORPSEDATABLOCK *corpseDataPtr;
5197 
5198 										corpseDataPtr = (NETCORPSEDATABLOCK *)(objectToHit->SBdataptr);
5199 										LOCALASSERT(corpseDataPtr);
5200 
5201 										if (corpseDataPtr->Android==0) {
5202 											if (frag) {
5203 												/* Took off a limb! */
5204 												LimbRip_AwardHealth();
5205 											}
5206 										}
5207 									}
5208 								}
5209 							} else {
5210 				  				CauseDamageToObject(objectToHit, damage, real_multiple,&attack_dir);
5211 							}
5212 						}
5213 						numhits++;
5214 					}
5215 				}
5216 			}
5217 		}
5218 	}
5219 
5220 
5221 	return(numhits);
5222 }
5223 
MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA * weaponPtr)5224 int MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA *weaponPtr)
5225 {
5226 	enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
5227 	int hits;
5228 
5229 	hits=MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
5230 
5231 	return(hits);
5232 }
5233 #if 0
5234 void WeaponCreateStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5235 
5236 	extern void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, DISPLAYBLOCK * dptr);
5237 
5238 	/* Setup animation. */
5239 	SHAPEANIMATIONCONTROLDATA sacd;
5240 	InitShapeAnimationControlData(&sacd);
5241 	sacd.seconds_per_frame = ONE_FIXED/16;
5242 	sacd.sequence_no = 0;
5243 	sacd.default_start_and_end_frames = 1;
5244 	sacd.reversed = 0;
5245 	sacd.stop_at_end = 1;
5246 	SetShapeAnimationSequence(&PlayersWeapon, &sacd);
5247 	sacd.sequence = &(PlayersWeapon.ShapeAnimControlBlock)->anim_header->anim_sequences[sacd.sequence_no];
5248 	sacd.current_frame=0;
5249 	CopyAnimationFrameToShape(&sacd, &PlayersWeapon);
5250 	WeaponFidgetPlaying=0;
5251 
5252 }
5253 #endif
WeaponSetStartFrame(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5254 void WeaponSetStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5255 
5256 	#if 0 //old shape animation stuff
5257 	extern void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, DISPLAYBLOCK * dptr);
5258 
5259 	/* Setup animation. */
5260 	SHAPEANIMATIONCONTROLDATA sacd;
5261 	InitShapeAnimationControlData(&sacd);
5262 	sacd.seconds_per_frame = ONE_FIXED/16;
5263 	sacd.sequence_no = 0;
5264 	sacd.default_start_and_end_frames = 1;
5265 	sacd.reversed = 0;
5266 	sacd.stop_at_end = 1;
5267 	SetShapeAnimationSequence(&PlayersWeapon, &sacd);
5268 	WeaponFidgetPlaying=0;
5269 	#endif
5270 
5271 }
5272 
PulseRifleSwapIn(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5273 void PulseRifleSwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5274 
5275 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5276 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED>>3);
5277 		PlayersWeaponHModelController.Looped=0;
5278 	}
5279 
5280 	Weapon_ThisBurst=-1;
5281 }
5282 
PulseRifleSwapOut(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5283 void PulseRifleSwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5284 
5285 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5286 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED>>3);
5287 		PlayersWeaponHModelController.Looped=0;
5288 	}
5289 
5290 }
5291 
PulseRifleGrenadeRecoil(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5292 void PulseRifleGrenadeRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5293 
5294 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5295 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,ONE_FIXED);
5296 		PlayersWeaponHModelController.Looped=0;
5297 	}
5298 
5299 }
5300 
PulseRifleReloadClip(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5301 void PulseRifleReloadClip(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5302 
5303 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5304 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,ONE_FIXED);
5305 		PlayersWeaponHModelController.Looped=0;
5306 	}
5307 
5308 }
5309 
MinigunStartSpin(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5310 void MinigunStartSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5311 
5312 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5313 
5314 	Old_Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5315 	Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5316 	Weapon_ThisBurst=-1;
5317 	Minigun_HeadJolt.EulerX=0;
5318 	Minigun_HeadJolt.EulerY=0;
5319 	Minigun_HeadJolt.EulerZ=0;
5320 	Minigun_MaxHeadJolt.EulerX=0;
5321 	Minigun_MaxHeadJolt.EulerY=0;
5322 	Minigun_MaxHeadJolt.EulerZ=0;
5323 
5324 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Fire) {
5325 		#if (MINIGUN_IDLE_SPEED)
5326 			InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,DIV_FIXED(ONE_FIXED,MINIGUN_IDLE_SPEED));
5327 			PlayersWeaponHModelController.Playing=1;
5328 		#else
5329 			InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,ONE_FIXED);
5330 			PlayersWeaponHModelController.Playing=0;
5331 		#endif
5332 	}
5333 
5334 }
5335 
MinigunStopSpin(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5336 void MinigunStopSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5337 
5338 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5339 
5340 	/* Spin down first. */
5341 
5342 	Minigun_SpinSpeed-=(NormalFrameTime<<3);
5343 	if (Minigun_SpinSpeed<MINIGUN_IDLE_SPEED) {
5344 
5345 		weaponPtr->StateTimeOutCounter = 0;
5346 		Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5347 
5348 		/* Stop Spin. */
5349 		PlayersWeaponHModelController.Playing=0;
5350 	} else {
5351 		/* Can't stop yet. */
5352 		weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
5353 
5354 	}
5355 
5356 	if (Minigun_SpinSpeed!=Old_Minigun_SpinSpeed) {
5357 		int hmspinrate;
5358 		if (Minigun_SpinSpeed) {
5359 			hmspinrate=DIV_FIXED(ONE_FIXED,Minigun_SpinSpeed);
5360 			HModel_ChangeSpeed(&PlayersWeaponHModelController,hmspinrate);
5361 			PlayersWeaponHModelController.Playing=1;
5362 		} else {
5363 			PlayersWeaponHModelController.Playing=0;
5364 		}
5365 	}
5366 
5367 	Old_Minigun_SpinSpeed=Minigun_SpinSpeed;
5368 
5369 	textprint("Minigun Spin Speed = %d\n",Minigun_SpinSpeed);
5370 
5371 	/* Think sounds. */
5372 	if (Minigun_SpinSpeed==0) {
5373 		/* No sound at all, ideally! */
5374   		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5375 			if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) {
5376 				/* Allow SID_MINIGUN_END to stop if it's going. */
5377 	       		Sound_Stop(weaponHandle);
5378 			}
5379 		}
5380 	} else {
5381 		/* Winding down - should be playing SID_MINIGUN_END. */
5382   		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5383 			if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) {
5384 				/* Stop other sounds... */
5385 	       		Sound_Stop(weaponHandle);
5386 			}
5387 		}
5388   		if(weaponHandle == SOUND_NOACTIVEINDEX) {
5389   			Sound_Play(SID_MINIGUN_END,"eh",&weaponHandle);
5390 			playerNoise=1;
5391 		}
5392 	}
5393 }
5394 
5395 #define MINIGUN_MOVING_IMPULSE	(-36000)
5396 #define MINIGUN_JOLTTIME_SHIFT	(2)
5397 
FireMinigun(PLAYER_WEAPON_DATA * weaponPtr)5398 int FireMinigun(PLAYER_WEAPON_DATA *weaponPtr) {
5399 
5400 	#if FORCE_MINIGUN_STOP
5401 	if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) {
5402 		Minigun_SpinSpeed+=(NormalFrameTime<<7);
5403 	}
5404 	#else
5405 	if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
5406 		&&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
5407 		&&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz)
5408 		&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)
5409 		){
5410 
5411 		Minigun_SpinSpeed+=(NormalFrameTime<<7);
5412 	} else {
5413 		Minigun_SpinSpeed-=(NormalFrameTime<<3);
5414 		if (Minigun_SpinSpeed<MINIGUN_IDLE_SPEED) {
5415 			Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5416 		}
5417 		return(0);
5418 	}
5419 	#endif
5420 	if (Minigun_SpinSpeed>=MINIGUN_MAX_SPEED) {
5421 
5422 		Minigun_SpinSpeed=MINIGUN_MAX_SPEED;
5423 
5424 		Weapon_ThisBurst+=FireAutomaticWeapon(weaponPtr);
5425 
5426 		/* Give the player an impulse? */
5427 		if ((Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
5428 			||(Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
5429 			||(Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0))
5430 		{
5431 			int impulse;
5432 
5433 			impulse=MUL_FIXED(MINIGUN_MOVING_IMPULSE,NormalFrameTime);
5434 
5435 			Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,impulse);
5436 			Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,impulse);
5437 			Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,impulse);
5438 
5439 			Minigun_MaxHeadJolt.EulerX=-(78+(FastRandom()&63));
5440 			Minigun_MaxHeadJolt.EulerY=-(78+(FastRandom()&63));
5441 			Minigun_MaxHeadJolt.EulerZ=300;
5442 
5443 			Minigun_HeadJolt.EulerX	= Minigun_MaxHeadJolt.EulerX;
5444 			Minigun_HeadJolt.EulerY	= Minigun_MaxHeadJolt.EulerY;
5445 			Minigun_HeadJolt.EulerZ	= Minigun_MaxHeadJolt.EulerZ;
5446 
5447 		}
5448 
5449 		return(1);
5450 	} else {
5451 		Weapon_ThisBurst=0;
5452 		Minigun_HeadJolt.EulerX=0;
5453 		Minigun_HeadJolt.EulerY=0;
5454 		Minigun_HeadJolt.EulerZ=0;
5455 
5456 		Minigun_MaxHeadJolt.EulerX=0;
5457 		Minigun_MaxHeadJolt.EulerY=0;
5458 		Minigun_MaxHeadJolt.EulerZ=0;
5459 	}
5460 
5461 	/* Maintain_Minigun called anyway. */
5462 
5463 	return(0);
5464 
5465 }
5466 
FireEmptyMinigun(PLAYER_WEAPON_DATA * weaponPtr)5467 int FireEmptyMinigun(PLAYER_WEAPON_DATA *weaponPtr) {
5468 
5469 	#if FORCE_MINIGUN_STOP
5470 	if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) {
5471 		Minigun_SpinSpeed+=(NormalFrameTime<<7);
5472 	}
5473 	#else
5474 	if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
5475 		&&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
5476 		&&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz)
5477 		&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)
5478 		){
5479 
5480 		Minigun_SpinSpeed+=(NormalFrameTime<<7);
5481 	} else {
5482 		Minigun_SpinSpeed-=(NormalFrameTime<<3);
5483 		if (Minigun_SpinSpeed<MINIGUN_IDLE_SPEED) {
5484 			Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5485 		}
5486 		return(0);
5487 	}
5488 	#endif
5489 	if (Minigun_SpinSpeed>=MINIGUN_MAX_SPEED) {
5490 
5491 		Minigun_SpinSpeed=MINIGUN_MAX_SPEED;
5492 
5493 		/* No bullets, no impulse. */
5494 
5495 		return(1);
5496 	} else {
5497 		Weapon_ThisBurst=0;
5498 		Minigun_HeadJolt.EulerX=0;
5499 		Minigun_HeadJolt.EulerY=0;
5500 		Minigun_HeadJolt.EulerZ=0;
5501 
5502 		Minigun_MaxHeadJolt.EulerX=0;
5503 		Minigun_MaxHeadJolt.EulerY=0;
5504 		Minigun_MaxHeadJolt.EulerZ=0;
5505 	}
5506 
5507 	/* Maintain_Minigun called anyway. */
5508 
5509 	return(0);
5510 
5511 }
5512 
5513 
Maintain_Minigun(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5514 void Maintain_Minigun(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5515 
5516    	if (weaponPtr->CurrentState!=WEAPONSTATE_FIRING_PRIMARY) {
5517 		Minigun_SpinSpeed-=(NormalFrameTime<<3);
5518 		if (Minigun_SpinSpeed<MINIGUN_IDLE_SPEED) {
5519 			Minigun_SpinSpeed=MINIGUN_IDLE_SPEED;
5520 		}
5521 		if (Weapon_ThisBurst!=0) {
5522 			Weapon_ThisBurst=-1;
5523 			Minigun_HeadJolt.EulerX=0;
5524 			Minigun_HeadJolt.EulerY=0;
5525 			Minigun_HeadJolt.EulerZ=0;
5526 
5527 			Minigun_MaxHeadJolt.EulerX=0;
5528 			Minigun_MaxHeadJolt.EulerY=0;
5529 			Minigun_MaxHeadJolt.EulerZ=0;
5530 		}
5531 		/* Not firing - play empty or wind down sound.  Which one? */
5532 		if (Minigun_SpinSpeed==0) {
5533 			/* No sound at all, ideally! */
5534 	   		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5535 				if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) {
5536 					/* Allow SID_MINIGUN_END to stop if it's going. */
5537 		       		Sound_Stop(weaponHandle);
5538 				}
5539 			}
5540 		} else if (Minigun_SpinSpeed<Old_Minigun_SpinSpeed) {
5541 			/* Winding down - should be playing SID_MINIGUN_END. */
5542 	   		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5543 				if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) {
5544 					/* Should be playing SID_MINIGUN_LOOP. */
5545 		       		Sound_Stop(weaponHandle);
5546 		   			Sound_Play(SID_MINIGUN_END,"eh",&weaponHandle);
5547 					playerNoise=1;
5548 				}
5549 			}
5550 			#if 0
5551 			/* Removed to stop multiple playings! */
5552 	   		if(weaponHandle == SOUND_NOACTIVEINDEX) {
5553 	   			Sound_Play(SID_MINIGUN_END,"eh",&weaponHandle);
5554 				playerNoise=1;
5555 			}
5556 			#endif
5557 		} else {
5558 			/* Winding up or steady - play SID_MINIGUN_EMPTY. */
5559 	   		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5560 				if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_EMPTY) {
5561 					/* Stop other sounds... */
5562 		       		Sound_Stop(weaponHandle);
5563 				}
5564 			}
5565 	   		if(weaponHandle == SOUND_NOACTIVEINDEX) {
5566 	   			Sound_Play(SID_MINIGUN_EMPTY,"elh",&weaponHandle);
5567 				playerNoise=1;
5568 			}
5569 		}
5570 	} else {
5571 		if (Weapon_ThisBurst<MINIGUN_MINIMUM_BURST) {
5572 			/* Forge a new fire request somehow? */
5573 		} else {
5574 			Weapon_ThisBurst=MINIGUN_MINIMUM_BURST;
5575 		}
5576 		/* Firing - play loop sound! */
5577    		if(weaponHandle != SOUND_NOACTIVEINDEX) {
5578 			if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_LOOP) {
5579 	       		Sound_Stop(weaponHandle);
5580 			}
5581 		}
5582    		if(weaponHandle == SOUND_NOACTIVEINDEX) {
5583    			Sound_Play(SID_MINIGUN_LOOP,"elh",&weaponHandle);
5584 			playerNoise=1;
5585 		}
5586 	}
5587 
5588 	if (Minigun_SpinSpeed!=Old_Minigun_SpinSpeed) {
5589 		int hmspinrate;
5590 		if (Minigun_SpinSpeed) {
5591 			hmspinrate=DIV_FIXED(ONE_FIXED,Minigun_SpinSpeed);
5592 			HModel_ChangeSpeed(&PlayersWeaponHModelController,hmspinrate);
5593 			PlayersWeaponHModelController.Playing=1;
5594 		} else {
5595 			PlayersWeaponHModelController.Playing=0;
5596 		}
5597 	}
5598 
5599 	if ((Minigun_HeadJolt.EulerX)
5600 		||(Minigun_HeadJolt.EulerY)
5601 		||(Minigun_HeadJolt.EulerZ)) {
5602 
5603 		int joltratex,joltratey,joltratez;
5604 
5605 		joltratex=MUL_FIXED((NormalFrameTime<<MINIGUN_JOLTTIME_SHIFT),Minigun_MaxHeadJolt.EulerX);
5606 		joltratey=MUL_FIXED((NormalFrameTime<<MINIGUN_JOLTTIME_SHIFT),Minigun_MaxHeadJolt.EulerY);
5607 		joltratez=MUL_FIXED((NormalFrameTime<<MINIGUN_JOLTTIME_SHIFT),Minigun_MaxHeadJolt.EulerZ);
5608 
5609 		if (Minigun_HeadJolt.EulerX>0) {
5610 			if (joltratex>Minigun_HeadJolt.EulerX) {
5611 				joltratex=Minigun_HeadJolt.EulerX;
5612 			}
5613 			Minigun_HeadJolt.EulerX-=joltratex;
5614 			if (Minigun_HeadJolt.EulerX<0) {
5615 				Minigun_HeadJolt.EulerX=0;
5616 			}
5617 		} else if (Minigun_HeadJolt.EulerX<0) {
5618 			if (joltratex<Minigun_HeadJolt.EulerX) {
5619 				joltratex=Minigun_HeadJolt.EulerX;
5620 			}
5621 			Minigun_HeadJolt.EulerX-=joltratex;
5622 			if (Minigun_HeadJolt.EulerX>0) {
5623 				Minigun_HeadJolt.EulerX=0;
5624 			}
5625 		}
5626 
5627         ((PLAYER_STATUS *)playerStatus)->ViewPanX += joltratex;
5628 		if ((((PLAYER_STATUS *)playerStatus)->ViewPanX>1024)
5629 			&&(((PLAYER_STATUS *)playerStatus)->ViewPanX<3200)) {
5630 			((PLAYER_STATUS *)playerStatus)->ViewPanX=3200;
5631 		}
5632 		/* Okay, that 3200 comes from 3072 + '128'.  '128' is hardcoded into pmove.c. */
5633 		((PLAYER_STATUS *)playerStatus)->ViewPanX &= wrap360;
5634 
5635 		if (Minigun_HeadJolt.EulerY>0) {
5636 			if (joltratey>Minigun_HeadJolt.EulerY) {
5637 				joltratey=Minigun_HeadJolt.EulerY;
5638 			}
5639 			Minigun_HeadJolt.EulerY-=joltratey;
5640 			if (Minigun_HeadJolt.EulerY<0) {
5641 				Minigun_HeadJolt.EulerY=0;
5642 			}
5643 		} else if (Minigun_HeadJolt.EulerY<0) {
5644 			if (joltratey<Minigun_HeadJolt.EulerY) {
5645 				joltratey=Minigun_HeadJolt.EulerY;
5646 			}
5647 			Minigun_HeadJolt.EulerY-=joltratey;
5648 			if (Minigun_HeadJolt.EulerY>0) {
5649 				Minigun_HeadJolt.EulerY=0;
5650 			}
5651 		}
5652 		joltratey&=wrap360;
5653 		/* Forcibly turn the player! */
5654 		{
5655 			MATRIXCH mat;
5656 	 	  	int cos = GetCos(joltratey);
5657 	 	  	int sin = GetSin(joltratey);
5658 	 	  	mat.mat11 = cos;
5659 	 	  	mat.mat12 = 0;
5660 	 	  	mat.mat13 = -sin;
5661 	 	  	mat.mat21 = 0;
5662 	 	  	mat.mat22 = 65536;
5663 	 	  	mat.mat23 = 0;
5664 	 	  	mat.mat31 = sin;
5665 	 	  	mat.mat32 = 0;
5666 	 	  	mat.mat33 = cos;
5667 
5668 			MatrixMultiply(&Player->ObStrategyBlock->DynPtr->OrientMat,&mat,&Player->ObStrategyBlock->DynPtr->OrientMat);
5669 
5670 		 	MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat, &Player->ObStrategyBlock->DynPtr->OrientEuler);
5671 		}
5672 
5673 		if (Minigun_HeadJolt.EulerZ>0) {
5674 			if (joltratex>Minigun_HeadJolt.EulerZ) {
5675 				joltratex=Minigun_HeadJolt.EulerZ;
5676 			}
5677 			Minigun_HeadJolt.EulerZ-=joltratez;
5678 			if (Minigun_HeadJolt.EulerZ<0) {
5679 				Minigun_HeadJolt.EulerZ=0;
5680 			}
5681 		} else if (Minigun_HeadJolt.EulerZ<0) {
5682 			if (joltratex<Minigun_HeadJolt.EulerZ) {
5683 				joltratex=Minigun_HeadJolt.EulerZ;
5684 			}
5685 			Minigun_HeadJolt.EulerZ-=joltratez;
5686 			if (Minigun_HeadJolt.EulerZ>0) {
5687 				Minigun_HeadJolt.EulerZ=0;
5688 			}
5689 		}
5690 		HeadOrientation.EulerZ+=joltratez;
5691 
5692 	}
5693 
5694 	Old_Minigun_SpinSpeed=Minigun_SpinSpeed;
5695 
5696 	textprint("Minigun Spin Speed = %d\n",Minigun_SpinSpeed);
5697 
5698 }
5699 
GrenadeLauncherRecoil(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5700 void GrenadeLauncherRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5701 
5702 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5703 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED*4)/3);
5704 		PlayersWeaponHModelController.Looped=0;
5705 	}
5706 }
5707 
GrenadeLauncherReload(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5708 void GrenadeLauncherReload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5709 
5710 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5711 
5712 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Reload) {
5713 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,(ONE_FIXED*4)/3);
5714 		PlayersWeaponHModelController.Looped=0;
5715 		GrenadeLauncher_UpdateBullets(weaponPtr);
5716 	}
5717 
5718 	if (PlayersWeaponHModelController.keyframe_flags) {
5719     	TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
5720 		TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
5721 
5722 		/* Reload grenade launcher ahead of schedule. */
5723 		weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
5724 		weaponPtr->PrimaryMagazinesRemaining--;
5725 		GrenadeLauncher_UpdateBullets(weaponPtr);
5726 
5727 	}
5728 }
5729 
GrenadeLauncherReload_Change(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5730 void GrenadeLauncherReload_Change(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5731 
5732 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5733 
5734 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Reload) {
5735 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,(ONE_FIXED*4)/3);
5736 		PlayersWeaponHModelController.Looped=0;
5737 		/* No update bullets here. */
5738 	}
5739 
5740 	if (PlayersWeaponHModelController.keyframe_flags) {
5741     	TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
5742 		TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
5743 
5744 		/* Reload grenade launcher if unloaded. */
5745 		if (weaponPtr->PrimaryRoundsRemaining==0) {
5746 			weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine;
5747 			weaponPtr->PrimaryMagazinesRemaining--;
5748 		}
5749 		GrenadeLauncher_UpdateBullets(weaponPtr);
5750 		/* A little cheat... */
5751 		if (weaponPtr->PrimaryRoundsRemaining<templateAmmoPtr->AmmoPerMagazine) {
5752 			GrenadeLauncherSectionPointers[0]->flags|=section_data_notreal;
5753 		}
5754 	}
5755 }
5756 
GrenadeLauncherNull(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5757 void GrenadeLauncherNull(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5758 
5759 	/* A bit of a hack - for resetting position. */
5760 
5761 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5762 
5763 	/* Pop the round in the breach... */
5764 	GrenadeLauncherSectionPointers[0]->flags|=section_data_notreal;
5765 	/* It'll be put back at the next update. */
5766 
5767 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) {
5768 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
5769 	}
5770 }
5771 
GrenadeLauncherIdle(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5772 void GrenadeLauncherIdle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5773 
5774 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5775 
5776 //	textprint("GL Rounds = %d\n",(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT));
5777 	/* Don't update on secondary fire! */
5778 
5779 	GrenadeLauncher_UpdateBullets(weaponPtr);
5780 
5781 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) {
5782 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
5783 	}
5784 
5785 }
5786 
GrenadeLauncherFidget(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5787 void GrenadeLauncherFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5788 
5789 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5790 
5791 //	textprint("GL Rounds = %d\n",(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT));
5792 	GrenadeLauncher_UpdateBullets(weaponPtr);
5793 
5794 	if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
5795 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
5796 	}
5797 
5798 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
5799 
5800 		if (WeaponFidgetPlaying) {
5801 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
5802 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
5803 				WeaponFidgetPlaying=0;
5804 			}
5805 		} else if ((FastRandom()&255)==0) {
5806 			/* Start animation. */
5807 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
5808 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0);
5809 				weaponPtr->StateTimeOutCounter=0;
5810 				WeaponFidgetPlaying=1;
5811 			}
5812 		}
5813 	}
5814 
5815 }
5816 
GrenadeLauncher_SwapIn(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5817 void GrenadeLauncher_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5818 
5819 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5820 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED/3);
5821 		PlayersWeaponHModelController.Looped=0;
5822 	}
5823 }
5824 
GrenadeLauncher_SwapOut(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5825 void GrenadeLauncher_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5826 
5827 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5828 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED/3);
5829 		PlayersWeaponHModelController.Looped=0;
5830 	}
5831 }
5832 
GrenadeLauncherInit(PLAYER_WEAPON_DATA * weaponPtr)5833 void GrenadeLauncherInit(PLAYER_WEAPON_DATA *weaponPtr) {
5834 
5835 	int a;
5836 
5837 	/* Setup grenades. */
5838 
5839 	for (a=0; a<6; a++) {
5840 		GrenadeLauncherSectionPointers[a]=GetThisSectionData(
5841 			PlayersWeaponHModelController.section_data,GrenadeLauncherBulletNames[a]);
5842 	}
5843 
5844 	GrenadeLauncher_UpdateBullets(weaponPtr);
5845 
5846 }
5847 
PulseRifleFidget(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5848 void PulseRifleFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5849 
5850 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
5851 
5852 	if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
5853 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
5854 	}
5855 
5856 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
5857 
5858 		if (WeaponFidgetPlaying) {
5859 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
5860 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
5861 				WeaponFidgetPlaying=0;
5862 			}
5863 		} else if ((FastRandom()&255)==0) {
5864 			/* Start animation. */
5865 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
5866 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0);
5867 				weaponPtr->StateTimeOutCounter=0;
5868 				WeaponFidgetPlaying=1;
5869 			}
5870 		}
5871 
5872 	}
5873 
5874 }
5875 
WristBlade_Idle(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5876 void WristBlade_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5877 
5878 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5879 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
5880 	}
5881 
5882 	/* Are we running? */
5883 
5884 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
5885 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
5886 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
5887 
5888 		/* Were we running? */
5889 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
5890 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
5891 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
5892 			}
5893 		} else {
5894 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
5895 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
5896 			}
5897 		}
5898 	} else {
5899 		TEMPLATE_WEAPON_DATA *twPtr;
5900 
5901 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
5902 
5903 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
5904 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
5905 		}
5906 
5907 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
5908 
5909 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
5910 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
5911 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
5912 				}
5913 			} else if ((FastRandom()&255)==0) {
5914 				/* Start animation. */
5915 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
5916 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
5917 					weaponPtr->StateTimeOutCounter=0;
5918 				}
5919 			}
5920 		}
5921 	}
5922 
5923 }
5924 
TemplateHands_SwapOut(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5925 void TemplateHands_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5926 
5927 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5928 		SECTION *root_section;
5929 
5930 		root_section=GetNamedHierarchyFromLibrary("pred_HUD","Template");
5931 		GLOBALASSERT(root_section);
5932 
5933 		PlayersWeaponHModelController.Sequence_Type=(int)HMSQT_PredatorHUD;
5934 		PlayersWeaponHModelController.Sub_Sequence=(int)PHSS_Go;
5935 		PlayersWeaponHModelController.Seconds_For_Sequence=(ONE_FIXED/3);
5936 		/* That to get the new sections right. */
5937 		Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section, 0, 1,0);
5938 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,(ONE_FIXED/3),0);
5939 
5940 	}
5941 }
5942 
WristBlade_Readying(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5943 void WristBlade_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5944 
5945 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5946 		SECTION *root_section;
5947 
5948 		root_section=GetNamedHierarchyFromLibrary("pred_HUD","wrist blade");
5949 		GLOBALASSERT(root_section);
5950 
5951 		PlayersWeaponHModelController.Sequence_Type=(int)HMSQT_PredatorHUD;
5952 		PlayersWeaponHModelController.Sub_Sequence=(int)PHSS_Come;
5953 		PlayersWeaponHModelController.Seconds_For_Sequence=(ONE_FIXED>>1);
5954 		/* That to get the new sections right. */
5955 		Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section, 0, 1,0);
5956 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Come,(ONE_FIXED>>1),0);
5957 
5958 	}
5959 }
5960 
WristBlade_Unreadying(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)5961 void WristBlade_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
5962 
5963 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
5964 
5965 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Go,ONE_FIXED>>1);
5966 		PlayersWeaponHModelController.Looped=0;
5967 	}
5968 }
5969 
StrikeTime(int time)5970 void StrikeTime(int time) {
5971 
5972 	char mbuf[128];
5973 
5974 	if (time<1) {
5975 		sprintf(mbuf,"STRIKETIME IS %d\n",WBStrikeTime);
5976 		NewOnScreenMessage(mbuf);
5977 		return;
5978 	}
5979 
5980 	sprintf(mbuf,"STRIKETIME %d -> %d\n",WBStrikeTime,time);
5981 	NewOnScreenMessage(mbuf);
5982 
5983 	TemplateWeapon[WEAPON_PRED_WRISTBLADE].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]=
5984 		(DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,time));
5985 	WBStrikeTime=time;
5986 
5987 }
5988 
GoGoGadgetCudgelPrimaryAttackAnimation(void)5989 void GoGoGadgetCudgelPrimaryAttackAnimation(void) {
5990 
5991 	/* Standard_Fire is the default. */
5992 
5993 	if ((FastRandom()&65535)<21645) {
5994 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire)) {
5995 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0);
5996 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
5997 				StaffAttack=0;
5998 			} else {
5999 				StaffAttack=1;
6000 			}
6001 			return;
6002 		}
6003 	}
6004 
6005 	if ((FastRandom()&65535)<32767) {
6006 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Secondary_Fire)) {
6007 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0);
6008 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6009 				StaffAttack=2;
6010 			} else {
6011 				StaffAttack=3;
6012 			}
6013 			return;
6014 		}
6015 	}
6016 
6017 	/* Still here? Use default. */
6018 
6019 	InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0);
6020 	if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6021 		StaffAttack=0;
6022 	} else {
6023 		StaffAttack=1;
6024 	}
6025 
6026 }
6027 
Cudgel_Strike(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6028 void Cudgel_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6029 
6030 	/* Let's cut'n'paster the wristblade code. */
6031 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6032 
6033 		GoGoGadgetCudgelPrimaryAttackAnimation();
6034 
6035 	} else {
6036 		if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Fire)
6037 			&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Secondary_Fire)) {
6038 			/* Something's changing state without resetting the timer... */
6039 			GoGoGadgetCudgelPrimaryAttackAnimation();
6040 		}
6041 
6042 		if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
6043 			/* End state. */
6044 			weaponPtr->StateTimeOutCounter = 0;
6045 			StaffAttack=-1;
6046 		} else {
6047 			/* Maintain attack. */
6048 			weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
6049 
6050 		}
6051 
6052 		{
6053 			/*  In the middle. */
6054 			/* Execute attack. */
6055 			int hits;
6056 
6057 			hits=0;
6058 
6059 			if (PlayersWeaponHModelController.keyframe_flags&1) {
6060 				hits++;
6061 			}
6062 
6063 			if (hits) {
6064 
6065 				enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
6066 
6067 				MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
6068 				PlayCudgelSound();
6069 				HtoHStrikes++;
6070 			}
6071 		}
6072 	}
6073 
6074 }
6075 
GoGoGadgetWristbladePrimaryAttackAnimation(void)6076 void GoGoGadgetWristbladePrimaryAttackAnimation(void) {
6077 
6078 	/* Attack_Jab is the default. */
6079 
6080 	if ((FastRandom()&65535)<21645) {
6081 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Attack_Primary)) {
6082 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
6083 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6084 				StaffAttack=6;
6085 			} else {
6086 				StaffAttack=7;
6087 			}
6088 			return;
6089 		}
6090 	}
6091 
6092 	if ((FastRandom()&65535)<32767) {
6093 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary)) {
6094 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0);
6095 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6096 				StaffAttack=8;
6097 			} else {
6098 				StaffAttack=9;
6099 			}
6100 			return;
6101 		}
6102 	}
6103 
6104 	/* Still here? Use default. */
6105 
6106 	InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Jab,-1,0);
6107 	if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6108 		StaffAttack=0;
6109 	} else {
6110 		StaffAttack=1;
6111 	}
6112 
6113 }
6114 
WristBlade_Strike(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6115 void WristBlade_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6116 
6117 	#if 0
6118 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6119 		if ((FastRandom()&65536)<32767) {
6120 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,WBStrikeTime,0);
6121 		} else {
6122 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,WBStrikeTime,0);
6123 			//InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,WBStrikeTime,0);
6124 		}
6125 	}
6126 
6127 	{
6128 		/* Execute attack. */
6129 		int hits;
6130 
6131 		hits=0;
6132 
6133 		if (PlayersWeaponHModelController.keyframe_flags&1) {
6134 			hits++;
6135 		}
6136 
6137 		if (hits) {
6138 
6139 			enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
6140 
6141 			MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
6142 			PlayPredSlashSound();
6143 
6144 		}
6145 
6146 	}
6147 	#else
6148 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6149 
6150 		GoGoGadgetWristbladePrimaryAttackAnimation();
6151 
6152 	} else {
6153 		if ((PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Jab)
6154 			&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Primary)
6155 			&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Secondary)) {
6156 			/* Something's changing state without resetting the timer... */
6157 			GoGoGadgetWristbladePrimaryAttackAnimation();
6158 		}
6159 
6160 		if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
6161 			/* End state. */
6162 			weaponPtr->StateTimeOutCounter = 0;
6163 			StaffAttack=-1;
6164 		} else {
6165 			/* Maintain attack. */
6166 			weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
6167 
6168 		}
6169 
6170 		{
6171 			//enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
6172 			/*  In the middle. */
6173 			/* Execute attack. */
6174 			int hits;
6175 
6176 			hits=0;
6177 
6178 			if (PlayersWeaponHModelController.keyframe_flags&1) {
6179 				hits++;
6180 			}
6181 
6182 			if (hits) {
6183 
6184 				enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
6185 
6186 				MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
6187 				PlayPredSlashSound();
6188 				HtoHStrikes++;
6189 			}
6190 		}
6191 	}
6192 	#endif
6193 
6194 }
6195 
WristBlade_Strike_Secondary(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6196 void WristBlade_Strike_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6197 
6198 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6199 
6200 		if ((FastRandom()&65536)<32767) {
6201 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
6202 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6203 				StaffAttack=2;
6204 			} else {
6205 				StaffAttack=3;
6206 			}
6207 		} else {
6208 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0);
6209 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
6210 				StaffAttack=4;
6211 			} else {
6212 				StaffAttack=5;
6213 			}
6214 		}
6215 
6216 	} else {
6217 		if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
6218 			/* End state. */
6219 			weaponPtr->StateTimeOutCounter = 0;
6220 			StaffAttack=-1;
6221 		} else {
6222 			/* Maintain attack. */
6223 			weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
6224 
6225 		}
6226 
6227 		{
6228 			//enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
6229 			/*  In the middle. */
6230 			/* Execute attack. */
6231 			int hits;
6232 
6233 			hits=0;
6234 
6235 			if (PlayersWeaponHModelController.keyframe_flags&1) {
6236 				hits++;
6237 			}
6238 
6239 			if (hits) {
6240 
6241 				enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].SecondaryAmmoID;
6242 
6243 				MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
6244 				PlayPredSlashSound();
6245 				HtoHStrikes++;
6246 
6247 		}
6248 
6249 	}
6250 	}
6251 
6252 }
6253 
PredPistol_SwapIn(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6254 void PredPistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6255 
6256 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6257 
6258 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,-1);
6259 		PlayersWeaponHModelController.Looped=0;
6260 
6261 	} else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
6262 		/* End state. */
6263 		weaponPtr->StateTimeOutCounter = 0;
6264 
6265 	} else {
6266 
6267 		/*  In the middle. */
6268 		weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
6269 
6270 	}
6271 
6272 }
6273 
PredPistol_SwapOut(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6274 void PredPistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6275 
6276 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6277 
6278 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,-1,0);
6279 		PlayersWeaponHModelController.Looped=0;
6280 
6281 	} else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
6282 		/* End state. */
6283 		weaponPtr->StateTimeOutCounter = 0;
6284 
6285 	} else {
6286 
6287 		/*  In the middle. */
6288 		weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
6289 
6290 	}
6291 
6292 }
6293 
PredPistol_Idle(void * playerStatus,PLAYER_WEAPON_DATA * weaponPtr)6294 void PredPistol_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6295 
6296 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6297 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
6298 	}
6299 
6300 	/* Are we running? */
6301 
6302 	#if 1
6303 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
6304 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
6305 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
6306 
6307 		/* Were we running? */
6308 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
6309 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
6310 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
6311 			}
6312 		} else {
6313 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
6314 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
6315 			}
6316 		}
6317 	} else {
6318 	#else
6319 	{
6320 	#endif
6321 		TEMPLATE_WEAPON_DATA *twPtr;
6322 
6323 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
6324 
6325 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
6326 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
6327 		}
6328 
6329 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
6330 
6331 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
6332 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
6333 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
6334 				}
6335 			} else if ((FastRandom()&255)==0) {
6336 				/* Start animation. */
6337 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
6338 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
6339 					weaponPtr->StateTimeOutCounter=0;
6340 				}
6341 			}
6342 		}
6343 	}
6344 
6345 	Flamethrower_Timer=0;
6346 
6347 }
6348 
6349 void PredPistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
6350 
6351 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
6352 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,ONE_FIXED,1);
6353 	}
6354 
6355 }
6356 
6357 int PlayerFireFlameThrower(PLAYER_WEAPON_DATA *weaponPtr) {
6358 
6359 	VECTORCH *firingpos;
6360 
6361 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
6362    	int oldAmmoCount;
6363 
6364 	ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon);
6365     {
6366     	oldAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16;
6367 		/* ammo is in 16.16. we want the integer part, rounded up */
6368 		if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) oldAmmoCount+=1;
6369 	}
6370 
6371 
6372    	{
6373    	   	/* theoretical number of bullets fired each frame, as a 16.16 number */
6374    	   	int bulletsToFire=MUL_FIXED(twPtr->FiringRate,NormalFrameTime);
6375 
6376     	if (bulletsToFire<weaponPtr->PrimaryRoundsRemaining)
6377     	{
6378     		weaponPtr->PrimaryRoundsRemaining -= bulletsToFire;
6379        	}
6380         else /* end of magazine */
6381         {
6382            	weaponPtr->PrimaryRoundsRemaining=0;
6383         }
6384     }
6385 
6386     {
6387     	int bulletsFired;
6388     	int newAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16;
6389 			/* ammo is in 16.16. we want the integer part, rounded up */
6390 			if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) newAmmoCount+=1;
6391 
6392         bulletsFired = oldAmmoCount-newAmmoCount;
6393 
6394 	}
6395 
6396 	CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,NormalFrameTime);
6397 
6398 	if ((PWMFSDP)&&(PlayersTarget.Distance>2500)) {	//Was 1700
6399 		VECTORCH null_vec={0,0,0};
6400 
6401 		textprint("Hierarchical Flamethrower Fire!\n");
6402 
6403 		firingpos=&PWMFSDP->World_Offset;
6404 
6405 		FireFlameThrower(firingpos,&null_vec,&PlayersWeapon.ObMat,0, &Flamethrower_Timer);
6406 
6407 	} else {
6408 		#if 0
6409 		firingpos=&CentreOfMuzzleOffset;
6410 		FireFlameThrower(&PlayersWeapon.ObWorld,firingpos,&PlayersWeapon.ObMat,1, &Flamethrower_Timer);
6411 		#else
6412 		VECTORCH Firing_Position;
6413 		VECTORCH null_vec={0,0,0};
6414 		int lerp;
6415 
6416 		/* Find a better place to fire from. */
6417 		Firing_Position=PlayersWeapon.ObWorld;
6418 
6419 		Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,200); //z: 300?
6420 		Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,200); //z: 300?
6421 		Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,200); //z: 300?
6422 
6423 		Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat21,50); //y: 150?
6424 		Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat22,50); //y: 150?
6425 		Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat23,50); //y: 150?
6426 
6427 		Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat11,200); //x: 250?
6428 		Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat12,200); //x: 250?
6429 		Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat13,200); //x: 250?
6430 		/* Interpolation... */
6431 		if (PWMFSDP) {
6432 			lerp=PlayersTarget.Distance-1600;
6433 			if (lerp<0) {
6434 				lerp=0;
6435 			}
6436 			lerp=MUL_FIXED(lerp,ONE_FIXED);
6437 			lerp=DIV_FIXED(lerp,(2500-1600));
6438 
6439 			textprint("lerp %d\n",lerp);
6440 
6441 			Firing_Position.vx=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vx);
6442 			Firing_Position.vy=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vy);
6443 			Firing_Position.vz=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vz);
6444 
6445 			Firing_Position.vx+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vx);
6446 			Firing_Position.vy+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vy);
6447 			Firing_Position.vz+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vz);
6448 		}
6449 
6450 		FireFlameThrower(&Firing_Position,&null_vec,&PlayersWeapon.ObMat,0, &Flamethrower_Timer);
6451 		#endif
6452 	}
6453 
6454 
6455 	return(1);
6456 
6457 }
6458 
6459 #define ALWAYS_EXIT_WOUNDS 1
6460 
6461 DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data,VECTORCH *incoming, VECTORCH *position, int FromHost) {
6462 
6463 	DAMAGEBLOCK tempdamage;
6464 	int healthdamage,armourdamage;
6465 	int wounds;
6466 	DISPLAYBLOCK *frag;
6467 
6468 	LOCALASSERT(HMC_Ptr==this_section_data->my_controller);
6469 
6470 	frag=NULL;
6471 
6472 	if ((FromHost==0)&&(sbPtr->I_SBtype==I_BehaviourNetGhost)) {
6473 		DamageNetworkGhost(sbPtr, damage, multiple,this_section_data,incoming);
6474 		return(NULL);
6475 	}
6476 
6477 	if (sbPtr->I_SBtype==I_BehaviourDummy) {
6478 		/* Dummys are INDESTRUCTIBLE. */
6479 		return(NULL);
6480 	}
6481 
6482 	if(sbPtr->I_SBtype==I_BehaviourMarinePlayer ||
6483 	   sbPtr->I_SBtype==I_BehaviourAlienPlayer ||
6484 	   sbPtr->I_SBtype==I_BehaviourPredatorPlayer)
6485 	{
6486 		//check for player invulnerability
6487 		PLAYER_STATUS *psPtr=(PLAYER_STATUS*)sbPtr->SBdataptr;
6488 		GLOBALASSERT(psPtr);
6489 		if(psPtr->invulnerabilityTimer>0)
6490 		{
6491 			//player is still invulnerable
6492 			return(NULL);
6493 		}
6494 	}
6495 
6496 	wounds=0;
6497 
6498 	/* Pass damage up test? */
6499 	if ( (this_section_data->sempai->flags&section_flag_passdamagetoparent)
6500 		&&(this_section_data->My_Parent)) {
6501 		/* Try again, a level up. */
6502 		return(CauseDamageToHModel(HMC_Ptr,sbPtr,damage,multiple,this_section_data->My_Parent,incoming,position,FromHost));
6503 	}
6504 
6505 	/* The section takes damage... and the SB takes the health and armour damage. */
6506 	tempdamage.Health=this_section_data->current_damage.Health;
6507 	tempdamage.Armour=this_section_data->current_damage.Armour;
6508 	DamageDamageBlock(&this_section_data->current_damage,damage,multiple);
6509 	if (this_section_data->sempai->flags&section_flag_doesnthurtsb) {
6510 		healthdamage=0;
6511 		armourdamage=0;
6512 	} else {
6513 		healthdamage=tempdamage.Health-this_section_data->current_damage.Health;
6514 		armourdamage=tempdamage.Armour-this_section_data->current_damage.Armour;
6515 	}
6516 
6517 	if (armourdamage>0) {
6518 		if (sbPtr->SBDamageBlock.Armour<armourdamage) sbPtr->SBDamageBlock.Armour=0;
6519 		else sbPtr->SBDamageBlock.Armour-=armourdamage;
6520 	}
6521 
6522 	if (healthdamage>0) {
6523 		if (sbPtr->SBDamageBlock.Health<healthdamage) sbPtr->SBDamageBlock.Health=0;
6524 		else sbPtr->SBDamageBlock.Health-=healthdamage;
6525 	}
6526 
6527 	/* Consider networking. */
6528 	if (AvP.Network != I_No_Network)
6529 	{
6530 		if (sbPtr->I_SBtype!=I_BehaviourNetGhost) {
6531 			AddNetMsg_GhostHierarchyDamaged(sbPtr,damage,multiple,this_section_data->sempai->IDnumber,incoming);
6532 		}
6533 	}
6534 
6535 	#if ALWAYS_EXIT_WOUNDS
6536 	/* otherwise, exit wounds! */
6537 	if ((incoming)&&(this_section_data->sempai->flags&section_sprays_anything)
6538 		&&(damage->MakeExitWounds)) {
6539 		enum PARTICLE_ID blood_type;
6540 		int a;
6541 		VECTORCH *startpos;
6542 		VECTORCH final_spray_direction;
6543 
6544 		if (this_section_data->sempai->flags&section_sprays_blood) {
6545 			blood_type=GetBloodType(sbPtr);
6546 			/* Er... default? */
6547 		} else if (this_section_data->sempai->flags&section_sprays_acid) {
6548 			blood_type=PARTICLE_ALIEN_BLOOD;
6549 		} else if (this_section_data->sempai->flags&section_sprays_predoblood) {
6550 			blood_type=PARTICLE_PREDATOR_BLOOD;
6551 		} else if (this_section_data->sempai->flags&section_sprays_sparks) {
6552 			blood_type=PARTICLE_SPARK;
6553 		} else {
6554 			blood_type=PARTICLE_FLAME;
6555 			/* Distinctive. */
6556 		}
6557 
6558 		if (position) {
6559 			startpos=position;
6560 		} else {
6561 			startpos=&this_section_data->World_Offset;
6562 		}
6563 		/* 'incoming' SHOULD be normalised. */
6564 		for (a=0; a<(multiple>>ONE_FIXED_SHIFT); a++) {
6565 
6566 			RotateAndCopyVector(incoming,&final_spray_direction,&sbPtr->DynPtr->OrientMat);
6567 
6568 			/* Scale down. */
6569 
6570 			//final_spray_direction.vx>>=1;
6571 			//final_spray_direction.vy>>=1;
6572 			//final_spray_direction.vz>>=1;
6573 
6574 			/* Add random element. */
6575 
6576 			final_spray_direction.vx+=( (FastRandom()&511)-256);
6577 			final_spray_direction.vy+=( (FastRandom()&511)-256);
6578 			final_spray_direction.vz+=( (FastRandom()&511)-256);
6579 
6580 			MakeParticle(startpos, &final_spray_direction, blood_type);
6581 		}
6582 	}
6583 	#endif
6584 
6585 	if (this_section_data->current_damage.Health<=0) {
6586 		/* Might want to create a frag here? */
6587 		if (damage->BlowUpSections) {
6588 
6589 			VECTORCH blastCentre;
6590 			/* Deduce blastCentre. */
6591 			blastCentre=this_section_data->World_Offset;
6592 
6593 			if (incoming) {
6594 				blastCentre.vx+=incoming->vx;
6595 				blastCentre.vy+=incoming->vy;
6596 				blastCentre.vz+=incoming->vz;
6597 			}
6598 
6599 			/* For the moment, this ALWAYS has priority. */
6600 			Pop_Section(sbPtr,this_section_data,&blastCentre,&wounds);
6601 
6602 			if (wounds&section_has_sparkoflife) {
6603 				/* Kill SB off! */
6604 				sbPtr->SBDamageBlock.Health=0;
6605 				/* That's the way... */
6606 			}
6607 
6608 		} else if ( ((this_section_data->sempai->flags&section_is_master_root)==0)
6609 			&&((this_section_data->sempai->flags&section_flag_never_frag)==0)
6610 			&&(((this_section_data->sempai->flags&section_sprays_acid)&&((this_section_data->sempai->flags&section_flag_fragonlyfordisks)==0))
6611 				||((this_section_data->sempai->StartingStats.Health<TotalKineticDamage(damage))&&((this_section_data->sempai->flags&section_flag_fragonlyfordisks)==0))
6612 				||((damage->Slicing>2)&&(this_section_data->sempai->flags&section_flag_fragonlyfordisks))
6613 				||((damage->Slicing>0)&&((this_section_data->sempai->flags&section_flag_fragonlyfordisks)==0))
6614 			)
6615 			){
6616 
6617 			MATRIXCH *orientptr;
6618 			{
6619 				/* Work out which orientation to use. */
6620 				if (this_section_data->My_Parent==NULL) {
6621 					/* The root (Gah!), so use sbPtr. */
6622 					orientptr=&sbPtr->DynPtr->OrientMat;
6623 				} else {
6624 					/* Use parent. */
6625 					orientptr=&this_section_data->My_Parent->SecMat;
6626 				}
6627 			}
6628 
6629 			/* Never frag off the root, it wouldn't make sense. */
6630 
6631 			frag=MakeHierarchicalDebris(sbPtr,this_section_data, &this_section_data->World_Offset, orientptr,&wounds,3);
6632 
6633 			/* Oh Dear!  Every section below and including this one becomes... unreal.
6634 			And if any of them contain the spark of life, we need to know. */
6635 
6636 			if (wounds&section_has_sparkoflife) {
6637 				/* Kill SB off! */
6638 				sbPtr->SBDamageBlock.Health=0;
6639 				/* That's the way... */
6640 			}
6641 		} else {
6642 			/* Don't frag the master root, and take care with non-aliens. */
6643 			if (this_section_data->sempai->flags&section_has_sparkoflife) {
6644 				/* However, if the master root is destroyed and is a critical section, */
6645 				sbPtr->SBDamageBlock.Health=0;
6646 				/* ...still kill them off. */
6647 			}
6648 			#if (ALWAYS_EXIT_WOUNDS==0)
6649 			/* otherwise, exit wounds! */
6650 			if ((incoming)&&(this_section_data->sempai->flags&section_sprays_anything)
6651 				&&(damage->MakeExitWounds)) {
6652 				enum PARTICLE_ID blood_type;
6653 				int a;
6654 				VECTORCH *startpos;
6655 				VECTORCH final_spray_direction;
6656 
6657 				if (this_section_data->sempai->flags&section_sprays_blood) {
6658 					blood_type=GetBloodType(sbPtr);
6659 					/* Er... default? */
6660 				} else if (this_section_data->sempai->flags&section_sprays_acid) {
6661 					blood_type=PARTICLE_ALIEN_BLOOD;
6662 				} else if (this_section_data->sempai->flags&section_sprays_predoblood) {
6663 					blood_type=PARTICLE_PREDATOR_BLOOD;
6664 				} else if (this_section_data->sempai->flags&section_sprays_sparks) {
6665 					blood_type=PARTICLE_SPARK;
6666 				} else {
6667 					blood_type=PARTICLE_FLAME;
6668 					/* Distinctive. */
6669 				}
6670 
6671 				if (position) {
6672 					startpos=position;
6673 				} else {
6674 					startpos=&this_section_data->World_Offset;
6675 				}
6676 				/* 'incoming' SHOULD be normalised. */
6677 				for (a=0; a<(multiple>>ONE_FIXED_SHIFT); a++) {
6678 
6679 					RotateAndCopyVector(incoming,&final_spray_direction,&sbPtr->DynPtr->OrientMat);
6680 
6681 					/* Scale down. */
6682 
6683 					//final_spray_direction.vx>>=1;
6684 					//final_spray_direction.vy>>=1;
6685 					//final_spray_direction.vz>>=1;
6686 
6687 					/* Add random element. */
6688 
6689 					final_spray_direction.vx+=( (FastRandom()&511)-256);
6690 					final_spray_direction.vy+=( (FastRandom()&511)-256);
6691 					final_spray_direction.vz+=( (FastRandom()&511)-256);
6692 
6693 					MakeParticle(startpos, &final_spray_direction, blood_type);
6694 				}
6695 			}
6696 			#endif
6697 		}
6698 	}
6699 
6700 	/* There... */
6701 
6702  	switch(sbPtr->I_SBtype)
6703 	{
6704 		case I_BehaviourAlien:
6705 		{
6706    	 	/* reduce alien health */
6707 			AlienIsDamaged(sbPtr, damage, multiple, wounds,this_section_data,incoming,frag);
6708 			break;
6709 		}
6710 		case I_BehaviourMarinePlayer:
6711 		case I_BehaviourAlienPlayer:
6712 		case I_BehaviourPredatorPlayer:
6713 		{
6714 			PlayerIsDamaged(sbPtr,damage,multiple,incoming);
6715 			break;
6716 		}
6717 		case I_BehaviourInanimateObject:
6718 		{
6719 			InanimateObjectIsDamaged(sbPtr,damage,multiple);
6720 			break;
6721 		}
6722 		case I_BehaviourPredator:
6723 		{
6724 			PredatorIsDamaged(sbPtr,damage,multiple,this_section_data,incoming);
6725 			break;
6726 		}
6727 		case I_BehaviourXenoborg:
6728 		{
6729 			XenoborgIsDamaged(sbPtr, damage, multiple, wounds,incoming);
6730 			break;
6731 		}
6732 		case I_BehaviourSeal:
6733 		case I_BehaviourMarine:
6734 		{
6735 			MarineIsDamaged(sbPtr,damage,multiple,wounds,this_section_data,incoming);
6736 			break;
6737 		}
6738 		case I_BehaviourQueenAlien:
6739 		{
6740 			QueenIsDamaged(sbPtr,damage,multiple,this_section_data,incoming,position);
6741 			break;
6742 		}
6743 		case I_BehaviourPredatorAlien:
6744 		{
6745 			GLOBALASSERT(0);
6746 			//PAQIsDamaged(sbPtr,damage,multiple);
6747 			break;
6748 		}
6749 		case I_BehaviourFaceHugger:
6750 		{
6751 			FacehuggerIsDamaged(sbPtr,damage,multiple);
6752 			break;
6753 		}
6754 		#if 0
6755 		/* Whoa, positive feedback! */
6756 		case I_BehaviourNetGhost:
6757 		{
6758 			DamageNetworkGhost(sbPtr, damage, multiple,this_section_data,incoming);
6759 			break;
6760 		}
6761 		#endif
6762 		case I_BehaviourAutoGun:
6763 		{
6764 			AGunIsDamaged(sbPtr, damage, multiple, wounds,incoming);
6765 			break;
6766 		}
6767 		case I_BehaviourNetCorpse:
6768 		{
6769 			CorpseIsDamaged(sbPtr,damage,multiple,wounds,this_section_data,incoming);
6770 			break;
6771 		}
6772 		default:
6773 			break;
6774 	}
6775 
6776 	return(frag);
6777 }
6778 
6779 VECTORCH HitAreaArray[HAM_end] = {
6780 	{0,0,0},
6781 	{0,0,1000},
6782 	{0,0,-1000},
6783 	{0,-1000,0},
6784 	{0,1000,0},
6785 	{-1000,0,0},
6786 	{1000,0,0},
6787 	{-1000,-1000,0},
6788 	{1000,-1000,0},
6789 	{-1000,1000,0},
6790 	{1000,1000,0},
6791 };
6792 
6793 VECTORCH Local_HitAreaArray[HAM_end];
6794 HITAREAMATRIX HitZone,HitAspect;
6795 
6796 void FindHitArea(DISPLAYBLOCK *dptr) {
6797 
6798 	int a;
6799 	MATRIXCH LtoV;
6800 	int nearest,neardist,dist;
6801 	int fbnearest,fbneardist;
6802 
6803 	MatrixMultiply(&Global_VDB_Ptr->VDB_Mat,&dptr->ObMat,&LtoV);
6804 
6805 	nearest=-1;
6806 	fbnearest=-1;
6807 	neardist=1000000;
6808 	fbneardist=1000000;
6809 
6810 	for (a=0; a<HAM_end; a++) {
6811 		RotateAndCopyVector(&HitAreaArray[a],&Local_HitAreaArray[a],&LtoV);
6812 
6813 		Local_HitAreaArray[a].vx+=dptr->ObView.vx;
6814 		Local_HitAreaArray[a].vy+=dptr->ObView.vy;
6815 		Local_HitAreaArray[a].vz+=dptr->ObView.vz;
6816 
6817 
6818 		dist=Approximate3dMagnitude(&Local_HitAreaArray[a]);
6819 
6820 		if ( (a!=HAM_Front) && (a!=HAM_Back) ) {
6821 			if (dist<neardist) {
6822 				nearest=a;
6823 				neardist=dist;
6824 			}
6825 		}
6826 		if ( (a==HAM_Front) || (a==HAM_Back) || (a==HAM_Centre) ) {
6827 			if (dist<fbneardist) {
6828 				fbnearest=a;
6829 				fbneardist=dist;
6830 			}
6831 		}
6832 	}
6833 
6834 	LOCALASSERT(nearest!=-1);
6835 	LOCALASSERT( (fbnearest==HAM_Front) || (fbnearest==HAM_Back) || (fbnearest==HAM_Centre) );
6836 
6837 	HitZone=nearest;
6838 	HitAspect=fbnearest;
6839 
6840 	switch(nearest){
6841 		case HAM_Centre:
6842 			textprint("Nearest = Centre\n");
6843 			break;
6844 		case HAM_Top:
6845 			textprint("Nearest = Top\n");
6846 			break;
6847 		case HAM_Base:
6848 			textprint("Nearest = Base\n");
6849 			break;
6850 		case HAM_Left:
6851 			textprint("Nearest = Left\n");
6852 			break;
6853 		case HAM_Right:
6854 			textprint("Nearest = Right\n");
6855 			break;
6856 		case HAM_TopLeft:
6857 			textprint("Nearest = TopLeft\n");
6858 			break;
6859 		case HAM_TopRight:
6860 			textprint("Nearest = TopRight\n");
6861 			break;
6862 		case HAM_BaseLeft:
6863 			textprint("Nearest = BaseLeft\n");
6864 			break;
6865 		case HAM_BaseRight:
6866 			textprint("Nearest = BaseRight\n");
6867 			break;
6868 		default:
6869 			GLOBALASSERT(0);
6870 			break;
6871 	}
6872 	switch (fbnearest) {
6873 		case HAM_Centre:
6874 			textprint("Aspect Centre\n");
6875 			break;
6876 		case HAM_Front:
6877 			textprint("Aspect Front\n");
6878 			break;
6879 		case HAM_Back:
6880 			textprint("Aspect Back\n");
6881 			break;
6882 	}
6883 
6884 }
6885 
6886 HITLOCATIONTABLE *GetThisHitLocationTable(char *id) {
6887 
6888 	int a;
6889 	extern HITLOCATIONTABLE Global_Hitlocation_Tables[];
6890 
6891 	a=0;
6892 	while (Global_Hitlocation_Tables[a].id!=NULL) {
6893 		if (strcmp(id,Global_Hitlocation_Tables[a].id)==0) {
6894 			return(&Global_Hitlocation_Tables[a]);
6895 		}
6896 		a++;
6897 	}
6898 	return(NULL);
6899 }
6900 
6901 HITLOCATIONTABLEENTRY *Get_Sublocation(STRATEGYBLOCK *sbPtr) {
6902 
6903 	HITLOCATIONTABLE *hltable;
6904 	HITLOCATIONTABLEENTRY *subtable,*entry;
6905 	int dice;
6906 
6907 	/* Identify table... */
6908 	switch (sbPtr->I_SBtype) {
6909 		case I_BehaviourMarine:
6910 		case I_BehaviourSeal:
6911 			{
6912 				/* Get hierarchy name... */
6913 				MARINE_STATUS_BLOCK *marineStatusPointer;
6914 
6915 				LOCALASSERT(sbPtr);
6916 				marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6917 				LOCALASSERT(marineStatusPointer);
6918 
6919 				hltable=GetThisHitLocationTable(marineStatusPointer->My_Weapon->HitLocationTableName);
6920 			}
6921 			break;
6922 		case I_BehaviourAlien:
6923 			{
6924 				ALIEN_STATUS_BLOCK *alienStatusPointer;
6925 
6926 				LOCALASSERT(sbPtr);
6927 				alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
6928 				LOCALASSERT(alienStatusPointer);
6929 
6930 				switch (alienStatusPointer->Type) {
6931 					case AT_Standard:
6932 					default:
6933 						hltable=GetThisHitLocationTable("alien");
6934 						break;
6935 					case AT_Predalien:
6936 						hltable=GetThisHitLocationTable("predalien");
6937 						break;
6938 					case AT_Praetorian:
6939 						hltable=GetThisHitLocationTable("praetorian");
6940 						break;
6941 				}
6942 			}
6943 			break;
6944 		case I_BehaviourPredator:
6945 			{
6946 				/* Get hierarchy name... */
6947 				PREDATOR_STATUS_BLOCK *predatorStatusPointer;
6948 
6949 				LOCALASSERT(sbPtr);
6950 				predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
6951 				LOCALASSERT(predatorStatusPointer);
6952 
6953 				hltable=GetThisHitLocationTable(predatorStatusPointer->Selected_Weapon->HitLocationTableName);
6954 			}
6955 			break;
6956 		case I_BehaviourXenoborg:
6957 			hltable=GetThisHitLocationTable("xenoborg");
6958 			break;
6959 		case I_BehaviourAutoGun:
6960 			hltable=GetThisHitLocationTable("sentrygun");
6961 			break;
6962 		case I_BehaviourNetCorpse:
6963 			{
6964 				NETCORPSEDATABLOCK *corpseDataPtr;
6965 
6966 				LOCALASSERT(sbPtr);
6967 				corpseDataPtr = (NETCORPSEDATABLOCK *)(sbPtr->SBdataptr);
6968 				LOCALASSERT(corpseDataPtr);
6969 
6970 				hltable=corpseDataPtr->hltable;
6971 				/* Special corpse case. */
6972 				HitZone=HAM_Centre;
6973 				HitAspect=HAM_Centre;
6974 			}
6975 			break;
6976 		case I_BehaviourNetGhost :
6977 			{
6978 				NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
6979 				hltable=ghostData->hltable;
6980 
6981 				if(ghostData->type==I_BehaviourNetCorpse)
6982 				{
6983 					//special corpse case here as well , I should imagine
6984 					HitZone=HAM_Centre;
6985 					HitAspect=HAM_Centre;
6986 				}
6987 
6988 			}
6989 			break;
6990 		default:
6991 			textprint("No hit table!\n");
6992 			hltable=NULL;
6993 			/* See ChrisF */
6994 			break;
6995 	}
6996 
6997 	if (hltable==NULL) {
6998 		/* Hey ho... */
6999 		return(NULL);
7000 	}
7001 
7002 	/* Now the fun bit. */
7003 
7004 	dice=FastRandom()&65535;
7005 
7006 	switch (HitZone) {
7007 		case HAM_Centre:
7008 			subtable=hltable->CentreLocs;
7009 			break;
7010 		case HAM_Top:
7011 			subtable=hltable->TopLocs;
7012 			break;
7013 		case HAM_Base:
7014 			subtable=hltable->BaseLocs;
7015 			break;
7016 		case HAM_Left:
7017 			subtable=hltable->LeftLocs;
7018 			break;
7019 		case HAM_Right:
7020 			subtable=hltable->RightLocs;
7021 			break;
7022 		case HAM_TopLeft:
7023 			subtable=hltable->TopLeftLocs;
7024 			break;
7025 		case HAM_TopRight:
7026 			subtable=hltable->TopRightLocs;
7027 			break;
7028 		case HAM_BaseLeft:
7029 			subtable=hltable->BaseLeftLocs;
7030 			break;
7031 		case HAM_BaseRight:
7032 			subtable=hltable->BaseRightLocs;
7033 			break;
7034 		default:
7035 			GLOBALASSERT(0);
7036 			break;
7037 	}
7038 
7039 	/* Now, get location. */
7040 
7041 	entry=subtable;
7042 
7043 	while (entry->section_name!=NULL) {
7044 		if (dice<entry->cprob) {
7045 			if (!( ( (HitAspect==HAM_Front)&&(entry->aspect&back_aspect) )
7046 				||( (HitAspect==HAM_Back)&&(entry->aspect&front_aspect) ) )) {
7047 				/* Okay! */
7048 				break;
7049 			}
7050 		}
7051 		dice-=entry->cprob;
7052 		entry++;
7053 	}
7054 
7055 	return(entry);
7056 }
7057 
7058 SECTION_DATA *HitLocationRoll(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *source) {
7059 
7060 	HITLOCATIONTABLEENTRY *entry;
7061 
7062 	if (sbPtr->SBdptr==NULL) {
7063 		/* Far case?  Hey ho... */
7064 		return(NULL);
7065 	}
7066 
7067 	if (sbPtr->SBdptr->HModelControlBlock==NULL) {
7068 		/* Not a hierarchy. */
7069 		return(NULL);
7070 	}
7071 
7072 	if ((source==NULL) || (source==Player->ObStrategyBlock)) {
7073 		/* Why not?  This shouldn't get called, really... */
7074 		FindHitArea(sbPtr->SBdptr);
7075 	} else {
7076 		HitZone=HAM_Top;
7077 		HitAspect=HAM_Centre;
7078 	}
7079 
7080 	entry=Get_Sublocation(sbPtr);
7081 
7082 	if (entry==NULL) {
7083 		/* Failure! */
7084 		return(NULL);
7085 	}
7086 
7087 	if (entry->section_name) {
7088 		/* Valid hit. */
7089 		SECTION_DATA *target;
7090 		target=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,entry->section_name);
7091 
7092 		if (target) {
7093 			/* Success! */
7094 			return(target);
7095 		}
7096 	}
7097 
7098 	/* Failure! */
7099 	return(NULL);
7100 }
7101 
7102 DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir) {
7103 
7104 	HITLOCATIONTABLEENTRY *entry;
7105 
7106 	if (sbPtr->SBdptr==NULL) {
7107 		/* Far case?  Hey ho... */
7108 		CauseDamageToObject(sbPtr, damage, multiple,attack_dir);
7109 		return(NULL);
7110 	}
7111 
7112 	LOCALASSERT(sbPtr->SBdptr->HModelControlBlock);
7113 
7114 	if ((source==NULL) || (source==Player->ObStrategyBlock)) {
7115 		FindHitArea(sbPtr->SBdptr);
7116 	} else {
7117 		HitZone=HAM_Top;
7118 		HitAspect=HAM_Centre;
7119 	}
7120 
7121 	entry=Get_Sublocation(sbPtr);
7122 
7123 	if (entry==NULL) {
7124 		/* Failure! */
7125 		CauseDamageToObject(sbPtr, damage, multiple,attack_dir);
7126 		return(NULL);
7127 	}
7128 
7129 	if (entry->section_name) {
7130 		/* Valid hit. */
7131 		SECTION_DATA *target;
7132 		target=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,entry->section_name);
7133 
7134 		if (target) {
7135 			/* Success! */
7136 			DISPLAYBLOCK *frag;
7137 			textprint("Damaged %s!\n",entry->section_name);
7138 			frag=CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, damage, multiple, target,attack_dir,NULL,0);
7139 			return(frag);
7140 		}
7141 	}
7142 
7143 	/* Failure!  Never mind. */
7144 
7145 	CauseDamageToObject(sbPtr, damage, multiple,attack_dir);
7146 	return(NULL);
7147 }
7148 
7149 void AlienClaw_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7150 
7151 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7152 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown,ONE_FIXED/3);
7153 		PlayersWeaponHModelController.Looped=0;
7154 		PlayersWeaponHModelController.Playing=0;
7155 	}
7156 
7157 	LastHand=0;
7158 	Alien_Visible_Weapon=0; //Claws
7159 }
7160 
7161 void AlienClaw_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7162 
7163 	/* ...Nothing? */
7164 
7165 }
7166 
7167 void AlienClaw_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7168 
7169 	/* ...Nothing? */
7170 
7171 	if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0)
7172 		&& (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) {
7173 		/* Jumping or falling... */
7174 		TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0;
7175 	} else {
7176 		TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1;
7177 	}
7178 
7179 	if (Alien_Visible_Weapon==1) {
7180 		/* Correct tail idle position. */
7181 		DELTA_CONTROLLER *XDelta,*YDelta;
7182 
7183 		GLOBALASSERT(Alien_Visible_Weapon==1);
7184 
7185 		XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta");
7186 		YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta");
7187 
7188 		XDelta->timer=32767;
7189 		YDelta->timer=32767;
7190 	}
7191 
7192 }
7193 
7194 void AlienClaw_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7195 
7196 	/* Look for surplus claw keyframe flags. */
7197 	{
7198 		/* Execute attack. */
7199 		int hits;
7200 
7201 		hits=0;
7202 
7203 		if (PlayersWeaponHModelController.keyframe_flags&1) {
7204 			hits++;
7205 		}
7206 
7207 		if (PlayersWeaponHModelController.keyframe_flags&2) {
7208 			hits++;
7209 		}
7210 
7211 		if (hits) {
7212 
7213 			HtoHStrikes+=hits;
7214 
7215 			MeleeWeapon_180Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED*hits,4000);
7216 			PlayAlienSwipeSound();
7217 
7218 		}
7219 	}
7220 
7221 	if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0)
7222 		&& (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) {
7223 		/* Jumping or falling... */
7224 		TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0;
7225 	} else {
7226 		TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1;
7227 	}
7228 
7229 	if (Alien_Visible_Weapon==1) {
7230 		/* Correct tail idle position. */
7231 		DELTA_CONTROLLER *XDelta,*YDelta;
7232 
7233 		GLOBALASSERT(Alien_Visible_Weapon==1);
7234 
7235 		XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta");
7236 		YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta");
7237 
7238 		XDelta->timer=32767;
7239 		YDelta->timer=32767;
7240 	}
7241 
7242 }
7243 
7244 void FixAlienStrikeSpeed(int time) {
7245 
7246 	ACStrikeTime=MUL_FIXED(time,AC_Speed_Factor);
7247 
7248 	TemplateWeapon[WEAPON_ALIEN_CLAW].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]=
7249 		(DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,ACStrikeTime));
7250 
7251 }
7252 
7253 void AlienStrikeTime(int time) {
7254 
7255 	if (time<1) return;
7256 
7257 	AC_Speed_Factor=time;
7258 
7259 }
7260 
7261 void WristBlade_WindUp(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7262 
7263 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7264 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7265 			(int)PHSS_PullBack,-1,0);
7266 
7267 		/* Setup base damage. */
7268 		Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty];
7269 		Player_Weapon_Damage.Special=0;
7270 
7271 		Alien_Tail_Clock=0;
7272 		Wristblade_StrikeType=0;
7273 
7274 		TemplateWeapon[WEAPON_PRED_WRISTBLADE].SecondaryIsAutomatic=1;
7275 
7276 	} else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening)
7277 		&&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) {
7278 
7279 		/* Finished poise move. */
7280 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7281 			(int)PHSS_Hold,-1,1);
7282 
7283 		Alien_Tail_Clock=-1;
7284 
7285 	} else if (Alien_Tail_Clock>=0) {
7286 
7287 		int flags,a;
7288 
7289 		Alien_Tail_Clock+=NormalFrameTime;
7290 
7291 		/* In the move... */
7292 		flags=PlayersWeaponHModelController.keyframe_flags;
7293 
7294 		for (a=0; a<6; a++) {
7295 			/* Gotta be less than six! */
7296 			if (flags&1) {
7297 				Wristblade_StrikeType++;
7298 			}
7299 			flags>>=1;
7300 		}
7301 
7302 	} else {
7303 		/* Windup finished and holding... timeout? */
7304 		Wristblade_StrikeType=-1;
7305 		GLOBALASSERT(Alien_Tail_Clock<0);
7306 		Alien_Tail_Clock-=NormalFrameTime;
7307 		if (Alien_Tail_Clock<-(ONE_FIXED<<2)) {
7308 			/* Time out? */
7309 			if (PlayersWeaponHModelController.Sub_Sequence!=PHSS_PullBack) {
7310 				InitHModelTweening_Backwards(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7311 					(int)PHSS_PullBack,-1,0);
7312 			} else {
7313 				/* In the timeout... */
7314 				if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
7315 					/* End fire, somehow. */
7316 					weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY;
7317 					weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
7318 					return;
7319 				}
7320 			}
7321 		}
7322 	}
7323 
7324 }
7325 
7326 void ThrowSecondaryStrongStrike(void) {
7327 
7328 	int attack=-1;
7329 
7330 	if ((FastRandom()&65535)<32767) {
7331 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7332 			(int)PHSS_Attack_Secondary_Strong_One)) {
7333 			attack=0;
7334 		} else {
7335 			attack=1;
7336 		}
7337 	} else {
7338 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7339 			(int)PHSS_Attack_Secondary_Strong_Two)) {
7340 			attack=1;
7341 		} else {
7342 			attack=0;
7343 		}
7344 	}
7345 
7346 	switch (attack) {
7347 		default:
7348 		case 0:
7349 			GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7350 				 (int)PHSS_Attack_Secondary_Strong_One));
7351 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7352 				(int)PHSS_Attack_Secondary_Strong_One,-1,0);
7353 
7354 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
7355 				StaffAttack=2;
7356 			} else {
7357 				StaffAttack=3;
7358 			}
7359 			break;
7360 		case 1:
7361 			GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7362 				 (int)PHSS_Attack_Secondary_Strong_Two));
7363 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7364 				(int)PHSS_Attack_Secondary_Strong_Two,-1,0);
7365 
7366 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
7367 				StaffAttack=2;
7368 			} else {
7369 				StaffAttack=3;
7370 			}
7371 			break;
7372 	}
7373 }
7374 
7375 void ThrowSecondaryWeakStrike(void) {
7376 
7377 	int attack=-1;
7378 
7379 	if ((FastRandom()&65535)<32767) {
7380 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7381 			(int)PHSS_Attack_Secondary_Weak_One)) {
7382 			attack=0;
7383 		} else {
7384 			attack=1;
7385 		}
7386 	} else {
7387 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7388 			(int)PHSS_Attack_Secondary_Weak_Two)) {
7389 			attack=1;
7390 		} else {
7391 			attack=0;
7392 		}
7393 	}
7394 
7395 	switch (attack) {
7396 		default:
7397 		case 0:
7398 			GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7399 				 (int)PHSS_Attack_Secondary_Weak_One));
7400 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7401 				(int)PHSS_Attack_Secondary_Weak_One,-1,0);
7402 
7403 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
7404 				StaffAttack=4;
7405 			} else {
7406 				StaffAttack=5;
7407 			}
7408 			break;
7409 		case 1:
7410 			GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,
7411 				 (int)PHSS_Attack_Secondary_Weak_Two));
7412 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,
7413 				(int)PHSS_Attack_Secondary_Weak_Two,-1,0);
7414 
7415 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
7416 				StaffAttack=4;
7417 			} else {
7418 				StaffAttack=5;
7419 			}
7420 			break;
7421 	}
7422 
7423 }
7424 
7425 void WristBlade_WindUpStrike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7426 
7427 	/* Eek!  Well, fire must have been released at this stage. */
7428 
7429 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_PredatorHUD);
7430 
7431 	if (PlayersWeaponHModelController.Tweening!=Controller_NoTweening) {
7432 		/* I don't wanna know right now... */
7433 		GLOBALASSERT(PlayersWeaponHModelController.Playing);
7434 		return;
7435 
7436 	}
7437 
7438 	/* Maintain this state... */
7439 	weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
7440 
7441 	if (PlayersWeaponHModelController.Sub_Sequence==PHSS_PullBack) {
7442 		int flag,multiplyer;
7443 
7444 		if (PlayersWeaponHModelController.Reversed) {
7445 			/* In the timeout. */
7446 			/* Stop quick refire... */
7447 			TemplateWeapon[WEAPON_PRED_WRISTBLADE].SecondaryIsAutomatic=0;
7448 			/* Wait, then end. */
7449 			if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
7450 				/* End state. */
7451 				weaponPtr->StateTimeOutCounter = 0;
7452 				StaffAttack=-1;
7453 			}
7454 			return;
7455 		}
7456 
7457 		/* Still in the pull back... wait for the right flag. */
7458 		flag=(1<<Wristblade_StrikeType);
7459 
7460 		if (PlayersWeaponHModelController.keyframe_flags&flag) {
7461 			/* Got it.  Fire that attack. */
7462 			switch (Wristblade_StrikeType) {
7463 				case -1:
7464 					multiplyer=ONE_FIXED;
7465 					ThrowSecondaryStrongStrike();
7466 					Player_Weapon_Damage.Special=1;
7467 					break;
7468 				default:
7469 					multiplyer=(ONE_FIXED>>1);
7470 					ThrowSecondaryWeakStrike();
7471 					Player_Weapon_Damage.Special=0;
7472 					break;
7473 			}
7474 			Player_Weapon_Damage.Impact 	=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Impact 	,multiplyer);
7475 			Player_Weapon_Damage.Cutting	=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Cutting	,multiplyer);
7476 			Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Penetrative,multiplyer);
7477 			Player_Weapon_Damage.Fire		=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Fire		,multiplyer);
7478 			Player_Weapon_Damage.Electrical	=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Electrical	,multiplyer);
7479 			Player_Weapon_Damage.Acid		=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Acid		,multiplyer);
7480 
7481 		} else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening)
7482 			&&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) {
7483 			/* Hit the end!  Whoops.  Fire big attack. */
7484 			ThrowSecondaryStrongStrike();
7485 			Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty];
7486 			Player_Weapon_Damage.Special=1;
7487 		}
7488 
7489 	} else if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Hold) {
7490 		/* In 'Held Back' stance: fire the biggest attack. */
7491 		ThrowSecondaryStrongStrike();
7492 		Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty];
7493 		Player_Weapon_Damage.Special=1;
7494 	} else {
7495 		/* In the attack.  Look for flags and do the damage stuff. */
7496 		if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
7497 			/* End state. */
7498 			weaponPtr->StateTimeOutCounter = 0;
7499 			StaffAttack=-1;
7500 		} else {
7501 			/* Maintain attack. */
7502 			weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
7503 		}
7504 
7505 		{
7506 			/*  In the middle. */
7507 			/* Execute attack. */
7508 			int hits;
7509 
7510 			hits=0;
7511 
7512 			if (PlayersWeaponHModelController.keyframe_flags&1) {
7513 				hits++;
7514 			}
7515 
7516 			if (hits) {
7517 
7518 				STRATEGYBLOCK *Trophy;
7519 				SECTION_DATA *head_sec;
7520 				enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].SecondaryAmmoID;
7521 
7522 
7523 				/* Intercept 'trophy' attack. */
7524 				if (Player_Weapon_Damage.Special) {
7525 					Trophy=GetTrophyTarget(&head_sec);
7526 				} else {
7527 					Trophy=NULL;
7528 				}
7529 				if (Trophy) {
7530 					/* Apply damage. */
7531 					CauseDamageToHModel(Trophy->SBdptr->HModelControlBlock, Trophy, &TemplateAmmo[AMMO_PRED_TROPHY_KILLSECTION].MaxDamage[AvP.Difficulty],
7532 						ONE_FIXED,head_sec,NULL,NULL,0);
7533 					if (PlayerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) {
7534 						PlayPredatorSound(0,PSC_Taunt,0,&PlayerStatusPtr->soundHandle,NULL);
7535 						playerNoise=1;
7536 					}
7537 					CurrentGameStats_TrophyCollected(Trophy);
7538 				} else {
7539 					MeleeWeapon_90Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED,TemplateAmmo[AmmoID].MaxRange);
7540 				}
7541 				PlayPredSlashSound();
7542 				HtoHStrikes++;
7543 			}
7544 		}
7545 
7546 	}
7547 
7548 }
7549 
7550 void AlienTail_Poise(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7551 
7552 	GLOBALASSERT(TemplateWeapon[WEAPON_ALIEN_CLAW].SecondaryIsAutomatic);
7553 
7554 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7555 		DELTA_CONTROLLER *XDelta,*YDelta;
7556 
7557 		/* Check we've got the tail. */
7558 
7559 		if (Alien_Visible_Weapon!=1) {
7560 
7561 			GetHierarchicalWeapon("alien_HUD","tail",(int)HMSQT_AlienHUD,(int)AHSS_TailCome);
7562 			ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon);
7563 
7564 			Alien_Visible_Weapon=1;
7565 			/* Create delta sequences. */
7566 			XDelta=Add_Delta_Sequence(&PlayersWeaponHModelController,
7567 				"XDelta",(int)HMSQT_AlienHUD,(int)AHSS_Hor_Delta,0);
7568 			YDelta=Add_Delta_Sequence(&PlayersWeaponHModelController,
7569 				"YDelta",(int)HMSQT_AlienHUD,(int)AHSS_Ver_Delta,0);
7570 		} else {
7571 
7572 			XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta");
7573 			YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta");
7574 
7575 		}
7576 
7577 		XDelta->timer=32767;
7578 		YDelta->timer=32767;
7579 
7580 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7581 			(int)AHSS_TailCome,ONE_FIXED,0);
7582 
7583 		/* Setup base damage. */
7584 		Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_TAIL].MaxDamage[AvP.Difficulty];
7585 
7586 		Player_Weapon_Damage.Impact=0;
7587 		Player_Weapon_Damage.Cutting=0;
7588 		Player_Weapon_Damage.Penetrative=30;
7589 		Player_Weapon_Damage.Fire=0;
7590 		Player_Weapon_Damage.Electrical=0;
7591 		Player_Weapon_Damage.Acid=0;
7592 
7593 		Player_Weapon_Damage.BlowUpSections=0;
7594 		Player_Weapon_Damage.Special=0;
7595 
7596 		Alien_Tail_Target=NULL;
7597 		COPY_NAME(Alien_Tail_Target_SBname,Null_Name);
7598 
7599 		Alien_Tail_Clock=0;
7600 
7601 	} else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening)
7602 		&&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) {
7603 
7604 		/* Finished poise move. */
7605 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7606 			(int)AHSS_TailHold,ONE_FIXED,1);
7607 
7608 		Alien_Tail_Clock=-1;
7609 
7610 		textprint("Tail Max. Pen. Damage = %d\n",Player_Weapon_Damage.Penetrative);
7611 
7612 	} else if (Alien_Tail_Clock!=-1) {
7613 
7614 		Alien_Tail_Clock+=NormalFrameTime;
7615 
7616 		while (Alien_Tail_Clock>=1000) {
7617 			Player_Weapon_Damage.Penetrative+=1;
7618 			Alien_Tail_Clock-=1000;
7619 		}
7620 
7621 		textprint("Tail Pen. Damage = %d\n",Player_Weapon_Damage.Penetrative);
7622 
7623 	} else {
7624 		textprint("Tail Max. Pen. Damage = %d - Poised.\n",Player_Weapon_Damage.Penetrative);
7625 	}
7626 
7627 }
7628 
7629 int tail_xcal=120;
7630 int tail_ycal=220;
7631 
7632 void ComputeTailDeltaValues(DELTA_CONTROLLER *XDelta,DELTA_CONTROLLER *YDelta) {
7633 
7634 	int temp_timer,screenX,screenY;
7635 	VECTORCH target_pos;
7636 
7637 	extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
7638 	VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
7639 
7640 	GetTargetingPointOfObject(Alien_Tail_Target->SBdptr,&target_pos);
7641 	TranslatePointIntoViewspace(&target_pos);
7642 
7643 	screenX = WideMulNarrowDiv
7644 				(
7645 					target_pos.vx,
7646 					VDBPtr->VDB_ProjX,
7647 					target_pos.vz
7648 				);
7649 	screenY = WideMulNarrowDiv
7650 				(
7651 					target_pos.vy,
7652 					VDBPtr->VDB_ProjY,
7653 					target_pos.vz
7654 				);
7655 
7656 
7657 	if (MIRROR_CHEATMODE) {
7658 		screenX=-screenX;
7659 	}
7660 
7661 	temp_timer=screenX*(-tail_xcal);
7662 	temp_timer+=32767;
7663 
7664 	if (temp_timer<0) temp_timer=0;
7665 	if (temp_timer>65535) temp_timer=65535;
7666 	XDelta->timer=temp_timer;
7667 
7668 	temp_timer=screenY*(tail_ycal);
7669 	temp_timer+=32767;
7670 
7671 	if (temp_timer<0) temp_timer=0;
7672 	if (temp_timer>65535) temp_timer=65535;
7673 	YDelta->timer=temp_timer;
7674 
7675 	textprint("Target Screen X,Y %d %d\n",screenX,screenY);
7676 
7677 }
7678 
7679 void AlienTail_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7680 
7681 	DELTA_CONTROLLER *XDelta,*YDelta;
7682 
7683 	GLOBALASSERT(Alien_Visible_Weapon==1);
7684 
7685 	XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta");
7686 	YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta");
7687 
7688 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7689 
7690 		DISPLAYBLOCK *target;
7691 
7692 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7693 			(int)AHSS_TailStrike,(ONE_FIXED/6),0);
7694 
7695 		/* Find target. */
7696 		target=AlienTail_TargetSelect();
7697 
7698 		if (target) {
7699 			Alien_Tail_Target=target->ObStrategyBlock;
7700 			COPY_NAME(Alien_Tail_Target_SBname,Alien_Tail_Target->SBname);
7701 			/* Set XDelta and YDelta. */
7702 			ComputeTailDeltaValues(XDelta,YDelta);
7703 		} else {
7704 			XDelta->timer=32767;
7705 			YDelta->timer=32767;
7706 		}
7707 
7708 		/* Don't bother with the next bit. */
7709 		return;
7710 	}
7711 
7712 	/* Check target validity. */
7713 
7714 	if (Validate_Target(Alien_Tail_Target,Alien_Tail_Target_SBname)==0) {
7715 		/* Lost it somehow. */
7716 		Alien_Tail_Target=NULL;
7717 		COPY_NAME(Alien_Tail_Target_SBname,Null_Name);
7718 	}
7719 
7720 	if (Alien_Tail_Target) {
7721 		if (Alien_Tail_Target->SBdptr==NULL) {
7722 			/* Likewise, moved off screen. */
7723 			Alien_Tail_Target=NULL;
7724 			COPY_NAME(Alien_Tail_Target_SBname,Null_Name);
7725 		} else {
7726 			/* Do we still have a target?  Correct for aiming. */
7727 			ComputeTailDeltaValues(XDelta,YDelta);
7728 		}
7729 	}
7730 
7731 	if (PlayersWeaponHModelController.keyframe_flags&1) {
7732 
7733 		/* Just for now, do damage anyway... */
7734 		if (Alien_Tail_Target) {
7735 
7736 			int multiple;
7737 
7738 			multiple=ONE_FIXED;
7739 			/* Consider target aspect. */
7740 			{
7741 				VECTORCH attack_dir,displacement;
7742 
7743 				displacement.vx = Alien_Tail_Target->DynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx;
7744 				displacement.vy = Alien_Tail_Target->DynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy;
7745 				displacement.vz = Alien_Tail_Target->DynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz;
7746 
7747 				GetDirectionOfAttack(Alien_Tail_Target,&displacement,&attack_dir);
7748 
7749 				if (attack_dir.vz>0) {
7750 					multiple<<=1;
7751 				}
7752 
7753 				if (Alien_Tail_Target->SBdptr->HModelControlBlock) {
7754 					HtoHDamageToHModel(Alien_Tail_Target, &Player_Weapon_Damage,multiple, NULL, &attack_dir);
7755 				} else {
7756 	  				CauseDamageToObject(Alien_Tail_Target, &Player_Weapon_Damage,multiple, &attack_dir);
7757 				}
7758 			}
7759 		}
7760 		PlayAlienTailSound();
7761 		/* Slower recoil... */
7762 		HModel_ChangeSpeed(&PlayersWeaponHModelController,(ONE_FIXED));
7763 		HtoHStrikes++;
7764 
7765 	}
7766 
7767 }
7768 
7769 void AlienClaw_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7770 
7771 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7772 
7773 		int alien_speed;
7774 
7775 		/* Consider possibility of bite first... */
7776 		Biting=GetBitingTarget();
7777 		if (Biting) {
7778 			/* Fix the name. */
7779 			COPY_NAME(Biting_SBname,Biting->SBname);
7780 			/* Fix the speed. */
7781 			FixAlienStrikeSpeed(ONE_FIXED/3);
7782 			/* Init attack. */
7783 			Bit=0;
7784 			/* Then leave. */
7785 			return;
7786 		}
7787 
7788 		alien_speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
7789 
7790 		/* Speed: < 5000 = standing.  > 22000 = jumping.
7791 			In practice, walk/fall = 18000 ish, jump = 27000 ish. */
7792 
7793 		/* Check we've got the claws. */
7794 
7795 		if (Alien_Visible_Weapon!=0) {
7796 
7797 			GetHierarchicalWeapon("alien_HUD","claws",(int)HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown);
7798 			ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon);
7799 
7800 			Alien_Visible_Weapon=0;
7801 
7802 		}
7803 
7804 		/* Setup base damage. */
7805 
7806 		Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_CLAW].MaxDamage[AvP.Difficulty];
7807 
7808 		/* Choose attack type and speed. */
7809 
7810 		if ((alien_speed<5000)&&(PlayerStatusPtr->ShapeState==PMph_Standing)
7811 			&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)) {
7812 			/* Standing on solid ground. */
7813 
7814 			TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1;
7815 
7816 			FixAlienStrikeSpeed(ONE_FIXED/3);
7817 
7818 			textprint("Standing Claw, Speed %d\n",alien_speed);
7819 
7820 			if ((FastRandom()&65536)>32768) {
7821 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7822 					(int)AHSS_Both_In,ACStrikeTime,0);
7823 			} else {
7824 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7825 					(int)AHSS_Both_Down,ACStrikeTime,0);
7826 			}
7827 
7828 		} else {
7829 
7830 			/* Crouching, falling, or running? */
7831 
7832 			if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0)
7833 				&& (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) {
7834 				/* Jumping or falling... */
7835 				TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0;
7836 			} else {
7837 				TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1;
7838 			}
7839 
7840 			if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
7841 				/* If crouching, falling or no, slower strike. */
7842 				if (  /* Gravity points vaguely down... */
7843 					(Player->ObStrategyBlock->DynPtr->GravityDirection.vx<46341)
7844 					&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vx>-46341)
7845 					&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vy>46341)
7846 					&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz<46341)
7847 					&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz>-46341)
7848 				   ) {
7849 					FixAlienStrikeSpeed(ONE_FIXED/4);
7850 				} else {
7851 					FixAlienStrikeSpeed(ONE_FIXED/3);
7852 				}
7853 			} else {
7854 				FixAlienStrikeSpeed(ONE_FIXED/5);
7855 			}
7856 
7857 			/* Speed test here, for jumping? */
7858 
7859 			if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0)
7860 				&& (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0)
7861 				&& (alien_speed>22000) ) {
7862 
7863 				/* Must be jumping. */
7864 				FixAlienStrikeSpeed(ONE_FIXED/3);
7865 				/* Extra damage for pounce. */
7866 				Player_Weapon_Damage.Impact+=10;
7867 				Player_Weapon_Damage.Cutting+=10;
7868 				if ((FastRandom()&65536)>32768) {
7869 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7870 						(int)AHSS_PounceIn,ACStrikeTime,0);
7871 				} else {
7872 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7873 						(int)AHSS_PounceDown,ACStrikeTime,0);
7874 				}
7875 
7876 			} else if (LastHand) {
7877 				if ((FastRandom()&65536)>32768) {
7878 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7879 						(int)AHSS_LeftSwipeIn,(ONE_FIXED/6),0);
7880 				} else {
7881 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7882 						(int)AHSS_LeftSwipeDown,(ONE_FIXED/6),0);
7883 				}
7884 				LastHand=0;
7885 			} else {
7886 				if ((FastRandom()&65536)>32768) {
7887 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7888 						(int)AHSS_RightSwipeIn,(ONE_FIXED/6),0);
7889 				} else {
7890 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
7891 						(int)AHSS_RightSwipeDown,(ONE_FIXED/6),0);
7892 				}
7893 				LastHand=1;
7894 			}
7895 		}
7896 
7897 		PlayersWeaponHModelController.Playing=1;
7898 	}
7899 
7900 	/* Now we're in the attack. */
7901 	if (Biting) {
7902 		/* Kinda placeholder. */
7903 		if (weaponPtr->StateTimeOutCounter<(WEAPONSTATE_INITIALTIMEOUTCOUNT>>1)) {
7904 			if (Bit==0) {
7905 				SECTION_DATA *head_sec;
7906 				Bit=1;
7907 				/* Try the bite. */
7908 				head_sec=CheckBiteIntegrity();
7909 				if (head_sec)
7910 				{
7911 					AVP_BEHAVIOUR_TYPE pre_bite_type=Biting->I_SBtype;
7912 
7913 					CurrentGameStats_HeadBitten(Biting);
7914 
7915 					/* Munch! */
7916 					if (SUPERGORE_MODE) {
7917 						CauseDamageToHModel(Biting->SBdptr->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION_SUPER].MaxDamage[AvP.Difficulty],
7918 							ONE_FIXED,head_sec,NULL,NULL,0);
7919 					} else {
7920 						CauseDamageToHModel(Biting->SBdptr->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage[AvP.Difficulty],
7921 							ONE_FIXED,head_sec,NULL,NULL,0);
7922 					}
7923 
7924 					/* Side effects, anyone? */
7925 					{
7926 						BiteAttack_AwardHealth(Biting,pre_bite_type);
7927 					}
7928 					/* Play a sound? */
7929 					if (PlayerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) {
7930 						Sound_Stop(PlayerStatusPtr->soundHandle);
7931 					}
7932 					Sound_Play(SID_ALIEN_JAW_ATTACK,"de",&(Player->ObStrategyBlock->DynPtr->Position),&PlayerStatusPtr->soundHandle);
7933 					HtoHStrikes++;
7934 
7935 					/* KJL 11:55:27 30/07/98 - Cue Special FX! */
7936 					{
7937 						extern void AlienBiteAttackHasHappened(void);
7938 						AlienBiteAttackHasHappened();
7939 					}
7940 
7941 				}
7942 				else
7943 				{
7944 					/* Play a different sound? */
7945 				}
7946 			}
7947 		}
7948 	} else {
7949 		/* Execute attack. */
7950 		int hits;
7951 
7952 		hits=0;
7953 
7954 		if (PlayersWeaponHModelController.keyframe_flags&1) {
7955 			hits++;
7956 		}
7957 
7958 		if (PlayersWeaponHModelController.keyframe_flags&2) {
7959 			hits++;
7960 		}
7961 
7962 		if (hits) {
7963 
7964 			HtoHStrikes+=hits;
7965 
7966 			MeleeWeapon_180Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED*hits,4000);
7967 			PlayAlienSwipeSound();
7968 
7969 		}
7970 
7971 	}
7972 
7973 }
7974 
7975 void AlienGrab_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7976 
7977 	/* Same as for claws, ATM */
7978 
7979 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
7980 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown,ONE_FIXED/3);
7981 		PlayersWeaponHModelController.Looped=0;
7982 		PlayersWeaponHModelController.Playing=0;
7983 	}
7984 
7985 	LastHand=0;
7986 	Alien_Visible_Weapon=0; //Claws
7987 }
7988 
7989 void AlienGrab_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7990 
7991 	/* ...Nothing? */
7992 
7993 }
7994 
7995 void AlienGrab_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
7996 
7997 	/* ...Nothing? */
7998 
7999 }
8000 
8001 void AlienGrab_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8002 
8003 	/* Eating function. */
8004 
8005 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8006 
8007 		int alien_speed;
8008 
8009 		alien_speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
8010 
8011 		/* Speed: < 5000 = standing.  > 22000 = jumping.
8012 			In practice, walk/fall = 18000 ish, jump = 27000 ish. */
8013 
8014 		/* Check we've got the claws. */
8015 
8016 		if (Alien_Visible_Weapon!=2) {
8017 
8018 			GetHierarchicalWeapon("alien_HUD","eat",(int)HMSQT_AlienHUD,(int)AHSS_Eat);
8019 
8020 			Alien_Visible_Weapon=2;
8021 
8022 		}
8023 
8024 		/* Setup base damage. */
8025 
8026 		Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_CLAW].MaxDamage[AvP.Difficulty];
8027 
8028 		/* Choose attack type and speed. */
8029 
8030 		if ((alien_speed<5000)&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)
8031 			&&( /* Gravity check. */
8032 			(Player->ObStrategyBlock->DynPtr->GravityDirection.vx<46341)
8033 			&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vx>-46341)
8034 			&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vy>46341)
8035 			&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz<46341)
8036 			&&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz>-46341)
8037 			)) {
8038 			/* Standing on solid ground. */
8039 
8040 			TemplateWeapon[WEAPON_ALIEN_GRAB].PrimaryIsAutomatic=1;
8041 
8042 			TemplateWeapon[WEAPON_ALIEN_GRAB].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]=
8043 				(DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,(ONE_FIXED/3)));
8044 
8045 			if ((FastRandom()&65536)>32768) {
8046 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
8047 					(int)AHSS_Eat,(ONE_FIXED/3),0);
8048 			} else {
8049 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD,
8050 					(int)AHSS_Eat,(ONE_FIXED/3),0);
8051 			}
8052 			PlayersWeaponHModelController.Playing=1;
8053 
8054 		} else {
8055 
8056 			/* No joy. */
8057 
8058 		}
8059 
8060 	}
8061 
8062 	{
8063 		/* Execute attack. */
8064 		int hits;
8065 
8066 		hits=0;
8067 
8068 		if (PlayersWeaponHModelController.keyframe_flags&1) {
8069 			hits++;
8070 		}
8071 
8072 		if (PlayersWeaponHModelController.keyframe_flags&2) {
8073 			hits++;
8074 		}
8075 
8076 		if (hits) {
8077 
8078 			PC_Alien_Eat_Attack(hits);
8079 			PlayAlienSwipeSound();
8080 
8081 		}
8082 
8083 	}
8084 
8085 }
8086 
8087 int Target_IsEdible(STRATEGYBLOCK *candidate) {
8088 
8089 	switch (candidate->I_SBtype) {
8090 		case I_BehaviourAlien:
8091 		case I_BehaviourQueenAlien:
8092 		case I_BehaviourFaceHugger:
8093 		case I_BehaviourXenoborg:
8094 		case I_BehaviourPredatorAlien:
8095 			{
8096 				return(0);
8097 				break;
8098 			}
8099 		case I_BehaviourPredator:
8100 		case I_BehaviourMarine:
8101 		case I_BehaviourSeal:
8102 			{
8103 				if (NPC_IsDead(candidate)) {
8104 					/* Must be dead to be eaten. */
8105 					return(1);
8106 				} else {
8107 					return(0);
8108 				}
8109 				break;
8110 			}
8111 		case I_BehaviourNetGhost:
8112 			{
8113 				NETGHOSTDATABLOCK *dataptr;
8114 				dataptr=candidate->SBdataptr;
8115 				switch (dataptr->type) {
8116 					case I_BehaviourMarinePlayer:
8117 					case I_BehaviourAlienPlayer:
8118 					case I_BehaviourPredatorPlayer:
8119 						/* Put a test in, once we have dead ghosts. */
8120 						return(0);
8121 						break;
8122 					default:
8123 						return(0);
8124 						break;
8125 				}
8126 			}
8127 			break;
8128 		default:
8129 			return(0);
8130 			break;
8131 	}
8132 
8133 }
8134 
8135 void Placeholder_Eating_Effect(STRATEGYBLOCK *sbPtr) {
8136 
8137 	VECTORCH final_spray_direction;
8138 	enum PARTICLE_ID blood_type;
8139 	/* Spray is go! */
8140 
8141 	/* Add random element. */
8142 
8143 	final_spray_direction.vx=( (FastRandom()&2047)-1024);
8144 	final_spray_direction.vy=( -(FastRandom()&511)); /* Should be upwards. */
8145 	final_spray_direction.vz=( (FastRandom()&2047)-1024);
8146 
8147 	/* Identify spray type. */
8148 
8149 	blood_type=GetBloodType(sbPtr);
8150 
8151 	/* Call spray function. */
8152 
8153 	MakeParticle(&sbPtr->DynPtr->Position, &final_spray_direction, blood_type);
8154 
8155 }
8156 
8157 #define EAT_ATTACK_RANGE 1500
8158 
8159 int PC_Alien_Eat_Attack(int hits)
8160 {
8161 	int numberOfObjects = NumOnScreenBlocks;
8162 	int numhits=0;
8163 
8164 	while (numberOfObjects)
8165 	{
8166 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
8167 		STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
8168 		GLOBALASSERT(objectPtr);
8169 
8170 		/* does object have a strategy block? */
8171 		if (sbPtr)
8172 		{
8173 			/* is it in the frustrum? */
8174 			if ( (objectPtr->ObView.vz >0)
8175 				&& (objectPtr->ObView.vz >  objectPtr->ObView.vx)
8176 				&& (objectPtr->ObView.vz > -objectPtr->ObView.vx)
8177 				&& (objectPtr->ObView.vz >  objectPtr->ObView.vy)
8178 				&& (objectPtr->ObView.vz > -objectPtr->ObView.vy) ) {
8179 
8180 				int dist=Approximate3dMagnitude(&objectPtr->ObView);
8181 
8182 				if (dist<EAT_ATTACK_RANGE)	{
8183 
8184 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
8185 			  	  	if (dynPtr)
8186 					{
8187 
8188 						if (Target_IsEdible(sbPtr)) {
8189 							/* Go go gadget eat? */
8190 							textprint("Eating! Yum Yum...\n");
8191 							Placeholder_Eating_Effect(sbPtr);
8192 						}
8193 
8194 						numhits++;
8195 					}
8196 			  	}
8197 			}
8198 		}
8199 	}
8200 
8201 	return(numhits);
8202 }
8203 
8204 void PlasmaCaster_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8205 
8206 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8207 	LOCALASSERT(playerStatusPtr);
8208 
8209 	/* Note, not the same as WristConsole_Idle! */
8210 
8211 	/* Do charge, then sequences. */
8212 
8213 	/* Jumpstart plasmacaster. */
8214 	if (playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart) {
8215 		int jumpgap,jumpcharge;
8216 
8217 		jumpgap=Caster_Jumpstart-playerStatusPtr->PlasmaCasterCharge;
8218 
8219 		if (playerStatusPtr->FieldCharge>=MUL_FIXED(jumpgap,Caster_ChargeRatio)) {
8220 			/* We have enough. */
8221 			jumpcharge=jumpgap;
8222 		} else {
8223 			//jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio);
8224 			/* Don't drain insufficient charge. */
8225 			jumpcharge=0;
8226 		}
8227 
8228 		playerStatusPtr->PlasmaCasterCharge+=jumpcharge;
8229 		playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio);
8230 		CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio));
8231 		LOCALASSERT(playerStatusPtr->FieldCharge>=0);
8232 
8233 	}
8234 
8235 	if ((playerStatusPtr->PlasmaCasterCharge<Caster_TrickleLevel)&&(Caster_TrickleRate)) {
8236 		if (playerStatusPtr->FieldCharge>0) {
8237 			int chargerate;
8238 			int optimumchargerate;
8239 
8240 			optimumchargerate=MUL_FIXED(Caster_TrickleRate,NormalFrameTime);
8241 			/* optimumchargerate is for the CASTER. */
8242 
8243 			if (playerStatusPtr->FieldCharge>=MUL_FIXED(optimumchargerate,Caster_ChargeRatio)) {
8244 				chargerate=optimumchargerate;
8245 			} else {
8246 				GLOBALASSERT(Caster_ChargeRatio);
8247 				chargerate=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio);
8248 			}
8249 
8250 			if (playerStatusPtr->PlasmaCasterCharge+chargerate>Caster_TrickleLevel) {
8251 				chargerate=Caster_TrickleLevel-playerStatusPtr->PlasmaCasterCharge;
8252 			}
8253 
8254 			playerStatusPtr->FieldCharge-=MUL_FIXED(chargerate,Caster_ChargeRatio);
8255 			CurrentGameStats_ChargeUsed(MUL_FIXED(chargerate,Caster_ChargeRatio));
8256 			LOCALASSERT(playerStatusPtr->FieldCharge>=0);
8257 			playerStatusPtr->PlasmaCasterCharge+=chargerate;
8258 			LOCALASSERT(playerStatusPtr->PlasmaCasterCharge<=Caster_TrickleLevel);
8259 		}
8260 	}
8261 
8262 	if (ShowPredoStats) {
8263 		PrintDebuggingText("Plasma Caster Charge = %d\n",playerStatusPtr->PlasmaCasterCharge);
8264 	}
8265 
8266 	/* Now anim control. */
8267 
8268 	if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Primary) {
8269 		if (PlayersWeaponHModelController.Tweening!=0) {
8270 			PlayersWeaponHModelController.Playing=1;
8271 			return;
8272 		}
8273 		GLOBALASSERT(PlayersWeaponHModelController.Looped==0);
8274 		if (!(HModelAnimation_IsFinished(&PlayersWeaponHModelController))) {
8275 			return;
8276 		}
8277 	}
8278 
8279 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8280 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
8281 	}
8282 
8283 	/* Are we running? */
8284 
8285 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
8286 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
8287 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
8288 
8289 		/* Were we running? */
8290 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
8291 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
8292 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
8293 			}
8294 		} else {
8295 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
8296 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
8297 			}
8298 		}
8299 	} else {
8300 		TEMPLATE_WEAPON_DATA *twPtr;
8301 
8302 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
8303 
8304 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
8305 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
8306 		}
8307 
8308 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
8309 
8310 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
8311 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
8312 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
8313 				}
8314 			} else if ((FastRandom()&255)==0) {
8315 				/* Start animation. */
8316 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
8317 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
8318 					weaponPtr->StateTimeOutCounter=0;
8319 				}
8320 			}
8321 		}
8322 	}
8323 
8324 	/* Be very quiet... we're hunting wabbits! */
8325 	if(weaponHandle != SOUND_NOACTIVEINDEX) {
8326    		Sound_Stop(weaponHandle);
8327 	}
8328 
8329 }
8330 
8331 int SecondaryFirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr) {
8332 
8333 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8334 	LOCALASSERT(playerStatusPtr);
8335 
8336 	if (PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Primary) {
8337 		/* Start Animation. */
8338 		GLOBALASSERT(PlayersWeaponHModelController.section_data);
8339 		GLOBALASSERT(PlayersWeaponHModelController.Playing==1);
8340 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
8341 	} else {
8342 		if (PlayersWeaponHModelController.keyframe_flags) {
8343 			PlayersWeaponHModelController.Playing=0;
8344 		}
8345 	}
8346 
8347 	/* Handle field charge. */
8348 	if (playerStatusPtr->PlasmaCasterCharge<ONE_FIXED) {
8349 		if (playerStatusPtr->FieldCharge>0) {
8350 			int chargerate;
8351 			int optimumchargerate;
8352 
8353 			//optimumchargerate=NormalFrameTime>>CASTER_CHARGETIME; /* 8 sec recharge? */
8354 
8355 			if (Caster_Chargetime==0) {
8356 				optimumchargerate=65536;
8357 			} else {
8358 				optimumchargerate=DIV_FIXED(NormalFrameTime,Caster_Chargetime);
8359 			}
8360 			/* optimumchargerate is for the CASTER. */
8361 
8362 			if (playerStatusPtr->FieldCharge>=MUL_FIXED(optimumchargerate,Caster_ChargeRatio)) {
8363 				chargerate=optimumchargerate;
8364 			} else {
8365 				GLOBALASSERT(Caster_ChargeRatio);
8366 				chargerate=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio);
8367 			}
8368 
8369 			if (playerStatusPtr->PlasmaCasterCharge+chargerate>ONE_FIXED) {
8370 				chargerate=ONE_FIXED-playerStatusPtr->PlasmaCasterCharge;
8371 			}
8372 
8373 			playerStatusPtr->FieldCharge-=MUL_FIXED(chargerate,Caster_ChargeRatio);
8374 			CurrentGameStats_ChargeUsed(MUL_FIXED(chargerate,Caster_ChargeRatio));
8375 			LOCALASSERT(playerStatusPtr->FieldCharge>=0);
8376 			playerStatusPtr->PlasmaCasterCharge+=chargerate;
8377 			LOCALASSERT(playerStatusPtr->PlasmaCasterCharge<=ONE_FIXED);
8378 
8379 			if (chargerate) {
8380 				/* Play a charging sound! */
8381 		  		if(weaponHandle != SOUND_NOACTIVEINDEX) {
8382 					if (ActiveSounds[weaponHandle].soundIndex!=SID_PREDATOR_PLASMACASTER_CHARGING) {
8383 						/* Stop other sounds... */
8384 			       		Sound_Stop(weaponHandle);
8385 					}
8386 				}
8387 		  		if(weaponHandle == SOUND_NOACTIVEINDEX) {
8388 		  			Sound_Play(SID_PREDATOR_PLASMACASTER_CHARGING,"ehl",&weaponHandle);
8389 				}
8390 			} else {
8391 				/* Be very quiet... we're hunting wabbits! */
8392 				if(weaponHandle != SOUND_NOACTIVEINDEX) {
8393 			   		Sound_Stop(weaponHandle);
8394 				}
8395 			}
8396 		}
8397 	} else {
8398 		/* Be very quiet... we're hunting wabbits! */
8399 		if(weaponHandle != SOUND_NOACTIVEINDEX) {
8400 	   		Sound_Stop(weaponHandle);
8401 		}
8402 	}
8403 
8404 	return(1);
8405 }
8406 
8407 int FirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr) {
8408 
8409 	int jumpcharge;
8410 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8411 	LOCALASSERT(playerStatusPtr);
8412 
8413 	if (playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart) {
8414 		return(0);
8415 	}
8416 
8417 	/* Fix plasmacaster damage. */
8418 
8419 	#if 0
8420 	Player_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty];
8421 
8422 	Player_Weapon_Damage.Impact 	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Impact 	,playerStatusPtr->PlasmaCasterCharge);
8423 	Player_Weapon_Damage.Cutting	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting	,playerStatusPtr->PlasmaCasterCharge);
8424 	Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,playerStatusPtr->PlasmaCasterCharge);
8425 	Player_Weapon_Damage.Fire		=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire		,playerStatusPtr->PlasmaCasterCharge);
8426 	Player_Weapon_Damage.Electrical	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical	,playerStatusPtr->PlasmaCasterCharge);
8427 	Player_Weapon_Damage.Acid		=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid		,playerStatusPtr->PlasmaCasterCharge);
8428 
8429 	Player_Weapon_Damage.BlowUpSections=1;
8430 	Player_Weapon_Damage.Special=0;
8431 	#else
8432 	Player_Weapon_Damage=TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty];
8433 
8434 	if (Caster_PCKill>0) {
8435 
8436 		/* At least we can theoretically work it. */
8437 
8438 		if ((playerStatusPtr->PlasmaCasterCharge>=Caster_NPCKill)
8439 			&&(Caster_PCKill>Caster_NPCKill)) {
8440 			/* In the upper graph. */
8441 			int factor;
8442 
8443 			factor=playerStatusPtr->PlasmaCasterCharge-Caster_NPCKill;
8444 			factor=DIV_FIXED(factor,(Caster_PCKill-Caster_NPCKill));
8445 
8446 			Player_Weapon_Damage.Impact 	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact 		+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Impact 		,factor);
8447 			Player_Weapon_Damage.Cutting	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting		+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Cutting		,factor);
8448 			Player_Weapon_Damage.Penetrative=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative	+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Penetrative	,factor);
8449 			Player_Weapon_Damage.Fire		=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire			+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Fire		,factor);
8450 			Player_Weapon_Damage.Electrical	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical	+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Electrical	,factor);
8451 			Player_Weapon_Damage.Acid		=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid			+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Acid		,factor);
8452 
8453 		} else {
8454 			/* In the lower graph. */
8455 			int factor;
8456 
8457 			factor=playerStatusPtr->PlasmaCasterCharge;
8458 			factor=DIV_FIXED(factor,Caster_NPCKill);
8459 
8460 			Player_Weapon_Damage.Impact 	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact 	,factor);
8461 			Player_Weapon_Damage.Cutting	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting	,factor);
8462 			Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative,factor);
8463 			Player_Weapon_Damage.Fire		=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire		,factor);
8464 			Player_Weapon_Damage.Electrical	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical	,factor);
8465 			Player_Weapon_Damage.Acid		=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid		,factor);
8466 
8467 		}
8468 
8469 	}
8470 
8471 	Player_Weapon_Damage.BlowUpSections=1;
8472 	Player_Weapon_Damage.Special=0;
8473 	#endif
8474 
8475 	InitialiseEnergyBoltBehaviour(&Player_Weapon_Damage,playerStatusPtr->PlasmaCasterCharge);
8476 
8477 	/* Be very quiet... we're hunting wabbits! */
8478 	if(weaponHandle != SOUND_NOACTIVEINDEX) {
8479    		Sound_Stop(weaponHandle);
8480 	}
8481 
8482 	/* Jumpstart plasmacaster. */
8483 
8484 	if (playerStatusPtr->FieldCharge>=MUL_FIXED(Caster_Jumpstart,Caster_ChargeRatio)) {
8485 		jumpcharge=Caster_Jumpstart;
8486 	} else {
8487 		//jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio);
8488 		/* Not enough - drain nothing! */
8489 		jumpcharge=0;
8490 	}
8491 
8492 	playerStatusPtr->PlasmaCasterCharge=jumpcharge;
8493 	playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio);
8494 	CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio));
8495 	LOCALASSERT(playerStatusPtr->FieldCharge>=0);
8496 
8497 	return(1);
8498 }
8499 
8500 void Secondary_PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8501 	/* Restart anim. */
8502 	PlayersWeaponHModelController.Playing=1;
8503 
8504 	/* Be very quiet... we're hunting wabbits! */
8505 	if(weaponHandle != SOUND_NOACTIVEINDEX) {
8506    		Sound_Stop(weaponHandle);
8507 	}
8508 }
8509 
8510 void PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8511 
8512 	int jumpcharge;
8513 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8514 	LOCALASSERT(playerStatusPtr);
8515 
8516 	PlayersWeaponHModelController.Playing=1;
8517 
8518 	/* Be very quiet... we're hunting wabbits! */
8519 	if(weaponHandle != SOUND_NOACTIVEINDEX) {
8520    		Sound_Stop(weaponHandle);
8521 	}
8522 
8523 	#if 0
8524 	if (playerStatusPtr->PlasmaCasterCharge<Caster_Jumpstart) {
8525 		return;
8526 	}
8527 	#endif
8528 
8529 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8530 
8531 		if (playerStatusPtr->PlasmaCasterCharge<Caster_MinCharge) {
8532 			/* Don't fire at all! */
8533 			Sound_Play(SID_PREDATOR_PLASMACASTER_EMPTY,"h");
8534 			return;
8535 		}
8536 
8537 		/* Fix plasmacaster damage. */
8538 		#if 0
8539 		int multiplyer,a;
8540 		a=playerStatusPtr->PlasmaCasterCharge;
8541 
8542 		/* These values computed by hand! */
8543 		multiplyer=MUL_FIXED(a,a);
8544 		multiplyer=MUL_FIXED(multiplyer,26653);
8545 		multiplyer+=MUL_FIXED(a,38883);
8546 		/* Should fit for JUMPCHARGE == 0.1*max. */
8547 		LOCALASSERT(multiplyer>=0);
8548 
8549 		Player_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty];
8550 
8551 		Player_Weapon_Damage.Impact 	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Impact 	,multiplyer);
8552 		Player_Weapon_Damage.Cutting	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting	,multiplyer);
8553 		Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,multiplyer);
8554 		Player_Weapon_Damage.Fire		=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire		,multiplyer);
8555 		Player_Weapon_Damage.Electrical	=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical	,multiplyer);
8556 		Player_Weapon_Damage.Acid		=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid		,multiplyer);
8557 
8558 		Player_Weapon_Damage.BlowUpSections=1;
8559 		Player_Weapon_Damage.Special=0;
8560 		#else
8561 		Player_Weapon_Damage=TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty];
8562 
8563 		if (Caster_PCKill>0) {
8564 
8565 			/* At least we can theoretically work it. */
8566 
8567 			if ((playerStatusPtr->PlasmaCasterCharge>=Caster_NPCKill)
8568 				&&(Caster_PCKill>Caster_NPCKill)) {
8569 				/* In the upper graph. */
8570 				int factor;
8571 
8572 				factor=playerStatusPtr->PlasmaCasterCharge-Caster_NPCKill;
8573 				factor=DIV_FIXED(factor,(Caster_PCKill-Caster_NPCKill));
8574 
8575 				Player_Weapon_Damage.Impact 	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact 		+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Impact 		,factor);
8576 				Player_Weapon_Damage.Cutting	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting		+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Cutting		,factor);
8577 				Player_Weapon_Damage.Penetrative=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative	+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Penetrative	,factor);
8578 				Player_Weapon_Damage.Fire		=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire			+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Fire		,factor);
8579 				Player_Weapon_Damage.Electrical	=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical	+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Electrical	,factor);
8580 				Player_Weapon_Damage.Acid		=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid			+MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Acid		,factor);
8581 
8582 			} else {
8583 				/* In the lower graph. */
8584 				int factor;
8585 
8586 				factor=playerStatusPtr->PlasmaCasterCharge;
8587 				factor=DIV_FIXED(factor,Caster_NPCKill);
8588 
8589 				Player_Weapon_Damage.Impact 	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact 	,factor);
8590 				Player_Weapon_Damage.Cutting	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting	,factor);
8591 				Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative,factor);
8592 				Player_Weapon_Damage.Fire		=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire		,factor);
8593 				Player_Weapon_Damage.Electrical	=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical	,factor);
8594 				Player_Weapon_Damage.Acid		=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid		,factor);
8595 
8596 			}
8597 
8598 		}
8599 
8600 		Player_Weapon_Damage.BlowUpSections=1;
8601 		Player_Weapon_Damage.Special=0;
8602 		#endif
8603 
8604 		InitialiseEnergyBoltBehaviour(&Player_Weapon_Damage,playerStatusPtr->PlasmaCasterCharge);
8605 
8606 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
8607 
8608 		/* Jumpstart plasmacaster. */
8609 
8610 		if (playerStatusPtr->FieldCharge>=MUL_FIXED(Caster_Jumpstart,Caster_ChargeRatio)) {
8611 			jumpcharge=Caster_Jumpstart;
8612 		} else {
8613 			GLOBALASSERT(Caster_ChargeRatio);
8614 			jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio);
8615 		}
8616 
8617 		playerStatusPtr->PlasmaCasterCharge=jumpcharge;
8618 		playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio);
8619 		CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio));
8620 		LOCALASSERT(playerStatusPtr->FieldCharge>=0);
8621 
8622 	}
8623 }
8624 
8625 #define FIREPREDPISTOL_FIELDCHARGE (ONE_FIXED>>2)
8626 
8627 int FirePredPistol(PLAYER_WEAPON_DATA *weaponPtr)
8628 {
8629 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
8630 
8631 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8632 	LOCALASSERT(playerStatusPtr);
8633 
8634     if (playerStatusPtr->FieldCharge>=FIREPREDPISTOL_FIELDCHARGE)
8635     {
8636 		FireProjectileAmmo(twPtr->PrimaryAmmoID);
8637 		playerStatusPtr->FieldCharge-=FIREPREDPISTOL_FIELDCHARGE;
8638 		CurrentGameStats_ChargeUsed(FIREPREDPISTOL_FIELDCHARGE);
8639 		return(1);
8640     }
8641     else /* instantaneous line of sight */
8642     {
8643 		return(0);
8644 	}
8645 }
8646 
8647 #define FIRESPEARGUN_FIELDCHARGE (0)
8648 #define SPEAR_PLAYER_IMPULSE 	(-8000)
8649 
8650 int FireSpeargun(PLAYER_WEAPON_DATA *weaponPtr)
8651 {
8652 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
8653 
8654 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
8655 	LOCALASSERT(playerStatusPtr);
8656 
8657     if (playerStatusPtr->FieldCharge>=FIRESPEARGUN_FIELDCHARGE)
8658     {
8659 		/* Ammo check already happened. */
8660 		if (!(PIGSTICKING_MODE)) {
8661 		  	weaponPtr->PrimaryRoundsRemaining -= 65536;
8662 		}
8663 
8664 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
8665 
8666 		//FireProjectileAmmo(twPtr->PrimaryAmmoID);
8667 		if (PlayersTarget.DispPtr)
8668 		{
8669 
8670 			if (AccuracyStats_TargetFilter(PlayersTarget.DispPtr->ObStrategyBlock)) {
8671 				CurrentGameStats_WeaponHit(PlayerStatusPtr->SelectedWeaponSlot,1);
8672 			}
8673 
8674 			if (PlayersTarget.HModelSection!=NULL) {
8675 				textprint("Hitting a hierarchical section.\n");
8676 				GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller);
8677 			}
8678 
8679 			if (PIGSTICKING_MODE) {
8680 				/* Cheat mode goes here! */
8681 				int hitroll=0;
8682 
8683 				while (SpreadfireSpears[hitroll].vz>0) {
8684 					VECTORCH world_vec;
8685 					MATRIXCH transpose;
8686 
8687 					transpose=Global_VDB_Ptr->VDB_Mat;
8688 					TransposeMatrixCH(&transpose);
8689 					RotateAndCopyVector(&SpreadfireSpears[hitroll],&world_vec,&transpose);
8690 					CastLOSSpear(Player->ObStrategyBlock,&Global_VDB_Ptr->VDB_World,&world_vec, AMMO_PRED_RIFLE, 1,0);
8691 
8692 					hitroll++;
8693 				}
8694 			} else {
8695 				HandleSpearImpact(&(PlayersTarget.Position),PlayersTarget.DispPtr->ObStrategyBlock,twPtr->PrimaryAmmoID,&GunMuzzleDirectionInWS, 1, PlayersTarget.HModelSection);
8696 			}
8697 		}
8698 
8699 		if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
8700 			&&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
8701 			&&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz)
8702 			&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)
8703 			){
8704 			/* Behave normally! */
8705 		} else {
8706 			/* Kickback! */
8707 			Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,SPEAR_PLAYER_IMPULSE);
8708 			Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,SPEAR_PLAYER_IMPULSE);
8709 			Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,SPEAR_PLAYER_IMPULSE);
8710 		}
8711 
8712 		if (!(PIGSTICKING_MODE)) {
8713 			playerStatusPtr->FieldCharge-=FIRESPEARGUN_FIELDCHARGE;
8714 			CurrentGameStats_ChargeUsed(FIRESPEARGUN_FIELDCHARGE);
8715 		}
8716 		return(1);
8717     }
8718     else /* instantaneous line of sight */
8719     {
8720 		return(0);
8721 	}
8722 }
8723 
8724 int Tail_TargetFilter(STRATEGYBLOCK *candidate) {
8725 
8726 	switch (candidate->I_SBtype) {
8727 		case I_BehaviourPredator:
8728 		case I_BehaviourXenoborg:
8729 		case I_BehaviourMarine:
8730 		case I_BehaviourSeal:
8731 		case I_BehaviourAutoGun:
8732 		case I_BehaviourPredatorDisc_SeekTrack:
8733 		case I_BehaviourInanimateObject:
8734 		case I_BehaviourRubberDuck:
8735 		case I_BehaviourPlacedLight:
8736 		case I_BehaviourDormantPredator:
8737 		case I_BehaviourTrackObject:
8738 			return(1);
8739 			break;
8740 		case I_BehaviourNetGhost:
8741 			{
8742 				NETGHOSTDATABLOCK *dataptr;
8743 				dataptr=candidate->SBdataptr;
8744 				switch (dataptr->type) {
8745 					case I_BehaviourPredator:
8746 					case I_BehaviourXenoborg:
8747 					case I_BehaviourMarine:
8748 					case I_BehaviourSeal:
8749 					case I_BehaviourAutoGun:
8750 					case I_BehaviourPredatorDisc_SeekTrack:
8751 					case I_BehaviourInanimateObject:
8752 					case I_BehaviourRubberDuck:
8753 					case I_BehaviourPlacedLight:
8754 					case I_BehaviourDormantPredator:
8755 					case I_BehaviourMarinePlayer:
8756 					case I_BehaviourPredatorPlayer:
8757 						return(1);
8758 						break;
8759 					case I_BehaviourAlienPlayer:
8760 					{
8761 						switch (netGameData.gameType) {
8762 							case NGT_Individual:
8763 								return(1);
8764 								break;
8765 							case NGT_CoopDeathmatch:
8766 								return(0);
8767 								break;
8768 							case NGT_LastManStanding:
8769 								return(0);
8770 								break;
8771 							case NGT_PredatorTag:
8772 								return(1);
8773 								break;
8774 							case NGT_Coop:
8775 								return(0);
8776 								break;
8777 							case NGT_AlienTag:
8778 								return(1); //However, there shouldn't be more than one alien in alien tag anyway.
8779 								break;
8780 							default:
8781 								return(0);
8782 								break;
8783 						}
8784 						break;
8785 					}
8786 					default:
8787 						return(0);
8788 						break;
8789 				}
8790 			}
8791 			break;
8792 		default:
8793 			return(0);
8794 			break;
8795 	}
8796 
8797 }
8798 
8799 #define ALIEN_TAIL_RANGE (4000)
8800 
8801 DISPLAYBLOCK *AlienTail_TargetSelect(void)
8802 {
8803 	int numberOfObjects = NumOnScreenBlocks;
8804 	DISPLAYBLOCK *nearest;
8805 	STRATEGYBLOCK *sbPtr;
8806 	int neardist;
8807 
8808 	nearest=NULL;
8809 	neardist=100000;
8810 
8811 	while (numberOfObjects)
8812 	{
8813 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
8814 		sbPtr = objectPtr->ObStrategyBlock;
8815 		GLOBALASSERT(objectPtr);
8816 
8817 		/* does object have a strategy block? */
8818 		if (sbPtr)
8819 		{
8820 			if (Tail_TargetFilter(sbPtr)) {
8821 				/* is it in the frustrum? */
8822 				if ( (objectPtr->ObView.vz >0)
8823 					&& (objectPtr->ObView.vz >  (objectPtr->ObView.vx>>1))
8824 					&& (objectPtr->ObView.vz > -(objectPtr->ObView.vx>>1))
8825 					&& (objectPtr->ObView.vz >  (objectPtr->ObView.vy>>1))
8826 					&& (objectPtr->ObView.vz > -(objectPtr->ObView.vy>>1)) ) {
8827 
8828 					int dist=Approximate3dMagnitude(&objectPtr->ObView);
8829 
8830 					if (dist<ALIEN_TAIL_RANGE)	{
8831 
8832 						DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
8833 				  	  	if (dynPtr)
8834 						{
8835 							//if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&dynPtr->Position,ALIEN_TAIL_RANGE)) {
8836 							if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&dynPtr->Position)) {
8837 					  			/* Consider target validity here? */
8838 
8839 								if (dist<neardist) {
8840 									nearest=objectPtr;
8841 									neardist=dist;
8842 								}
8843 							}
8844 						}
8845 				  	}
8846 				}
8847 			}
8848 		}
8849 	}
8850 
8851 	if (nearest) {
8852 		return(nearest);
8853 	}
8854 
8855 	/* Let's see if we've missed something obvious. */
8856 	if (PlayersTarget.DispPtr) {
8857 		if (PlayersTarget.Distance<ALIEN_TAIL_RANGE) {
8858 			if (PlayersTarget.DispPtr->ObStrategyBlock) {
8859 				sbPtr=PlayersTarget.DispPtr->ObStrategyBlock;
8860 				/* It must be in the frustrum... */
8861 				if (sbPtr) {
8862 					if (sbPtr->DynPtr) {
8863 						if (Tail_TargetFilter(sbPtr)) {
8864 							/* May as well hit this, then. */
8865 							return(PlayersTarget.DispPtr);
8866 						}
8867 					}
8868 				}
8869 			}
8870 		}
8871 	}
8872 
8873 	return(NULL);
8874 }
8875 
8876 /* Plasmacaster function set. */
8877 
8878 void WristConsole_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8879 
8880 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8881 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
8882 	}
8883 
8884 	/* Are we running? */
8885 
8886 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
8887 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
8888 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
8889 
8890 		/* Were we running? */
8891 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
8892 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
8893 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
8894 			}
8895 		} else {
8896 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
8897 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
8898 			}
8899 		}
8900 	} else {
8901 		TEMPLATE_WEAPON_DATA *twPtr;
8902 
8903 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
8904 
8905 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
8906 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
8907 		}
8908 
8909 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
8910 
8911 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
8912 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
8913 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
8914 				}
8915 			} else if ((FastRandom()&255)==0) {
8916 				/* Start animation. */
8917 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
8918 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
8919 					weaponPtr->StateTimeOutCounter=0;
8920 				}
8921 			}
8922 		}
8923 	}
8924 
8925 }
8926 
8927 void TemplateHands_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8928 
8929 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8930 		GLOBALASSERT(PlayersWeaponHModelController.section_data);
8931 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,ONE_FIXED/3);
8932 		PlayersWeaponHModelController.Looped=0;
8933 
8934 		/* Stop pred hud sound. */
8935 		if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) {
8936 			Sound_Stop(predHUDSoundHandle);
8937 		}
8938 	}
8939 
8940 	/* Init damage for plasmacaster. */
8941 
8942 	Player_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty];
8943 
8944 	Player_Weapon_Damage.Impact=0;
8945 	Player_Weapon_Damage.Cutting=0;
8946 	Player_Weapon_Damage.Penetrative=0;
8947 	Player_Weapon_Damage.Fire=0;
8948 	Player_Weapon_Damage.Electrical=0;
8949 	Player_Weapon_Damage.Acid=0;
8950 	Player_Weapon_Damage.Special=0;
8951 
8952 }
8953 
8954 void WristConsole_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8955 
8956 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8957 		SECTION *root_section;
8958 
8959 		root_section=GetNamedHierarchyFromLibrary("pred_HUD","wrist display");
8960 		GLOBALASSERT(root_section);
8961 
8962 		#if 0
8963 		Dispel_HModel(&PlayersWeaponHModelController);
8964 		Create_HModel(&PlayersWeaponHModelController,root_section);
8965 		GLOBALASSERT(PlayersWeaponHModelController.section_data);
8966 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,131625);	/* 2.1s */
8967 		PlayersWeaponHModelController.Looped=0;
8968 		#else
8969 		PlayersWeaponHModelController.Sequence_Type=HMSQT_PredatorHUD;
8970 		PlayersWeaponHModelController.Sub_Sequence=PHSS_Come;
8971 		Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section,0,1,1);
8972 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Come,129434,0);	/* 2.1s */
8973 		#endif
8974 
8975 		/* Stop pred hud sound. */
8976 		if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) {
8977 			Sound_Stop(predHUDSoundHandle);
8978 		}
8979 
8980 	}
8981 
8982 }
8983 
8984 void WristConsole_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8985 
8986 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
8987 
8988 		GLOBALASSERT(PlayersWeaponHModelController.section_data);
8989 		#if 0
8990 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Go,104857); /* 1.6s */
8991 		PlayersWeaponHModelController.Looped=0;
8992 		#else
8993 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,96666,0); /* 1.6s */
8994 		#endif
8995 	}
8996 }
8997 
8998 void WristConsole_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
8999 
9000 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9001 		GLOBALASSERT(PlayersWeaponHModelController.section_data);
9002 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
9003 	}
9004 }
9005 
9006 void SADAR_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9007 
9008 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9009 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED);
9010 		PlayersWeaponHModelController.Looped=0;
9011 	}
9012 
9013 }
9014 
9015 void SADAR_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9016 
9017 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9018 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED,1);
9019 		PlayersWeaponHModelController.Looped=0;
9020 	}
9021 
9022 }
9023 
9024 void SADAR_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9025 
9026 	if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
9027 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
9028 	}
9029 
9030 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
9031 
9032 		if (WeaponFidgetPlaying) {
9033 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
9034 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
9035 				WeaponFidgetPlaying=0;
9036 			}
9037 		} else if ((FastRandom()&255)==0) {
9038 			/* Start animation. */
9039 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
9040 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0);
9041 				weaponPtr->StateTimeOutCounter=0;
9042 				WeaponFidgetPlaying=1;
9043 			}
9044 		}
9045 
9046 	}
9047 
9048 }
9049 
9050 void SADAR_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9051 
9052 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9053 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
9054 	}
9055 
9056 }
9057 
9058 void SADAR_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9059 
9060 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9061 		//InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6)-(ONE_FIXED>>4),0);
9062 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6));
9063 		PlayersWeaponHModelController.Looped=0;
9064 	}
9065 
9066 }
9067 
9068 void SADAR_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9069 
9070 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9071 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,((ONE_FIXED*3)/2),0);
9072 	}
9073 
9074 }
9075 
9076 void Minigun_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9077 
9078 	TEMPLATE_WEAPON_DATA *twPtr;
9079 
9080     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9081 
9082 	Weapon_ThisBurst=-1;
9083 
9084 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9085 		/* Just play the readying sound. */
9086 		Sound_Play(SID_WIL_MINIGUN_READY,"h");
9087 	}
9088 
9089 	Flamethrower_Timer=0;
9090 }
9091 
9092 void GenericMarineWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9093 
9094 	TEMPLATE_WEAPON_DATA *twPtr;
9095 
9096     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9097 
9098 	Weapon_ThisBurst=-1;
9099 
9100 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9101 		int time;
9102 
9103 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]);
9104 
9105 		GLOBALASSERT(time!=0);
9106 
9107 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time);
9108 		PlayersWeaponHModelController.Looped=0;
9109 	}
9110 
9111 	Flamethrower_Timer=0;
9112 	StaffAttack=-1;
9113 	LastHand=1;
9114 }
9115 
9116 void GenericMarineWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9117 
9118 	TEMPLATE_WEAPON_DATA *twPtr;
9119 
9120     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9121 
9122 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9123 		int time;
9124 
9125 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
9126 		time-=(ONE_FIXED>>4);
9127 
9128 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0);
9129 		PlayersWeaponHModelController.Looped=0;
9130 	}
9131 }
9132 
9133 void GenericMarineWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9134 
9135 	TEMPLATE_WEAPON_DATA *twPtr;
9136 
9137     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9138 
9139 	#if 0
9140 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9141 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9142 	}
9143 	#endif
9144 
9145 	if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
9146 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9147 	}
9148 
9149 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
9150 
9151 		if (WeaponFidgetPlaying) {
9152 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
9153 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9154 				WeaponFidgetPlaying=0;
9155 			}
9156 		} else if ((FastRandom()&255)==0) {
9157 			/* Start animation. */
9158 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
9159 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0);
9160 				weaponPtr->StateTimeOutCounter=0;
9161 				WeaponFidgetPlaying=1;
9162 			}
9163 		}
9164 
9165 	}
9166 
9167 	Flamethrower_Timer=0;
9168 	StaffAttack=-1;
9169 
9170 }
9171 
9172 void GenericMarineWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9173 
9174 	TEMPLATE_WEAPON_DATA *twPtr;
9175 
9176     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9177 
9178 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9179 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,ONE_FIXED,1);
9180 	}
9181 
9182 }
9183 
9184 void GenericMarineWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9185 
9186 	TEMPLATE_WEAPON_DATA *twPtr;
9187 
9188     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9189 
9190 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9191 		int time;
9192 
9193 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]);
9194 		time-=(ONE_FIXED>>4);
9195 
9196 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0);
9197 		PlayersWeaponHModelController.Looped=0;
9198 	}
9199 	StaffAttack=-1;
9200 }
9201 
9202 void GenericPredatorWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9203 
9204 	TEMPLATE_WEAPON_DATA *twPtr;
9205 
9206     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9207 
9208 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9209 		int time;
9210 
9211 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]);
9212 
9213 		GLOBALASSERT(time!=0);
9214 
9215 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,time);
9216 		PlayersWeaponHModelController.Looped=0;
9217 	}
9218 
9219 	Flamethrower_Timer=0;
9220 }
9221 
9222 void GenericPredatorWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9223 
9224 	TEMPLATE_WEAPON_DATA *twPtr;
9225 
9226     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9227 
9228 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9229 		int time;
9230 
9231 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
9232 		time-=(ONE_FIXED>>4);
9233 
9234 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0);
9235 		PlayersWeaponHModelController.Looped=0;
9236 	}
9237 }
9238 
9239 void GenericPredatorWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9240 
9241 	TEMPLATE_WEAPON_DATA *twPtr;
9242 
9243     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9244 
9245 	#if 0
9246 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9247 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9248 	}
9249 	#endif
9250 
9251 	if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)
9252 		&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Run)) {
9253 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9254 	}
9255 
9256 	/* Are we running? */
9257 
9258 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
9259 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
9260 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
9261 
9262 		/* Were we running? */
9263 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
9264 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
9265 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
9266 			}
9267 		} else {
9268 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
9269 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
9270 			}
9271 		}
9272 	} else {
9273 		TEMPLATE_WEAPON_DATA *twPtr;
9274 
9275 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9276 
9277 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
9278 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
9279 		}
9280 
9281 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
9282 
9283 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
9284 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
9285 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
9286 				}
9287 			} else if ((FastRandom()&255)==0) {
9288 				/* Start animation. */
9289 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
9290 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
9291 					weaponPtr->StateTimeOutCounter=0;
9292 				}
9293 			}
9294 		}
9295 	}
9296 
9297 }
9298 
9299 void GenericPredatorWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9300 
9301 	TEMPLATE_WEAPON_DATA *twPtr;
9302 
9303     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9304 
9305 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9306 
9307 		int time;
9308 
9309 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]);
9310 		time-=(ONE_FIXED>>4);
9311 
9312 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,1);
9313 	}
9314 
9315 }
9316 
9317 void SpearGun_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9318 
9319 	TEMPLATE_WEAPON_DATA *twPtr;
9320 
9321     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9322 
9323 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9324 
9325 		int time;
9326 
9327 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]);
9328 		time-=(ONE_FIXED>>4);
9329 
9330 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,0);
9331 	}
9332 
9333 }
9334 
9335 void GenericPredatorWeapon_Firing_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9336 
9337 	TEMPLATE_WEAPON_DATA *twPtr;
9338 
9339     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9340 
9341 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9342 
9343 		int time;
9344 
9345 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_SECONDARY]);
9346 		time-=(ONE_FIXED>>4);
9347 
9348 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,time,1);
9349 	}
9350 
9351 }
9352 
9353 void GenericPredatorWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9354 
9355 	/* Plays 'Program', actually... */
9356 	TEMPLATE_WEAPON_DATA *twPtr;
9357 
9358     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9359 
9360 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9361 		int time;
9362 
9363 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]);
9364 		time-=(ONE_FIXED>>4);
9365 
9366 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Program,time,0);
9367 		PlayersWeaponHModelController.Looped=0;
9368 	}
9369 }
9370 
9371 #if 0
9372 void PredatorDisc_Throwing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9373 
9374 	TEMPLATE_WEAPON_DATA *twPtr;
9375 
9376     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9377 
9378 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9379 
9380 		int time;
9381 
9382 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]);
9383 		time-=(ONE_FIXED>>4);
9384 
9385 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,0);
9386 	}
9387 
9388 	if (PlayersWeaponHModelController.keyframe_flags&1) {
9389 		SECTION_DATA *disc_section;
9390 		disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk");
9391 		GLOBALASSERT(disc_section);
9392 		/* Throw Disc. */
9393 		if (FirePredatorDisc(weaponPtr,disc_section)) {
9394 			/* Mask disc. */
9395 			disc_section->flags|=section_data_notreal;
9396 		}
9397 	}
9398 }
9399 #else
9400 void PredatorDisc_Throwing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9401 
9402 	TEMPLATE_WEAPON_DATA *twPtr;
9403 
9404     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9405 
9406 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9407 
9408 		int time;
9409 
9410 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]);
9411 		time-=(ONE_FIXED>>4);
9412 
9413 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
9414 	} else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
9415 		weaponPtr->StateTimeOutCounter=0;
9416 	} else {
9417 		weaponPtr->StateTimeOutCounter=(ONE_FIXED>>1);
9418 	}
9419 
9420 	if (PlayersWeaponHModelController.keyframe_flags&1) {
9421 		SECTION_DATA *disc_section;
9422 		disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk");
9423 		GLOBALASSERT(disc_section);
9424 		/* Throw Disc. */
9425 		if (FirePredatorDisc(weaponPtr,disc_section)) {
9426 			/* Mask disc. */
9427 			disc_section->flags|=section_data_notreal;
9428 		}
9429 	}
9430 }
9431 #endif
9432 
9433 void PredatorDisc_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9434 
9435 	TEMPLATE_WEAPON_DATA *twPtr;
9436 
9437     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9438 
9439 	/* A bit like the Alien Claw one. */
9440 
9441 	if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)
9442 		&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Run)) {
9443 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1);
9444 	}
9445 
9446 	/* Are we running? */
9447 
9448 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
9449 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
9450 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
9451 
9452 		/* Were we running? */
9453 		if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) {
9454 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
9455 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
9456 			}
9457 		} else {
9458 			if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) {
9459 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1);
9460 			}
9461 		}
9462 	} else {
9463 		TEMPLATE_WEAPON_DATA *twPtr;
9464 
9465 	    twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9466 
9467 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) {
9468 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
9469 		}
9470 
9471 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
9472 
9473 			if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) {
9474 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
9475 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1);
9476 				}
9477 			} else if ((FastRandom()&255)==0) {
9478 				/* Start animation. */
9479 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
9480 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
9481 					weaponPtr->StateTimeOutCounter=0;
9482 				}
9483 			}
9484 		}
9485 	}
9486 
9487 	if (PlayersWeaponHModelController.keyframe_flags&1) {
9488 		SECTION_DATA *disc_section;
9489 		disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk");
9490 		if (disc_section) {
9491 			/* Throw Disc. */
9492 			if (FirePredatorDisc(weaponPtr,disc_section)) {
9493 				/* Mask disc. */
9494 				disc_section->flags|=section_data_notreal;
9495 			}
9496 		}
9497 	}
9498 
9499 }
9500 
9501 int PredatorDisc_Prefiring(PLAYER_WEAPON_DATA *weaponPtr) {
9502 
9503 	/* Hey ho. */
9504 
9505 	return(1);
9506 }
9507 
9508 int FirePredatorDisc(PLAYER_WEAPON_DATA *weaponPtr,SECTION_DATA *disc_section) {
9509 
9510   	#if 0
9511   	PC_PRED_DISC_BEHAV_BLOCK bblk;
9512 
9513 	PredDisc_GetFirstTarget(&bblk, PlayersTarget.DispPtr, &disc_section->World_Offset);
9514 
9515 	if ((bblk.Target==NULL)&&(ThisDiscMode==I_Search_Destroy)) {
9516 		NewOnScreenMessage("NO TARGET");
9517         weaponPtr->CurrentState = WEAPONSTATE_WAITING;
9518 		return(0);
9519 	} else {
9520 	  	weaponPtr->PrimaryRoundsRemaining -= 65536;
9521 		InitialiseDiscBehaviour(bblk.Target,disc_section);
9522 		return(1);
9523 	}
9524 	#else
9525 	if (SmartTarget_Object) {
9526 		InitialiseDiscBehaviour(SmartTarget_Object->ObStrategyBlock,disc_section);
9527 	} else {
9528 		InitialiseDiscBehaviour(NULL,disc_section);
9529 	}
9530 	weaponPtr->PrimaryRoundsRemaining -= 65536;
9531 	return(1);
9532 	#endif
9533 }
9534 
9535 void PredatorDisc_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9536 
9537 	/* Right.  Go, recreate disc, then come. */
9538 	TEMPLATE_WEAPON_DATA *twPtr;
9539 
9540     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9541 
9542 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9543 		int time;
9544 
9545 		time=DIV_FIXED(ONE_FIXED,(twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]<<1));
9546 		time-=(ONE_FIXED>>4);
9547 
9548 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0);
9549 		PlayersWeaponHModelController.Looped=0;
9550 		PlayersWeaponHModelController.LoopAfterTweening=0;
9551 	}
9552 
9553 	if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening)
9554 		&&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) {
9555 
9556 		SECTION_DATA *disc_section;
9557 		int time;
9558 
9559 		if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Come) {
9560 			/* If this is the second time, end. */
9561 			weaponPtr->StateTimeOutCounter = 0;
9562 		} else {
9563 			disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk");
9564 			GLOBALASSERT(disc_section);
9565 			/* Appear Disc. */
9566 			disc_section->flags&=~section_data_notreal;
9567 
9568 			time=DIV_FIXED(ONE_FIXED,(twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]<<1));
9569 			time-=(ONE_FIXED>>4);
9570 
9571 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Come,time,0);
9572 			PlayersWeaponHModelController.Looped=0;
9573 			PlayersWeaponHModelController.LoopAfterTweening=0;
9574 		}
9575 	} else {
9576 		/* Stay in this state. */
9577 		weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
9578 	}
9579 }
9580 
9581 void SpikeyThing_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9582 
9583 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9584 	LOCALASSERT(playerStatusPtr);
9585 
9586 	/* We must be in the animation. */
9587 
9588 	/* Maintain this state... */
9589 	weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
9590 	GLOBALASSERT(PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Secondary);
9591 
9592 	/* Force Decloak. */
9593 	if (playerStatusPtr->cloakOn) {
9594 		playerStatusPtr->cloakOn=0;
9595 		Sound_Play(SID_PRED_CLOAKOFF,"h");
9596 		//playerNoise=1;
9597 	}
9598 
9599 	/* ...Unless we're at the end. */
9600 	if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
9601 		/* End state. */
9602 		weaponPtr->StateTimeOutCounter = 0;
9603 	}
9604 
9605 	if (PlayersWeaponHModelController.keyframe_flags&1) {
9606 		if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) {
9607 			Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0;
9608 		}
9609 	}
9610 
9611 	if (PlayersWeaponHModelController.keyframe_flags&2) {
9612 		NPC_DATA *NpcData;
9613 
9614 		switch (AvP.Difficulty) {
9615 			case I_Easy:
9616 				NpcData=GetThisNpcData(I_PC_Predator_Easy);
9617 				break;
9618 			default:
9619 			case I_Medium:
9620 				NpcData=GetThisNpcData(I_PC_Predator_Medium);
9621 				break;
9622 			case I_Hard:
9623 				NpcData=GetThisNpcData(I_PC_Predator_Hard);
9624 				break;
9625 			case I_Impossible:
9626 				NpcData=GetThisNpcData(I_PC_Predator_Impossible);
9627 				break;
9628 		}
9629 		LOCALASSERT(NpcData);
9630 
9631 		/* Ouch. */
9632 		Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
9633 		playerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
9634 
9635 		/* Now yell a bit? */
9636 		if (playerStatusPtr->soundHandle!=SOUND_NOACTIVEINDEX) {
9637 			Sound_Stop(playerStatusPtr->soundHandle);
9638 		}
9639 		Sound_Play(SID_PRED_NEWROAR,"hev",&playerStatusPtr->soundHandle,VOLUME_MAX);
9640 		if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Medicomp_Special;
9641 		playerNoise=1;
9642 
9643 		if (GREENFLASH_INTENSITY>PlayerDamagedOverlayIntensity)
9644 		{
9645 			PlayerDamagedOverlayIntensity=GREENFLASH_INTENSITY;
9646 		}
9647 
9648 		{
9649 			/* Auto change to wristblade? */
9650 			int slot;
9651 
9652 			/* Try flashback weapon... */
9653 			slot=playerStatusPtr->PreviouslySelectedWeaponSlot;
9654 			if (slot==-1) {
9655 				slot=SlotForThisWeapon(WEAPON_PRED_WRISTBLADE);
9656 			}
9657 			if (slot==-1) {
9658 				/* Argh! Whadda ya mean, you've got no wristblade? */
9659 				GLOBALASSERT(0);
9660 			}
9661 
9662 			{
9663 		    	playerStatusPtr->SwapToWeaponSlot = slot;
9664 				weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
9665 			    weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
9666 			}
9667 		}
9668 	}
9669 }
9670 
9671 void Extinguisher_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9672 
9673 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9674 	LOCALASSERT(playerStatusPtr);
9675 
9676 	/* We must be in the animation. */
9677 
9678 	/* Maintain this state... */
9679 	weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
9680 	GLOBALASSERT(PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Primary);
9681 
9682 	/* Force Decloak. */
9683 	if (playerStatusPtr->cloakOn) {
9684 		playerStatusPtr->cloakOn=0;
9685 		Sound_Play(SID_PRED_CLOAKOFF,"h");
9686 		//playerNoise=1;
9687 	}
9688 
9689 	/* ...Unless we're at the end. */
9690 	if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
9691 		/* End state. */
9692 		weaponPtr->StateTimeOutCounter = 0;
9693 	}
9694 
9695 	if (PlayersWeaponHModelController.keyframe_flags&1) {
9696 		if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) {
9697 			Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0;
9698 		}
9699 	}
9700 
9701 	/* That's all, folks. */
9702 }
9703 
9704 int FireSpikeyThing(PLAYER_WEAPON_DATA *weaponPtr) {
9705 
9706     TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9707 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9708 	NPC_DATA *NpcData;
9709 
9710 	switch (AvP.Difficulty) {
9711 		case I_Easy:
9712 			NpcData=GetThisNpcData(I_PC_Predator_Easy);
9713 			break;
9714 		default:
9715 		case I_Medium:
9716 			NpcData=GetThisNpcData(I_PC_Predator_Medium);
9717 			break;
9718 		case I_Hard:
9719 			NpcData=GetThisNpcData(I_PC_Predator_Hard);
9720 			break;
9721 		case I_Impossible:
9722 			NpcData=GetThisNpcData(I_PC_Predator_Impossible);
9723 			break;
9724 	}
9725 	LOCALASSERT(NpcData);
9726 	LOCALASSERT(playerStatusPtr);
9727 
9728 	#if QUIRKAFLEEG
9729 	if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
9730     	if (weaponPtr->PrimaryRoundsRemaining<ONE_FIXED) {
9731 			return(FireExtinguisher(weaponPtr));
9732 		}
9733 	}
9734 	#endif
9735 
9736 	if (playerStatusPtr->FieldCharge<=MEDICOMP_USE_THRESHOLD) {
9737 		return(0);
9738 	}
9739 
9740 	if ((Player->ObStrategyBlock->SBDamageBlock.Health==NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)
9741 		&&(Player->ObStrategyBlock->SBDamageBlock.IsOnFire==0)) {
9742 		return(0);
9743 	}
9744 
9745 	#if QUIRKAFLEEG
9746 	if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) {
9747     	if (weaponPtr->PrimaryRoundsRemaining<ONE_FIXED) {
9748 			return(0);
9749 		} else {
9750 	    	weaponPtr->PrimaryRoundsRemaining-=ONE_FIXED;
9751 		}
9752 	}
9753 	#endif
9754 
9755 	if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
9756 		/* Force Decloak. */
9757 		playerStatusPtr->cloakOn=0;
9758 		Sound_Play(SID_PRED_CLOAKOFF,"h");
9759 		//playerNoise=1;
9760 	}
9761 
9762 	GLOBALASSERT(AvP.PlayerType==I_Predator);
9763 
9764 	/* No longer will we do that wussey instant healing thing! */
9765 	playerStatusPtr->FieldCharge-=MEDICOMP_DRAIN_BLOCK;
9766 	CurrentGameStats_ChargeUsed(MEDICOMP_DRAIN_BLOCK);
9767 	/* But we do do the instant charging thing. */
9768 	LOCALASSERT(playerStatusPtr->FieldCharge>=0);
9769 
9770 	GLOBALASSERT(PlayersWeaponHModelController.section_data);
9771 	InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0);
9772 
9773 	return(1);
9774 
9775 }
9776 
9777 int FireExtinguisher(PLAYER_WEAPON_DATA *weaponPtr) {
9778 
9779     TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9780 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9781 
9782 	/* Ha ha ha.  I made a funny! */
9783 
9784 	LOCALASSERT(playerStatusPtr);
9785 
9786 	if (playerStatusPtr->FieldCharge<=EXTINGUISHER_USE_THRESHOLD) {
9787 		return(0);
9788 	}
9789 
9790 	if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire==0) {
9791 		return(0);
9792 	}
9793 
9794 
9795 	if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) {
9796 		/* Force Decloak. */
9797 		playerStatusPtr->cloakOn=0;
9798 		Sound_Play(SID_PRED_CLOAKOFF,"h");
9799 		//playerNoise=1;
9800 	}
9801 
9802 	GLOBALASSERT(AvP.PlayerType==I_Predator);
9803 
9804 	/* No longer will we do that wussey instant healing thing! */
9805 	playerStatusPtr->FieldCharge-=EXTINGUISHER_DRAIN_BLOCK;
9806 	CurrentGameStats_ChargeUsed(EXTINGUISHER_DRAIN_BLOCK);
9807 	/* But we do do the instant charging thing. */
9808 	LOCALASSERT(playerStatusPtr->FieldCharge>=0);
9809 
9810 	GLOBALASSERT(PlayersWeaponHModelController.section_data);
9811 	InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
9812 
9813 	return(1);
9814 
9815 }
9816 
9817 void Staff_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9818 
9819 	TEMPLATE_WEAPON_DATA *twPtr;
9820 
9821     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9822 
9823 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9824 		int time;
9825 
9826 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]);
9827 
9828 		GLOBALASSERT(time!=0);
9829 
9830 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,time);
9831 		PlayersWeaponHModelController.Looped=0;
9832 	}
9833 	/* Handle staff sections. */
9834 	PlayerStaff1=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff R blade");
9835 	PlayerStaff2=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff ROOT");
9836 	PlayerStaff3=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff L blade");
9837 	StaffAttack=-1;
9838 
9839 }
9840 
9841 void Staff_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9842 
9843 	TEMPLATE_WEAPON_DATA *twPtr;
9844 
9845     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9846 
9847 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9848 		int time;
9849 
9850 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
9851 		time-=(ONE_FIXED>>4);
9852 
9853 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0);
9854 		PlayersWeaponHModelController.Looped=0;
9855 	}
9856 	/* Handle staff sections. */
9857 	PlayerStaff1=NULL;
9858 	PlayerStaff2=NULL;
9859 	PlayerStaff3=NULL;
9860 	StaffAttack=-1;
9861 }
9862 
9863 void Staff_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9864 
9865 	TEMPLATE_WEAPON_DATA *twPtr;
9866 
9867     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9868 
9869 	/* Are we running? */
9870 
9871 	if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0)
9872 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0)
9873 		|| (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) {
9874 
9875 		/* Were we running? */
9876 
9877 		if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) {
9878 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1);
9879 		}
9880 	} else {
9881 
9882 		if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
9883 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
9884 		}
9885 
9886 		if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
9887 
9888 			if (WeaponFidgetPlaying) {
9889 				if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
9890 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1);
9891 					WeaponFidgetPlaying=0;
9892 				}
9893 			} else if ((FastRandom()&255)==0) {
9894 				/* Start animation. */
9895 				#if 1
9896 				if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) {
9897 					InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0);
9898 					weaponPtr->StateTimeOutCounter=0;
9899 					WeaponFidgetPlaying=1;
9900 				}
9901 				#endif
9902 			}
9903 
9904 		}
9905 	}
9906 }
9907 
9908 void StaffAttack_Basic(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
9909 
9910 	TEMPLATE_WEAPON_DATA *twPtr;
9911 
9912     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
9913 
9914 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
9915 
9916 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0);
9917 		if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
9918 			StaffAttack=1;
9919 		} else {
9920 			StaffAttack=0;
9921 		}
9922 	} else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) {
9923 		/* End state. */
9924 		weaponPtr->StateTimeOutCounter = 0;
9925 		StaffAttack=-1;
9926 	} else {
9927 		enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID;
9928 		/*  In the middle. */
9929 		weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1);
9930 
9931 		Staff_Manager(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],PlayerStaff1,PlayerStaff2,PlayerStaff3,
9932 			Player->ObStrategyBlock);
9933 
9934 	}
9935 
9936 }
9937 
9938 int PointIsInPlayer(VECTORCH *point) {
9939 	/* Special case. */
9940 	VECTORCH max,min;
9941 
9942 	max.vx=Player->ObShapeData->shapemaxx;
9943 	min.vx=Player->ObShapeData->shapeminx;
9944 	max.vy=Player->ObShapeData->shapemaxy;
9945 	min.vy=Player->ObShapeData->shapeminy;
9946 	max.vz=Player->ObShapeData->shapemaxz;
9947 	min.vz=Player->ObShapeData->shapeminz;
9948 
9949 	RotateVector(&max,&Player->ObMat);
9950 	RotateVector(&min,&Player->ObMat);
9951 
9952 	max.vx+=Player->ObStrategyBlock->DynPtr->Position.vx;
9953 	max.vy+=Player->ObStrategyBlock->DynPtr->Position.vy;
9954 	max.vz+=Player->ObStrategyBlock->DynPtr->Position.vz;
9955 
9956 	min.vx+=Player->ObStrategyBlock->DynPtr->Position.vx;
9957 	min.vy+=Player->ObStrategyBlock->DynPtr->Position.vy;
9958 	min.vz+=Player->ObStrategyBlock->DynPtr->Position.vz;
9959 	/* Now test. */
9960 	if ((point->vx>min.vx)&&(point->vx<max.vx)&&
9961 		(point->vy>min.vy)&&(point->vy<max.vy)&&
9962 		(point->vz>min.vz)&&(point->vz<max.vz)) {
9963 		/* Success. */
9964 		return(1);
9965 	}
9966 
9967 	return(0);
9968 }
9969 
9970 int IsPointInsideObject(VECTORCH *point, STRATEGYBLOCK *sbPtr, SECTION_DATA **hit_section) {
9971 
9972 	DISPLAYBLOCK *dPtr;
9973 
9974 	dPtr=sbPtr->SBdptr;
9975 
9976 	if (dPtr==Player) {
9977 		GLOBALASSERT(dPtr);
9978 	}
9979 
9980 	if (dPtr==NULL) {
9981 		*hit_section=NULL;
9982 		return(0);
9983 	}
9984 	if (dPtr->SfxPtr) {
9985 		*hit_section=NULL;
9986 		return(0);
9987 	}
9988 	if (dPtr==Player) {
9989 		/* Special case for player. */
9990 		if (PointIsInPlayer(point)) {
9991 			/* Hit! */
9992 			*hit_section=NULL;
9993 			return(1);
9994 		}
9995 	} else if (dPtr->HModelControlBlock) {
9996 		SECTION_DATA *hs;
9997 		/* Hierarchy case. */
9998 		hs=PointInHModel(dPtr->HModelControlBlock,point);
9999 		if (hs) {
10000 			*hit_section=hs;
10001 			return(1);
10002 		} else {
10003 			*hit_section=NULL;
10004 			return(0);
10005 		}
10006 	} else {
10007 		VECTORCH offset;
10008 		int dist;
10009 		/* Use shape data. */
10010 		if (dPtr->ObShapeData==NULL) {
10011 			*hit_section=NULL;
10012 			return(0);
10013 		}
10014 		offset.vx=dPtr->ObWorld.vx-point->vx;
10015 		offset.vy=dPtr->ObWorld.vy-point->vy;
10016 		offset.vz=dPtr->ObWorld.vz-point->vz;
10017 		dist=Approximate3dMagnitude(&offset);
10018 		if (dist<dPtr->ObShapeData->shaperadius) {
10019 			/* Hit! */
10020 			*hit_section=NULL;
10021 			return(1);
10022 		}
10023 	}
10024 	*hit_section=NULL;
10025 	return(0);
10026 }
10027 
10028 int Staff_Manager(DAMAGE_PROFILE *damage,SECTION_DATA *section1,SECTION_DATA *section2,SECTION_DATA *section3,
10029 	STRATEGYBLOCK *wielder)	{
10030 
10031 	SECTION_DATA *hit_section;
10032 	int numberOfObjects = NumActiveBlocks;
10033 	int numhits;
10034 	int hitatall=0;
10035 
10036 	GLOBALASSERT(wielder->SBdptr);
10037 
10038 	while (numberOfObjects)
10039 	{
10040 		DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects];
10041 		STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
10042 		GLOBALASSERT(objectPtr);
10043 
10044 		numhits=0;
10045 
10046 		if (objectPtr==Player) {
10047 			GLOBALASSERT(objectPtr);
10048 			/* So I can breakpoint it. */
10049 		}
10050 
10051 		/* does object have a strategy block? */
10052 		if ((sbPtr)&&(sbPtr!=wielder))
10053 		{
10054 
10055 			DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
10056 
10057 			if (dynPtr) {
10058 
10059 				if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,wielder->SBdptr,&wielder->DynPtr->Position,10000)) {
10060 
10061 					/* Deduce if each section has hit. */
10062 
10063 					if (IsPointInsideObject(&section1->World_Offset,sbPtr,&hit_section)) {
10064 						numhits++;
10065 					} else if (IsPointInsideObject(&section2->World_Offset,sbPtr,&hit_section)) {
10066 						numhits++;
10067 					} else if (IsPointInsideObject(&section3->World_Offset,sbPtr,&hit_section)) {
10068 						numhits++;
10069 					}
10070 
10071 				}
10072 			}
10073 		}
10074 
10075 		if (numhits) {
10076 			hitatall++;
10077 			if (sbPtr->SBdptr->HModelControlBlock) {
10078 				#if 0
10079 				if (hit_section==NULL) {
10080 					HtoHDamageToHModel(sbPtr, damage, NormalFrameTime, NULL, NULL);
10081 				} else {
10082 					CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, damage, NormalFrameTime, hit_section,NULL,NULL,0);
10083 				}
10084 				#else
10085 				HtoHDamageToHModel(sbPtr, damage, NormalFrameTime, NULL, NULL);
10086 				#endif
10087 			} else {
10088 				CauseDamageToObject(sbPtr, damage, NormalFrameTime,NULL);
10089 			}
10090 		}
10091 
10092 	}
10093 	return(hitatall);
10094 }
10095 
10096 /* Cheat mode in here! */
10097 #define BITE_RANGE 	((SNIPERMUNCH_MODE)? 100000:3000)
10098 #define BITE_RADIUS	((SNIPERMUNCH_MODE)? 1500:200)
10099 
10100 #define TROPHY_RANGE 	(3000)
10101 #define TROPHY_RADIUS	(200)
10102 
10103 SECTION_DATA *CheckBiteIntegrity(void) {
10104 
10105 	VECTORCH targetpos;
10106 	DISPLAYBLOCK *objectPtr;
10107 
10108 	if (Biting==NULL) {
10109 		return(NULL);
10110 	}
10111 	if (!(Validate_Strategy(Biting,Biting_SBname))) {
10112 		return(NULL);
10113 	}
10114 	if (!(Biting->SBdptr)) {
10115 		/* Gone far? */
10116 		return(NULL);
10117 	}
10118 	objectPtr=Biting->SBdptr;
10119 
10120 	GetTargetingPointOfObject(objectPtr,&targetpos);
10121 	targetpos.vx-=Global_VDB_Ptr->VDB_World.vx;
10122 	targetpos.vy-=Global_VDB_Ptr->VDB_World.vy;
10123 	targetpos.vz-=Global_VDB_Ptr->VDB_World.vz;
10124 	RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat);
10125 
10126 	/* is it in the range band? */
10127 	if ((targetpos.vz >0)
10128 		&& (targetpos.vz <  (BITE_RANGE<<1))) {
10129 
10130 		DYNAMICSBLOCK *dynPtr = Biting->DynPtr;
10131 		GLOBALASSERT(dynPtr);
10132 
10133 		if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(BITE_RANGE<<1))) {
10134 
10135 			SECTION_DATA *head;
10136 			/* The minute his *head* is in view... */
10137 			head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
10138 			if (head!=NULL) {
10139 				if (head->flags&section_data_notreal) {
10140 					/* Is it still attached? */
10141 					head=NULL;
10142 				}
10143 			}
10144 			/* We'll have the head now if at all. */
10145 			if (head) {
10146 				VECTORCH temp_view;
10147 				int dist;
10148 				/* I assume if we're alive, we have a head. */
10149 				temp_view=head->View_Offset;
10150 				temp_view.vz=0;
10151 				dist=Approximate3dMagnitude(&temp_view);
10152 				/* Scale radius with FOV here? */
10153 				if (dist<(BITE_RADIUS<<1)) {
10154 					/* Aw, okay. */
10155 					return(head);
10156 				}
10157 			}
10158 		}
10159 	}
10160 	/* If you got here, you failed. */
10161 	return(NULL);
10162 }
10163 
10164 int AlienBite_TargetFilter(STRATEGYBLOCK *sbPtr) {
10165 
10166 	/* Is it tasty, mm?  Is it... crunchable? */
10167 
10168 	if ((sbPtr->I_SBtype==I_BehaviourMarine)
10169 		||(sbPtr->I_SBtype==I_BehaviourSeal))
10170 	{
10171 		MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
10172 		GLOBALASSERT(marineStatusPointer);
10173 
10174 		if (!marineStatusPointer->Android && !NPC_IsDead(sbPtr))
10175 		{
10176 			return(1);
10177 		}
10178 	}
10179 	else if (sbPtr->I_SBtype==I_BehaviourNetCorpse)
10180 	{
10181 		NETCORPSEDATABLOCK *corpseDataPtr;
10182 
10183 		corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
10184 		LOCALASSERT(corpseDataPtr);
10185 
10186 		if (((corpseDataPtr->timer/2)<ONE_FIXED)||corpseDataPtr->Android)
10187 		{
10188 			/* Already fading. */
10189 			return(0);
10190 		}
10191 		else if ((corpseDataPtr->Type==I_BehaviourMarine)
10192 			||(corpseDataPtr->Type==I_BehaviourSeal)
10193 			||(corpseDataPtr->Type==I_BehaviourPredator)
10194 			)
10195 		{
10196 			/* Of course it's dead! */
10197 			return(1);
10198 		}
10199 	} else if (sbPtr->I_SBtype==I_BehaviourNetGhost) {
10200 		NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
10201 		LOCALASSERT(ghostData);
10202 
10203 		//check for opponent in network game
10204 		if(ghostData->type==I_BehaviourNetCorpse)
10205 		{
10206 			if(ghostData->subtype==I_BehaviourMarinePlayer ||
10207 			   ghostData->subtype==I_BehaviourPredatorPlayer)
10208 			{
10209 				return 1;
10210 			}
10211 		}
10212 		else if (ghostData->type==I_BehaviourMarinePlayer ||
10213 				 ghostData->type==I_BehaviourPredatorPlayer)
10214 		{
10215 			// We don't want to allow bite attacks against players
10216 			// that have respawn invulnerability
10217 			if(!ghostData->invulnerable)
10218 			{
10219 				return 1;
10220 			}
10221 		}
10222 	} else if (sbPtr->I_SBtype==I_BehaviourPredator) {
10223 
10224 		/* There's always got to be a difficult one! */
10225 		SECTION_DATA *head;
10226 
10227 		if (!sbPtr->SBdptr) {
10228 			return(0);
10229 		}
10230 		/* The minute his *head* is in view... */
10231 		head=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,"head");
10232 		/* Is it still attached? */
10233 		if (head) {
10234 			if (head->flags&section_data_notreal) {
10235 				head=NULL;
10236 			}
10237 		}
10238 		/* We'll have the head now if at all. */
10239 		if (head) {
10240 			DAMAGEBLOCK temp_damage;
10241 
10242 			temp_damage=head->current_damage;
10243 
10244 			DamageDamageBlock(&temp_damage,&TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage[AvP.Difficulty],ONE_FIXED);
10245 
10246 			if (temp_damage.Health<=0) {
10247 				/* Killed the head, that'll do. */
10248 				return(1);
10249 			}
10250 			/* So the head lived, huh?  Let's try the body. */
10251 			temp_damage=sbPtr->SBDamageBlock;
10252 			DamageDamageBlock(&temp_damage,&TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage[AvP.Difficulty],ONE_FIXED);
10253 
10254 			if (temp_damage.Health<=0) {
10255 				/* Killed the body, that'll do too. */
10256 				return(1);
10257 			}
10258 
10259 		}
10260 		return(0);
10261 	}
10262 
10263 	return(0);
10264 
10265 }
10266 
10267 STRATEGYBLOCK *GetBitingTarget(void) {
10268 
10269 	/* Sweep OnScreenBlockList. */
10270 
10271 	int numberOfObjects = NumOnScreenBlocks;
10272 
10273 	while (numberOfObjects)
10274 	{
10275 		STRATEGYBLOCK *sbPtr;
10276 		VECTORCH targetpos;
10277 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
10278 
10279 		GLOBALASSERT(objectPtr);
10280 		sbPtr = objectPtr->ObStrategyBlock;
10281 
10282 		/* does object have a strategy block? */
10283 		if (sbPtr) {
10284 
10285 			if (AlienBite_TargetFilter(sbPtr)) {
10286 
10287 				GLOBALASSERT(objectPtr->HModelControlBlock);
10288 
10289 				GetTargetingPointOfObject(objectPtr,&targetpos);
10290 				targetpos.vx-=Global_VDB_Ptr->VDB_World.vx;
10291 				targetpos.vy-=Global_VDB_Ptr->VDB_World.vy;
10292 				targetpos.vz-=Global_VDB_Ptr->VDB_World.vz;
10293 				RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat);
10294 
10295 				/* is it in the range band? */
10296 				if ((targetpos.vz >0)
10297 					&& (targetpos.vz <  BITE_RANGE)) {
10298 
10299 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
10300 				  	if (dynPtr) {
10301 
10302 						if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(BITE_RANGE<<1))) {
10303 
10304 							SECTION_DATA *head;
10305 							/* The minute his *head* is in view... */
10306 							head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
10307 							/* Is it still attached? */
10308 							if (head) {
10309 								if (head->flags&section_data_notreal) {
10310 									head=NULL;
10311 								}
10312 							}
10313 							/* We'll have the head now if at all. */
10314 							if (head) {
10315 								VECTORCH temp_view;
10316 								int dist;
10317 								/* I assume if we're alive, we have a head. */
10318 								temp_view=head->View_Offset;
10319 								temp_view.vz=0;
10320 								dist=Approximate3dMagnitude(&temp_view);
10321 								if (dist<BITE_RADIUS) {
10322 									/* Aw, okay. */
10323 									return(sbPtr);
10324 								}
10325 							}
10326 						}
10327 					}
10328 				}
10329 			}
10330 		}
10331 	}
10332 
10333 	return(NULL);
10334 
10335 }
10336 
10337 int Trophy_TargetFilter(STRATEGYBLOCK *sbPtr) {
10338 
10339 	/* Only works on dead'uns. */
10340 
10341 	if (sbPtr->I_SBtype==I_BehaviourNetCorpse)
10342 	{
10343 		NETCORPSEDATABLOCK *corpseDataPtr;
10344 
10345 		corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
10346 		LOCALASSERT(corpseDataPtr);
10347 
10348 		if ((corpseDataPtr->timer/2)<ONE_FIXED)
10349 		{
10350 			/* Already fading. */
10351 			return(0);
10352 		}
10353 		else if ((corpseDataPtr->Type==I_BehaviourMarine)
10354 			||(corpseDataPtr->Type==I_BehaviourSeal)
10355 			||(corpseDataPtr->Type==I_BehaviourAlien)
10356 			||(corpseDataPtr->Type==I_BehaviourPredator)
10357 			)
10358 		{
10359 			/* Of course it's dead! */
10360 			return(1);
10361 		}
10362 	} else if (sbPtr->I_SBtype==I_BehaviourNetGhost) {
10363 		NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
10364 		LOCALASSERT(ghostData);
10365 
10366 		//check for opponent in network game
10367 		if(ghostData->type==I_BehaviourNetCorpse)
10368 		{
10369 			if(ghostData->subtype==I_BehaviourMarinePlayer ||
10370 			   ghostData->subtype==I_BehaviourPredatorPlayer ||
10371 			   ghostData->subtype==I_BehaviourAlienPlayer)
10372 			{
10373 				return 1;
10374 			}
10375 		}
10376 	} else if (sbPtr->I_SBtype==I_BehaviourHierarchicalFragment) {
10377 
10378 		DISPLAYBLOCK *objectPtr;
10379 		HDEBRIS_BEHAV_BLOCK *debrisDataPtr;
10380 
10381 		debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr;
10382 		LOCALASSERT(debrisDataPtr);
10383 
10384 		/* Check type. */
10385 
10386 		if ((debrisDataPtr->Type==I_BehaviourMarine)
10387 			||(debrisDataPtr->Type==I_BehaviourSeal)
10388 			||(debrisDataPtr->Type==I_BehaviourAlien)
10389 			||(debrisDataPtr->Type==I_BehaviourPredator)
10390 			) {
10391 
10392 			objectPtr=sbPtr->SBdptr;
10393 			if (objectPtr) {
10394 				if (objectPtr->HModelControlBlock) {
10395 					SECTION_DATA *head;
10396 					/* Test for the head... */
10397 					head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
10398 					/* Is it still attached? */
10399 					if (head) {
10400 						if (head->flags&section_data_notreal) {
10401 							head=NULL;
10402 						}
10403 					}
10404 					if (head) {
10405 						if ((HModel_DepthTest(objectPtr->HModelControlBlock,head,1))==0) {
10406 							/* Fragment is big enough. */
10407 							return(1);
10408 						}
10409 					}
10410 				}
10411 			}
10412 		}
10413 	} else if (sbPtr->I_SBtype==I_BehaviourSpeargunBolt) {
10414 
10415 		DISPLAYBLOCK *objectPtr;
10416 		SPEAR_BEHAV_BLOCK *spearDataPtr;
10417 
10418 		spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr;
10419 		LOCALASSERT(spearDataPtr);
10420 
10421 		/* Check type. */
10422 
10423 		if ((spearDataPtr->Type==I_BehaviourMarine)
10424 			||(spearDataPtr->Type==I_BehaviourSeal)
10425 			||(spearDataPtr->Type==I_BehaviourAlien)
10426 			||(spearDataPtr->Type==I_BehaviourPredator)
10427 			) {
10428 
10429 			objectPtr=sbPtr->SBdptr;
10430 			if (objectPtr) {
10431 				if (objectPtr->HModelControlBlock) {
10432 					SECTION_DATA *head;
10433 					/* Test for the head... */
10434 					head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
10435 					/* Is it still attached? */
10436 					if (head) {
10437 						if (head->flags&section_data_notreal) {
10438 							head=NULL;
10439 						}
10440 					}
10441 					if (head) {
10442 						if ((HModel_DepthTest(objectPtr->HModelControlBlock,head,1))==0) {
10443 							/* Fragment is big enough. */
10444 							return(1);
10445 						}
10446 					}
10447 				}
10448 			}
10449 		}
10450 	}
10451 
10452 	return(0);
10453 
10454 }
10455 
10456 STRATEGYBLOCK *GetTrophyTarget(SECTION_DATA **head_section_data) {
10457 
10458 	/* Sweep OnScreenBlockList. */
10459 
10460 	int numberOfObjects = NumOnScreenBlocks;
10461 
10462 	*head_section_data=NULL;
10463 
10464 	while (numberOfObjects)
10465 	{
10466 		STRATEGYBLOCK *sbPtr;
10467 		VECTORCH targetpos;
10468 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects];
10469 
10470 		GLOBALASSERT(objectPtr);
10471 		sbPtr = objectPtr->ObStrategyBlock;
10472 
10473 		/* does object have a strategy block? */
10474 		if (sbPtr) {
10475 
10476 			if (Trophy_TargetFilter(sbPtr)) {
10477 
10478 				GLOBALASSERT(objectPtr->HModelControlBlock);
10479 
10480 				GetTargetingPointOfObject(objectPtr,&targetpos);
10481 				targetpos.vx-=Global_VDB_Ptr->VDB_World.vx;
10482 				targetpos.vy-=Global_VDB_Ptr->VDB_World.vy;
10483 				targetpos.vz-=Global_VDB_Ptr->VDB_World.vz;
10484 				RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat);
10485 
10486 				/* is it in the range band? */
10487 				if ((targetpos.vz >0)
10488 					&& (targetpos.vz <  TROPHY_RANGE)) {
10489 
10490 					DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
10491 				  	if (dynPtr) {
10492 
10493 						//if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(TROPHY_RANGE<<1))) {
10494 						if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&dynPtr->Position)) {
10495 
10496 							SECTION_DATA *head;
10497 							/* The minute his *head* is in view... */
10498 							head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
10499 							/* Is it still attached? */
10500 							if (head) {
10501 								if (head->flags&section_data_notreal) {
10502 									head=NULL;
10503 								}
10504 							}
10505 							/* We'll have the head now if at all. */
10506 							if (head) {
10507 								VECTORCH temp_view;
10508 								int dist;
10509 								/* I assume if we're alive, we have a head. */
10510 								temp_view=head->View_Offset;
10511 								temp_view.vz=0;
10512 								dist=Approximate3dMagnitude(&temp_view);
10513 								if (dist<TROPHY_RADIUS) {
10514 									/* Aw, okay. */
10515 									*head_section_data=head;
10516 									return(sbPtr);
10517 								}
10518 							}
10519 						}
10520 					}
10521 				}
10522 			}
10523 		}
10524 	}
10525 
10526 	return(NULL);
10527 
10528 }
10529 
10530 extern void AutoSwapToDisc(void) {
10531 
10532 	int slot;
10533 	PLAYER_WEAPON_DATA *weaponPtr;
10534 
10535     weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]);
10536 
10537 	slot=SlotForThisWeapon(WEAPON_PRED_DISC);
10538 	if (slot==-1) {
10539 		/* Maybe you're not a predator... */
10540 		return;
10541    	#if 0
10542 	} else if (weaponPtr->CurrentState==WEAPONSTATE_IDLE) {
10543         PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo=(slot+1);
10544    	#else
10545 	} else {
10546 		AutoSwap=slot;
10547    	#endif
10548 	}
10549 
10550 }
10551 
10552 extern void AutoSwapToDisc_OutOfSequence(void) {
10553 
10554 	int slot;
10555 	PLAYER_WEAPON_DATA *weaponPtr;
10556 
10557     weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]);
10558 
10559 	slot=SlotForThisWeapon(WEAPON_PRED_DISC);
10560 
10561 	if (slot!=-1) {
10562 		AutoSwap=slot;
10563 	}
10564 
10565 }
10566 
10567 #define SPEAR_NPC_IMPULSE	(20000)
10568 
10569 void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data)
10570 {
10571 	VECTORCH incoming,*invec;
10572 	DISPLAYBLOCK *fragged_section;
10573 
10574 	fragged_section=NULL;
10575 
10576 	if(sbPtr)
10577 	{
10578 		if (sbPtr->DynPtr) {
10579 			MATRIXCH WtoLMat;
10580 			/* Consider incoming hit direction. */
10581 			WtoLMat=sbPtr->DynPtr->OrientMat;
10582 			TransposeMatrixCH(&WtoLMat);
10583 			RotateAndCopyVector(directionPtr,&incoming,&WtoLMat);
10584 			invec=&incoming;
10585 		} else {
10586 			invec=NULL;
10587 		}
10588 
10589 		if (this_section_data)
10590 		{
10591 			if (sbPtr->SBdptr)
10592 			{
10593 				//if (sbPtr->SBdptr->HModelControlBlock && (sbPtr->I_SBtype != I_BehaviourNetGhost))
10594 				if (sbPtr->SBdptr->HModelControlBlock)
10595 				{
10596 					/* Netghost case now handled properly. */
10597 					AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point,this_section_data);
10598 
10599 					GLOBALASSERT(sbPtr->SBdptr->HModelControlBlock==this_section_data->my_controller);
10600 					fragged_section=CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED, this_section_data,invec,positionPtr,0);
10601 					/* No longer return: do knockback. */
10602 					//return;
10603 				}
10604 				else
10605 				{
10606 		  			CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec);
10607 				}
10608 			}
10609 			else
10610 			{
10611 		  		CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec);
10612 			}
10613 		}
10614 		else
10615 		{
10616 		  	CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec);
10617 		}
10618 
10619 		if (sbPtr->DynPtr)
10620 		{
10621 			DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
10622 			/* Forget torque for the moment. */
10623 
10624 			/*
10625 			Knock the character back - unless it is the alien queen.
10626 			*/
10627 			if(sbPtr->I_SBtype!=I_BehaviourQueenAlien)
10628 			{
10629 				dynPtr->LinImpulse.vx+=MUL_FIXED(directionPtr->vx,(SPEAR_NPC_IMPULSE));
10630 				dynPtr->LinImpulse.vy+=MUL_FIXED(directionPtr->vy,(SPEAR_NPC_IMPULSE));
10631 				dynPtr->LinImpulse.vz+=MUL_FIXED(directionPtr->vz,(SPEAR_NPC_IMPULSE));
10632 			}
10633 
10634 			if (fragged_section) {
10635 
10636 				fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(directionPtr->vx,SPEAR_NPC_IMPULSE);
10637 				fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(directionPtr->vy,SPEAR_NPC_IMPULSE);
10638 				fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(directionPtr->vz,SPEAR_NPC_IMPULSE);
10639 			}
10640 		}
10641 
10642 
10643 	}
10644 
10645 
10646 	/* check to see if we've shot off a body part, or we're stuck into the environment */
10647 	{
10648 		char needToAddSpear = 0;
10649 
10650 		if (fragged_section)
10651 		{
10652 			needToAddSpear = 1;
10653 		}
10654 		else if (sbPtr)
10655 		{
10656 			DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
10657 
10658 			if (dispPtr)
10659 			if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl))
10660 			{
10661 				needToAddSpear=1;
10662 			}
10663 		}
10664 		else
10665 		{
10666 			needToAddSpear = 1;
10667 		}
10668 		if (needToAddSpear) CreateSpearPossiblyWithFragment(fragged_section,&LOS_Point,directionPtr);
10669 	}
10670 }
10671 
10672 
10673 void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr)
10674 {
10675 
10676 	if (dispPtr)
10677 	{
10678 		STRATEGYBLOCK *sbPtr;
10679 		DYNAMICSBLOCK *dynPtr;
10680 		SPEAR_BEHAV_BLOCK *newBehaviourDataBlock;
10681 		int android;
10682 
10683 		AVP_BEHAVIOUR_TYPE Type;
10684 		int SubType;
10685 
10686 		sbPtr = dispPtr->ObStrategyBlock;
10687 		LOCALASSERT(sbPtr);
10688 
10689 		dynPtr = sbPtr->DynPtr;
10690 		LOCALASSERT(dynPtr);
10691 
10692 		LOCALASSERT(sbPtr->I_SBtype == I_BehaviourHierarchicalFragment);
10693 
10694 		newBehaviourDataBlock=(SPEAR_BEHAV_BLOCK*)AllocateMem(sizeof(SPEAR_BEHAV_BLOCK));
10695 
10696 		android=((HDEBRIS_BEHAV_BLOCK *) sbPtr->SBdataptr)->Android;
10697 
10698 		Splice_HModels(&(newBehaviourDataBlock->HierarchicalFragment),(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).section_data);
10699 
10700 		Type=((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type;
10701 		SubType=((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType;
10702 
10703 		/* we don't need the old extra sb data */
10704 		Dispel_HModel(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController));
10705 		DeallocateMem(sbPtr->SBdataptr);
10706 
10707 		dispPtr->HModelControlBlock = &(newBehaviourDataBlock->HierarchicalFragment);
10708 
10709 		sbPtr->SBdataptr =(void*) newBehaviourDataBlock;
10710 
10711 		if (!sbPtr->SBdataptr)
10712 		{
10713 			// Failed to allocate a strategy block data pointer
10714 			RemoveBehaviourStrategy(sbPtr);
10715 			return;
10716 		}
10717 		sbPtr->I_SBtype = I_BehaviourSpeargunBolt;
10718 
10719 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->counter = 5*ONE_FIXED;
10720 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Stuck = 0;
10721 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->SpearThroughFragment = 1;
10722 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Android = android;
10723 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Type = Type;
10724 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->SubType = SubType;
10725 
10726 
10727 		dynPtr->LinVelocity.vx = spearDirectionPtr->vx/4;
10728 		dynPtr->LinVelocity.vy = spearDirectionPtr->vy/4;
10729 		dynPtr->LinVelocity.vz = spearDirectionPtr->vz/4;
10730 		dynPtr->LinImpulse.vx = 0;
10731 		dynPtr->LinImpulse.vy = 0;
10732 		dynPtr->LinImpulse.vz = 0;
10733 		dynPtr->AngVelocity.EulerX = 0;
10734 		dynPtr->AngVelocity.EulerY = 0;
10735 		dynPtr->AngVelocity.EulerZ = 0;
10736 		dynPtr->GravityOn = 0;
10737 		dynPtr->StopOnCollision = 1;
10738 
10739 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vx = spearPositionPtr->vx - dynPtr->Position.vx;
10740 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vy = spearPositionPtr->vy - dynPtr->Position.vy;
10741 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vz = spearPositionPtr->vz - dynPtr->Position.vz;
10742 		{
10743 			MATRIXCH mat;
10744 			MakeMatrixFromDirection(spearDirectionPtr,&mat);
10745 			((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Orient = mat;
10746 		}
10747 
10748 		/* Ooooh!  Not initialised at all! CDF 23/9/98, hassled about an assert */
10749 		/* KJL 10:37:56 05/10/98 - Just keeping you on your toes :) */
10750 
10751 		InitHModelTweening(&(((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->HierarchicalFragment),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
10752 		ProveHModel(dispPtr->HModelControlBlock,dispPtr);
10753 		/* And just for now... */
10754 		((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->HierarchicalFragment.Playing=0;
10755 
10756 		/* Baaaad Kevin!  And why couldn't you have called the HModelController 'HModelController' like God intended? */
10757 		/* KJL 10:38:17 05/10/98 - Hey, I was trying to be descriptive. */
10758 
10759 	    Sound_Play(SID_PLASMABOLT_HIT,"d",&dynPtr->Position);
10760 
10761 	}
10762 	else /* there is no hierarchical fragment; we've stuck into the environment */
10763 	{
10764 		DYNAMICSBLOCK *dynPtr;
10765 
10766 		dispPtr = MakeObject(I_BehaviourSpeargunBolt,spearPositionPtr);
10767 		if (dispPtr == 0) return;		 // Failed to allocate display block
10768 
10769 		/* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */
10770 		dispPtr->ObMaxX = 10;
10771 		dispPtr->ObMaxY = 10;
10772 		dispPtr->ObMaxZ = 10;
10773 		dispPtr->ObMinX = -10;
10774 		dispPtr->ObMinY = -10;
10775 		dispPtr->ObMinZ = -10;
10776 
10777 		/* setup dynamics block */
10778 		dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
10779 		dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS;
10780 
10781 		if (!dynPtr)
10782 		{
10783 			// Failed to allocate a dynamics block
10784 			RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
10785 			return;
10786 		}
10787 
10788 		dispPtr->ObStrategyBlock->DynPtr = dynPtr;
10789 
10790 		/* give missile a maximum lifetime */
10791 		dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK));
10792 
10793 		if (dispPtr->ObStrategyBlock->SBdataptr == 0)
10794 		{
10795 			// Failed to allocate a strategy block data pointer
10796 			RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
10797 			return;
10798 		}
10799 		memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK));
10800 
10801 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 20*ONE_FIXED;
10802 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Stuck = 1;
10803 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SpearThroughFragment = 0;
10804 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Android = 0;
10805 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Type = I_BehaviourNull;
10806 		((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SubType = 0;
10807 
10808 		dynPtr->Position= *spearPositionPtr;
10809 		dynPtr->PrevPosition= *spearPositionPtr;
10810 		{
10811 			MATRIXCH mat;
10812 			MakeMatrixFromDirection(spearDirectionPtr,&mat);
10813 			dynPtr->OrientMat = mat;
10814 			MatrixToEuler(&mat,&dynPtr->OrientEuler);
10815 		}
10816 		dynPtr->PrevOrientMat = dynPtr->OrientMat;
10817 		{
10818 			VECTORCH pos = dynPtr->Position;
10819 			pos.vx += spearDirectionPtr->vx;
10820 			pos.vy += spearDirectionPtr->vy;
10821 			pos.vz += spearDirectionPtr->vz;
10822 			MakeFocusedExplosion(&(dynPtr->Position), &pos, 20, PARTICLE_SPARK);
10823 			MakeLightElement(&(dynPtr->Position),LIGHTELEMENT_ELECTRICAL_SPARKS);
10824 		}
10825 
10826 		if(AvP.Network != I_No_Network)
10827 		{
10828 			//send location here , so as to avoid having to update it every frame
10829 			AddNetMsg_LocalObjectState(dispPtr->ObStrategyBlock);
10830 		}
10831 
10832 		#if 0 // no network yet!
10833 		if(AvP.Network != I_No_Network)	AddNetGameObjectID(dispPtr->ObStrategyBlock);
10834 		#endif
10835 	    Sound_Play(SID_SPEARGUN_HITTING_WALL,"d",&dynPtr->Position);
10836 		return;
10837 	}
10838 }
10839 
10840 void LimbRip_AwardHealth(void) {
10841 
10842 	NPC_DATA *NpcData;
10843 	int health_bonus;
10844 
10845 	NpcData=GetThisNpcData(I_PC_Alien_MaxStats);
10846 	LOCALASSERT(NpcData);
10847 
10848 	switch (AvP.Difficulty) {
10849 		case I_Easy:
10850 			health_bonus=5;
10851 			break;
10852 		case I_Medium:
10853 		default:
10854 			health_bonus=2;
10855 			break;
10856 		case I_Hard:
10857 			health_bonus=1;
10858 			break;
10859 		case I_Impossible:
10860 			health_bonus=0;
10861 			break;
10862 	}
10863 
10864 	/* Now add some health. */
10865 	Player->ObStrategyBlock->SBDamageBlock.Health+=(health_bonus<<ONE_FIXED_SHIFT);
10866 	if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
10867 		Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
10868 	}
10869 	PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
10870 
10871 }
10872 
10873 void BiteAttack_AwardHealth(STRATEGYBLOCK *sbPtr,AVP_BEHAVIOUR_TYPE pre_bite_type) {
10874 
10875 	NPC_DATA *NpcData;
10876 
10877 	/* Have all your armour back? */
10878 	NpcData=GetThisNpcData(I_PC_Alien_MaxStats);
10879 	LOCALASSERT(NpcData);
10880 
10881 	if ((pre_bite_type==I_BehaviourMarine)
10882 		||(pre_bite_type==I_BehaviourSeal)
10883 		||(pre_bite_type==I_BehaviourPredator)) {
10884 
10885 		/* Add some armour... */
10886 		Player->ObStrategyBlock->SBDamageBlock.Armour+=(BITE_ARMOUR_RECOVERY<<ONE_FIXED_SHIFT);
10887 		if (Player->ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT)) {
10888 			Player->ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
10889 		}
10890 		PlayerStatusPtr->Armour=Player->ObStrategyBlock->SBDamageBlock.Armour;
10891 
10892 		/* And some health, too. */
10893 		Player->ObStrategyBlock->SBDamageBlock.Health+=(BITE_HEALTH_RECOVERY<<ONE_FIXED_SHIFT);
10894 		if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
10895 			Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
10896 		}
10897 		PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
10898 
10899 		return;
10900 	}
10901 
10902 	if (pre_bite_type==I_BehaviourNetCorpse) {
10903 		/* It probably is still a corpse now... */
10904 		NETCORPSEDATABLOCK *corpseDataPtr;
10905 
10906 		corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
10907 		LOCALASSERT(corpseDataPtr);
10908 
10909 		if ((corpseDataPtr->Type==I_BehaviourMarine)
10910 			||(corpseDataPtr->Type==I_BehaviourSeal)
10911 			||(corpseDataPtr->Type==I_BehaviourPredator)
10912 			) {
10913 			/* No armour, just a bit of health. */
10914 			Player->ObStrategyBlock->SBDamageBlock.Health+=(20<<ONE_FIXED_SHIFT);
10915 			if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
10916 				Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
10917 			}
10918 			PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
10919 		}
10920 	}
10921 
10922 	if(pre_bite_type==I_BehaviourNetGhost)
10923 	{
10924 		//rather higher health awards for getting network opponents
10925 		NETGHOSTDATABLOCK *ghostData;
10926 		NPC_DATA* StartingHealth;
10927 
10928 			switch (AvP.Difficulty) {
10929 				case I_Easy:
10930 					StartingHealth=GetThisNpcData(I_PC_Alien_Easy);
10931 					break;
10932 				default:
10933 				case I_Medium:
10934 					StartingHealth=GetThisNpcData(I_PC_Alien_Medium);
10935 					break;
10936 				case I_Hard:
10937 					StartingHealth=GetThisNpcData(I_PC_Alien_Hard);
10938 					break;
10939 				case I_Impossible:
10940 					StartingHealth=GetThisNpcData(I_PC_Alien_Impossible);
10941 					break;
10942 			}
10943 
10944 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
10945 		LOCALASSERT(ghostData);
10946 
10947 		if(ghostData->type==I_BehaviourNetCorpse)
10948 		{
10949 			if(ghostData->subtype==I_BehaviourMarinePlayer ||
10950 			   ghostData->subtype==I_BehaviourPredatorPlayer)
10951 			{
10952 				/* Add some armour... */
10953 				Player->ObStrategyBlock->SBDamageBlock.Armour+=(BITE_ARMOUR_RECOVERY<<ONE_FIXED_SHIFT);
10954 				if (Player->ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT)) {
10955 					Player->ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
10956 				}
10957 				PlayerStatusPtr->Armour=Player->ObStrategyBlock->SBDamageBlock.Armour;
10958 
10959 				/* And some health, too. */
10960 				Player->ObStrategyBlock->SBDamageBlock.Health+=(20<<ONE_FIXED_SHIFT);
10961 				if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
10962 					Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
10963 				}
10964 
10965 				//make sure player has at least starting health
10966 				if(Player->ObStrategyBlock->SBDamageBlock.Health<(StartingHealth->StartingStats.Health<<ONE_FIXED_SHIFT))
10967 				{
10968 					Player->ObStrategyBlock->SBDamageBlock.Health=StartingHealth->StartingStats.Health<<ONE_FIXED_SHIFT;
10969 				}
10970 
10971 				PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
10972 			}
10973 		}
10974 		else if(ghostData->type==I_BehaviourMarinePlayer ||
10975 				ghostData->type==I_BehaviourPredatorPlayer)
10976 		{
10977 			//killed  player character with a bite attack
10978 
10979 			/* Add some armour... */
10980 			Player->ObStrategyBlock->SBDamageBlock.Armour+=(StartingHealth->StartingStats.Armour<<ONE_FIXED_SHIFT);
10981 			if (Player->ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT)) {
10982 				Player->ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
10983 			}
10984 			PlayerStatusPtr->Armour=Player->ObStrategyBlock->SBDamageBlock.Armour;
10985 
10986 			/* And some health, too. */
10987 			Player->ObStrategyBlock->SBDamageBlock.Health+=(StartingHealth->StartingStats.Health<<ONE_FIXED_SHIFT);
10988 			if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<<ONE_FIXED_SHIFT)) {
10989 				Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
10990 			}
10991 
10992 			PlayerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health;
10993 		}
10994 
10995 	}
10996 
10997 }
10998 
10999 int PlayerFirePredPistolFlechettes(PLAYER_WEAPON_DATA *weaponPtr) {
11000 
11001 	extern VECTORCH CentreOfMuzzleOffset;
11002 	VECTORCH *firingpos;
11003 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
11004 	LOCALASSERT(playerStatusPtr);
11005 
11006 	/* Another cheap copy of the flamethrower function. */
11007 
11008 	ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon);
11009 
11010 	if (playerStatusPtr->FieldCharge>0) {
11011 		playerStatusPtr->FieldCharge-=(NormalFrameTime);
11012 		CurrentGameStats_ChargeUsed(NormalFrameTime);
11013 		if (playerStatusPtr->FieldCharge<0) {
11014 			playerStatusPtr->FieldCharge=0;
11015 		}
11016 	} else {
11017 		return(0);
11018 	}
11019 
11020 	if (PWMFSDP) {
11021 		VECTORCH null_vec={0,0,0};
11022 
11023 		textprint("Hierarchical Flechettes Fire!\n");
11024 
11025 		firingpos=&PWMFSDP->World_Offset;
11026 
11027 		FirePredPistolFlechettes(firingpos,&null_vec,&PlayersWeapon.ObMat,0,&Flamethrower_Timer,TRUE);
11028 
11029 	} else {
11030 		firingpos=&CentreOfMuzzleOffset;
11031 		FirePredPistolFlechettes(&PlayersWeapon.ObWorld,firingpos,&PlayersWeapon.ObMat,1,&Flamethrower_Timer,TRUE);
11032 	}
11033 
11034 
11035 	return(1);
11036 
11037 }
11038 
11039 int PredPistolSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr) {
11040 
11041 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
11042 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
11043 
11044 	LOCALASSERT(playerStatusPtr);
11045 
11046 	if (playerStatusPtr->FieldCharge>=PredPistol_ShotCost) {
11047 
11048 		playerStatusPtr->FieldCharge-=PredPistol_ShotCost;
11049 		CurrentGameStats_ChargeUsed(PredPistol_ShotCost);
11050 
11051 		FireProjectileAmmo(twPtr->PrimaryAmmoID);
11052 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
11053 
11054 		return(1);
11055 	}
11056 
11057 	return(0);
11058 }
11059 
11060 void ChangeHUDToAlternateShapeSet(char *riffname,char *setname) {
11061 
11062 	HIERARCHY_SHAPE_REPLACEMENT* replacement_array;
11063 	int a;
11064 
11065 	replacement_array=GetHierarchyAlternateShapeSetFromLibrary(riffname,setname);
11066 
11067 	if (replacement_array==NULL) {
11068 		return;
11069 	}
11070 
11071 	a=0;
11072 
11073 	while (replacement_array[a].replaced_section_name!=NULL) {
11074 		SECTION_DATA *target_section;
11075 
11076 		target_section=GetThisSectionData(PlayersWeaponHModelController.section_data,
11077 			replacement_array[a].replaced_section_name);
11078 		if (target_section) {
11079 			target_section->Shape=replacement_array[a].replacement_shape;
11080 			#if 1
11081 			target_section->ShapeNum=replacement_array[a].replacement_shape_index;
11082 			#endif
11083 
11084 			Setup_Texture_Animation_For_Section(target_section);
11085 		}
11086 		a++;
11087 	}
11088 }
11089 
11090 int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr) {
11091 
11092 	if (sbPtr==NULL) {
11093 		return(0);
11094 	}
11095 
11096 	switch (sbPtr->I_SBtype) {
11097 		case I_BehaviourPredator:
11098 			/* Valid. */
11099 			if (NPC_IsDead(sbPtr)) {
11100 				return(1);
11101 			} else {
11102 				return(1);
11103 			}
11104 			break;
11105 		case I_BehaviourAlien:
11106 		case I_BehaviourQueenAlien:
11107 		case I_BehaviourFaceHugger:
11108 		case I_BehaviourXenoborg:
11109 		case I_BehaviourMarine:
11110 		case I_BehaviourSeal:
11111 		case I_BehaviourPredatorAlien:
11112 			/* Valid. */
11113 			if (NPC_IsDead(sbPtr)) {
11114 				return(1);
11115 			} else {
11116 				return(1);
11117 			}
11118 			break;
11119 		case I_BehaviourNetCorpse:
11120 			{
11121 				NETCORPSEDATABLOCK *corpseDataPtr;
11122 			    LOCALASSERT(sbPtr);
11123 				corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
11124 				LOCALASSERT(corpseDataPtr);
11125 
11126 				if (corpseDataPtr->validityTimer>0) {
11127 					return(1);
11128 				} else {
11129 					return(0);
11130 				}
11131 			}
11132 			break;
11133 		case I_BehaviourNetGhost:
11134 			{
11135 				NETGHOSTDATABLOCK *dataptr;
11136 				dataptr=sbPtr->SBdataptr;
11137 				switch (dataptr->type) {
11138 					case I_BehaviourPredatorPlayer:
11139 						return(1);
11140 						break;
11141 					case I_BehaviourMarinePlayer:
11142 					case I_BehaviourAlienPlayer:
11143 					case I_BehaviourRocket:
11144 					case I_BehaviourGrenade:
11145 					case I_BehaviourFlareGrenade:
11146 					case I_BehaviourFragmentationGrenade:
11147 					case I_BehaviourClusterGrenade:
11148 					case I_BehaviourNPCPredatorDisc:
11149 					case I_BehaviourPredatorDisc_SeekTrack:
11150 					case I_BehaviourAlien:
11151 					case I_BehaviourProximityGrenade:
11152 						return(1);
11153 						break;
11154 					default:
11155 						return(0);
11156 						break;
11157 				}
11158 			}
11159 			break;
11160 		default:
11161 			return(0);
11162 			break;
11163 	}
11164 
11165 	return(0);
11166 
11167 }
11168 
11169 int FriendlyFireDamageFilter(DAMAGE_PROFILE *damage) {
11170 
11171 	BOOL VulnerableToAlienDamage = TRUE;
11172 	BOOL VulnerableToMarineDamage = TRUE;
11173 	BOOL VulnerableToPredatorDamage = TRUE;
11174 
11175 	if(AvP.PlayerType == I_Alien)
11176 	{
11177 		VulnerableToAlienDamage = FALSE;
11178 	}
11179 	else if(AvP.PlayerType == I_Marine)
11180 	{
11181 		VulnerableToMarineDamage = FALSE;
11182 		if(netGameData.gameType==NGT_Coop)
11183 		{
11184 			VulnerableToPredatorDamage = FALSE;
11185 		}
11186 	}
11187 	else if(AvP.PlayerType == I_Predator)
11188 	{
11189 		VulnerableToPredatorDamage = FALSE;
11190 		if(netGameData.gameType==NGT_Coop)
11191 		{
11192 			VulnerableToMarineDamage = FALSE;
11193 		}
11194 	}
11195 
11196 	/* Does this damage type hurt you? */
11197 
11198 	switch (damage->Id) {
11199 		case AMMO_ALIEN_CLAW:
11200 		case AMMO_ALIEN_TAIL:
11201 		case AMMO_ALIEN_BITE_KILLSECTION:
11202 		case AMMO_ALIEN_BITE_KILLSECTION_SUPER:
11203 		case AMMO_PC_ALIEN_BITE:
11204 			return(VulnerableToAlienDamage);
11205 			break;
11206 
11207 		case AMMO_10MM_CULW:
11208 		case AMMO_SMARTGUN:
11209 		case AMMO_FLAMETHROWER:
11210 		case AMMO_SADAR_TOW:
11211 		case AMMO_GRENADE:
11212 		case AMMO_MINIGUN:
11213 		case AMMO_PULSE_GRENADE:
11214 		case AMMO_FRAGMENTATION_GRENADE:
11215 		case AMMO_PROXIMITY_GRENADE:
11216 		case AMMO_SADAR_BLAST:
11217 		case AMMO_PULSE_GRENADE_STRIKE:
11218 		case AMMO_CUDGEL:
11219 		case AMMO_FLECHETTE_POSTMAX:
11220 		case AMMO_FRISBEE:
11221 		case AMMO_FRISBEE_BLAST:
11222 		case AMMO_FRISBEE_FIRE:
11223 		case AMMO_MARINE_PISTOL_PC:
11224 			return(VulnerableToMarineDamage);
11225 			break;
11226 
11227 		case AMMO_PRED_WRISTBLADE:
11228 		case AMMO_PRED_PISTOL:
11229 		case AMMO_PRED_RIFLE:
11230 		case AMMO_PRED_ENERGY_BOLT:
11231 		case AMMO_PRED_DISC:
11232 		case AMMO_PRED_STAFF:
11233 		case AMMO_HEAVY_PRED_WRISTBLADE:
11234 		case AMMO_PREDPISTOL_STRIKE:
11235 		case AMMO_PLASMACASTER_NPCKILL:
11236 		case AMMO_PLASMACASTER_PCKILL:
11237 		case AMMO_PRED_TROPHY_KILLSECTION:
11238 			return(VulnerableToPredatorDamage);
11239 			break;
11240 
11241 		default: ;
11242 	}
11243 
11244 	return TRUE;
11245 }
11246 
11247 
11248 /*-------------------**
11249 ** Load/Save Globals **
11250 **-------------------*/
11251 #include "savegame.h"
11252 
11253 typedef struct weapons_c_save_block
11254 {
11255 	SAVE_BLOCK_HEADER header;
11256 
11257 	int Alien_Visible_Weapon;
11258 	int Alien_Tail_Clock;
11259 	int Wristblade_StrikeType;
11260 	DAMAGE_PROFILE Player_Weapon_Damage;
11261 	int playerNoise;
11262 	int PlayerDamagedOverlayIntensity;
11263 	int HtoHStrikes;
11264 	int WeaponFidgetPlaying;
11265 	int Old_Minigun_SpinSpeed;
11266 	int Minigun_SpinSpeed;
11267 	int Weapon_ThisBurst;
11268 	EULER Minigun_MaxHeadJolt;
11269 	EULER Minigun_HeadJolt;
11270 	int Flamethrower_Timer;
11271 	int StaffAttack;
11272 	int GrenadeLauncherSelectedAmmo;
11273 	int LastHand;  // For alien claws
11274 	VECTORCH PlayersWeaponCameraOffset;
11275 	VECTORCH PlayerGunBarrelOffset;
11276 }WEAPONS_C_SAVE_BLOCK;
11277 
11278 void Load_WeaponsCGlobals(SAVE_BLOCK_HEADER* header)
11279 {
11280 	WEAPONS_C_SAVE_BLOCK* block = (WEAPONS_C_SAVE_BLOCK*) header;
11281 
11282 	//check the size of the save block
11283 	if(header->size!=sizeof(*block)) return;
11284 
11285 	Alien_Visible_Weapon = block->Alien_Visible_Weapon;
11286 	Alien_Tail_Clock = block->Alien_Tail_Clock;
11287 	Wristblade_StrikeType = block->Wristblade_StrikeType;
11288 	Player_Weapon_Damage = block->Player_Weapon_Damage;
11289 	playerNoise = block->playerNoise;
11290 	PlayerDamagedOverlayIntensity = block->PlayerDamagedOverlayIntensity;
11291 	HtoHStrikes = block->HtoHStrikes;
11292 	WeaponFidgetPlaying = block->WeaponFidgetPlaying;
11293 	Old_Minigun_SpinSpeed = block->Old_Minigun_SpinSpeed;
11294 	Minigun_SpinSpeed = block->Minigun_SpinSpeed;
11295 	Weapon_ThisBurst = block->Weapon_ThisBurst;
11296 	Minigun_MaxHeadJolt = block->Minigun_MaxHeadJolt;
11297 	Minigun_HeadJolt = block->Minigun_HeadJolt;
11298 	Flamethrower_Timer = block->Flamethrower_Timer;
11299 	StaffAttack = block->StaffAttack;
11300 	GrenadeLauncherSelectedAmmo = block->GrenadeLauncherSelectedAmmo;
11301 	LastHand = block->LastHand;  // For alien claws
11302 
11303 	PlayersWeaponCameraOffset = block->PlayersWeaponCameraOffset;
11304 	PlayerGunBarrelOffset = block->PlayerGunBarrelOffset;
11305 
11306 	Load_SoundState(&weaponHandle);
11307 }
11308 
11309 void Save_WeaponsCGlobals()
11310 {
11311 	WEAPONS_C_SAVE_BLOCK* block;
11312 
11313 	GET_SAVE_BLOCK_POINTER(block);
11314 
11315 	//fill in the header
11316 	block->header.size = sizeof(*block);
11317 	block->header.type = SaveBlock_WeaponsCGlobals;
11318 
11319 	block->Alien_Visible_Weapon = Alien_Visible_Weapon;
11320 	block->Alien_Tail_Clock = Alien_Tail_Clock;
11321 	block->Wristblade_StrikeType = Wristblade_StrikeType;
11322 	block->Player_Weapon_Damage = Player_Weapon_Damage;
11323 	block->playerNoise = playerNoise;
11324 	block->PlayerDamagedOverlayIntensity = PlayerDamagedOverlayIntensity;
11325 	block->HtoHStrikes = HtoHStrikes;
11326 	block->WeaponFidgetPlaying = WeaponFidgetPlaying;
11327 	block->Old_Minigun_SpinSpeed = Old_Minigun_SpinSpeed;
11328 	block->Minigun_SpinSpeed = Minigun_SpinSpeed;
11329 	block->Weapon_ThisBurst = Weapon_ThisBurst;
11330 	block->Minigun_MaxHeadJolt = Minigun_MaxHeadJolt;
11331 	block->Minigun_HeadJolt = Minigun_HeadJolt;
11332 	block->Flamethrower_Timer = Flamethrower_Timer;
11333 	block->StaffAttack = StaffAttack;
11334 	block->GrenadeLauncherSelectedAmmo = GrenadeLauncherSelectedAmmo;
11335 	block->LastHand = LastHand;  // For alien claws
11336 
11337 	block->PlayersWeaponCameraOffset = PlayersWeaponCameraOffset;
11338 	block->PlayerGunBarrelOffset = PlayerGunBarrelOffset;
11339 
11340 
11341 
11342 	Save_SoundState(&weaponHandle);
11343 }
11344 
11345 void MarinePistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11346 
11347 	TEMPLATE_WEAPON_DATA *twPtr;
11348 	DELTA_CONTROLLER *StockBack;
11349 
11350     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11351 
11352 	StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11353 	if (StockBack) {
11354 		/* Get rid of it. */
11355 		Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11356 	}
11357 
11358 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11359 
11360 		if (weaponPtr->PrimaryRoundsRemaining>=65536) {
11361 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0);
11362 		} else {
11363 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0);
11364 		}
11365 		{
11366 			SECTION_DATA *casing;
11367 			/* Make a little casing. */
11368 
11369 			casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round");
11370 
11371 			if (casing) {
11372 				MakePistolCasing(&casing->World_Offset,&casing->SecMat);
11373 			}
11374 		}
11375 	}
11376 
11377 }
11378 
11379 void MarinePistol_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11380 
11381 	DELTA_CONTROLLER *StockBack;
11382 
11383 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
11384 
11385 	StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11386 	if (StockBack) {
11387 		/* Get rid of it. */
11388 		Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11389 	}
11390 
11391 	if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
11392 		if (weaponPtr->PrimaryRoundsRemaining) {
11393 			InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
11394 		}
11395 	}
11396 
11397 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
11398 
11399 		if (WeaponFidgetPlaying) {
11400 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
11401 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
11402 				WeaponFidgetPlaying=0;
11403 			}
11404 		} else if ((FastRandom()&255)==0) {
11405 			/* Start animation. */
11406 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
11407 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,(ONE_FIXED<<1),0);
11408 				weaponPtr->StateTimeOutCounter=0;
11409 				WeaponFidgetPlaying=1;
11410 			}
11411 		}
11412 
11413 	}
11414 
11415 }
11416 
11417 void MarinePistol_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11418 
11419 	TEMPLATE_WEAPON_DATA *twPtr;
11420 	DELTA_CONTROLLER *StockBack;
11421 
11422     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11423 
11424 	StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11425 	if (StockBack) {
11426 		/* Get rid of it. */
11427 		Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11428 	}
11429 
11430 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11431 		int time;
11432 
11433 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]);
11434 		time-=(ONE_FIXED>>4);
11435 
11436 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0);
11437 		PlayersWeaponHModelController.Looped=0;
11438 
11439 		if ((AvP.Network != I_No_Network)&&(PISTOL_INFINITE_AMMO)) {
11440 			/* Pistol infinite ammo hack? */
11441 			weaponPtr->PrimaryMagazinesRemaining++;
11442 		}
11443 	}
11444 	StaffAttack=-1;
11445 }
11446 
11447 DISPLAYBLOCK *MakePistolCasing(VECTORCH *position,MATRIXCH *orient) {
11448 
11449 	DISPLAYBLOCK *dispPtr;
11450 	STRATEGYBLOCK *sbPtr;
11451 	MODULEMAPBLOCK *mmbptr;
11452 	MODULE m_temp;
11453 
11454 	if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL;
11455 
11456 	mmbptr = &TempModuleMap;
11457 
11458 	CreateShapeInstance(mmbptr,"Pistol case");
11459 
11460 	m_temp.m_numlights = 0;
11461 	m_temp.m_lightarray = NULL;
11462 	m_temp.m_mapptr = mmbptr;
11463 	m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
11464 	m_temp.m_dptr = NULL;
11465 	AllocateModuleObject(&m_temp);
11466 	dispPtr = m_temp.m_dptr;
11467 	if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */
11468 
11469 	dispPtr->ObMyModule = NULL;     /* Module that created us */
11470 	dispPtr->ObWorld = *position;
11471 
11472 	sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
11473 
11474 	if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block
11475 
11476 	sbPtr->I_SBtype = I_BehaviourFragment;
11477 
11478 	{
11479 		DYNAMICSBLOCK *dynPtr;
11480 		VECTORCH impulse;
11481 
11482 		sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK ));
11483 		if (sbPtr->SBdataptr == 0)
11484 		{
11485 			// Failed to allocate a strategy block data pointer
11486 			RemoveBehaviourStrategy(sbPtr);
11487 			return(DISPLAYBLOCK*)NULL;
11488 		}
11489 
11490 
11491 		((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME;
11492 
11493 		dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS);
11494 
11495 		if (dynPtr == 0)
11496 		{
11497 			// Failed to allocate a dynamics block
11498 			RemoveBehaviourStrategy(sbPtr);
11499 			return(DISPLAYBLOCK*)NULL;
11500 		}
11501 
11502 		dynPtr->Position = *position;
11503 		dynPtr->OrientMat= *orient;
11504 
11505 		dynPtr->AngVelocity.EulerX = 0;
11506 		dynPtr->AngVelocity.EulerY = ((FastRandom()&4095)<<2);
11507 		dynPtr->AngVelocity.EulerZ = 0;
11508 
11509 		impulse.vx=0;
11510 		impulse.vy=0;
11511 		impulse.vz=6000;
11512 
11513 		RotateVector(&impulse,orient);
11514 
11515 		dynPtr->LinImpulse = impulse;
11516 
11517 		sbPtr->SBflags.not_on_motiontracker=1;
11518 	}
11519 
11520     return dispPtr;
11521 
11522 }
11523 
11524 void MarineTwoPistols_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11525 
11526 	TEMPLATE_WEAPON_DATA *twPtr;
11527 
11528 	DELTA_CONTROLLER *FireRight;
11529 	DELTA_CONTROLLER *FireLeft;
11530 
11531 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
11532 	if (FireRight==NULL) {
11533 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
11534 		FireRight->Playing=0;
11535 		FireRight->Active=0;
11536 	}
11537 
11538 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
11539 	if (FireLeft==NULL) {
11540 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
11541 		FireLeft->Playing=0;
11542 		FireLeft->Active=0;
11543 	}
11544 
11545     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11546 
11547 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11548 
11549 		if (LastHand==0) {
11550 			if (weaponPtr->PrimaryRoundsRemaining>=65536) {
11551 				Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Standard_Fire,-1);
11552 				FireRight->Playing=1;
11553 				FireRight->Active=1;
11554 			} else {
11555 				Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1);
11556 				FireRight->Playing=1;
11557 				FireRight->Active=1;
11558 			}
11559 			{
11560 				SECTION_DATA *casing;
11561 				/* Make a little casing. */
11562 
11563 				casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round");
11564 
11565 				if (casing) {
11566 					MakePistolCasing(&casing->World_Offset,&casing->SecMat);
11567 				}
11568 			}
11569 		} else {
11570 			if (weaponPtr->SecondaryRoundsRemaining>=65536) {
11571 				Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Secondary_Fire,-1);
11572 				FireLeft->Playing=1;
11573 				FireLeft->Active=1;
11574 			} else {
11575 				Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1);
11576 				FireLeft->Playing=1;
11577 				FireLeft->Active=1;
11578 			}
11579 			{
11580 				SECTION_DATA *casing;
11581 				/* Make a little casing. */
11582 
11583 				casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum L Pistol round");
11584 
11585 				if (casing) {
11586 					MakePistolCasing(&casing->World_Offset,&casing->SecMat);
11587 				}
11588 			}
11589 		}
11590 		if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) {
11591 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>1),HMSQT_MarineHUD,(int)MHSS_Stationary,-1,0);
11592 		}
11593 	}
11594 }
11595 
11596 void MarineTwoPistols_SecondaryFiring(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11597 
11598 	TEMPLATE_WEAPON_DATA *twPtr;
11599 
11600 	DELTA_CONTROLLER *FireRight;
11601 	DELTA_CONTROLLER *FireLeft;
11602 
11603 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
11604 	if (FireRight==NULL) {
11605 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
11606 		FireRight->Playing=0;
11607 		FireRight->Active=0;
11608 	}
11609 
11610 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
11611 	if (FireLeft==NULL) {
11612 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
11613 		FireLeft->Playing=0;
11614 		FireLeft->Active=0;
11615 	}
11616 
11617     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11618 
11619 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11620 
11621 		if (LastHand==0) {
11622 			if (weaponPtr->PrimaryRoundsRemaining>=65536) {
11623 				Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Standard_Fire,-1);
11624 				FireRight->Playing=1;
11625 				FireRight->Active=1;
11626 			} else {
11627 				Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1);
11628 				FireRight->Playing=1;
11629 				FireRight->Active=1;
11630 			}
11631 			{
11632 				SECTION_DATA *casing;
11633 				/* Make a little casing. */
11634 
11635 				casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round");
11636 
11637 				if (casing) {
11638 					MakePistolCasing(&casing->World_Offset,&casing->SecMat);
11639 				}
11640 			}
11641 		} else {
11642 			if (weaponPtr->SecondaryRoundsRemaining>=65536) {
11643 				Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Secondary_Fire,-1);
11644 				FireLeft->Playing=1;
11645 				FireLeft->Active=1;
11646 			} else {
11647 				Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1);
11648 				FireLeft->Playing=1;
11649 				FireLeft->Active=1;
11650 			}
11651 			{
11652 				SECTION_DATA *casing;
11653 				/* Make a little casing. */
11654 
11655 				casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum L Pistol round");
11656 
11657 				if (casing) {
11658 					MakePistolCasing(&casing->World_Offset,&casing->SecMat);
11659 				}
11660 			}
11661 		}
11662 
11663 		/* Start Crossover sequence too. */
11664 
11665 		if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Tertiary_Fire) {
11666 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Tertiary_Fire,-1,0);
11667 		}
11668 	}
11669 }
11670 
11671 int AreTwoPistolsInTertiaryFire(void) {
11672 
11673 	PLAYER_WEAPON_DATA *weaponPtr;
11674 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
11675 
11676     weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
11677 
11678 	if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Tertiary_Fire) {
11679 		if ((weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)
11680 			&&((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))
11681 			) {
11682 			/* This to trap single player's reflection. */
11683 			return(1);
11684 		} else {
11685 			return(0);
11686 		}
11687 	} else {
11688 		return(1);
11689 	}
11690 
11691 }
11692 
11693 int FireMarineTwoPistols(PLAYER_WEAPON_DATA *weaponPtr, int secondary)
11694 {
11695 	TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber];
11696    	TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID];
11697 
11698 	DELTA_CONTROLLER *FireRight;
11699 	DELTA_CONTROLLER *FireLeft;
11700 
11701 	/* Deduce which pistol can fire, if either? */
11702 
11703 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
11704 	if (FireRight==NULL) {
11705 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
11706 		FireRight->Playing=0;
11707 		FireRight->Active=0;
11708 	}
11709 
11710 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
11711 	if (FireLeft==NULL) {
11712 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
11713 		FireLeft->Playing=0;
11714 		FireLeft->Active=0;
11715 	}
11716 
11717 	if (LastHand==0) {
11718 		/* Look to the left. */
11719 		if (!DeltaAnimation_IsFinished(FireLeft)) {
11720 			/* Left should not be able to fire. */
11721 			return(0);
11722 		}
11723 		if (weaponPtr->SecondaryRoundsRemaining) {
11724 			/* Fire left. */
11725 			LastHand=1;
11726 			PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash L");
11727 		  	weaponPtr->SecondaryRoundsRemaining -= 65536;
11728 		} else {
11729 			/* Try the other hand... */
11730 			if (!DeltaAnimation_IsFinished(FireRight)) {
11731 				/* Right should not be able to fire. */
11732 				return(0);
11733 			}
11734 			if (weaponPtr->PrimaryRoundsRemaining) {
11735 				/* Fire right. */
11736 				LastHand=0;
11737 				PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash");
11738 			  	weaponPtr->PrimaryRoundsRemaining -= 65536;
11739 			}
11740 		}
11741 	} else {
11742 		if (!DeltaAnimation_IsFinished(FireRight)) {
11743 			/* Right should not be able to fire. */
11744 			return(0);
11745 		}
11746 		if (weaponPtr->PrimaryRoundsRemaining) {
11747 			/* Fire right. */
11748 			LastHand=0;
11749 			PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash");
11750 		  	weaponPtr->PrimaryRoundsRemaining -= 65536;
11751 		} else {
11752 			/* Try the other hand... */
11753 			if (!DeltaAnimation_IsFinished(FireLeft)) {
11754 				/* Left should not be able to fire. */
11755 				return(0);
11756 			}
11757 			if (weaponPtr->SecondaryRoundsRemaining) {
11758 				/* Fire left. */
11759 				LastHand=1;
11760 				PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash L");
11761 			  	weaponPtr->SecondaryRoundsRemaining -= 65536;
11762 			}
11763 		}
11764 	}
11765 
11766 	{
11767 		/* Force gun judder */
11768 		if (secondary) {
11769 			weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY;
11770 			weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
11771 		} else {
11772 			weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY;
11773 			weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
11774 		}
11775 		CalculatePlayersTarget(twPtr,weaponPtr);
11776 	}
11777 
11778     /* does ammo create an actual object? */
11779     if (templateAmmoPtr->CreatesProjectile)
11780     {
11781 		FireProjectileAmmo(twPtr->PrimaryAmmoID);
11782 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
11783     }
11784     else /* instantaneous line of sight */
11785     {
11786 		PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,1);
11787 		CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1);
11788 	}
11789 	return(1);
11790 }
11791 
11792 int FireMarineTwoPistolsPrimary(PLAYER_WEAPON_DATA *weaponPtr) {
11793 
11794 	return(FireMarineTwoPistols(weaponPtr,0));
11795 
11796 }
11797 
11798 int FireMarineTwoPistolsSecondary(PLAYER_WEAPON_DATA *weaponPtr) {
11799 
11800 	return(FireMarineTwoPistols(weaponPtr,1));
11801 
11802 }
11803 
11804 void MarineTwoPistols_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11805 
11806 	DELTA_CONTROLLER *FireRight;
11807 	DELTA_CONTROLLER *FireLeft;
11808 
11809 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
11810 
11811 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
11812 	if (FireRight==NULL) {
11813 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
11814 		FireRight->Playing=0;
11815 		FireRight->Active=0;
11816 	}
11817 
11818 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
11819 	if (FireLeft==NULL) {
11820 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
11821 		FireLeft->Playing=0;
11822 		FireLeft->Active=0;
11823 	}
11824 
11825 	if (!DeltaAnimation_IsFinished(FireRight)) {
11826 		/* Just leave it alone... */
11827 		return;
11828 	}
11829 
11830 	/* If we're in Tertiary Fire, leave it alone for a moment. */
11831 	if (PlayersWeaponHModelController.Sub_Sequence==MHSS_Tertiary_Fire) {
11832 		if (PlayersWeaponHModelController.Tweening!=Controller_NoTweening) {
11833 			return;
11834 		}
11835 		if (weaponPtr->StateTimeOutCounter < (ONE_FIXED>>2)) {
11836 			return;
11837 		}
11838 	}
11839 
11840 	if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) {
11841 		if (PlayersWeaponHModelController.Sub_Sequence==MHSS_Tertiary_Fire) {
11842 			InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>1),HMSQT_MarineHUD,(int)MHSS_Stationary,-1,0);
11843 		} else {
11844 			InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED);
11845 		}
11846 	}
11847 
11848 	if (weaponPtr->StateTimeOutCounter > ONE_FIXED) {
11849 
11850 		if (WeaponFidgetPlaying) {
11851 			if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) {
11852 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
11853 				WeaponFidgetPlaying=0;
11854 			}
11855 		} else if ((FastRandom()&255)==0) {
11856 			/* Start animation. */
11857 			if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) {
11858 				InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,(ONE_FIXED<<1),0);
11859 				weaponPtr->StateTimeOutCounter=0;
11860 				WeaponFidgetPlaying=1;
11861 			}
11862 		}
11863 
11864 	}
11865 
11866 }
11867 
11868 void MarineTwoPistols_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11869 
11870 	TEMPLATE_WEAPON_DATA *twPtr;
11871 	DELTA_CONTROLLER *FireRight;
11872 	DELTA_CONTROLLER *FireLeft;
11873 
11874 	GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD);
11875 
11876 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
11877 	if (FireRight==NULL) {
11878 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
11879 		FireRight->Playing=0;
11880 		FireRight->Active=0;
11881 	}
11882 
11883 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
11884 	if (FireLeft==NULL) {
11885 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
11886 		FireLeft->Playing=0;
11887 		FireLeft->Active=0;
11888 	}
11889 
11890     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11891 
11892 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11893 		int time;
11894 
11895 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]);
11896 		time-=(ONE_FIXED>>4);
11897 
11898 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0);
11899 		PlayersWeaponHModelController.Looped=0;
11900 		FireRight->Active=0;
11901 		FireLeft->Active=0;
11902 
11903 
11904 		/* Pistol infinite ammo hack? */
11905 		if ((AvP.Network != I_No_Network)&&(PISTOL_INFINITE_AMMO)) {
11906 			weaponPtr->PrimaryMagazinesRemaining++;
11907 			weaponPtr->SecondaryMagazinesRemaining++;
11908 		}
11909 
11910 	}
11911 	StaffAttack=-1;
11912 }
11913 
11914 static void MarineZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) {
11915 
11916 	int weaponNum;
11917 	int slot;
11918 
11919 	/* Let's cut this into a function. */
11920 
11921 	if (AvP.PlayerType!=I_Marine) {
11922 		/* For now. */
11923 		return;
11924 	}
11925 
11926 	if ((weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER)
11927 		&& (
11928 				(GrenadeLauncherData.ProximityRoundsRemaining!=0)
11929 			  	||(GrenadeLauncherData.FragmentationRoundsRemaining!=0)
11930 			 	||(GrenadeLauncherData.StandardRoundsRemaining!=0)
11931 				||(GrenadeLauncherData.ProximityMagazinesRemaining!=0)
11932 			  	||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0)
11933 			 	||(GrenadeLauncherData.StandardMagazinesRemaining!=0)
11934 			)
11935 		) {
11936 		/* Deal with Al's 'grenade launcher change ammo' case... */
11937 		GrenadeLauncher_EmergencyChangeAmmo(weaponPtr);
11938 		return;
11939 	}
11940 
11941 	/* Now the serious bit. */
11942 
11943 	weaponNum=0;
11944 
11945 	/* Now, step up until you get to NULL or find a weapon with ammo. */
11946 	//weaponNum--;
11947 	while (MarineWeaponHierarchy[weaponNum]!=NULL_WEAPON) {
11948 
11949 		slot=SlotForThisWeapon(MarineWeaponHierarchy[weaponNum]);
11950 		if (slot!=-1) {
11951 			if (playerStatusPtr->WeaponSlot[slot].Possessed==1) {
11952 				if (WeaponHasAmmo(slot)) {
11953 					/* Okay! */
11954 					break;
11955 				}
11956 			}
11957 		}
11958 		weaponNum++;
11959 	}
11960 
11961 	if (MarineWeaponHierarchy[weaponNum]==NULL_WEAPON) {
11962 		/* No possible action. */
11963 		return;
11964 	}
11965 	if (MarineWeaponHierarchy[weaponNum]==weaponPtr->WeaponIDNumber) {
11966 		/* If you found the current weapon, do nothing. */
11967 		return;
11968 	}
11969 
11970 	/* So, change to this weapon. */
11971 	playerStatusPtr->SwapToWeaponSlot = slot;
11972 	weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
11973 	weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
11974 
11975 }
11976 
11977 void MarinePistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
11978 
11979 	TEMPLATE_WEAPON_DATA *twPtr;
11980 	DELTA_CONTROLLER *StockBack;
11981 
11982     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
11983 
11984 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
11985 		int time;
11986 
11987 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
11988 		time-=(ONE_FIXED>>4);
11989 
11990 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0);
11991 		PlayersWeaponHModelController.Looped=0;
11992 
11993 		if (weaponPtr->PrimaryRoundsRemaining==0) {
11994 			StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
11995 			if (StockBack==NULL) {
11996 				StockBack=Add_Delta_Sequence(&PlayersWeaponHModelController,"StockBack",HMSQT_MarineHUD,MHSS_Right_Out,ONE_FIXED);
11997 			}
11998 			if (StockBack) {
11999 				StockBack->Playing=0;
12000 				StockBack->timer=65535;
12001 				StockBack->lastframe_timer=65535;
12002 			}
12003 		}
12004 
12005 		/* Alter Two Pistols ammo? */
12006 		{
12007 			int slot;
12008 
12009 			slot=SlotForThisWeapon(WEAPON_TWO_PISTOLS);
12010 			if (slot!=-1) {
12011        			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->PrimaryRoundsRemaining;
12012 				/* Now split the clips between the pistols? */
12013 
12014        			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=(weaponPtr->PrimaryMagazinesRemaining)>>1;
12015        			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].SecondaryMagazinesRemaining=(weaponPtr->PrimaryMagazinesRemaining)>>1;
12016 				if (weaponPtr->PrimaryMagazinesRemaining&1) {
12017 	       			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining++;
12018 				}
12019 
12020 			}
12021 		}
12022 	}
12023 }
12024 
12025 void MarineTwoPistols_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
12026 
12027 	TEMPLATE_WEAPON_DATA *twPtr;
12028 
12029     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
12030 
12031 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
12032 		int time;
12033 
12034 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
12035 		time-=(ONE_FIXED>>4);
12036 
12037 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0);
12038 		PlayersWeaponHModelController.Looped=0;
12039 		/* Alter Pistol ammo? */
12040 		{
12041 			int slot;
12042 
12043 			slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL);
12044 			if (slot!=-1) {
12045 				if (weaponPtr->PrimaryRoundsRemaining==0) {
12046 	       			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=weaponPtr->PrimaryMagazinesRemaining+weaponPtr->SecondaryMagazinesRemaining;
12047 	       			if (((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining>99) {
12048 						((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=99;
12049 	       			};
12050 	       			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->SecondaryRoundsRemaining;
12051 					weaponPtr->SecondaryRoundsRemaining=0;
12052 	       			weaponPtr->PrimaryRoundsRemaining=((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining;
12053 				} else {
12054 	       			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=weaponPtr->PrimaryMagazinesRemaining+weaponPtr->SecondaryMagazinesRemaining;
12055 	       			((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->PrimaryRoundsRemaining;
12056 				}
12057 			}
12058 		}
12059 	}
12060 }
12061 
12062 void MarinePistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
12063 
12064 	TEMPLATE_WEAPON_DATA *twPtr;
12065 	DELTA_CONTROLLER *StockBack;
12066 
12067     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
12068 
12069 	Weapon_ThisBurst=-1;
12070 
12071 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
12072 		int time;
12073 
12074 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]);
12075 
12076 		GLOBALASSERT(time!=0);
12077 
12078 		if (weaponPtr->PrimaryRoundsRemaining==0) {
12079 			StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack");
12080 			if (StockBack==NULL) {
12081 				StockBack=Add_Delta_Sequence(&PlayersWeaponHModelController,"StockBack",HMSQT_MarineHUD,MHSS_Right_Out,ONE_FIXED);
12082 			}
12083 			if (StockBack) {
12084 				StockBack->Playing=0;
12085 				StockBack->timer=65535;
12086 				StockBack->lastframe_timer=65535;
12087 				StockBack->Active=1;
12088 			}
12089 		}
12090 
12091 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time);
12092 		PlayersWeaponHModelController.Looped=0;
12093 	}
12094 
12095 	Flamethrower_Timer=0;
12096 	StaffAttack=-1;
12097 	LastHand=1;
12098 }
12099 
12100 void MarineTwoPistols_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
12101 
12102 	TEMPLATE_WEAPON_DATA *twPtr;
12103 	DELTA_CONTROLLER *FireRight;
12104 	DELTA_CONTROLLER *FireLeft;
12105 
12106 	FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight");
12107 	if (FireRight==NULL) {
12108 		FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED);
12109 		FireRight->Playing=0;
12110 		FireRight->Active=0;
12111 	}
12112 
12113 	FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft");
12114 	if (FireLeft==NULL) {
12115 		FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED);
12116 		FireLeft->Playing=0;
12117 		FireLeft->Active=0;
12118 	}
12119 
12120     twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
12121 
12122 	Weapon_ThisBurst=-1;
12123 
12124 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
12125 		int time;
12126 
12127 		time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]);
12128 
12129 		GLOBALASSERT(time!=0);
12130 
12131 		InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time);
12132 		PlayersWeaponHModelController.Looped=0;
12133 
12134 		if (weaponPtr->PrimaryRoundsRemaining==0) {
12135 			Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1);
12136 			FireRight->Playing=0;
12137 			FireRight->timer=65535;
12138 			FireRight->lastframe_timer=65535;
12139 			FireRight->Active=1;
12140 		}
12141 
12142 		if (weaponPtr->SecondaryRoundsRemaining==0) {
12143 			Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1);
12144 			FireLeft->Playing=0;
12145 			FireLeft->timer=65535;
12146 			FireLeft->lastframe_timer=65535;
12147 			FireLeft->Active=1;
12148 		}
12149 
12150 	}
12151 
12152 	Flamethrower_Timer=0;
12153 	StaffAttack=-1;
12154 	LastHand=1;
12155 }
12156 
12157 void Frisbee_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
12158 
12159 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
12160 
12161 		Sound_Stop(weaponHandle);
12162 		Sound_Play(SID_ED_SKEETERLAUNCH,"h");
12163 
12164 		//InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6));
12165 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0);
12166 		PlayersWeaponHModelController.Looped=0;
12167 		FireNonAutomaticWeapon(weaponPtr);
12168 	}
12169 
12170 }
12171 
12172 void Frisbee_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) {
12173 
12174 	/* Clumsy, but here we go. */
12175 
12176 	AddLightingEffectToObject(Player,LFX_MUZZLEFLASH);
12177 	if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) {
12178 		//InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1);
12179 		InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0);
12180 	}
12181 
12182 }
12183 
12184 static void PredatorZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) {
12185 
12186 	int weaponNum;
12187 	int slot;
12188 
12189 	/* Let's cut this into a function. */
12190 
12191 	if (AvP.PlayerType!=I_Predator) {
12192 		/* For now. */
12193 		return;
12194 	}
12195 
12196 	/* Now the serious bit. */
12197 
12198 	weaponNum=0;
12199 
12200 	/* Now, step up until you get to NULL or find a weapon with ammo. */
12201 	//weaponNum--;
12202 	while (PredatorWeaponHierarchy[weaponNum]!=NULL_WEAPON) {
12203 
12204 		slot=SlotForThisWeapon(PredatorWeaponHierarchy[weaponNum]);
12205 		if (slot!=-1) {
12206 			if (playerStatusPtr->WeaponSlot[slot].Possessed==1) {
12207 				if (Predator_WeaponHasAmmo(playerStatusPtr,slot)) {
12208 					/* Okay! */
12209 					break;
12210 				}
12211 			}
12212 		}
12213 		weaponNum++;
12214 	}
12215 
12216 	if (PredatorWeaponHierarchy[weaponNum]==NULL_WEAPON) {
12217 		/* No possible action. */
12218 		return;
12219 	}
12220 	if (PredatorWeaponHierarchy[weaponNum]==weaponPtr->WeaponIDNumber) {
12221 		/* If you found the current weapon, do nothing. */
12222 		return;
12223 	}
12224 
12225 	/* So, change to this weapon. */
12226 	playerStatusPtr->SwapToWeaponSlot = slot;
12227 	weaponPtr->CurrentState = WEAPONSTATE_UNREADYING;
12228 	weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT;
12229 
12230 }
12231