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§ion_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§ion_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§ion_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§ion_sprays_blood) {
6545 blood_type=GetBloodType(sbPtr);
6546 /* Er... default? */
6547 } else if (this_section_data->sempai->flags§ion_sprays_acid) {
6548 blood_type=PARTICLE_ALIEN_BLOOD;
6549 } else if (this_section_data->sempai->flags§ion_sprays_predoblood) {
6550 blood_type=PARTICLE_PREDATOR_BLOOD;
6551 } else if (this_section_data->sempai->flags§ion_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§ion_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§ion_is_master_root)==0)
6609 &&((this_section_data->sempai->flags§ion_flag_never_frag)==0)
6610 &&(((this_section_data->sempai->flags§ion_sprays_acid)&&((this_section_data->sempai->flags§ion_flag_fragonlyfordisks)==0))
6611 ||((this_section_data->sempai->StartingStats.Health<TotalKineticDamage(damage))&&((this_section_data->sempai->flags§ion_flag_fragonlyfordisks)==0))
6612 ||((damage->Slicing>2)&&(this_section_data->sempai->flags§ion_flag_fragonlyfordisks))
6613 ||((damage->Slicing>0)&&((this_section_data->sempai->flags§ion_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§ion_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§ion_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§ion_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§ion_sprays_blood) {
6658 blood_type=GetBloodType(sbPtr);
6659 /* Er... default? */
6660 } else if (this_section_data->sempai->flags§ion_sprays_acid) {
6661 blood_type=PARTICLE_ALIEN_BLOOD;
6662 } else if (this_section_data->sempai->flags§ion_sprays_predoblood) {
6663 blood_type=PARTICLE_PREDATOR_BLOOD;
6664 } else if (this_section_data->sempai->flags§ion_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(§ion1->World_Offset,sbPtr,&hit_section)) {
10064 numhits++;
10065 } else if (IsPointInsideObject(§ion2->World_Offset,sbPtr,&hit_section)) {
10066 numhits++;
10067 } else if (IsPointInsideObject(§ion3->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§ion_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§ion_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§ion_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§ion_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§ion_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§ion_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