4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
#include "npc_common.h"
 
 
2
#include "dynamics.h"
 
 
3
#include "lighting.h"
 
 
4
#include "npc_sentrygun.h"
 
 
5
#include "npc_facehugger.h"
 
 
6
#include "npc_xenoborg.h"
 
 
7
#include "npc_queen.h"
 
 
8
#include "npc_facehugger.h"
 
 
9
#include "npc_predator.h"
 
 
10
#include "videoscreen.h"
 
 
11
#include "debris.h"
 
 
12
#include "weaponbehaviour.h"
 
 
13
#include "bh_light.h"
 
 
14
#include "bh_track.h"
 
 
15
#include "projload.hpp"
 
 
16
#include "kshape.h"
 
 
17
#include "userprofile.h"
 
 
18
#include "hud.h"
 
 
19
 
 
 
20
#define BITE_HEALTH_RECOVERY        (50)
 
 
21
#define BITE_ARMOUR_RECOVERY        (30)
 
 
22
#define MEDICOMP_USE_THRESHOLD        ( 10 * ONE_FIXED)
 
 
23
#define EXTINGUISHER_USE_THRESHOLD    (3 * ONE_FIXED)
 
 
24
#define GREENFLASH_INTENSITY        (5 * ONE_FIXED)
 
 
25
#define PROBABILITYOFJAMMING        32
 
 
26
#define Random16BitNumber (FastRandom() & 65535)
 
 
27
 
 
 
28
GRENADE_LAUNCHER_DATA GrenadeLauncherData;
 
 
29
 
 
 
30
static const int PredPistol_ShotCost = 120000;  /* Changed from 60000 (Fox value), 1/3/99 */
 
 
31
static const int Caster_Jumpstart = 10000;
 
 
32
static const int Caster_Chargetime = 150000;
 
 
33
static const int Caster_ChargeRatio = 400000;
 
 
34
 
 
 
35
int ACStrikeTime = (ONE_FIXED / 6);
 
 
36
static int Weapon_ThisBurst = -1;
 
 
37
int StaffAttack = -1;
 
 
38
int RightHand;
 
 
39
int AllowGoldWeapons = 0; // flag to indicate the Gold version weapons should be allowed
 
 
40
 
 
 
41
const VECTORCH null_vec = {0, 0, 0};
 
 
42
 
 
 
43
static int Flamethrower_Timer = 0;
 
 
44
static int Bit = 0;
 
 
45
static int RAPIDFIRE_AMMO_COUNTER = 0;
 
 
46
static int Alien_Visible_Weapon;
 
 
47
static int Alien_Tail_Clock = -1;
 
 
48
static int WeaponFidgetPlaying = 0;
 
 
49
static int Old_Minigun_SpinSpeed = 0;
 
 
50
static int Minigun_SpinSpeed = 0;
 
 
51
 
 
 
52
static STRATEGYBLOCK *Alien_Tail_Target;
 
 
53
static DAMAGE_PROFILE Player_Weapon_Damage;
 
 
54
static char Alien_Tail_Target_SBname[SB_NAME_LENGTH];
 
 
55
static char Biting_SBname[SB_NAME_LENGTH];
 
 
56
 
 
 
57
extern EULER HeadOrientation;
 
 
58
extern struct KObject VisibleObjects[maxobjects];
 
 
59
extern int numVisObjs;
 
 
60
 
 
 
61
extern uint8_t Null_Name[8];
 
 
62
extern int weaponHandle;
 
 
63
extern int predHUDSoundHandle;
 
 
64
extern MATRIXCH IdentityMatrix;
 
 
65
extern DISPLAYBLOCK *SmartTarget_Object;
 
 
66
 
 
 
67
static EULER Minigun_MaxHeadJolt;
 
 
68
static EULER Minigun_HeadJolt;
 
 
69
 
 
 
70
STRATEGYBLOCK *Biting = NULL;
 
 
71
 
 
 
72
/* Line Of Sight information used by FireLineOfSightWeapon() */
 
 
73
VECTORCH     LOS_Point;         /* point in world space which player has hit */
 
 
74
int         LOS_Lambda;        /* distance in mm to point from player */
 
 
75
DISPLAYBLOCK*    LOS_ObjectHitPtr;    /* pointer to object that was hit */
 
 
76
VECTORCH    LOS_ObjectNormal;    /* normal of the object's face which was hit */
 
 
77
SECTION_DATA*    LOS_HModel_Section;    /* Section of HModel hit */
 
 
78
 
 
 
79
static SECTION_DATA *GrenadeLauncherSectionPointers[6];
 
 
80
 
 
 
81
static SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */
 
 
82
HMODELCONTROLLER PlayersWeaponHModelController;
 
 
83
 
 
 
84
extern void InanimateObjectIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple);
 
 
85
extern void PlayerIsDamaged(const DAMAGE_PROFILE *damage, int multiplier, VECTORCH* incoming);
 
 
86
extern int SlotForThisWeapon(enum WEAPON_ID weaponID);
 
 
87
extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name, const char* shape_set_name);
 
 
88
extern const SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
 
 
89
 
 
 
90
void GetDirectionOfAttack(STRATEGYBLOCK *sbPtr, VECTORCH *WorldVector, VECTORCH *Output)
 
 
91
{
 
 
92
    assert(sbPtr);
 
 
93
 
 
 
94
    if (sbPtr->DynPtr == NULL)
 
 
95
    {
 
 
96
        /* Handle as best we can. */
 
 
97
        Output->vx = 0;
 
 
98
        Output->vy = 0;
 
 
99
        Output->vz = 0;
 
 
100
    }
 
 
101
    else
 
 
102
    {
 
 
103
        /* Consider incoming hit direction. */
 
 
104
        MATRIXCH WtoLMat = sbPtr->DynPtr->OrientMat;
 
 
105
        TransposeMatrixCH(&WtoLMat);
 
 
106
        RotateAndCopyVector(WorldVector,Output,&WtoLMat);
 
 
107
        Normalise(Output);
 
 
108
    }
 
 
109
}
 
 
110
 
 
 
111
static int Predator_WeaponHasAmmo(int slot)
 
 
112
{
 
 
113
    struct PLAYER_WEAPON_DATA *this_weaponPtr = &PlayerStatus.WeaponSlot[slot];
 
 
114
 
 
 
115
    switch (this_weaponPtr->WeaponIDNumber)
 
 
116
    {
 
 
117
        case WEAPON_PRED_WRISTBLADE:
 
 
118
                return 1;
 
 
119
        case WEAPON_PRED_MEDICOMP:
 
 
120
                return ((PlayerStatus.FieldCharge > EXTINGUISHER_USE_THRESHOLD) && (PlayerStatus.FieldCharge > MEDICOMP_USE_THRESHOLD)) ;
 
 
121
        case WEAPON_PRED_RIFLE:
 
 
122
        case WEAPON_PRED_DISC:
 
 
123
                return this_weaponPtr->PrimaryRoundsRemaining;
 
 
124
        case WEAPON_PRED_PISTOL:
 
 
125
                return (PlayerStatus.FieldCharge > PredPistol_ShotCost);
 
 
126
        case WEAPON_PRED_SHOULDERCANNON:
 
 
127
                return (!(PlayerStatus.PlasmaCasterCharge < Caster_Jumpstart)
 
 
128
                && (PlayerStatus.FieldCharge < MUL_FIXED((Caster_Jumpstart - PlayerStatus.PlasmaCasterCharge), Caster_ChargeRatio)) );
 
 
129
        default:
 
 
130
                return 0;
 
 
131
    }
 
 
132
}
 
 
133
 
 
 
134
static void PredatorZeroAmmoFunctionality() 
 
 
135
{
 
 
136
    static enum WEAPON_ID PredatorWeaponHierarchy[] = 
 
 
137
    {
 
 
138
        WEAPON_PRED_RIFLE,
 
 
139
        WEAPON_PRED_WRISTBLADE,
 
 
140
        //WEAPON_PRED_DISC,
 
 
141
        //WEAPON_PRED_SHOULDERCANNON,
 
 
142
        //WEAPON_PRED_PISTOL,
 
 
143
        NULL_WEAPON
 
 
144
    };
 
 
145
 
 
 
146
    int slot;
 
 
147
    int weaponNum = 0;
 
 
148
 
 
 
149
    while (PredatorWeaponHierarchy[weaponNum] != NULL_WEAPON)
 
 
150
    {
 
 
151
        slot = SlotForThisWeapon(PredatorWeaponHierarchy[weaponNum]);
 
 
152
 
 
 
153
        if (slot != -1)
 
 
154
        {
 
 
155
            if (PlayerStatus.WeaponSlot[slot].Possessed && Predator_WeaponHasAmmo(slot))
 
 
156
            {
 
 
157
                if (PredatorWeaponHierarchy[weaponNum] != PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
158
                {
 
 
159
                    /* So, change to this weapon. */
 
 
160
                    PlayerStatus.SwapToWeaponSlot = slot;
 
 
161
                    PlayerStatus.WeaponState = WEAPONSTATE_UNREADYING;
 
 
162
                    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
163
                    break;
 
 
164
                }
 
 
165
            }
 
 
166
        }
 
 
167
 
 
 
168
        weaponNum++;
 
 
169
    }
 
 
170
}
 
 
171
 
 
 
172
static int WeaponHasAmmo(int slot)
 
 
173
{
 
 
174
    struct PLAYER_WEAPON_DATA *this_weaponPtr = &PlayerStatus.WeaponSlot[slot];
 
 
175
 
 
 
176
    switch(this_weaponPtr->WeaponIDNumber)
 
 
177
    {
 
 
178
        case WEAPON_GRENADELAUNCHER:
 
 
179
            return 0;
 
 
180
        case WEAPON_CUDGEL:
 
 
181
            return 1;
 
 
182
        default:
 
 
183
        {
 
 
184
            return (this_weaponPtr->SecondaryRoundsRemaining != 0
 
 
185
            || this_weaponPtr->PrimaryRoundsRemaining != 0
 
 
186
            || this_weaponPtr->MagazinesRemaining != 0);
 
 
187
        }
 
 
188
    }
 
 
189
}
 
 
190
 
 
 
191
void MarineZeroAmmoFunctionality()
 
 
192
{
 
 
193
    static enum WEAPON_ID MarineWeaponHierarchy[] =
 
 
194
    {
 
 
195
        WEAPON_PULSERIFLE,
 
 
196
        WEAPON_SMARTGUN,
 
 
197
        WEAPON_SADAR,
 
 
198
        WEAPON_GRENADELAUNCHER,
 
 
199
        WEAPON_FLAMETHROWER,
 
 
200
        WEAPON_MINIGUN,
 
 
201
        WEAPON_FRISBEE_LAUNCHER,
 
 
202
        WEAPON_TWO_PISTOLS,
 
 
203
        WEAPON_MARINE_PISTOL,
 
 
204
        WEAPON_CUDGEL,
 
 
205
        NULL_WEAPON
 
 
206
    };
 
 
207
 
 
 
208
    int weaponNum = 0;
 
 
209
    centre_gunsight();
 
 
210
 
 
 
211
    while (MarineWeaponHierarchy[weaponNum] != NULL_WEAPON)
 
 
212
    {
 
 
213
        int slot = SlotForThisWeapon(MarineWeaponHierarchy[weaponNum]);
 
 
214
 
 
 
215
        if (slot != -1)
 
 
216
        {
 
 
217
            if (PlayerStatus.WeaponSlot[slot].Possessed && WeaponHasAmmo(slot))
 
 
218
            {
 
 
219
                if (MarineWeaponHierarchy[weaponNum] == PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
220
                {
 
 
221
                    return; // If you found the current weapon, do nothing.
 
 
222
                }
 
 
223
                else
 
 
224
                {
 
 
225
                    /* So, change to this weapon. */
 
 
226
                    PlayerStatus.SwapToWeaponSlot = slot;
 
 
227
                    PlayerStatus.WeaponState = WEAPONSTATE_UNREADYING;
 
 
228
                    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
229
                }
 
 
230
 
 
 
231
                return;
 
 
232
            }
 
 
233
        }
 
 
234
 
 
 
235
        weaponNum++;
 
 
236
    }
 
 
237
}
 
 
238
 
 
 
239
static void GetHierarchicalWeapon(const char *riffname, const char *hierarchyname, int sequence_type, int sub_sequence) 
 
 
240
{
 
 
241
    const SECTION *root_section = GetNamedHierarchyFromLibrary(riffname, hierarchyname);
 
 
242
 
 
 
243
    assert(root_section);
 
 
244
 
 
 
245
    Dispel_HModel(&PlayersWeaponHModelController);
 
 
246
    Create_HModel(&PlayersWeaponHModelController, root_section);
 
 
247
    InitHModelSequence(&PlayersWeaponHModelController, sequence_type, sub_sequence, ONE_FIXED); // Was >>3
 
 
248
 
 
 
249
    /* Causes that 'one frame' flicker? */
 
 
250
    //ProveHModel(&PlayersWeaponHModelController, &PlayerStatus.weapon);
 
 
251
 
 
 
252
    PlayersWeaponHModelController.Playing = 0;
 
 
253
    PlayersWeaponHModelController.Looped = 0;
 
 
254
 
 
 
255
    PWMFSDP = GetThisSectionData(PlayersWeaponHModelController.section_data, "dum flash");
 
 
256
 
 
 
257
    if (PWMFSDP == NULL)
 
 
258
    {
 
 
259
        PWMFSDP = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum flash");
 
 
260
        /* ?&$(*"*&^ pred pistol!!! */
 
 
261
 
 
 
262
        if (PWMFSDP == NULL)
 
 
263
            PWMFSDP = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum Flash");
 
 
264
    }
 
 
265
 
 
 
266
    /* Could be NULL though, I don't care at this stage. */
 
 
267
}
 
 
268
 
 
 
269
static void ChangeHUDToAlternateShapeSet(const char *setname) 
 
 
270
{
 
 
271
    int a=0;
 
 
272
    HIERARCHY_SHAPE_REPLACEMENT* replacement_array = GetHierarchyAlternateShapeSetFromLibrary("MarineWeapons", setname);
 
 
273
 
 
 
274
    if (NULL != replacement_array)
 
 
275
    while (replacement_array[a].replaced_section_name != NULL)
 
 
276
    {
 
 
277
        SECTION_DATA *target_section = GetThisSectionData(PlayersWeaponHModelController.section_data, replacement_array[a].replaced_section_name);
 
 
278
 
 
 
279
        if (target_section)
 
 
280
        {
 
 
281
            target_section->Shape = replacement_array[a].replacement_shape;
 
 
282
            target_section->ShapeNum = replacement_array[a].replacement_shape_index;
 
 
283
            Setup_Texture_Animation_For_Section(target_section);
 
 
284
        }
 
 
285
        a++;
 
 
286
    }
 
 
287
}
 
 
288
 
 
 
289
static void GrenadeLauncherInit()
 
 
290
{
 
 
291
    static const char *GrenadeLauncherBulletNames[6] =
 
 
292
    {
 
 
293
        "bulletF",    //05_
 
 
294
        "bulletA",    //_
 
 
295
        "bulletB",    //01_
 
 
296
        "bulletC",    //02_
 
 
297
        "bulletD",    //03_
 
 
298
        "bulletE",    //04_
 
 
299
    };
 
 
300
 
 
 
301
    int a = 0;
 
 
302
 
 
 
303
    for (; a < 6; a++)
 
 
304
        GrenadeLauncherSectionPointers[a] = GetThisSectionData(PlayersWeaponHModelController.section_data, GrenadeLauncherBulletNames[a]);
 
 
305
 
 
 
306
    switch (GrenadeLauncherData.SelectedAmmo)
 
 
307
    {
 
 
308
        default:
 
 
309
        case AMMO_GRENADE:
 
 
310
            ChangeHUDToAlternateShapeSet("Grenade");
 
 
311
        break;
 
 
312
        case AMMO_FRAGMENTATION_GRENADE:
 
 
313
            ChangeHUDToAlternateShapeSet("Frag");
 
 
314
        break;
 
 
315
        case AMMO_PROXIMITY_GRENADE:
 
 
316
            ChangeHUDToAlternateShapeSet("Proxmine");
 
 
317
    }
 
 
318
}
 
 
319
 
 
 
320
void GrabWeaponShape()
 
 
321
{
 
 
322
    extern void create_player_hmodel();
 
 
323
    PlayerStatus.twPtr = &TemplateWeapon[PlayerStatus.SelectedWeapon->WeaponIDNumber];
 
 
324
 
 
 
325
    switch(AvP.PlayerType)
 
 
326
    {
 
 
327
        case I_Marine:
 
 
328
            GetHierarchicalWeapon("MarineWeapons", PlayerStatus.twPtr->HierarchyName, HMSQT_MarineHUD, MHSS_Stationary);
 
 
329
 
 
 
330
            if (WEAPON_GRENADELAUNCHER == PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
331
                GrenadeLauncherInit();
 
 
332
        break;
 
 
333
        case I_Predator:
 
 
334
            GetHierarchicalWeapon("pred_HUD", PlayerStatus.twPtr->HierarchyName, HMSQT_PredatorHUD, PlayerStatus.twPtr->InitialSubSequence);
 
 
335
        break;
 
 
336
        case I_Alien:
 
 
337
            //GetHierarchicalWeapon("alien_HUD", "eat", HMSQT_AlienHUD, AHSS_LeftSwipeDown);
 
 
338
            GetHierarchicalWeapon("alien_HUD", "claws", HMSQT_AlienHUD, AHSS_LeftSwipeDown);
 
 
339
            Alien_Visible_Weapon = 0;
 
 
340
    }
 
 
341
 
 
 
342
    centre_gunsight();
 
 
343
    create_player_hmodel();
 
 
344
}
 
 
345
 
 
 
346
void RequestChangeOfWeaponNo(int weapon_nr)
 
 
347
{
 
 
348
    if (weapon_nr != PlayerStatus.SelectedWeaponSlot && PlayerStatus.WeaponSlot[weapon_nr].Possessed)
 
 
349
    {
 
 
350
        switch(PlayerStatus.WeaponState)
 
 
351
        {
 
 
352
            case WEAPONSTATE_IDLE:
 
 
353
            {
 
 
354
                PlayerStatus.SwapToWeaponSlot = weapon_nr;
 
 
355
                PlayerStatus.PreviouslySelectedWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
356
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
357
            }
 
 
358
            break;
 
 
359
            case WEAPONSTATE_SWAPPING_OUT:
 
 
360
            {
 
 
361
            }
 
 
362
            break;
 
 
363
            case WEAPONSTATE_SWAPPING_IN:
 
 
364
            {
 
 
365
            }
 
 
366
            default:
 
 
367
            break;
 
 
368
        }
 
 
369
    }
 
 
370
}
 
 
371
 
 
 
372
void RequestChangeOfWeapon(int x)
 
 
373
{
 
 
374
    enum WEAPON_SLOT newSlot = PlayerStatus.SelectedWeaponSlot;
 
 
375
 
 
 
376
    if(PlayerStatus.WeaponState == WEAPONSTATE_IDLE)
 
 
377
    while(1)
 
 
378
    {
 
 
379
        if(x)    
 
 
380
        {
 
 
381
            if(++newSlot == MAX_NO_OF_WEAPON_SLOTS)
 
 
382
                newSlot = WEAPON_SLOT_1;
 
 
383
        }
 
 
384
        else
 
 
385
        {
 
 
386
            if(--newSlot == MIN_NO_OF_WEAPON_SLOTS)
 
 
387
                newSlot = MAX_NO_OF_WEAPON_SLOTS - 1;
 
 
388
        }
 
 
389
 
 
 
390
        if (PlayerStatus.WeaponSlot[newSlot].Possessed)
 
 
391
        {
 
 
392
            if ((!PlayerStatus.WeaponSlot[newSlot].PrimaryRoundsRemaining &&
 
 
393
            !PlayerStatus.WeaponSlot[newSlot].MagazinesRemaining) ||
 
 
394
            WEAPON_CUDGEL == PlayerStatus.WeaponSlot[newSlot].WeaponIDNumber)
 
 
395
            {
 
 
396
                switch(PlayerStatus.WeaponSlot[newSlot].WeaponIDNumber)
 
 
397
                {
 
 
398
                    default:
 
 
399
                    {
 
 
400
                        static int i_was_here = 0;
 
 
401
                        if (i_was_here)
 
 
402
                        {
 
 
403
                            i_was_here = 0;
 
 
404
                            return;
 
 
405
                        }
 
 
406
 
 
 
407
                        i_was_here = 1;
 
 
408
                        continue;
 
 
409
                    }
 
 
410
                }
 
 
411
            }
 
 
412
            else
 
 
413
            {
 
 
414
                /*
 
 
415
                switch (PlayerStatus.WeaponSlot[newSlot].WeaponIDNumber)
 
 
416
                {
 
 
417
                    case WEAPON_FRISBEE_LAUNCHER:
 
 
418
                    case WEAPON_MARINE_PISTOL:
 
 
419
                    case WEAPON_TWO_PISTOLS:
 
 
420
                    {
 
 
421
                        // Disallow Gold version weapons with regular version
 
 
422
                        if (!AllowGoldWeapons)
 
 
423
                            continue;
 
 
424
                    }
 
 
425
                    break;
 
 
426
 
 
 
427
                    default:
 
 
428
                        break;
 
 
429
                }
 
 
430
                */
 
 
431
            }
 
 
432
 
 
 
433
            if(newSlot != PlayerStatus.SelectedWeaponSlot)
 
 
434
            {
 
 
435
                PlayerStatus.SwapToWeaponSlot = newSlot;
 
 
436
                PlayerStatus.PreviouslySelectedWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
437
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
438
                return;
 
 
439
            }
 
 
440
 
 
 
441
        break;
 
 
442
        }
 
 
443
    }
 
 
444
}
 
 
445
 
 
 
446
void three_dots()
 
 
447
{
 
 
448
    //VECTORCH shotvector = {0, 0, 65535};
 
 
449
    VECTORCH shotvector;
 
 
450
    THREE_LASER_DOT_DESC PredatorLaserTarget;
 
 
451
 
 
 
452
    MATRIXCH matrix    = Global_VDB.VDB_Mat;
 
 
453
    TransposeMatrixCH(&matrix);
 
 
454
    RotateVector(&shotvector, &matrix);
 
 
455
 
 
 
456
    // find position/orientation of predator's targeting sights
 
 
457
    int i;
 
 
458
 
 
 
459
    VECTORCH offset[3] = { {0, -50, 0}, {43, 25, 0}, {-43, 25, 0} };
 
 
460
 
 
 
461
    for(i=0; i < 3; i++)
 
 
462
    {
 
 
463
        VECTORCH position = offset[i];
 
 
464
        //position.vx -= 200;
 
 
465
 
 
 
466
        RotateVector(&position, &matrix);
 
 
467
        position.vx += Global_VDB.VDB_World.vx;
 
 
468
        position.vy += Global_VDB.VDB_World.vy;
 
 
469
        position.vz += Global_VDB.VDB_World.vz;
 
 
470
 
 
 
471
shotvector.vx = offset[i].vx;
 
 
472
shotvector.vy = offset[i].vy;
 
 
473
shotvector.vz = 65535;
 
 
474
RotateVector(&shotvector, &matrix);
 
 
475
 
 
 
476
        if(FindPolygonInLineOfSight(&shotvector, &position, PlayerStatus.DisplayBlock))
 
 
477
        {
 
 
478
            PredatorLaserTarget.Normal[i] = LOS_ObjectNormal;
 
 
479
            MakeParticle(&position, &shotvector, PARTICLE_PLASMATRAIL);
 
 
480
 
 
 
481
            if (PlayerStatus.Target.DispPtr)
 
 
482
            {
 
 
483
                PredatorLaserTarget.Position[i] = LOS_Point;    
 
 
484
            }
 
 
485
            else
 
 
486
            {
 
 
487
                /* pretend the target is right in front of the player, but a very long way off */
 
 
488
                PredatorLaserTarget.Position[i].vx = PlayerStatus.DisplayBlock->ObWorld.vx + (Global_VDB.VDB_Mat.mat13<<7);
 
 
489
                PredatorLaserTarget.Position[i].vy = PlayerStatus.DisplayBlock->ObWorld.vy + (Global_VDB.VDB_Mat.mat23<<7);
 
 
490
                PredatorLaserTarget.Position[i].vz = PlayerStatus.DisplayBlock->ObWorld.vz + (Global_VDB.VDB_Mat.mat33<<7);
 
 
491
            }
 
 
492
        }
 
 
493
    }
 
 
494
 
 
 
495
    RenderLaserTarget(&PredatorLaserTarget);
 
 
496
}
 
 
497
 
 
 
498
static void PositionPlayersWeapon()
 
 
499
{
 
 
500
    PlayerStatus.weapon.ObMat = Global_VDB.VDB_Mat;
 
 
501
    TransposeMatrixCH(&PlayerStatus.weapon.ObMat);
 
 
502
 
 
 
503
    PlayerStatus.weapon.ObView.vx = PlayerStatus.twPtr->RestPosition.vx + PlayerStatus.WeaponPositionOffset.vx;
 
 
504
    PlayerStatus.weapon.ObView.vy = PlayerStatus.twPtr->RestPosition.vy + PlayerStatus.WeaponPositionOffset.vy;
 
 
505
    PlayerStatus.weapon.ObView.vz = PlayerStatus.twPtr->RestPosition.vz + PlayerStatus.WeaponPositionOffset.vz;
 
 
506
 
 
 
507
    VECTORCH offset = PlayerStatus.weapon.ObView;
 
 
508
    RotateVector(&offset, &PlayerStatus.weapon.ObMat);
 
 
509
 
 
 
510
    PlayerStatus.weapon.ObWorld.vx = Global_VDB.VDB_World.vx + offset.vx;
 
 
511
    PlayerStatus.weapon.ObWorld.vy = Global_VDB.VDB_World.vy + offset.vy;
 
 
512
    PlayerStatus.weapon.ObWorld.vz = Global_VDB.VDB_World.vz + offset.vz;
 
 
513
}
 
 
514
 
 
 
515
static void CalculateTorqueAtPoint(EULER *rotationPtr, VECTORCH *pointPtr, STRATEGYBLOCK *sbPtr)
 
 
516
{
 
 
517
    VECTORCH normal,point;
 
 
518
    int intersectionPlane;
 
 
519
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
520
 
 
 
521
    /* if the strategy block doesn't have a dynamics or display block, skip it */
 
 
522
    if (!dynPtr || !sbPtr->DisplayBlock)
 
 
523
        return;
 
 
524
 
 
 
525
    {
 
 
526
        MATRIXCH mat = dynPtr->OrientMat;
 
 
527
        TransposeMatrixCH(&mat);
 
 
528
 
 
 
529
        point.vx = pointPtr->vx - dynPtr->Position.vx;
 
 
530
        point.vy = pointPtr->vy - dynPtr->Position.vy;
 
 
531
        point.vz = pointPtr->vz - dynPtr->Position.vz;
 
 
532
 
 
 
533
        RotateVector(&point, &mat);
 
 
534
        normal = point;
 
 
535
    }
 
 
536
 
 
 
537
    {                              
 
 
538
        int x = abs(normal.vx);
 
 
539
        int y = abs(normal.vy);
 
 
540
        int z = abs(normal.vz);
 
 
541
 
 
 
542
        if (x > y)
 
 
543
            intersectionPlane = (x > z) ? ix : iz;
 
 
544
        else
 
 
545
            intersectionPlane = (y > z) ? iy : iz;
 
 
546
    }
 
 
547
 
 
 
548
    switch (intersectionPlane)
 
 
549
    {
 
 
550
        case ix:
 
 
551
        {
 
 
552
            rotationPtr->EulerX = 0;
 
 
553
 
 
 
554
            if (point.vx > 0)
 
 
555
            {
 
 
556
                rotationPtr->EulerY = -point.vz;
 
 
557
                   rotationPtr->EulerZ = point.vy;
 
 
558
            }
 
 
559
            else
 
 
560
            {
 
 
561
                 rotationPtr->EulerY = point.vz;
 
 
562
                   rotationPtr->EulerZ = -point.vy;
 
 
563
            }
 
 
564
        break;
 
 
565
        }
 
 
566
        case iy:
 
 
567
        {
 
 
568
            rotationPtr->EulerY = 0;
 
 
569
 
 
 
570
            if (point.vy > 0)
 
 
571
            {
 
 
572
                   rotationPtr->EulerX = point.vz;
 
 
573
                 rotationPtr->EulerZ = -point.vx;
 
 
574
            }
 
 
575
            else
 
 
576
            {
 
 
577
                 rotationPtr->EulerX = -point.vz;
 
 
578
                   rotationPtr->EulerZ = point.vx;
 
 
579
            }
 
 
580
        break;
 
 
581
        }    
 
 
582
        case iz:
 
 
583
        {
 
 
584
            rotationPtr->EulerZ = 0;
 
 
585
 
 
 
586
            if (point.vz > 0)
 
 
587
            {
 
 
588
                  rotationPtr->EulerX = -point.vy;
 
 
589
                rotationPtr->EulerY = point.vx;
 
 
590
            }
 
 
591
            else
 
 
592
            {
 
 
593
                rotationPtr->EulerX = point.vy;
 
 
594
                rotationPtr->EulerY = -point.vx;
 
 
595
            }
 
 
596
        break;
 
 
597
        }    
 
 
598
        default:
 
 
599
            break;
 
 
600
    }
 
 
601
 
 
 
602
    {
 
 
603
        struct shapeheader* shapePtr = GetShapeData(sbPtr->DisplayBlock->ObShape);
 
 
604
        rotationPtr->EulerX = DIV_FIXED(rotationPtr->EulerX, shapePtr->shaperadius);
 
 
605
        rotationPtr->EulerY = DIV_FIXED(rotationPtr->EulerY, shapePtr->shaperadius);
 
 
606
        rotationPtr->EulerZ = DIV_FIXED(rotationPtr->EulerZ, shapePtr->shaperadius);
 
 
607
    }
 
 
608
}
 
 
609
 
 
 
610
static void DamageDamageBlock(DAMAGEBLOCK *DBPtr, const DAMAGE_PROFILE *damage, int multiple) 
 
 
611
{
 
 
612
    int ArmourDamage = 0;
 
 
613
    int HealthDamage = 0;
 
 
614
    int Fraction = multiple & (ONE_FIXED - 1);
 
 
615
    int Integer = multiple >> ONE_FIXED_SHIFT;
 
 
616
 
 
 
617
    /* We must apply damage sequentially. Fraction first, then each 'multiple'. 
 
 
618
    Otherwise, an armour damaging attack hitting multiple times in one frame
 
 
619
    would behave differently depending on the framerate.  Sure, that case might
 
 
620
    never arise, but that's not the point!
 
 
621
    */
 
 
622
 
 
 
623
    if (Fraction)
 
 
624
    {
 
 
625
        if (damage->Impact)
 
 
626
        {
 
 
627
            int tempdamage = damage->Impact * Fraction;
 
 
628
            HealthDamage += tempdamage / 10;
 
 
629
            int unblocked = MUL_FIXED(((damage->Impact*ONE_FIXED)-DBPtr->Armour), Fraction);
 
 
630
 
 
 
631
            if (unblocked > 0)
 
 
632
                HealthDamage += unblocked;
 
 
633
 
 
 
634
            tempdamage >>= 4;
 
 
635
 
 
 
636
            if (!DBPtr->PerfectArmour)
 
 
637
                ArmourDamage += tempdamage;
 
 
638
        }
 
 
639
 
 
 
640
        if (damage->Cutting)
 
 
641
        {
 
 
642
            int tempdamage = damage->Cutting * Fraction;
 
 
643
            HealthDamage += tempdamage >> 2;
 
 
644
            int unblocked = MUL_FIXED(((damage->Cutting*ONE_FIXED)-DBPtr->Armour), Fraction);
 
 
645
 
 
 
646
            if (unblocked > 0)
 
 
647
                HealthDamage += unblocked;
 
 
648
 
 
 
649
            if (!DBPtr->PerfectArmour)
 
 
650
                ArmourDamage += tempdamage >> 3;
 
 
651
        }
 
 
652
 
 
 
653
        if (damage->Penetrative)
 
 
654
        {
 
 
655
            int tempdamage = damage->Penetrative * Fraction;
 
 
656
            HealthDamage += tempdamage / 10;
 
 
657
 
 
 
658
            int unblocked = MUL_FIXED(((damage->Penetrative*ONE_FIXED)-(DBPtr->Armour>>6)), Fraction);
 
 
659
 
 
 
660
            if (unblocked > 0)
 
 
661
                HealthDamage += unblocked;
 
 
662
 
 
 
663
            if (!DBPtr->PerfectArmour)
 
 
664
                ArmourDamage += tempdamage >> 4;
 
 
665
        }
 
 
666
 
 
 
667
        if (damage->Fire && !DBPtr->FireResistant)
 
 
668
        {
 
 
669
            int tempdamage = damage->Fire * Fraction;
 
 
670
 
 
 
671
            if (DBPtr->Combustability == 2)
 
 
672
            {
 
 
673
                tempdamage <<= 1;
 
 
674
            }
 
 
675
            else if (DBPtr->Combustability == 3)
 
 
676
            {
 
 
677
                tempdamage >>= 2;
 
 
678
            }
 
 
679
 
 
 
680
            HealthDamage += tempdamage;
 
 
681
 
 
 
682
            if(!DBPtr->IsOnFire)
 
 
683
                DBPtr->IsOnFire = !(FastRandom() & 3);
 
 
684
DBPtr->IsOnFire = 1;
 
 
685
 
 
 
686
            if (!DBPtr->PerfectArmour)
 
 
687
                ArmourDamage += tempdamage >> 3;
 
 
688
        }
 
 
689
 
 
 
690
        if (damage->Electrical && !DBPtr->ElectricResistant)
 
 
691
        {
 
 
692
            int tempdamage = damage->Electrical * Fraction;
 
 
693
 
 
 
694
            if (DBPtr->ElectricSensitive)
 
 
695
                tempdamage <<= 2;
 
 
696
 
 
 
697
            HealthDamage += tempdamage;
 
 
698
        }
 
 
699
 
 
 
700
        if (damage->Acid && !DBPtr->AcidResistant)
 
 
701
        {
 
 
702
            int tempdamage = damage->Acid * Fraction;
 
 
703
            int unblocked = 0;
 
 
704
 
 
 
705
            switch(AvP.Difficulty)
 
 
706
            {
 
 
707
                case I_Hard:
 
 
708
                {
 
 
709
                    ArmourDamage += tempdamage;
 
 
710
 
 
 
711
                    if (ArmourDamage > DBPtr->Armour)
 
 
712
                    {
 
 
713
                        /* Now we're through. */
 
 
714
                        unblocked = tempdamage - DBPtr->Armour;
 
 
715
                    }
 
 
716
                }
 
 
717
                break;
 
 
718
                default:    
 
 
719
                {
 
 
720
                    ArmourDamage += tempdamage >> 1;
 
 
721
 
 
 
722
                    if (ArmourDamage > DBPtr->Armour)
 
 
723
                    {
 
 
724
                        /* Now we're through. */
 
 
725
                        unblocked = tempdamage - (DBPtr->Armour<<1);
 
 
726
                    }
 
 
727
                }
 
 
728
            }
 
 
729
 
 
 
730
            if (unblocked > 0)
 
 
731
                HealthDamage += unblocked;
 
 
732
        }
 
 
733
 
 
 
734
        /* Apply Damage. */
 
 
735
 
 
 
736
        if (ArmourDamage > 0)
 
 
737
        {
 
 
738
            if (DBPtr->Armour < ArmourDamage)
 
 
739
                DBPtr->Armour = 0;
 
 
740
            else
 
 
741
                DBPtr->Armour -= ArmourDamage;
 
 
742
        }
 
 
743
 
 
 
744
        if (HealthDamage > 0)
 
 
745
        {
 
 
746
            if (DBPtr->Health < HealthDamage)
 
 
747
            {
 
 
748
                DBPtr->Health = 0;
 
 
749
                return;
 
 
750
            }
 
 
751
            else
 
 
752
                DBPtr->Health -= HealthDamage;
 
 
753
        }
 
 
754
    }
 
 
755
 
 
 
756
    while (Integer)
 
 
757
    {
 
 
758
        ArmourDamage = 0;
 
 
759
        HealthDamage = 0;
 
 
760
 
 
 
761
        if (damage->Impact)
 
 
762
        {
 
 
763
            /* Impact damage. */
 
 
764
            int tempdamage = damage->Impact * ONE_FIXED;
 
 
765
            HealthDamage += tempdamage / 10;
 
 
766
            int unblocked = tempdamage - DBPtr->Armour;
 
 
767
 
 
 
768
            if (unblocked > 0)
 
 
769
                HealthDamage += unblocked;
 
 
770
 
 
 
771
            if (!DBPtr->PerfectArmour)
 
 
772
                ArmourDamage += tempdamage >> 4;
 
 
773
        }
 
 
774
 
 
 
775
        if (damage->Cutting)
 
 
776
        {
 
 
777
            /* Cutting damage. */
 
 
778
            int tempdamage = damage->Cutting * ONE_FIXED;
 
 
779
            HealthDamage += tempdamage >> 2;
 
 
780
            int unblocked = tempdamage - DBPtr->Armour;
 
 
781
 
 
 
782
            if (unblocked > 0)
 
 
783
                HealthDamage += unblocked;
 
 
784
 
 
 
785
            if (!DBPtr->PerfectArmour)
 
 
786
                ArmourDamage += tempdamage >> 3;
 
 
787
        }
 
 
788
 
 
 
789
        if (damage->Penetrative)
 
 
790
        {
 
 
791
            /* Penetrative damage. */
 
 
792
            int tempdamage = damage->Penetrative * ONE_FIXED;
 
 
793
            HealthDamage += tempdamage / 10;
 
 
794
            int unblocked = tempdamage - (DBPtr->Armour >> 6);
 
 
795
 
 
 
796
            if (unblocked > 0)
 
 
797
                HealthDamage += unblocked;
 
 
798
 
 
 
799
            if (!DBPtr->PerfectArmour)
 
 
800
                ArmourDamage += tempdamage >> 4;
 
 
801
        }
 
 
802
 
 
 
803
        if (damage->Fire && !DBPtr->FireResistant)
 
 
804
        {
 
 
805
            int tempdamage = damage->Fire * ONE_FIXED;
 
 
806
 
 
 
807
            if (DBPtr->Combustability == 2)
 
 
808
            {
 
 
809
                tempdamage <<= 1;
 
 
810
            }
 
 
811
            else if (DBPtr->Combustability == 3)
 
 
812
            {
 
 
813
                tempdamage >>= 2;
 
 
814
            }
 
 
815
 
 
 
816
            if(!DBPtr->IsOnFire)
 
 
817
                DBPtr->IsOnFire = !(FastRandom() & 3);
 
 
818
DBPtr->IsOnFire = 1;
 
 
819
 
 
 
820
            HealthDamage += tempdamage;
 
 
821
 
 
 
822
            if (!DBPtr->PerfectArmour)
 
 
823
                ArmourDamage += tempdamage >> 3;
 
 
824
        }
 
 
825
 
 
 
826
        if (damage->Electrical && !DBPtr->ElectricResistant)
 
 
827
        {
 
 
828
            int tempdamage = damage->Electrical * ONE_FIXED;
 
 
829
 
 
 
830
            if (DBPtr->ElectricSensitive)
 
 
831
                tempdamage <<= 2;
 
 
832
 
 
 
833
            HealthDamage += tempdamage;
 
 
834
        }
 
 
835
 
 
 
836
        if (damage->Acid && !DBPtr->AcidResistant)
 
 
837
        {
 
 
838
            int unblocked = 0;
 
 
839
            int tempdamage = damage->Acid * ONE_FIXED;
 
 
840
 
 
 
841
            switch(AvP.Difficulty)
 
 
842
            {
 
 
843
                case I_Hard:
 
 
844
                {
 
 
845
                    ArmourDamage += tempdamage;
 
 
846
 
 
 
847
                    if (ArmourDamage>DBPtr->Armour)
 
 
848
                    {
 
 
849
                        /* Now we're through. */
 
 
850
                        unblocked = tempdamage-DBPtr->Armour;
 
 
851
                    }
 
 
852
                }
 
 
853
                break;
 
 
854
                default:    
 
 
855
                {
 
 
856
                    ArmourDamage += tempdamage >> 1;
 
 
857
 
 
 
858
                    if (ArmourDamage > DBPtr->Armour)
 
 
859
                    {
 
 
860
                        /* Now we're through. */
 
 
861
                        unblocked = tempdamage - (DBPtr->Armour << 1);
 
 
862
                    }
 
 
863
                }
 
 
864
            }
 
 
865
 
 
 
866
            if (unblocked > 0)
 
 
867
                HealthDamage += unblocked;
 
 
868
        }
 
 
869
 
 
 
870
        if (ArmourDamage > 0)
 
 
871
        {
 
 
872
            if (DBPtr->Armour < ArmourDamage)
 
 
873
                DBPtr->Armour = 0;
 
 
874
            else
 
 
875
                DBPtr->Armour -= ArmourDamage;
 
 
876
        }
 
 
877
 
 
 
878
        if (HealthDamage > 0)
 
 
879
        {
 
 
880
            if (DBPtr->Health < HealthDamage)
 
 
881
            {
 
 
882
                DBPtr->Health = 0;
 
 
883
                return;
 
 
884
            }
 
 
885
            else
 
 
886
                DBPtr->Health -= HealthDamage;
 
 
887
        }
 
 
888
 
 
 
889
        Integer--;
 
 
890
    }
 
 
891
}
 
 
892
 
 
 
893
static void Pop_Section(STRATEGYBLOCK *sbPtr, SECTION_DATA *section_data, VECTORCH *blastcentre, int *wounds)
 
 
894
{
 
 
895
    /* 'Explode' this section, then frag off all it's children! */
 
 
896
 
 
 
897
    assert(section_data);
 
 
898
 
 
 
899
    enum PARTICLE_ID blood_type;
 
 
900
 
 
 
901
    if (!(section_data->sempai->flags & section_sprays_anything))
 
 
902
    {
 
 
903
        blood_type = PARTICLE_NULL;
 
 
904
    }
 
 
905
    else
 
 
906
    {
 
 
907
        if (section_data->sempai->flags & section_sprays_blood)
 
 
908
        {
 
 
909
            blood_type = GetBloodType(sbPtr);
 
 
910
        }
 
 
911
        else if (section_data->sempai->flags & section_sprays_acid)
 
 
912
        {
 
 
913
            blood_type = PARTICLE_ALIEN_BLOOD;
 
 
914
        }
 
 
915
        else if (section_data->sempai->flags & section_sprays_predoblood)
 
 
916
        {
 
 
917
            blood_type = PARTICLE_PREDATOR_BLOOD;
 
 
918
        }
 
 
919
        else if (section_data->sempai->flags & section_sprays_sparks)
 
 
920
        {
 
 
921
            blood_type = PARTICLE_SPARK;
 
 
922
        }
 
 
923
        else
 
 
924
        {
 
 
925
            blood_type = PARTICLE_NULL;
 
 
926
        }
 
 
927
 
 
 
928
        if (section_data->sempai->Shape && (blood_type != PARTICLE_NULL))
 
 
929
        {
 
 
930
            if (CHEATMODE_SUPERGORE == UserProfile.active_bonus)
 
 
931
                MakeBloodExplosion(&section_data->World_Offset, section_data->sempai->Shape->shaperadius, blastcentre, 500, blood_type);
 
 
932
            else
 
 
933
                MakeBloodExplosion(&section_data->World_Offset, section_data->sempai->Shape->shaperadius, blastcentre, 100, blood_type);
 
 
934
        }
 
 
935
    }
 
 
936
 
 
 
937
    /* Right, should have a blood type set.  Now, trim off the extra bits... */
 
 
938
 
 
 
939
    if ((section_data->First_Child != NULL) && !(section_data->flags & section_data_terminate_here))
 
 
940
    {
 
 
941
        SECTION_DATA *child_ptr = section_data->First_Child;
 
 
942
        int temp_wounds = 0;
 
 
943
 
 
 
944
        while (child_ptr != NULL)
 
 
945
        {
 
 
946
            assert(child_ptr->My_Parent == section_data);
 
 
947
            /* Please work! */            
 
 
948
            //MakeHierarchicalDebris(sbPtr, child_ptr, &child_ptr->World_Offset, &child_ptr->SecMat, &temp_wounds, 2); //jadda
 
 
949
            // or you better be sorry
 
 
950
 
 
 
951
            (*wounds) |= temp_wounds;
 
 
952
 
 
 
953
            child_ptr = child_ptr->Next_Sibling;
 
 
954
        }
 
 
955
    }
 
 
956
 
 
 
957
    /* Now trim off THIS bit, permanently. */
 
 
958
 
 
 
959
    (*wounds) |= section_data->sempai->flags & section_flags_wounding;
 
 
960
 
 
 
961
    section_data->flags |= section_data_notreal;
 
 
962
    section_data->flags |= section_data_terminate_here;
 
 
963
    /* ~Fin~ */
 
 
964
}
 
 
965
 
 
 
966
int TotalKineticDamage(const DAMAGE_PROFILE *damage)
 
 
967
{
 
 
968
    return (damage->Impact + damage->Penetrative + damage->Cutting);
 
 
969
}
 
 
970
 
 
 
971
DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data,
 
 
972
VECTORCH *incoming, VECTORCH *position, int FromHost)
 
 
973
{
 
 
974
    int wounds = 0;
 
 
975
    DISPLAYBLOCK *frag = NULL;
 
 
976
 
 
 
977
    if (sbPtr->DamageBlock.Indestructable || sbPtr->please_destroy_me)
 
 
978
        return NULL;
 
 
979
 
 
 
980
    assert(HMC_Ptr == this_section_data->my_controller);
 
 
981
 
 
 
982
    if((I_BehaviourNetGhost == sbPtr->type) && !FromHost)
 
 
983
    {
 
 
984
        DamageNetworkGhost(sbPtr, damage, multiple, this_section_data, incoming);
 
 
985
        return NULL;
 
 
986
    }
 
 
987
 
 
 
988
    /* Pass damage up test? */
 
 
989
    if ((this_section_data->sempai->flags & section_flag_passdamagetoparent) && this_section_data->My_Parent)
 
 
990
    {
 
 
991
        /* Try again, a level up. */
 
 
992
        return CauseDamageToHModel(HMC_Ptr, sbPtr, damage,multiple, this_section_data->My_Parent, incoming, position, FromHost);
 
 
993
    }
 
 
994
 
 
 
995
    if (this_section_data->sempai->flags & section_flag_doesnthurtsb)
 
 
996
    {
 
 
997
        DamageDamageBlock(&this_section_data->current_damage, damage, multiple);
 
 
998
    }
 
 
999
    else
 
 
1000
    {
 
 
1001
        /* The section takes damage... and the SB takes the health and armour damage. */
 
 
1002
        int Health = this_section_data->current_damage.Health;
 
 
1003
        int Armour = this_section_data->current_damage.Armour;
 
 
1004
        DamageDamageBlock(&this_section_data->current_damage, damage, multiple);
 
 
1005
 
 
 
1006
        int healthdamage = Health - this_section_data->current_damage.Health;
 
 
1007
        int armourdamage = Armour - this_section_data->current_damage.Armour;
 
 
1008
 
 
 
1009
        if (armourdamage > 0)
 
 
1010
        {
 
 
1011
            if (sbPtr->DamageBlock.Armour < armourdamage)
 
 
1012
                sbPtr->DamageBlock.Armour = 0;
 
 
1013
            else
 
 
1014
                sbPtr->DamageBlock.Armour -= armourdamage;
 
 
1015
        }
 
 
1016
 
 
 
1017
        if (healthdamage > 0)
 
 
1018
        {
 
 
1019
            if (sbPtr->DamageBlock.Health < healthdamage)
 
 
1020
                sbPtr->DamageBlock.Health = 0;
 
 
1021
            else
 
 
1022
                sbPtr->DamageBlock.Health -= healthdamage;
 
 
1023
        }
 
 
1024
    }
 
 
1025
 
 
 
1026
    /* Consider networking. */
 
 
1027
    if ((SinglePlayer != AvP.PlayMode) && (sbPtr->type != I_BehaviourNetGhost))
 
 
1028
        AddNetMsg_GhostHierarchyDamaged(sbPtr, damage, multiple, this_section_data->sempai->IDnumber, incoming);
 
 
1029
 
 
 
1030
    if(damage->MakeExitWounds && incoming && (this_section_data->sempai->flags & section_sprays_anything))
 
 
1031
    {
 
 
1032
        enum PARTICLE_ID blood_type;
 
 
1033
        int a;
 
 
1034
        VECTORCH *startpos;
 
 
1035
        VECTORCH final_spray_direction;
 
 
1036
 
 
 
1037
        if (this_section_data->sempai->flags & section_sprays_blood)
 
 
1038
        {
 
 
1039
            blood_type = GetBloodType(sbPtr);
 
 
1040
            /* Er... default? */
 
 
1041
        }
 
 
1042
        else if (this_section_data->sempai->flags & section_sprays_acid)
 
 
1043
        {
 
 
1044
            blood_type = PARTICLE_ALIEN_BLOOD;
 
 
1045
        }
 
 
1046
        else if (this_section_data->sempai->flags & section_sprays_predoblood)
 
 
1047
        {
 
 
1048
            blood_type = PARTICLE_PREDATOR_BLOOD;
 
 
1049
        }
 
 
1050
        else if (this_section_data->sempai->flags & section_sprays_sparks)
 
 
1051
        {
 
 
1052
            blood_type = PARTICLE_SPARK;
 
 
1053
        }
 
 
1054
        else
 
 
1055
        {
 
 
1056
            blood_type = PARTICLE_FLAME;
 
 
1057
            /* Distinctive. */
 
 
1058
        }
 
 
1059
 
 
 
1060
        startpos = position ? position : &this_section_data->World_Offset;
 
 
1061
 
 
 
1062
        /* 'incoming' SHOULD be normalised. */
 
 
1063
        for (a=0; a < (multiple >> ONE_FIXED_SHIFT); a++)
 
 
1064
        {
 
 
1065
            RotateAndCopyVector(incoming, &final_spray_direction, &sbPtr->DynPtr->OrientMat);
 
 
1066
 
 
 
1067
            /* Scale down. */
 
 
1068
 
 
 
1069
            //final_spray_direction.vx>>=1;
 
 
1070
            //final_spray_direction.vy>>=1;
 
 
1071
            //final_spray_direction.vz>>=1;
 
 
1072
 
 
 
1073
            final_spray_direction.vx += ( (FastRandom() & 511)-256);
 
 
1074
            final_spray_direction.vy += ( (FastRandom() & 511)-256);
 
 
1075
            final_spray_direction.vz += ( (FastRandom() & 511)-256);
 
 
1076
 
 
 
1077
            MakeBloodParticle(startpos, &final_spray_direction, blood_type);
 
 
1078
        }
 
 
1079
    }
 
 
1080
 
 
 
1081
    if (this_section_data->current_damage.Health <= 0)
 
 
1082
    {
 
 
1083
        /* Might want to create a frag here? */
 
 
1084
        if (damage->BlowUpSections)
 
 
1085
        {
 
 
1086
            /* Deduce blastCentre. */
 
 
1087
            VECTORCH blastCentre = this_section_data->World_Offset;
 
 
1088
 
 
 
1089
            if (incoming)
 
 
1090
            {
 
 
1091
                blastCentre.vx += incoming->vx;
 
 
1092
                blastCentre.vy += incoming->vy;
 
 
1093
                blastCentre.vz += incoming->vz;
 
 
1094
            }
 
 
1095
 
 
 
1096
            /* For the moment, this ALWAYS has priority. */
 
 
1097
            Pop_Section(sbPtr, this_section_data, &blastCentre, &wounds);
 
 
1098
 
 
 
1099
            if (wounds & section_has_sparkoflife)
 
 
1100
            {
 
 
1101
                /* Kill SB off! */
 
 
1102
                sbPtr->DamageBlock.Health = 0;
 
 
1103
                /* That's the way... */
 
 
1104
            }
 
 
1105
        }
 
 
1106
        else if ( !(this_section_data->sempai->flags & section_is_master_root)
 
 
1107
            && !(this_section_data->sempai->flags & section_flag_never_frag)
 
 
1108
            && (
 
 
1109
                ((this_section_data->sempai->flags & section_sprays_acid) && !(this_section_data->sempai->flags &
section_flag_fragonlyfordisks))
 
 
1110
                || ((this_section_data->sempai->StartingStats.Health < TotalKineticDamage(damage)) && !(this_section_data->sempai->flags
& section_flag_fragonlyfordisks))
 
 
1111
                || ((damage->Slicing > 2) && (this_section_data->sempai->flags & section_flag_fragonlyfordisks))
 
 
1112
                || ((damage->Slicing > 0) && !(this_section_data->sempai->flags & section_flag_fragonlyfordisks) )))
 
 
1113
        {
 
 
1114
            /* Work out which orientation to use. */
 
 
1115
            /* The root (Gah!), so use sbPtr. */
 
 
1116
            MATRIXCH *orientptr = (NULL != this_section_data->My_Parent) ? &this_section_data->My_Parent->SecMat :
&sbPtr->DynPtr->OrientMat;
 
 
1117
 
 
 
1118
            /* Never frag off the root, it wouldn't make sense. */
 
 
1119
 
 
 
1120
            frag = MakeHierarchicalDebris(sbPtr, this_section_data, &this_section_data->World_Offset, orientptr, &wounds, 0, incoming);
 
 
1121
 
 
 
1122
            /* Oh Dear!  Every section below and including this one becomes... unreal. 
 
 
1123
            And if any of them contain the spark of life, we need to know. */
 
 
1124
 
 
 
1125
            if (wounds & section_has_sparkoflife)
 
 
1126
            {
 
 
1127
                /* Kill SB off! */
 
 
1128
                sbPtr->DamageBlock.Health = 0;
 
 
1129
                /* That's the way... */
 
 
1130
            }
 
 
1131
        }
 
 
1132
        else
 
 
1133
        {
 
 
1134
            /* Don't frag the master root, and take care with non-aliens. */
 
 
1135
 
 
 
1136
            if (this_section_data->sempai->flags & section_has_sparkoflife)
 
 
1137
            {
 
 
1138
                /* However, if the master root is destroyed and is a critical section, */
 
 
1139
                sbPtr->DamageBlock.Health = 0;
 
 
1140
                /* ...still kill them off. */
 
 
1141
            }
 
 
1142
        }
 
 
1143
    }
 
 
1144
 
 
 
1145
     switch(sbPtr->type)
 
 
1146
    {
 
 
1147
        case I_BehaviourAlien:
 
 
1148
            AlienIsDamaged(sbPtr, damage, multiple, wounds, this_section_data, incoming);
 
 
1149
        break;
 
 
1150
        case I_BehaviourAlienPlayer:
 
 
1151
        case I_BehaviourMarinePlayer:
 
 
1152
        case I_BehaviourPredatorPlayer:
 
 
1153
            PlayerIsDamaged(damage, multiple, incoming);
 
 
1154
        break;
 
 
1155
        case I_BehaviourInanimateObject: InanimateObjectIsDamaged(sbPtr, damage, multiple); break;
 
 
1156
        case I_BehaviourMarine:
 
 
1157
            MarineIsDamaged(sbPtr, damage, multiple, wounds, this_section_data, incoming);
 
 
1158
        break;
 
 
1159
        case I_BehaviourCorpse:
 
 
1160
            CorpseIsDamaged(sbPtr, damage, wounds, incoming);
 
 
1161
        break;
 
 
1162
        case I_BehaviourPredator:
 
 
1163
            PredatorIsDamaged(sbPtr, damage, multiple, this_section_data, incoming);
 
 
1164
        break;
 
 
1165
        case I_BehaviourAutoGun:
 
 
1166
            SentryGunIsDamaged(sbPtr, damage, multiple, wounds,incoming);
 
 
1167
        break;
 
 
1168
        case I_BehaviourFaceHugger:
 
 
1169
            FacehuggerIsDamaged(sbPtr, damage, incoming);
 
 
1170
        break;
 
 
1171
        case I_BehaviourQueenAlien:
 
 
1172
            QueenIsDamaged(sbPtr, damage, multiple, this_section_data, incoming, position);
 
 
1173
        break;
 
 
1174
        case I_BehaviourXenoborg:
 
 
1175
            XenoborgIsDamaged(sbPtr, damage, multiple, wounds,incoming);
 
 
1176
        default:
 
 
1177
        break;
 
 
1178
    }
 
 
1179
 
 
 
1180
return frag;
 
 
1181
}
 
 
1182
 
 
 
1183
static int FriendlyFireDamageFilter(const DAMAGE_PROFILE *damage) 
 
 
1184
{
 
 
1185
    int VulnerableToAlienDamage = 1;
 
 
1186
    int VulnerableToMarineDamage = 1;
 
 
1187
    int VulnerableToPredatorDamage = 1;
 
 
1188
 
 
 
1189
    switch(AvP.PlayerType)
 
 
1190
    {
 
 
1191
        case I_Alien:
 
 
1192
        {
 
 
1193
            VulnerableToAlienDamage = 0;
 
 
1194
        }
 
 
1195
        break;
 
 
1196
        case I_Marine:
 
 
1197
        {
 
 
1198
            VulnerableToMarineDamage = 0;
 
 
1199
 
 
 
1200
            if(netGameData.gameType == NGT_Coop)
 
 
1201
                VulnerableToPredatorDamage = 0;
 
 
1202
        }
 
 
1203
        case I_Predator:
 
 
1204
        {
 
 
1205
            VulnerableToPredatorDamage = 0;
 
 
1206
 
 
 
1207
            if(netGameData.gameType == NGT_Coop)
 
 
1208
                VulnerableToMarineDamage = 0;
 
 
1209
        }
 
 
1210
    }
 
 
1211
 
 
 
1212
    switch (damage->Id)
 
 
1213
    {
 
 
1214
        case AMMO_ALIEN_CLAW:
 
 
1215
        case AMMO_ALIEN_TAIL:
 
 
1216
        case AMMO_ALIEN_BITE_KILLSECTION:
 
 
1217
        case AMMO_ALIEN_BITE_KILLSECTION_SUPER:
 
 
1218
        case AMMO_PC_ALIEN_BITE:
 
 
1219
            return VulnerableToAlienDamage;
 
 
1220
        case AMMO_10MM_CULW:
 
 
1221
        case AMMO_SMARTGUN:
 
 
1222
        case AMMO_FLAMETHROWER:
 
 
1223
        case AMMO_SADAR_TOW:
 
 
1224
        case AMMO_GRENADE:
 
 
1225
        case EXPLOSIONFIRE_BLAST:
 
 
1226
        case AMMO_MINIGUN:
 
 
1227
        case AMMO_PULSE_GRENADE:
 
 
1228
        case AMMO_FRAGMENTATION_GRENADE:
 
 
1229
        case AMMO_PROXIMITY_GRENADE:
 
 
1230
        case AMMO_CUDGEL:
 
 
1231
        case AMMO_FLECHETTE:
 
 
1232
        case AMMO_FRISBEE:
 
 
1233
        case AMMO_FRISBEE_FIRE:
 
 
1234
        case AMMO_MARINE_PISTOL:
 
 
1235
            return VulnerableToMarineDamage;
 
 
1236
        case AMMO_PRED_WRISTBLADE:
 
 
1237
        case AMMO_HEAVY_PRED_WRISTBLADE:
 
 
1238
        case AMMO_PRED_RIFLE:
 
 
1239
        case AMMO_PLASMACASTER:
 
 
1240
        case AMMO_PRED_PISTOL_BLAST:
 
 
1241
        case AMMO_PRED_DISC:
 
 
1242
        case AMMO_PRED_TROPHY_KILLSECTION:
 
 
1243
            return VulnerableToPredatorDamage;
 
 
1244
        default:
 
 
1245
            return 1;
 
 
1246
    }
 
 
1247
}
 
 
1248
 
 
 
1249
void CauseDamageToObject(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, VECTORCH *incoming)
 
 
1250
{
 
 
1251
    if (sbPtr->DamageBlock.Indestructable || sbPtr->please_destroy_me) // this is mostly for PARTICLE_EXPLOSIONFIRE
 
 
1252
        return;
 
 
1253
 
 
 
1254
    if(damage->ExplosivePower && (NULL != incoming))
 
 
1255
        sbPtr->DynPtr->LinImpulse = *incoming;
 
 
1256
 
 
 
1257
    switch(sbPtr->type)
 
 
1258
    {
 
 
1259
        case I_BehaviourFragment:
 
 
1260
        return;
 
 
1261
        case I_BehaviourMarinePlayer:
 
 
1262
        case I_BehaviourAlienPlayer:
 
 
1263
        case I_BehaviourPredatorPlayer:
 
 
1264
        {
 
 
1265
            if(SinglePlayer != AvP.PlayMode)
 
 
1266
            {
 
 
1267
                if (netGameData.disableFriendlyFire && (netGameData.gameType == NGT_CoopDeathmatch || netGameData.gameType == NGT_Coop))
 
 
1268
                {
 
 
1269
                    if (!FriendlyFireDamageFilter(damage))
 
 
1270
                        return;
 
 
1271
                }
 
 
1272
            }
 
 
1273
 
 
 
1274
            DamageDamageBlock(&sbPtr->DamageBlock, damage, multiple);
 
 
1275
            PlayerIsDamaged(damage, multiple, incoming);
 
 
1276
        }
 
 
1277
        return;
 
 
1278
        case I_BehaviourInanimateObject:
 
 
1279
        {
 
 
1280
            if (damage->Id == AMMO_NPC_OBSTACLE_CLEAR)
 
 
1281
            {
 
 
1282
                INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->dataptr;
 
 
1283
 
 
 
1284
                if (objStatPtr->explosionType)
 
 
1285
                    return; /* Try not to blunder through fatal things... */
 
 
1286
            }
 
 
1287
 
 
 
1288
            DamageDamageBlock(&sbPtr->DamageBlock, damage, multiple);
 
 
1289
            InanimateObjectIsDamaged(sbPtr, damage, multiple);
 
 
1290
        }
 
 
1291
        return;
 
 
1292
        case I_BehaviourHierarchicalFragment:
 
 
1293
        {
 
 
1294
            HDEBRIS_BEHAV_BLOCK *hdbhv = (HDEBRIS_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
1295
 
 
 
1296
            if(damage->ExplosivePower)
 
 
1297
            {
 
 
1298
                Extreme_Gibbing(sbPtr, hdbhv->HModelController.section_data, ONE_FIXED, incoming);
 
 
1299
                sbPtr->please_destroy_me = 1;
 
 
1300
            }
 
 
1301
        }
 
 
1302
        return;
 
 
1303
        case I_BehaviourGrenade:
 
 
1304
        case I_BehaviourFlare:
 
 
1305
        case I_BehaviourFragmentationGrenade:
 
 
1306
        case I_BehaviourProximityGrenade:
 
 
1307
        case I_BehaviourRocket:
 
 
1308
        case I_BehaviourPulseGrenade:
 
 
1309
        case I_BehaviourPredatorEnergyBolt:
 
 
1310
        case I_BehaviourFrisbee:
 
 
1311
        {
 
 
1312
            /* make it explode! */
 
 
1313
            ((ONE_SHOT_BEHAV_BLOCK * )sbPtr->dataptr)->counter = 0;
 
 
1314
        }
 
 
1315
        return;
 
 
1316
        case I_BehaviourPredator:
 
 
1317
        {
 
 
1318
            switch(damage->Id)
 
 
1319
            {
 
 
1320
                case AMMO_PLASMACASTER:
 
 
1321
                break;
 
 
1322
                default:
 
 
1323
                DamageDamageBlock(&sbPtr->DamageBlock, damage, multiple);
 
 
1324
                PredatorIsDamaged(sbPtr, damage, multiple, NULL, incoming);
 
 
1325
            }
 
 
1326
        }
 
 
1327
        return;
 
 
1328
        case I_BehaviourNetGhost:
 
 
1329
            DamageNetworkGhost(sbPtr, damage, multiple, NULL, incoming);
 
 
1330
        return;
 
 
1331
        default:
 
 
1332
        {
 
 
1333
            DamageDamageBlock(&sbPtr->DamageBlock, damage, multiple);
 
 
1334
 
 
 
1335
            switch(sbPtr->type)
 
 
1336
            {
 
 
1337
                case I_BehaviourAlien:
 
 
1338
                    AlienIsDamaged(sbPtr, damage, multiple, 0, NULL, incoming);
 
 
1339
                break;
 
 
1340
                case I_BehaviourVideoScreen:
 
 
1341
                    VideoScreenIsDamaged(sbPtr, damage, multiple);
 
 
1342
                break;
 
 
1343
                case I_BehaviourPlacedLight:
 
 
1344
                    PlacedLightIsDamaged(sbPtr, damage, multiple);
 
 
1345
                break;
 
 
1346
                case I_BehaviourMarine:
 
 
1347
                    MarineIsDamaged(sbPtr, damage, multiple, 0, NULL, incoming);
 
 
1348
                break;
 
 
1349
                case I_BehaviourCorpse:
 
 
1350
                    CorpseIsDamaged(sbPtr, damage, 0, incoming);
 
 
1351
                break;
 
 
1352
                case I_BehaviourFaceHugger:
 
 
1353
                    FacehuggerIsDamaged(sbPtr, damage, incoming);
 
 
1354
                break;
 
 
1355
                case I_BehaviourXenoborg:
 
 
1356
                    XenoborgIsDamaged(sbPtr, damage, multiple, 0, incoming);
 
 
1357
                break;
 
 
1358
                case I_BehaviourQueenAlien:
 
 
1359
                    QueenIsDamaged(sbPtr, damage, multiple, NULL, incoming, NULL);
 
 
1360
                break;
 
 
1361
                case I_BehaviourTrackObject:
 
 
1362
                    TrackObjectIsDamaged(sbPtr, damage, multiple);
 
 
1363
                break;
 
 
1364
                case I_BehaviourAutoGun:
 
 
1365
                    SentryGunIsDamaged(sbPtr, damage, multiple, 0, incoming);
 
 
1366
                break;
 
 
1367
                case I_BehaviourDummy:
 
 
1368
                    if(sbPtr->DamageBlock.Health <= 0) // this is needed for platform lift squash
 
 
1369
                        sbPtr->please_destroy_me = 1;
 
 
1370
                default:
 
 
1371
                break;
 
 
1372
            }
 
 
1373
        }
 
 
1374
    }
 
 
1375
}
 
 
1376
 
 
 
1377
void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data)
 
 
1378
{
 
 
1379
    /* 'multiple' is now in FIXED POINT!  */
 
 
1380
 
 
 
1381
    if (LOS_ObjectHitPtr->Module)
 
 
1382
    {
 
 
1383
        /* bad idea to put bullethole on a morphing object */
 
 
1384
        if(!LOS_ObjectHitPtr->ObMorphCtrl)
 
 
1385
            MakeDecal(DECAL_BULLETHOLE, &LOS_ObjectNormal, positionPtr, LOS_ObjectHitPtr->Module->m_index);
 
 
1386
 
 
 
1387
        /* cause a ricochet 1 in 8 times */
 
 
1388
        if ((FastRandom() & 65535) < 8192)
 
 
1389
            MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr);
 
 
1390
    }
 
 
1391
    else if(sbPtr)
 
 
1392
    {
 
 
1393
        VECTORCH incoming,*invec;
 
 
1394
 
 
 
1395
        if (sbPtr->DynPtr)
 
 
1396
        {
 
 
1397
            MATRIXCH WtoLMat = sbPtr->DynPtr->OrientMat;
 
 
1398
            /* Consider incoming hit direction. */
 
 
1399
            TransposeMatrixCH(&WtoLMat);
 
 
1400
            RotateAndCopyVector(directionPtr, &incoming, &WtoLMat);
 
 
1401
            invec = &incoming;
 
 
1402
        }
 
 
1403
        else
 
 
1404
        {
 
 
1405
            invec = NULL;
 
 
1406
        }
 
 
1407
 
 
 
1408
        if (this_section_data && sbPtr->DisplayBlock && sbPtr->DisplayBlock->HModelControlBlock)
 
 
1409
        {
 
 
1410
            /* Netghost case now handled properly. */
 
 
1411
            AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point, this_section_data);
 
 
1412
 
 
 
1413
            assert(sbPtr->DisplayBlock->HModelControlBlock == this_section_data->my_controller);
 
 
1414
            CauseDamageToHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr, &TemplateAmmo[AmmoID].MaxDamage, multiple, this_section_data, invec,
positionPtr, 0);
 
 
1415
 
 
 
1416
            if(sbPtr->type == I_BehaviourQueenAlien)
 
 
1417
            {
 
 
1418
                /* cause a ricochet 1 in 8 times */
 
 
1419
                if ((FastRandom() & 65535) < 8192)
 
 
1420
                    MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr);
 
 
1421
            }
 
 
1422
        }
 
 
1423
        else
 
 
1424
        {
 
 
1425
            CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage, multiple,invec);
 
 
1426
        }
 
 
1427
 
 
 
1428
        if (sbPtr->DynPtr)
 
 
1429
        {
 
 
1430
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1431
            EULER rotation;
 
 
1432
            int magnitudeOfForce = (5000 * TotalKineticDamage(&TemplateAmmo[AmmoID].MaxDamage)) / dynPtr->Mass;
 
 
1433
            /* okay, not too sure yet what this should do */
 
 
1434
            dynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx, magnitudeOfForce);
 
 
1435
            dynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy, magnitudeOfForce);
 
 
1436
            dynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz, magnitudeOfForce);
 
 
1437
 
 
 
1438
            CalculateTorqueAtPoint(&rotation, positionPtr, sbPtr);
 
 
1439
        }
 
 
1440
    }
 
 
1441
}
 
 
1442
 
 
 
1443
int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr)
 
 
1444
{
 
 
1445
    switch (sbPtr->type)
 
 
1446
    {
 
 
1447
        case I_BehaviourAlien:
 
 
1448
        case I_BehaviourMarine:
 
 
1449
        case I_BehaviourPredator:
 
 
1450
        case I_BehaviourFaceHugger:
 
 
1451
        case I_BehaviourXenoborg:
 
 
1452
        case I_BehaviourQueenAlien:
 
 
1453
                return 1;
 
 
1454
        case I_BehaviourCorpse:
 
 
1455
        {
 
 
1456
            CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)sbPtr->dataptr;
 
 
1457
 
 
 
1458
            return (corpseDataPtr->validityTimer > 0);
 
 
1459
        }
 
 
1460
        case I_BehaviourNetGhost:
 
 
1461
        {
 
 
1462
            NETGHOSTDATABLOCK *dataptr = sbPtr->dataptr;
 
 
1463
 
 
 
1464
            switch (dataptr->type)
 
 
1465
            {
 
 
1466
                case I_BehaviourPredatorPlayer:
 
 
1467
                    return 1;
 
 
1468
                case I_BehaviourMarinePlayer:
 
 
1469
                case I_BehaviourAlienPlayer:
 
 
1470
                case I_BehaviourRocket:
 
 
1471
                case I_BehaviourGrenade:
 
 
1472
                case I_BehaviourFlare:
 
 
1473
                case I_BehaviourFragmentationGrenade:
 
 
1474
                case I_BehaviourPredatorDisc_SeekTrack:
 
 
1475
                case I_BehaviourAlien:
 
 
1476
                case I_BehaviourProximityGrenade:
 
 
1477
                    return 1;
 
 
1478
                default:
 
 
1479
                    return 0;
 
 
1480
            }
 
 
1481
        }
 
 
1482
        default:
 
 
1483
            return 0;
 
 
1484
    }
 
 
1485
}
 
 
1486
 
 
 
1487
static void PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID)
 
 
1488
{
 
 
1489
    VECTORCH shotvector = {0, 0, 65535};
 
 
1490
 
 
 
1491
    if (Weapon_ThisBurst > 0)
 
 
1492
    {
 
 
1493
        EULER judder = { 0,0,0 };
 
 
1494
        MATRIXCH juddermat = { 0,0,0,0,0,0,0,0,0 };
 
 
1495
 
 
 
1496
        // jiggle the weapon around when you shoot
 
 
1497
        int speed = Approximate3dMagnitude(&PlayerStatus.sbptr->DynPtr->LinVelocity);
 
 
1498
 
 
 
1499
        if (PlayerStatus.twPtr->RecoilMaxXTilt > 0)
 
 
1500
            judder.EulerX = (FastRandom() % PlayerStatus.twPtr->RecoilMaxXTilt) - PlayerStatus.twPtr->RecoilMaxXTilt / 2;
 
 
1501
 
 
 
1502
        if (PlayerStatus.twPtr->RecoilMaxYTilt > 0)
 
 
1503
            judder.EulerY = (FastRandom() % PlayerStatus.twPtr->RecoilMaxYTilt) - PlayerStatus.twPtr->RecoilMaxYTilt / 2;
 
 
1504
 
 
 
1505
        judder.EulerX = MUL_FIXED(judder.EulerX, (ONE_FIXED + (speed << 2)));
 
 
1506
        judder.EulerY = MUL_FIXED(judder.EulerY, (ONE_FIXED + (speed << 2)));
 
 
1507
        PlayerStatus.WeaponPositionOffset.vx = judder.EulerX;
 
 
1508
        PlayerStatus.WeaponPositionOffset.vy = judder.EulerY;
 
 
1509
        judder.EulerX &= wrap360;
 
 
1510
        judder.EulerY &= wrap360;
 
 
1511
 
 
 
1512
        CreateEulerMatrix(&judder, &juddermat);
 
 
1513
        RotateVector(&shotvector, &juddermat);
 
 
1514
        Normalise(&shotvector);
 
 
1515
    }
 
 
1516
 
 
 
1517
    RotateVector(&shotvector, &PWMFSDP->SecMat);
 
 
1518
 
 
 
1519
    if(FindPolygonInLineOfSight(&shotvector, &PWMFSDP->World_Offset,  PlayerStatus.DisplayBlock))
 
 
1520
    {
 
 
1521
        VECTORCH incoming, *invec;
 
 
1522
        if (LOS_ObjectHitPtr->Module)
 
 
1523
        {
 
 
1524
            /* bad idea to put bullethole on a morphing object */
 
 
1525
            if(!LOS_ObjectHitPtr->ObMorphCtrl)
 
 
1526
                MakeDecal(DECAL_BULLETHOLE, &LOS_ObjectNormal, &LOS_Point, LOS_ObjectHitPtr->Module->m_index);
 
 
1527
 
 
 
1528
            /* cause a ricochet 1 in 8 times */
 
 
1529
            if ((FastRandom() & 65535) < 8192)
 
 
1530
                MakeImpactSparks(&shotvector, &LOS_ObjectNormal, &LOS_Point);
 
 
1531
        }
 
 
1532
        else if(LOS_ObjectHitPtr->ObStrategyBlock)
 
 
1533
        {
 
 
1534
            STRATEGYBLOCK *target = LOS_ObjectHitPtr->ObStrategyBlock;
 
 
1535
 
 
 
1536
            if (target->DynPtr)
 
 
1537
            {
 
 
1538
                MATRIXCH WtoLMat = target->DynPtr->OrientMat;
 
 
1539
                /* Consider incoming hit direction. */
 
 
1540
                TransposeMatrixCH(&WtoLMat);
 
 
1541
                RotateAndCopyVector(&shotvector, &incoming, &WtoLMat);
 
 
1542
                invec = &incoming;
 
 
1543
            }
 
 
1544
            else
 
 
1545
            {
 
 
1546
                invec = NULL;
 
 
1547
            }
 
 
1548
 
 
 
1549
            if (AccuracyStats_TargetFilter(target))
 
 
1550
                CurrentGameStats_WeaponHit(PlayerStatus.SelectedWeaponSlot, 1);
 
 
1551
 
 
 
1552
            if (NULL != LOS_HModel_Section)
 
 
1553
            {
 
 
1554
                #if DEBUG
 
 
1555
                {
 
 
1556
                    printf("Hitting a hierarchical section.\n");
 
 
1557
                    assert(LOS_ObjectHitPtr->HModelControlBlock == LOS_HModel_Section->my_controller);
 
 
1558
                }
 
 
1559
                #endif
 
 
1560
 
 
 
1561
                /* Netghost case now handled properly. */
 
 
1562
                AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point, LOS_HModel_Section);
 
 
1563
 
 
 
1564
                assert(target->DisplayBlock->HModelControlBlock == LOS_HModel_Section->my_controller);
 
 
1565
                CauseDamageToHModel(LOS_ObjectHitPtr->HModelControlBlock, target, &TemplateAmmo[AmmoID].MaxDamage, ONE_FIXED , LOS_HModel_Section, invec,
&LOS_Point, 0);
 
 
1566
 
 
 
1567
                if(target->type == I_BehaviourQueenAlien)
 
 
1568
                {
 
 
1569
                    /* cause a ricochet 1 in 8 times */
 
 
1570
                    if ((FastRandom() & 65535) < 8192)
 
 
1571
                        MakeImpactSparks(&shotvector, &LOS_ObjectNormal, &LOS_Point);
 
 
1572
                }
 
 
1573
            }
 
 
1574
            else
 
 
1575
            {
 
 
1576
                CauseDamageToObject(target, &TemplateAmmo[AmmoID].MaxDamage, ONE_FIXED , invec);
 
 
1577
            }
 
 
1578
        }
 
 
1579
    }
 
 
1580
}
 
 
1581
 
 
 
1582
static DISPLAYBLOCK *MakePistolCasing(VECTORCH *position,MATRIXCH *orient) 
 
 
1583
{
 
 
1584
    extern int NumActiveBlocks;
 
 
1585
    VECTORCH impulse = { 0, 0, 6000 };
 
 
1586
 
 
 
1587
    if( (NumActiveBlocks > maxobjects - 5) || (NumActiveStBlocks > maxstblocks-5))
 
 
1588
        return NULL;
 
 
1589
 
 
 
1590
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFragment);
 
 
1591
 
 
 
1592
    if(NULL == sbPtr)
 
 
1593
    return NULL;
 
 
1594
 
 
 
1595
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(GetLoadedShapeMSL("Pistol case"));
 
 
1596
    sbPtr->dataptr = malloc(sizeof(ONE_SHOT_BEHAV_BLOCK ));
 
 
1597
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC);
 
 
1598
 
 
 
1599
    if((dispPtr == NULL) || (NULL == sbPtr->dataptr) || (NULL == dynPtr))
 
 
1600
    {
 
 
1601
        RemoveBehaviourStrategy(sbPtr);
 
 
1602
        return NULL;
 
 
1603
    }
 
 
1604
 
 
 
1605
    dynPtr->Mass = 1;
 
 
1606
    dynPtr->IsStatic = 0;
 
 
1607
    dynPtr->IgnoreSameObjectsAsYou = 1;
 
 
1608
    dynPtr->OnlyCollideWithEnvironment = 1;
 
 
1609
 
 
 
1610
    dispPtr->ObWorld = *position;
 
 
1611
    dispPtr->ObStrategyBlock = sbPtr;
 
 
1612
 
 
 
1613
    ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = ALIEN_DYINGTIME;
 
 
1614
 
 
 
1615
    dynPtr->Position = *position;
 
 
1616
    dynPtr->OrientMat = *orient;
 
 
1617
 
 
 
1618
    dynPtr->AngVelocity.EulerX = 0;
 
 
1619
    dynPtr->AngVelocity.EulerY = ((FastRandom()&4095)<<2);
 
 
1620
    dynPtr->AngVelocity.EulerZ = 0;
 
 
1621
 
 
 
1622
    RotateVector(&impulse, orient);
 
 
1623
 
 
 
1624
    dynPtr->LinImpulse = impulse;
 
 
1625
 
 
 
1626
return dispPtr;
 
 
1627
}
 
 
1628
 
 
 
1629
static void GrenadeLauncher_UpdateBullets() 
 
 
1630
{
 
 
1631
    unsigned int a = 0;
 
 
1632
 
 
 
1633
    for (; a < 6; a++)
 
 
1634
    {
 
 
1635
        // Flags the correct number of bullets as visible...
 
 
1636
 
 
 
1637
        if (a > PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
1638
            GrenadeLauncherSectionPointers[a]->flags |= section_data_notreal; // Not vis.
 
 
1639
        else
 
 
1640
            GrenadeLauncherSectionPointers[a]->flags &= ~section_data_notreal; // Vis.
 
 
1641
    }
 
 
1642
}
 
 
1643
 
 
 
1644
static int SpotEffectWeaponHandle = SOUND_NOACTIVEINDEX;
 
 
1645
 
 
 
1646
void maintain_marine_weapons()
 
 
1647
{
 
 
1648
    if (Weapon_ThisBurst > 0)
 
 
1649
    {
 
 
1650
        PlayerStatus.WeaponPositionOffset.vz = (FastRandom() % PlayerStatus.twPtr->RecoilMaxRandomZ) - PlayerStatus.twPtr->RecoilMaxZ;
 
 
1651
    }
 
 
1652
    else if(PlayerStatus.WeaponPositionOffset.vz)
 
 
1653
    {
 
 
1654
        if (PlayerStatus.WeaponPositionOffset.vz > 0 )
 
 
1655
        {
 
 
1656
            PlayerStatus.WeaponPositionOffset.vz -= MUL_FIXED(300, NormalFrameTime);
 
 
1657
 
 
 
1658
            if (PlayerStatus.WeaponPositionOffset.vz < 0)
 
 
1659
                PlayerStatus.WeaponPositionOffset.vz = 0;
 
 
1660
        }
 
 
1661
        else if (PlayerStatus.WeaponPositionOffset.vz < 0 )
 
 
1662
        {
 
 
1663
            PlayerStatus.WeaponPositionOffset.vz += MUL_FIXED(300, NormalFrameTime);
 
 
1664
 
 
 
1665
            if (PlayerStatus.WeaponPositionOffset.vz > 0)
 
 
1666
                PlayerStatus.WeaponPositionOffset.vz = 0;
 
 
1667
        }
 
 
1668
    }
 
 
1669
 
 
 
1670
    PositionPlayersWeapon();
 
 
1671
 
 
 
1672
    switch(PlayerStatus.WeaponState)
 
 
1673
    {
 
 
1674
        case WEAPONSTATE_FIRING_PRIMARY:
 
 
1675
{
 
 
1676
extern void GunMuzzleSmoke(MATRIXCH *orientationPtr, VECTORCH *positionPtr);
 
 
1677
GunMuzzleSmoke(&PWMFSDP->SecMat, &PWMFSDP->World_Offset);
 
 
1678
}
 
 
1679
        case WEAPONSTATE_IDLE:
 
 
1680
        case WEAPONSTATE_FIRING_SECONDARY:
 
 
1681
        {
 
 
1682
            PlayerStatus.twPtr->maintain_weapon();
 
 
1683
        }
 
 
1684
        break;
 
 
1685
        case WEAPONSTATE_READYING:
 
 
1686
        {
 
 
1687
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
1688
            {
 
 
1689
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
1690
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
1691
            }
 
 
1692
            else
 
 
1693
            {
 
 
1694
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
1695
            }
 
 
1696
        }
 
 
1697
        break;
 
 
1698
        case WEAPONSTATE_UNREADYING:
 
 
1699
        {
 
 
1700
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
1701
            {
 
 
1702
                PlayerStatus.SelectedWeaponSlot = PlayerStatus.SwapToWeaponSlot;
 
 
1703
                PlayerStatus.SelectedWeapon = &PlayerStatus.WeaponSlot[PlayerStatus.SwapToWeaponSlot];
 
 
1704
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_IN;
 
 
1705
            }
 
 
1706
            else
 
 
1707
            {
 
 
1708
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
1709
            }
 
 
1710
        }
 
 
1711
        break;
 
 
1712
        case WEAPONSTATE_SWAPPING_IN:
 
 
1713
        {
 
 
1714
            RightHand = 0;
 
 
1715
            Weapon_ThisBurst = -1;
 
 
1716
            PlayerStatus.SmartGunMode = 1;
 
 
1717
            GrabWeaponShape();
 
 
1718
            PlayerStatus.WeaponStateTimeOutCounter = PlayerStatus.twPtr->swap_in_out;
 
 
1719
            InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Come, PlayerStatus.WeaponStateTimeOutCounter);
 
 
1720
            PlayersWeaponHModelController.Looped = 0;
 
 
1721
            PlayerStatus.WeaponState = WEAPONSTATE_READYING;
 
 
1722
 
 
 
1723
            switch(PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
1724
            {
 
 
1725
                case WEAPON_MINIGUN:
 
 
1726
                    Sound_Play(SID_MINIGUN_READY, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
1727
                break;
 
 
1728
                case WEAPON_GRENADELAUNCHER:
 
 
1729
                    GrenadeLauncher_UpdateBullets();
 
 
1730
                default:
 
 
1731
                break;
 
 
1732
            }
 
 
1733
        }
 
 
1734
        break;
 
 
1735
        case WEAPONSTATE_SWAPPING_OUT:
 
 
1736
        {
 
 
1737
            PlayerStatus.WeaponStateTimeOutCounter = PlayerStatus.twPtr->swap_in_out;
 
 
1738
            InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Go, PlayerStatus.WeaponStateTimeOutCounter);
 
 
1739
            PlayersWeaponHModelController.Looped = 0;
 
 
1740
            PlayerStatus.WeaponState = WEAPONSTATE_UNREADYING;
 
 
1741
        }
 
 
1742
        break;
 
 
1743
        case WEAPONSTATE_JAMMED:
 
 
1744
        {
 
 
1745
            if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
1746
            {
 
 
1747
                switch(PlayerStatus.SelectedWeaponSlot)
 
 
1748
                {
 
 
1749
                    case WEAPON_PULSERIFLE:
 
 
1750
                        Sound_Play(SID_PULSE_RIFLE_FIRING_EMPTY, "ehv", &SpotEffectWeaponHandle, 60);
 
 
1751
                    break;
 
 
1752
                    case WEAPON_SMARTGUN:
 
 
1753
                        Sound_Play(SID_NOAMMO, "eh", &SpotEffectWeaponHandle);
 
 
1754
                    default:
 
 
1755
                    break;
 
 
1756
                }
 
 
1757
            }
 
 
1758
            else
 
 
1759
            {
 
 
1760
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
1761
                Weapon_ThisBurst = -1;
 
 
1762
            }
 
 
1763
        }
 
 
1764
        break;
 
 
1765
        case WEAPONSTATE_WAITING:
 
 
1766
        default:
 
 
1767
        break;
 
 
1768
    }
 
 
1769
}
 
 
1770
 
 
 
1771
void marine_weapon_idle()
 
 
1772
{
 
 
1773
    PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
1774
 
 
 
1775
    if (WeaponFidgetPlaying)
 
 
1776
    {
 
 
1777
        if (PlayersWeaponHModelController.sequence_timer == (ONE_FIXED-1))
 
 
1778
        {
 
 
1779
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
1780
            WeaponFidgetPlaying = 0;
 
 
1781
        }
 
 
1782
    }
 
 
1783
    else if (!(FastRandom() & 255))
 
 
1784
    {
 
 
1785
        /* Start animation. */
 
 
1786
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Fidget))
 
 
1787
        {
 
 
1788
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Fidget, ONE_FIXED, 0);
 
 
1789
            PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
1790
            WeaponFidgetPlaying = 1;
 
 
1791
        }
 
 
1792
    }
 
 
1793
}
 
 
1794
 
 
 
1795
 
 
 
1796
void DrawPlayersMuzzleFlash(enum MUZZLE_FLASH_ID muzzleFlashID)
 
 
1797
{
 
 
1798
    VECTORCH shotvector = {0, 0, 65535};
 
 
1799
    RotateVector(&shotvector, &PWMFSDP->SecMat);
 
 
1800
    DrawMuzzleFlash(&PWMFSDP->World_Offset, &shotvector, muzzleFlashID);
 
 
1801
}
 
 
1802
 
 
 
1803
void maintain_pulserifle()
 
 
1804
{
 
 
1805
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
1806
    {
 
 
1807
        case MHSS_Stationary:
 
 
1808
        case MHSS_Fidget:
 
 
1809
        {
 
 
1810
            if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon || ((Weapon_ThisBurst < PULSERIFLE_MINIMUM_BURST) && (Weapon_ThisBurst >= 0)))
 
 
1811
            {
 
 
1812
                if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
1813
                {
 
 
1814
                    if (Weapon_ThisBurst == -1)
 
 
1815
                        Weapon_ThisBurst = 0;
 
 
1816
 
 
 
1817
                    RAPIDFIRE_AMMO_COUNTER += MUL_FIXED(100/6 * ONE_FIXED, NormalFrameTime);
 
 
1818
 
 
 
1819
                    if (RAPIDFIRE_AMMO_COUNTER > ONE_FIXED)
 
 
1820
                    {
 
 
1821
                        if (128 > (FastRandom() & 65535))
 
 
1822
                        {
 
 
1823
                            PlayerStatus.WeaponState = WEAPONSTATE_JAMMED;
 
 
1824
                            Weapon_ThisBurst = 0;
 
 
1825
                            return;
 
 
1826
                        }
 
 
1827
 
 
 
1828
                        static int weaponPitchTimer = 0;
 
 
1829
                        PlayerFireLineOfSightAmmo(AMMO_10MM_CULW);
 
 
1830
                        CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
1831
                        PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
1832
                        Weapon_ThisBurst++;
 
 
1833
                        RAPIDFIRE_AMMO_COUNTER = 0;
 
 
1834
                        AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
1835
 
 
 
1836
                        if(weaponHandle == SOUND_NOACTIVEINDEX) 
 
 
1837
                        {
 
 
1838
                            Sound_Play(SID_PULSE_START, "h");      
 
 
1839
                            Sound_Play(SID_PULSE_LOOP, "elh", &weaponHandle);                    
 
 
1840
                            weaponPitchTimer = ONE_FIXED >> 3;
 
 
1841
                        }
 
 
1842
                        else
 
 
1843
                        {
 
 
1844
                            weaponPitchTimer -= NormalFrameTime;
 
 
1845
 
 
 
1846
                            if (weaponPitchTimer <= 0)
 
 
1847
                            {
 
 
1848
                                weaponPitchTimer = ONE_FIXED >> 3;
 
 
1849
                                Sound_ChangePitch(weaponHandle, (FastRandom() & 63) - 32);
 
 
1850
                            }
 
 
1851
                        }
 
 
1852
 
 
 
1853
                        PlayerStatus.muzzle_flash = 1;
 
 
1854
                        PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
1855
                    }
 
 
1856
                return;
 
 
1857
                }
 
 
1858
                else if(SpotEffectWeaponHandle == SOUND_NOACTIVEINDEX)
 
 
1859
                {
 
 
1860
                    Sound_Play(SID_PULSE_RIFLE_FIRING_EMPTY, "ehv", &SpotEffectWeaponHandle, 60);
 
 
1861
                }
 
 
1862
            }
 
 
1863
            else if(!PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
1864
            {
 
 
1865
                if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
1866
                {
 
 
1867
                    Sound_Play(SID_PULSE_END, "h");
 
 
1868
                    Sound_Stop(weaponHandle);
 
 
1869
                }
 
 
1870
 
 
 
1871
                if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
1872
                {
 
 
1873
                    Weapon_ThisBurst = -1;
 
 
1874
                    InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, ONE_FIXED);
 
 
1875
                    PlayersWeaponHModelController.Looped = 0;
 
 
1876
                    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
1877
                    return;
 
 
1878
                }
 
 
1879
                else if (!PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
1880
                {
 
 
1881
                    MarineZeroAmmoFunctionality();
 
 
1882
                    return;
 
 
1883
                }
 
 
1884
            }
 
 
1885
 
 
 
1886
            Weapon_ThisBurst = -1;
 
 
1887
 
 
 
1888
            if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
1889
            {
 
 
1890
                Sound_Play(SID_PULSE_END, "h");
 
 
1891
                Sound_Stop(weaponHandle);
 
 
1892
            }
 
 
1893
 
 
 
1894
            if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
1895
            {
 
 
1896
                if (PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
1897
                {
 
 
1898
                    InitialisePulseGrenadeBehaviour(&PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat);
 
 
1899
                    CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
1900
                    Sound_Play(SID_PULSEGRENADELAUNCH, "h");
 
 
1901
                    InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Secondary_Fire, ONE_FIXED);
 
 
1902
                    PlayersWeaponHModelController.Looped = 0;
 
 
1903
                    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
1904
                    PlayerStatus.WeaponState = WEAPONSTATE_FIRING_SECONDARY;
 
 
1905
                return;
 
 
1906
                }
 
 
1907
                else if(SpotEffectWeaponHandle == SOUND_NOACTIVEINDEX)
 
 
1908
                {
 
 
1909
                    Sound_Play(SID_PULSE_RIFLE_FIRING_EMPTY, "eh", &SpotEffectWeaponHandle);
 
 
1910
                }
 
 
1911
            }
 
 
1912
 
 
 
1913
            marine_weapon_idle();
 
 
1914
        }
 
 
1915
        break;
 
 
1916
        case MHSS_Standard_Reload:
 
 
1917
        {
 
 
1918
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
1919
            {
 
 
1920
                PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
1921
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 99;
 
 
1922
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
1923
            }
 
 
1924
            else
 
 
1925
            {
 
 
1926
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
1927
                return;
 
 
1928
            }
 
 
1929
        }
 
 
1930
        break;
 
 
1931
        case MHSS_Secondary_Fire:
 
 
1932
        {
 
 
1933
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
1934
            {
 
 
1935
                PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining--;
 
 
1936
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
1937
            }
 
 
1938
            else
 
 
1939
            {
 
 
1940
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
1941
                return;
 
 
1942
            }
 
 
1943
        }
 
 
1944
        break;
 
 
1945
        default:
 
 
1946
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
1947
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
1948
    }
 
 
1949
 
 
 
1950
    PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
1951
}
 
 
1952
 
 
 
1953
static int oldRandomValue = -1;
 
 
1954
 
 
 
1955
void maintain_smartgun()
 
 
1956
{
 
 
1957
    if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
1958
    {
 
 
1959
        if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon || ((Weapon_ThisBurst < SMARTGUN_MINIMUM_BURST) && (Weapon_ThisBurst >= 0)))
 
 
1960
        {
 
 
1961
            if (Weapon_ThisBurst == -1)
 
 
1962
                Weapon_ThisBurst = 0;
 
 
1963
 
 
 
1964
            RAPIDFIRE_AMMO_COUNTER += MUL_FIXED(50 * ONE_FIXED, NormalFrameTime);
 
 
1965
 
 
 
1966
            if (RAPIDFIRE_AMMO_COUNTER > ONE_FIXED)
 
 
1967
            {
 
 
1968
                if (256 > (FastRandom() & 65535))
 
 
1969
                {
 
 
1970
                    PlayerStatus.WeaponState = WEAPONSTATE_JAMMED;
 
 
1971
                    Weapon_ThisBurst = 0;
 
 
1972
                    return;
 
 
1973
                }
 
 
1974
 
 
 
1975
                PlayerFireLineOfSightAmmo(AMMO_SMARTGUN);
 
 
1976
                CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
1977
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
1978
                RAPIDFIRE_AMMO_COUNTER = 0;
 
 
1979
                Weapon_ThisBurst += 1;
 
 
1980
 
 
 
1981
                AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
1982
                PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
1983
                PlayerStatus.muzzle_flash = 1;
 
 
1984
 
 
 
1985
                if(weaponHandle == SOUND_NOACTIVEINDEX) 
 
 
1986
                {
 
 
1987
                    int rand = FastRandom() % 3;
 
 
1988
 
 
 
1989
                    if (rand == oldRandomValue)
 
 
1990
                        rand = (rand + 1) % 3;
 
 
1991
 
 
 
1992
                    oldRandomValue = rand;
 
 
1993
 
 
 
1994
                    switch (rand)
 
 
1995
                    {
 
 
1996
                        case 0:
 
 
1997
                            Sound_Play(SID_SMART1, "ehpd", &weaponHandle, (FastRandom()&255)-128,
&PlayerStatus.sbptr->DynPtr->Position);
 
 
1998
                        break;
 
 
1999
                        case 1:
 
 
2000
                            Sound_Play(SID_SMART2, "ehpd", &weaponHandle, (FastRandom()&255)-128,
&PlayerStatus.sbptr->DynPtr->Position);
 
 
2001
                        break;
 
 
2002
                        case 2:
 
 
2003
                            Sound_Play(SID_SMART3, "ehpd", &weaponHandle, (FastRandom()&255)-128,
&PlayerStatus.sbptr->DynPtr->Position);
 
 
2004
                        default:
 
 
2005
                        break;
 
 
2006
                    }
 
 
2007
                }
 
 
2008
            }
 
 
2009
 
 
 
2010
            return;
 
 
2011
        }
 
 
2012
        else
 
 
2013
        {
 
 
2014
            Weapon_ThisBurst = -1;
 
 
2015
        }
 
 
2016
    }
 
 
2017
    else
 
 
2018
    {
 
 
2019
        Weapon_ThisBurst = -1;
 
 
2020
 
 
 
2021
        if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
2022
        {
 
 
2023
            if(SpotEffectWeaponHandle == SOUND_NOACTIVEINDEX)
 
 
2024
                Sound_Play(SID_NOAMMO, "eh", &SpotEffectWeaponHandle);
 
 
2025
 
 
 
2026
            PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
2027
        }
 
 
2028
        else if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
2029
        {
 
 
2030
            if (ONE_FIXED == PlayerStatus.WeaponStateTimeOutCounter)
 
 
2031
            {
 
 
2032
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, ONE_FIXED);
 
 
2033
                PlayersWeaponHModelController.Looped = 0;
 
 
2034
            }
 
 
2035
            else if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2036
            {
 
 
2037
                PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
2038
                PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2039
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 500;
 
 
2040
                return;
 
 
2041
            }
 
 
2042
 
 
 
2043
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2044
 
 
 
2045
            return;
 
 
2046
        }
 
 
2047
    }
 
 
2048
 
 
 
2049
    if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && (ONE_FIXED == PlayerStatus.WeaponStateTimeOutCounter))
 
 
2050
    {
 
 
2051
        PlayerStatus.SmartGunMode = !PlayerStatus.SmartGunMode;
 
 
2052
        Sound_Play(SID_SMART_MODESWITCH, NULL);
 
 
2053
        PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2054
        return;
 
 
2055
    }
 
 
2056
    else
 
 
2057
    {
 
 
2058
        if (ONE_FIXED != PlayerStatus.WeaponStateTimeOutCounter)
 
 
2059
        {
 
 
2060
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2061
 
 
 
2062
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2063
                PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
2064
 
 
 
2065
            return;
 
 
2066
        }
 
 
2067
    }
 
 
2068
 
 
 
2069
    if ((PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary) && (PlayersWeaponHModelController.Sub_Sequence != MHSS_Fidget))
 
 
2070
        InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2071
 
 
 
2072
    marine_weapon_idle();
 
 
2073
}
 
 
2074
 
 
 
2075
void maintain_flamethrower()
 
 
2076
{
 
 
2077
    if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2078
    {
 
 
2079
        if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
2080
        {
 
 
2081
            ProveHModel(&PlayersWeaponHModelController, &PlayerStatus.weapon);
 
 
2082
 
 
 
2083
            RAPIDFIRE_AMMO_COUNTER += MUL_FIXED(15 * ONE_FIXED, NormalFrameTime);
 
 
2084
 
 
 
2085
            if (RAPIDFIRE_AMMO_COUNTER > ONE_FIXED)
 
 
2086
            {
 
 
2087
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
2088
                RAPIDFIRE_AMMO_COUNTER = 0;
 
 
2089
                PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
2090
            }
 
 
2091
 
 
 
2092
            FireFlameThrower(&PWMFSDP->World_Offset, &null_vec, &PlayerStatus.weapon.ObMat, 0, &Flamethrower_Timer);
 
 
2093
 
 
 
2094
            AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_OBJECTONFIRE);
 
 
2095
            AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
2096
 
 
 
2097
            if(weaponHandle == SOUND_NOACTIVEINDEX) 
 
 
2098
            {
 
 
2099
                Sound_Play(SID_INCIN_START, "h");
 
 
2100
                Sound_Play(SID_INCIN_LOOP, "elh", &weaponHandle);                    
 
 
2101
            }
 
 
2102
            return;
 
 
2103
        }
 
 
2104
        else
 
 
2105
        {
 
 
2106
            if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2107
            {
 
 
2108
                Sound_Play(SID_INCIN_END, "h");
 
 
2109
                Sound_Stop(weaponHandle);
 
 
2110
            }
 
 
2111
        }
 
 
2112
    }
 
 
2113
    else
 
 
2114
    {
 
 
2115
        if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2116
        {
 
 
2117
            Sound_Play(SID_INCIN_END, "h");
 
 
2118
            Sound_Stop(weaponHandle);
 
 
2119
        }
 
 
2120
 
 
 
2121
        if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
2122
        {
 
 
2123
            PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
2124
        }
 
 
2125
        else if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
2126
        {
 
 
2127
            if (ONE_FIXED == PlayerStatus.WeaponStateTimeOutCounter)
 
 
2128
            {
 
 
2129
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, ONE_FIXED);
 
 
2130
                PlayersWeaponHModelController.Looped = 0;
 
 
2131
            }
 
 
2132
            else if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2133
            {
 
 
2134
                PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
2135
                PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2136
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 100;
 
 
2137
                return;
 
 
2138
            }
 
 
2139
 
 
 
2140
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2141
 
 
 
2142
            return;
 
 
2143
        }
 
 
2144
    }
 
 
2145
 
 
 
2146
    PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
2147
 
 
 
2148
    if ((PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary) && (PlayersWeaponHModelController.Sub_Sequence != MHSS_Fidget))
 
 
2149
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
2150
 
 
 
2151
    marine_weapon_idle();
 
 
2152
}
 
 
2153
 
 
 
2154
#define SADAR_RECOIL (ONE_FIXED/6*2)
 
 
2155
#define SADAR_RELOAD (ONE_FIXED*3/2)
 
 
2156
 
 
 
2157
void maintain_sadar()
 
 
2158
{
 
 
2159
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
2160
    {
 
 
2161
        case MHSS_Stationary:
 
 
2162
        case MHSS_Fidget:
 
 
2163
        {
 
 
2164
            if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2165
            {
 
 
2166
                if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
2167
                {
 
 
2168
                    if (PlayerStatus.WeaponStateTimeOutCounter) //this stops atomatic fire
 
 
2169
                    {
 
 
2170
                        PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
2171
                        Sound_Play(SID_SADAR_FIRE, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
2172
                        PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
2173
                        CreateRocketKernel(&PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat, 1);
 
 
2174
                        CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
2175
                        InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Fire, SADAR_RECOIL);
 
 
2176
                        PlayersWeaponHModelController.Looped = 0;
 
 
2177
                        Weapon_ThisBurst = 1;
 
 
2178
                    }
 
 
2179
                }
 
 
2180
                else
 
 
2181
                {
 
 
2182
                    PlayerStatus.WeaponStateTimeOutCounter = SADAR_RECOIL;
 
 
2183
 
 
 
2184
                    marine_weapon_idle();
 
 
2185
                }
 
 
2186
            }
 
 
2187
            else
 
 
2188
            {
 
 
2189
                    MarineZeroAmmoFunctionality();
 
 
2190
            }
 
 
2191
        }
 
 
2192
        break;
 
 
2193
        case MHSS_Standard_Fire:
 
 
2194
        {
 
 
2195
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2196
            Weapon_ThisBurst = 0;
 
 
2197
 
 
 
2198
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2199
            {
 
 
2200
                if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2201
                {
 
 
2202
                    //InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, SADAR_RELOAD);
 
 
2203
                    //InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_MarineHUD, (int)MHSS_Standard_Reload, SADAR_RELOAD, 0);
 
 
2204
                    //PlayerStatus.WeaponStateTimeOutCounter = SADAR_RELOAD;
 
 
2205
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
2206
                PlayerStatus.SwapToWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
2207
                }
 
 
2208
                else
 
 
2209
                {
 
 
2210
                    MarineZeroAmmoFunctionality();
 
 
2211
                }
 
 
2212
            }
 
 
2213
        }
 
 
2214
        break;
 
 
2215
        case MHSS_Standard_Reload:
 
 
2216
        {
 
 
2217
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2218
 
 
 
2219
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2220
            {
 
 
2221
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
2222
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
2223
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
2224
            }
 
 
2225
        }
 
 
2226
        break;
 
 
2227
        default:
 
 
2228
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
2229
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2230
    }
 
 
2231
}
 
 
2232
 
 
 
2233
#define GRENADE_LAUNCHER_RECOIL_TIME (ONE_FIXED*4)/3
 
 
2234
 
 
 
2235
static int GrenadeLauncherChangeAmmo()
 
 
2236
{
 
 
2237
    unsigned int RoundsRemaining;
 
 
2238
    unsigned int MagazinesRemaining;
 
 
2239
 
 
 
2240
    switch(GrenadeLauncherData.SelectedAmmo)
 
 
2241
    {
 
 
2242
        case AMMO_GRENADE:
 
 
2243
        {
 
 
2244
            if (GrenadeLauncherData.FragmentationRoundsRemaining > 0 || GrenadeLauncherData.FragmentationMagazinesRemaining > 0)
 
 
2245
            {
 
 
2246
                GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE;
 
 
2247
                RoundsRemaining = GrenadeLauncherData.FragmentationRoundsRemaining;
 
 
2248
                MagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining;
 
 
2249
            }
 
 
2250
            else if (GrenadeLauncherData.ProximityRoundsRemaining > 0 || GrenadeLauncherData.ProximityMagazinesRemaining > 0)
 
 
2251
            {
 
 
2252
                GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE;
 
 
2253
                RoundsRemaining = GrenadeLauncherData.ProximityRoundsRemaining;
 
 
2254
                MagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining;
 
 
2255
            }
 
 
2256
            else
 
 
2257
            {
 
 
2258
                return 0;
 
 
2259
            }
 
 
2260
 
 
 
2261
            GrenadeLauncherData.StandardRoundsRemaining = PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
2262
            GrenadeLauncherData.StandardMagazinesRemaining = PlayerStatus.SelectedWeapon->MagazinesRemaining;
 
 
2263
        }
 
 
2264
        break;
 
 
2265
        case AMMO_FRAGMENTATION_GRENADE:
 
 
2266
        {
 
 
2267
            if (GrenadeLauncherData.ProximityRoundsRemaining > 0 || GrenadeLauncherData.ProximityMagazinesRemaining > 0)
 
 
2268
            {
 
 
2269
                GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE;
 
 
2270
                RoundsRemaining = GrenadeLauncherData.ProximityRoundsRemaining;
 
 
2271
                MagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining;
 
 
2272
            }
 
 
2273
            else if (GrenadeLauncherData.StandardRoundsRemaining > 0 || GrenadeLauncherData.StandardMagazinesRemaining > 0)
 
 
2274
            {
 
 
2275
                GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE;
 
 
2276
                RoundsRemaining = GrenadeLauncherData.StandardRoundsRemaining;
 
 
2277
                MagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining;
 
 
2278
            }
 
 
2279
            else
 
 
2280
            {
 
 
2281
                return 0;
 
 
2282
            }
 
 
2283
 
 
 
2284
            GrenadeLauncherData.FragmentationRoundsRemaining = PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
2285
            GrenadeLauncherData.FragmentationMagazinesRemaining = PlayerStatus.SelectedWeapon->MagazinesRemaining;
 
 
2286
        }
 
 
2287
        break;
 
 
2288
        case AMMO_PROXIMITY_GRENADE:
 
 
2289
        {
 
 
2290
            if (GrenadeLauncherData.StandardRoundsRemaining > 0 || GrenadeLauncherData.StandardMagazinesRemaining > 0)
 
 
2291
            {
 
 
2292
                GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE;
 
 
2293
                RoundsRemaining = GrenadeLauncherData.StandardRoundsRemaining;
 
 
2294
                MagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining;
 
 
2295
            }
 
 
2296
            else if (GrenadeLauncherData.FragmentationRoundsRemaining > 0 || GrenadeLauncherData.FragmentationMagazinesRemaining > 0)
 
 
2297
            {
 
 
2298
                GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE;
 
 
2299
                RoundsRemaining = GrenadeLauncherData.FragmentationRoundsRemaining;
 
 
2300
                MagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining;
 
 
2301
            }
 
 
2302
            else
 
 
2303
            {
 
 
2304
                return 0;
 
 
2305
            }
 
 
2306
 
 
 
2307
            GrenadeLauncherData.ProximityRoundsRemaining = PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
2308
            GrenadeLauncherData.ProximityMagazinesRemaining = PlayerStatus.SelectedWeapon->MagazinesRemaining;
 
 
2309
        }
 
 
2310
        break;
 
 
2311
        default:
 
 
2312
            assert(0);
 
 
2313
            return 0;
 
 
2314
    }
 
 
2315
 
 
 
2316
    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = RoundsRemaining;
 
 
2317
    PlayerStatus.SelectedWeapon->MagazinesRemaining = MagazinesRemaining;
 
 
2318
 
 
 
2319
return 1;
 
 
2320
}
 
 
2321
 
 
 
2322
void maintain_grenadelauncher()
 
 
2323
{
 
 
2324
    //printf("GL Rounds = %d\n", PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining);
 
 
2325
    static int real_reload = 0;
 
 
2326
 
 
 
2327
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
2328
    {
 
 
2329
        case MHSS_Stationary:
 
 
2330
        case MHSS_Fidget:
 
 
2331
        {
 
 
2332
            if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2333
            {
 
 
2334
                if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon && PlayerStatus.WeaponStateTimeOutCounter)
 
 
2335
                {
 
 
2336
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
2337
                    Sound_Play(SID_GRENADE_LAUNCH, "h");
 
 
2338
 
 
 
2339
                    switch(GrenadeLauncherData.SelectedAmmo)
 
 
2340
                    {
 
 
2341
                        case AMMO_GRENADE:
 
 
2342
                            CreateGrenadeKernel(I_BehaviourGrenade, &PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat, 1);
 
 
2343
                        break;
 
 
2344
                        case AMMO_FRAGMENTATION_GRENADE:
 
 
2345
                            CreateGrenadeKernel(I_BehaviourFragmentationGrenade, &PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat, 1);
 
 
2346
                        break;
 
 
2347
                        case AMMO_PROXIMITY_GRENADE:
 
 
2348
                            CreateGrenadeKernel(I_BehaviourProximityGrenade, &PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat, 1);
 
 
2349
                        default:
 
 
2350
                        break;
 
 
2351
                    }
 
 
2352
 
 
 
2353
                    GrenadeLauncher_UpdateBullets();
 
 
2354
                    // Pop the round in the breach...
 
 
2355
                    GrenadeLauncherSectionPointers[0]->flags |= section_data_notreal;
 
 
2356
                    // It'll be put back at the next update.
 
 
2357
 
 
 
2358
                    CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
2359
 
 
 
2360
                    PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
2361
                    InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Fire, GRENADE_LAUNCHER_RECOIL_TIME);
 
 
2362
                    PlayersWeaponHModelController.Looped = 0;
 
 
2363
                    return;
 
 
2364
                }
 
 
2365
            }
 
 
2366
            else if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
2367
            {
 
 
2368
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, GRENADE_LAUNCHER_RECOIL_TIME);
 
 
2369
                PlayersWeaponHModelController.Looped = 0;
 
 
2370
                PlayerStatus.WeaponStateTimeOutCounter = GRENADE_LAUNCHER_RECOIL_TIME;
 
 
2371
                real_reload = 1;
 
 
2372
                return;
 
 
2373
            }
 
 
2374
            else if(GrenadeLauncherChangeAmmo())
 
 
2375
            {
 
 
2376
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, GRENADE_LAUNCHER_RECOIL_TIME);
 
 
2377
                PlayersWeaponHModelController.Looped = 0;
 
 
2378
                PlayerStatus.WeaponStateTimeOutCounter = GRENADE_LAUNCHER_RECOIL_TIME;
 
 
2379
                real_reload = 1;
 
 
2380
                return;
 
 
2381
            }
 
 
2382
            else
 
 
2383
            {
 
 
2384
                MarineZeroAmmoFunctionality();
 
 
2385
                return;
 
 
2386
            }
 
 
2387
 
 
 
2388
            if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && GrenadeLauncherChangeAmmo()) // only reload different ammo
 
 
2389
            {
 
 
2390
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Reload, GRENADE_LAUNCHER_RECOIL_TIME);
 
 
2391
                PlayersWeaponHModelController.Looped = 0;
 
 
2392
                PlayerStatus.WeaponStateTimeOutCounter = GRENADE_LAUNCHER_RECOIL_TIME;
 
 
2393
                real_reload = 0;
 
 
2394
                return;
 
 
2395
            }
 
 
2396
 
 
 
2397
            PlayerStatus.WeaponStateTimeOutCounter = GRENADE_LAUNCHER_RECOIL_TIME;
 
 
2398
 
 
 
2399
            marine_weapon_idle();
 
 
2400
        }
 
 
2401
        break;
 
 
2402
        case MHSS_Standard_Fire:
 
 
2403
        {
 
 
2404
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2405
 
 
 
2406
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2407
            {
 
 
2408
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2409
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
2410
            }
 
 
2411
        }
 
 
2412
        break;
 
 
2413
        case MHSS_Standard_Reload:
 
 
2414
        {
 
 
2415
            if (PlayersWeaponHModelController.keyframe_flags)
 
 
2416
            {
 
 
2417
                if (real_reload)
 
 
2418
                {
 
 
2419
                    // Flag all bullets as visible...
 
 
2420
                    GrenadeLauncherSectionPointers[0]->flags &= ~section_data_notreal;
 
 
2421
                    GrenadeLauncherSectionPointers[1]->flags &= ~section_data_notreal;
 
 
2422
                    GrenadeLauncherSectionPointers[2]->flags &= ~section_data_notreal;
 
 
2423
                    GrenadeLauncherSectionPointers[3]->flags &= ~section_data_notreal;
 
 
2424
                    GrenadeLauncherSectionPointers[4]->flags &= ~section_data_notreal;
 
 
2425
                    GrenadeLauncherSectionPointers[5]->flags &= ~section_data_notreal;
 
 
2426
                }
 
 
2427
                else
 
 
2428
                {
 
 
2429
                    if (!PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2430
                    {
 
 
2431
                        PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 6;
 
 
2432
                        PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2433
                    }
 
 
2434
 
 
 
2435
                    /* A little cheat... */
 
 
2436
                    GrenadeLauncher_UpdateBullets();
 
 
2437
 
 
 
2438
                    if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining < 6)
 
 
2439
                        GrenadeLauncherSectionPointers[0]->flags |= section_data_notreal;
 
 
2440
                }
 
 
2441
 
 
 
2442
                switch (GrenadeLauncherData.SelectedAmmo)
 
 
2443
                {
 
 
2444
                    default:
 
 
2445
                    case AMMO_GRENADE:
 
 
2446
                        ChangeHUDToAlternateShapeSet("Grenade");
 
 
2447
                    break;
 
 
2448
                    case AMMO_FRAGMENTATION_GRENADE:
 
 
2449
                        ChangeHUDToAlternateShapeSet("Frag");
 
 
2450
                    break;
 
 
2451
                    case AMMO_PROXIMITY_GRENADE:
 
 
2452
                        ChangeHUDToAlternateShapeSet("Proxmine");
 
 
2453
                }
 
 
2454
            }
 
 
2455
 
 
 
2456
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2457
 
 
 
2458
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2459
            {
 
 
2460
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
2461
 
 
 
2462
                if (real_reload)
 
 
2463
                {
 
 
2464
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 6;
 
 
2465
                    PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2466
                }
 
 
2467
 
 
 
2468
                GrenadeLauncher_UpdateBullets();
 
 
2469
 
 
 
2470
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2471
            }
 
 
2472
        }
 
 
2473
        break;
 
 
2474
        default:
 
 
2475
        {
 
 
2476
            if ((PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary) && (PlayersWeaponHModelController.Sub_Sequence != MHSS_Fidget))
 
 
2477
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2478
        }
 
 
2479
    }
 
 
2480
}
 
 
2481
 
 
 
2482
#define MINIGUN_MOVING_IMPULSE    (-36000)
 
 
2483
#define MINIGUN_JOLTTIME_SHIFT    (2)
 
 
2484
 
 
 
2485
void maintain_minigun()
 
 
2486
{
 
 
2487
    if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon || ((Weapon_ThisBurst < MINIGUN_MINIMUM_BURST) && (Weapon_ThisBurst >= 0)))
 
 
2488
    {
 
 
2489
        if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Standard_Fire)
 
 
2490
        {
 
 
2491
            Old_Minigun_SpinSpeed = 0;
 
 
2492
            Minigun_SpinSpeed = 0;
 
 
2493
            Weapon_ThisBurst = -1;
 
 
2494
            Minigun_HeadJolt.EulerX = 0;
 
 
2495
            Minigun_HeadJolt.EulerY = 0;
 
 
2496
            Minigun_HeadJolt.EulerZ = 0;
 
 
2497
            Minigun_MaxHeadJolt.EulerX = 0;
 
 
2498
            Minigun_MaxHeadJolt.EulerY = 0;
 
 
2499
            Minigun_MaxHeadJolt.EulerZ = 0;
 
 
2500
 
 
 
2501
            InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Fire, ONE_FIXED);
 
 
2502
            PlayersWeaponHModelController.Playing = 0;
 
 
2503
        }
 
 
2504
 
 
 
2505
        if (Minigun_SpinSpeed >= MINIGUN_MAX_SPEED)
 
 
2506
        {
 
 
2507
            Minigun_SpinSpeed = MINIGUN_MAX_SPEED;
 
 
2508
 
 
 
2509
            if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2510
            {
 
 
2511
                if (Weapon_ThisBurst == -1)
 
 
2512
                    Weapon_ThisBurst = 0;
 
 
2513
 
 
 
2514
                RAPIDFIRE_AMMO_COUNTER += MUL_FIXED(100 * ONE_FIXED, NormalFrameTime);
 
 
2515
 
 
 
2516
                if (RAPIDFIRE_AMMO_COUNTER > ONE_FIXED)
 
 
2517
                {
 
 
2518
                    PlayerFireLineOfSightAmmo(AMMO_MINIGUN);
 
 
2519
                    CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
2520
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
2521
                    RAPIDFIRE_AMMO_COUNTER = 0;
 
 
2522
                    Weapon_ThisBurst += 1;
 
 
2523
                    PlayerStatus.muzzle_flash = 1;
 
 
2524
 
 
 
2525
                    /* Give the player an impulse? */
 
 
2526
                    if ((PlayerStatus.sbptr->DynPtr->LinVelocity.vx != 0)
 
 
2527
                    || (PlayerStatus.sbptr->DynPtr->LinVelocity.vy != 0)
 
 
2528
                    || (PlayerStatus.sbptr->DynPtr->LinVelocity.vz != 0))
 
 
2529
                    {
 
 
2530
                        int impulse = MUL_FIXED(MINIGUN_MOVING_IMPULSE, NormalFrameTime);
 
 
2531
 
 
 
2532
                        PlayerStatus.sbptr->DynPtr->LinImpulse.vx += MUL_FIXED(PlayerStatus.weapon.ObMat.mat31, impulse);
 
 
2533
                        PlayerStatus.sbptr->DynPtr->LinImpulse.vy += MUL_FIXED(PlayerStatus.weapon.ObMat.mat32, impulse);
 
 
2534
                        PlayerStatus.sbptr->DynPtr->LinImpulse.vz += MUL_FIXED(PlayerStatus.weapon.ObMat.mat33, impulse);
 
 
2535
 
 
 
2536
                        Minigun_MaxHeadJolt.EulerX = -(78+(FastRandom() & 63));
 
 
2537
                        Minigun_MaxHeadJolt.EulerY = -(78+(FastRandom() & 63));
 
 
2538
                        Minigun_MaxHeadJolt.EulerZ = 300;
 
 
2539
 
 
 
2540
                        Minigun_HeadJolt.EulerX    = Minigun_MaxHeadJolt.EulerX;
 
 
2541
                        Minigun_HeadJolt.EulerY    = Minigun_MaxHeadJolt.EulerY;
 
 
2542
                        Minigun_HeadJolt.EulerZ    = Minigun_MaxHeadJolt.EulerZ;
 
 
2543
                    }
 
 
2544
 
 
 
2545
                    AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
2546
                    PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
2547
 
 
 
2548
                    if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2549
                    {
 
 
2550
                        if (ActiveSounds[weaponHandle].soundIndex != SID_MINIGUN_LOOP)
 
 
2551
                            Sound_Stop(weaponHandle);
 
 
2552
                    }
 
 
2553
 
 
 
2554
                    if(weaponHandle == SOUND_NOACTIVEINDEX)
 
 
2555
                        Sound_Play(SID_MINIGUN_LOOP, "elhd", &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position);
 
 
2556
                }
 
 
2557
 
 
 
2558
                if (Minigun_HeadJolt.EulerX || Minigun_HeadJolt.EulerY || Minigun_HeadJolt.EulerZ)
 
 
2559
                {
 
 
2560
                    int joltratex = MUL_FIXED((NormalFrameTime << MINIGUN_JOLTTIME_SHIFT), Minigun_MaxHeadJolt.EulerX);
 
 
2561
                    int joltratey = MUL_FIXED((NormalFrameTime << MINIGUN_JOLTTIME_SHIFT), Minigun_MaxHeadJolt.EulerY);
 
 
2562
                    int joltratez = MUL_FIXED((NormalFrameTime << MINIGUN_JOLTTIME_SHIFT), Minigun_MaxHeadJolt.EulerZ);
 
 
2563
 
 
 
2564
                    if (Minigun_HeadJolt.EulerX > 0)
 
 
2565
                    {
 
 
2566
                        if (joltratex > Minigun_HeadJolt.EulerX)
 
 
2567
                            joltratex = Minigun_HeadJolt.EulerX;
 
 
2568
 
 
 
2569
                        Minigun_HeadJolt.EulerX -= joltratex;
 
 
2570
 
 
 
2571
                        if (Minigun_HeadJolt.EulerX < 0)
 
 
2572
                            Minigun_HeadJolt.EulerX = 0;
 
 
2573
                    }
 
 
2574
                    else if (Minigun_HeadJolt.EulerX < 0)
 
 
2575
                    {
 
 
2576
                        if (joltratex < Minigun_HeadJolt.EulerX)
 
 
2577
                            joltratex = Minigun_HeadJolt.EulerX;
 
 
2578
 
 
 
2579
                        Minigun_HeadJolt.EulerX -= joltratex;
 
 
2580
 
 
 
2581
                        if (Minigun_HeadJolt.EulerX > 0)
 
 
2582
                            Minigun_HeadJolt.EulerX = 0;
 
 
2583
                    }
 
 
2584
 
 
 
2585
                    PlayerStatus.ViewPanX += joltratex;
 
 
2586
 
 
 
2587
                    if ((PlayerStatus.ViewPanX > 1024) && (PlayerStatus.ViewPanX < 3200))
 
 
2588
                        PlayerStatus.ViewPanX = 3200;
 
 
2589
 
 
 
2590
                    /* Okay, that 3200 comes from 3072 + '128'.  '128' is hardcoded into pmove.c. */
 
 
2591
                    PlayerStatus.ViewPanX &= wrap360;
 
 
2592
 
 
 
2593
                    if (Minigun_HeadJolt.EulerY > 0)
 
 
2594
                    {
 
 
2595
                        if (joltratey > Minigun_HeadJolt.EulerY)
 
 
2596
                            joltratey = Minigun_HeadJolt.EulerY;
 
 
2597
 
 
 
2598
                        Minigun_HeadJolt.EulerY -= joltratey;
 
 
2599
 
 
 
2600
                        if (Minigun_HeadJolt.EulerY < 0)
 
 
2601
                            Minigun_HeadJolt.EulerY = 0;
 
 
2602
 
 
 
2603
                    }
 
 
2604
                    else if (Minigun_HeadJolt.EulerY < 0)
 
 
2605
                    {
 
 
2606
                        if (joltratey < Minigun_HeadJolt.EulerY)
 
 
2607
                            joltratey = Minigun_HeadJolt.EulerY;
 
 
2608
 
 
 
2609
                        Minigun_HeadJolt.EulerY -= joltratey;
 
 
2610
 
 
 
2611
                        if (Minigun_HeadJolt.EulerY > 0)
 
 
2612
                            Minigun_HeadJolt.EulerY = 0;
 
 
2613
                    }
 
 
2614
 
 
 
2615
                    joltratey &= wrap360;
 
 
2616
                    /* Forcibly turn the player! */        
 
 
2617
                    {
 
 
2618
                        MATRIXCH mat;       
 
 
2619
                        int cos = GetCos(joltratey);
 
 
2620
                        int sin = GetSin(joltratey);
 
 
2621
                        mat.mat11 = cos;         
 
 
2622
                        mat.mat12 = 0;
 
 
2623
                        mat.mat13 = -sin;
 
 
2624
                        mat.mat21 = 0;          
 
 
2625
                        mat.mat22 = 65536;          
 
 
2626
                        mat.mat23 = 0;          
 
 
2627
                        mat.mat31 = sin;          
 
 
2628
                        mat.mat32 = 0;          
 
 
2629
                        mat.mat33 = cos;          
 
 
2630
 
 
 
2631
                        MatrixMultiply(&PlayerStatus.sbptr->DynPtr->OrientMat,&mat, &PlayerStatus.sbptr->DynPtr->OrientMat);
 
 
2632
 
 
 
2633
                        MatrixToEuler(&PlayerStatus.sbptr->DynPtr->OrientMat, &PlayerStatus.sbptr->DynPtr->OrientEuler);
 
 
2634
                    }
 
 
2635
 
 
 
2636
                    if (Minigun_HeadJolt.EulerZ > 0)
 
 
2637
                    {
 
 
2638
                        if (joltratex > Minigun_HeadJolt.EulerZ)
 
 
2639
                            joltratex = Minigun_HeadJolt.EulerZ;
 
 
2640
 
 
 
2641
                        Minigun_HeadJolt.EulerZ -= joltratez;
 
 
2642
 
 
 
2643
                        if (Minigun_HeadJolt.EulerZ < 0)
 
 
2644
                            Minigun_HeadJolt.EulerZ = 0;
 
 
2645
 
 
 
2646
                    }
 
 
2647
                    else if (Minigun_HeadJolt.EulerZ < 0)
 
 
2648
                    {
 
 
2649
                        if (joltratex < Minigun_HeadJolt.EulerZ)
 
 
2650
                            joltratex = Minigun_HeadJolt.EulerZ;
 
 
2651
 
 
 
2652
                        Minigun_HeadJolt.EulerZ -= joltratez;
 
 
2653
 
 
 
2654
                        if (Minigun_HeadJolt.EulerZ > 0)
 
 
2655
                            Minigun_HeadJolt.EulerZ = 0;
 
 
2656
                    }
 
 
2657
 
 
 
2658
                    HeadOrientation.EulerZ += joltratez;
 
 
2659
                }
 
 
2660
            }
 
 
2661
            else
 
 
2662
            {
 
 
2663
                // steady - play SID_MINIGUN_EMPTY.
 
 
2664
                if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2665
                {
 
 
2666
                    if (ActiveSounds[weaponHandle].soundIndex != SID_MINIGUN_EMPTY)
 
 
2667
                    {
 
 
2668
                        // Stop other sounds...
 
 
2669
                        Sound_Stop(weaponHandle);
 
 
2670
                        Sound_Play(SID_MINIGUN_EMPTY, "elhd", &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position);
 
 
2671
                    }
 
 
2672
                }
 
 
2673
 
 
 
2674
                Weapon_ThisBurst = -1;
 
 
2675
            }
 
 
2676
        }
 
 
2677
        else
 
 
2678
        {
 
 
2679
            Minigun_SpinSpeed += NormalFrameTime << 7;
 
 
2680
 
 
 
2681
            PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
2682
 
 
 
2683
            // Winding up or steady - play SID_MINIGUN_EMPTY.
 
 
2684
            if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2685
            {
 
 
2686
                if (ActiveSounds[weaponHandle].soundIndex != SID_MINIGUN_EMPTY)
 
 
2687
                {
 
 
2688
                    // Stop other sounds...
 
 
2689
                    Sound_Stop(weaponHandle);
 
 
2690
                    Sound_Play(SID_MINIGUN_EMPTY, "elhd", &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position);
 
 
2691
                }
 
 
2692
            }
 
 
2693
        }
 
 
2694
    }
 
 
2695
    else
 
 
2696
    {
 
 
2697
        Weapon_ThisBurst = -1;
 
 
2698
 
 
 
2699
        PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
2700
 
 
 
2701
        if (Minigun_SpinSpeed)
 
 
2702
            Minigun_SpinSpeed -= NormalFrameTime << 3;
 
 
2703
 
 
 
2704
        if (Minigun_SpinSpeed < 0)
 
 
2705
        {
 
 
2706
            Minigun_SpinSpeed = Old_Minigun_SpinSpeed = 0;
 
 
2707
 
 
 
2708
            /* No sound at all, ideally! */
 
 
2709
               if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2710
               {
 
 
2711
                if (ActiveSounds[weaponHandle].soundIndex != SID_MINIGUN_END)
 
 
2712
                {
 
 
2713
                    /* Allow SID_MINIGUN_END to stop if it's going. */
 
 
2714
                    Sound_Stop(weaponHandle);
 
 
2715
                }
 
 
2716
            }
 
 
2717
 
 
 
2718
            if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining <= 0)
 
 
2719
            {
 
 
2720
                if(PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
2721
                {
 
 
2722
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 800;
 
 
2723
                    PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2724
                }
 
 
2725
                else
 
 
2726
                {
 
 
2727
                    MarineZeroAmmoFunctionality();
 
 
2728
                }
 
 
2729
            }
 
 
2730
        }
 
 
2731
        else if (Minigun_SpinSpeed < Old_Minigun_SpinSpeed)
 
 
2732
        {
 
 
2733
            /* Winding down - should be playing SID_MINIGUN_END. */
 
 
2734
               if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
2735
               {
 
 
2736
                if (ActiveSounds[weaponHandle].soundIndex != SID_MINIGUN_END)
 
 
2737
                {
 
 
2738
                    Sound_Stop(weaponHandle);
 
 
2739
                       Sound_Play(SID_MINIGUN_END, "ehd", &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position);
 
 
2740
                }
 
 
2741
            }
 
 
2742
        }
 
 
2743
    }
 
 
2744
 
 
 
2745
    if (Minigun_SpinSpeed != Old_Minigun_SpinSpeed)
 
 
2746
    {
 
 
2747
        if (Minigun_SpinSpeed)
 
 
2748
        {
 
 
2749
            HModel_ChangeSpeed(&PlayersWeaponHModelController, DIV_FIXED(ONE_FIXED, Minigun_SpinSpeed));
 
 
2750
            PlayersWeaponHModelController.Playing = 1;
 
 
2751
        }
 
 
2752
        else
 
 
2753
        {
 
 
2754
            PlayersWeaponHModelController.Playing = 0;
 
 
2755
        }
 
 
2756
    }
 
 
2757
 
 
 
2758
    Old_Minigun_SpinSpeed = Minigun_SpinSpeed;
 
 
2759
 
 
 
2760
    //printf("Minigun Spin Speed = %d\n", Minigun_SpinSpeed);
 
 
2761
}
 
 
2762
 
 
 
2763
#define PISTOL_RECOIL    (ONE_FIXED/3)
 
 
2764
 
 
 
2765
void maintain_pistol()
 
 
2766
{
 
 
2767
    Weapon_ThisBurst = PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
2768
 
 
 
2769
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
2770
    {
 
 
2771
        case MHSS_Stationary:
 
 
2772
        case MHSS_Fidget:
 
 
2773
        {
 
 
2774
            if ((PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon && PlayerStatus.WeaponStateTimeOutCounter) ||
PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
2775
            {
 
 
2776
                if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining > 0)
 
 
2777
                {
 
 
2778
                    PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
2779
                    AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
2780
                    PlayerStatus.muzzle_flash = 1;
 
 
2781
                    Sound_Play(SID_SHOTGUN, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
2782
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
2783
                    PlayerFireLineOfSightAmmo(AMMO_MARINE_PISTOL);
 
 
2784
                    CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
2785
                    PlayerStatus.WeaponStateTimeOutCounter = PISTOL_RECOIL;
 
 
2786
 
 
 
2787
                    {
 
 
2788
                        SECTION_DATA *casing = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum R Pistol round");
 
 
2789
 
 
 
2790
                        if (casing)
 
 
2791
                            MakePistolCasing(&casing->World_Offset, &casing->SecMat);
 
 
2792
                    }
 
 
2793
 
 
 
2794
                    if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2795
                        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 6), HMSQT_MarineHUD, (int)MHSS_Standard_Fire, -1, 0);
 
 
2796
                    else
 
 
2797
                        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 6), HMSQT_MarineHUD, (int)MHSS_Secondary_Fire, -1, 0);
 
 
2798
                return;
 
 
2799
                }
 
 
2800
 
 
 
2801
                Weapon_ThisBurst = -1;
 
 
2802
            }
 
 
2803
 
 
 
2804
            PlayerStatus.WeaponStateTimeOutCounter = !PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon;
 
 
2805
 
 
 
2806
            if (!PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2807
            {
 
 
2808
                if(PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
2809
                {
 
 
2810
                    int time = DIV_FIXED(ONE_FIXED, ((65536*2)/3));
 
 
2811
                    time -= ONE_FIXED >> 3;
 
 
2812
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_MarineHUD, (int)MHSS_Standard_Reload, time, 0);
 
 
2813
                    PlayersWeaponHModelController.Looped = 0;
 
 
2814
                    PlayerStatus.WeaponStateTimeOutCounter = time;
 
 
2815
                }
 
 
2816
                else
 
 
2817
                {
 
 
2818
                    MarineZeroAmmoFunctionality();
 
 
2819
                }
 
 
2820
 
 
 
2821
                return;
 
 
2822
            }
 
 
2823
 
 
 
2824
            marine_weapon_idle();
 
 
2825
        }
 
 
2826
        break;
 
 
2827
        case MHSS_Standard_Fire:
 
 
2828
        {
 
 
2829
            if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
2830
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime * 2;
 
 
2831
            else
 
 
2832
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2833
 
 
 
2834
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2835
            {
 
 
2836
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
2837
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
2838
            }
 
 
2839
        }
 
 
2840
        break;
 
 
2841
        case MHSS_Secondary_Fire:
 
 
2842
 
 
 
2843
            PlayerStatus.WeaponState = WEAPONSTATE_FIRING_SECONDARY;
 
 
2844
 
 
 
2845
            if (!(PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon || PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon))
 
 
2846
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
2847
        break;
 
 
2848
        case MHSS_Standard_Reload:
 
 
2849
        {
 
 
2850
            //if (Get_Delta_Sequence(&PlayersWeaponHModelController, "StockBack"))
 
 
2851
            //    Remove_Delta_Sequence(&PlayersWeaponHModelController, "StockBack");
 
 
2852
 
 
 
2853
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
2854
 
 
 
2855
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
2856
            {
 
 
2857
                PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
2858
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 12;
 
 
2859
 
 
 
2860
                if ((SinglePlayer != AvP.PlayMode) && netGameData.pistolInfiniteAmmo)
 
 
2861
                {
 
 
2862
                    /* Pistol infinite ammo hack? */
 
 
2863
                    PlayerStatus.SelectedWeapon->MagazinesRemaining++;
 
 
2864
                }
 
 
2865
 
 
 
2866
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
2867
            }
 
 
2868
        }
 
 
2869
        break;
 
 
2870
        default:
 
 
2871
        {
 
 
2872
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
2873
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
2874
        }
 
 
2875
    }
 
 
2876
}
 
 
2877
 
 
 
2878
void MarineTwoPistols_SwapOut()
 
 
2879
{
 
 
2880
    if (PlayerStatus.WeaponStateTimeOutCounter == ONE_FIXED)
 
 
2881
    {
 
 
2882
        int slot = SlotForThisWeapon(WEAPON_MARINE_PISTOL);
 
 
2883
        int time = DIV_FIXED(ONE_FIXED, ONE_FIXED);
 
 
2884
        time -= (ONE_FIXED>>4);
 
 
2885
 
 
 
2886
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_MarineHUD, (int)MHSS_Go, time, 0);
 
 
2887
        PlayersWeaponHModelController.Looped = 0;
 
 
2888
 
 
 
2889
        PlayerStatus.WeaponSlot[slot].MagazinesRemaining = PlayerStatus.SelectedWeapon->MagazinesRemaining;
 
 
2890
 
 
 
2891
        int temp_rounds = PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining + PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining;
 
 
2892
 
 
 
2893
        if(temp_rounds > 12)
 
 
2894
        {
 
 
2895
            PlayerStatus.WeaponSlot[slot].MagazinesRemaining++;
 
 
2896
            temp_rounds -= 12;
 
 
2897
        }
 
 
2898
 
 
 
2899
        if (PlayerStatus.WeaponSlot[slot].MagazinesRemaining > 99)
 
 
2900
            PlayerStatus.WeaponSlot[slot].MagazinesRemaining = 99;
 
 
2901
 
 
 
2902
        PlayerStatus.WeaponSlot[slot].PrimaryRoundsRemaining = temp_rounds;
 
 
2903
        PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 0;
 
 
2904
        PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining = 0;
 
 
2905
    }
 
 
2906
}
 
 
2907
 
 
 
2908
void MarineTwoPistols_SwapIn()
 
 
2909
{
 
 
2910
    DELTA_CONTROLLER *FireLeft;
 
 
2911
    DELTA_CONTROLLER *FireRight = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireRight");
 
 
2912
 
 
 
2913
    if (FireRight == NULL)
 
 
2914
    {
 
 
2915
        FireRight = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireRight", HMSQT_MarineHUD, MHSS_Standard_Fire, ONE_FIXED);
 
 
2916
        FireRight->Active = 0;
 
 
2917
    }
 
 
2918
 
 
 
2919
    FireLeft = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft");
 
 
2920
 
 
 
2921
    if (FireLeft == NULL)
 
 
2922
    {
 
 
2923
        FireLeft = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft", HMSQT_MarineHUD, MHSS_Secondary_Fire, ONE_FIXED);
 
 
2924
        FireLeft->Active = 0;
 
 
2925
    }
 
 
2926
 
 
 
2927
    if (PlayerStatus.WeaponStateTimeOutCounter == ONE_FIXED)
 
 
2928
    {
 
 
2929
        int time = DIV_FIXED(ONE_FIXED, ONE_FIXED);
 
 
2930
 
 
 
2931
        assert(time != 0);
 
 
2932
 
 
 
2933
        InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Come, time);
 
 
2934
        PlayersWeaponHModelController.Looped = 0;
 
 
2935
 
 
 
2936
        int slot_marine_pistol = SlotForThisWeapon(WEAPON_MARINE_PISTOL);
 
 
2937
 
 
 
2938
        if(PlayerStatus.WeaponSlot[slot_marine_pistol].PrimaryRoundsRemaining)
 
 
2939
        {
 
 
2940
            if(PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining)
 
 
2941
            {
 
 
2942
                PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining = PlayerStatus.WeaponSlot[slot_marine_pistol].PrimaryRoundsRemaining;
 
 
2943
                PlayerStatus.WeaponSlot[slot_marine_pistol].PrimaryRoundsRemaining = 0;
 
 
2944
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 12;
 
 
2945
                PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining--;
 
 
2946
                PlayerStatus.SelectedWeapon->MagazinesRemaining = PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining;
 
 
2947
                PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining = 0;
 
 
2948
            }
 
 
2949
            else
 
 
2950
            {
 
 
2951
                PlayerStatus.WeaponSlot[slot_marine_pistol].PrimaryRoundsRemaining = PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
2952
                PlayerStatus.SwapToWeaponSlot = slot_marine_pistol;
 
 
2953
                PlayerStatus.PreviouslySelectedWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
2954
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
2955
            }
 
 
2956
        }
 
 
2957
        else if(PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining > 1)
 
 
2958
        {
 
 
2959
            PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining = 12;
 
 
2960
            PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining -= 2;
 
 
2961
            PlayerStatus.SelectedWeapon->MagazinesRemaining = PlayerStatus.WeaponSlot[slot_marine_pistol].MagazinesRemaining;
 
 
2962
        }
 
 
2963
        else
 
 
2964
        {
 
 
2965
            PlayerStatus.SwapToWeaponSlot = slot_marine_pistol;
 
 
2966
            PlayerStatus.PreviouslySelectedWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
2967
            PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
2968
        }
 
 
2969
    }
 
 
2970
 
 
 
2971
    RightHand = 1;
 
 
2972
}
 
 
2973
 
 
 
2974
void MarineTwoPistols_SecondaryFiring()
 
 
2975
{
 
 
2976
    DELTA_CONTROLLER *FireRight = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireRight");
 
 
2977
 
 
 
2978
    int firing = 0;
 
 
2979
 
 
 
2980
    if (FireRight == NULL)
 
 
2981
    {
 
 
2982
        FireRight = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireRight", HMSQT_MarineHUD, MHSS_Standard_Fire, ONE_FIXED);
 
 
2983
        FireRight->Active = 0;
 
 
2984
    }
 
 
2985
 
 
 
2986
    DELTA_CONTROLLER *FireLeft = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft");
 
 
2987
 
 
 
2988
    if (FireLeft == NULL)
 
 
2989
    {
 
 
2990
        FireLeft = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft", HMSQT_MarineHUD, MHSS_Secondary_Fire, ONE_FIXED);
 
 
2991
        FireLeft->Active = 0;
 
 
2992
    }
 
 
2993
 
 
 
2994
    if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2995
    {
 
 
2996
        if(--PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
2997
            Start_Delta_Sequence(FireRight, HMSQT_MarineHUD, MHSS_Standard_Fire, -1);
 
 
2998
        else
 
 
2999
            Start_Delta_Sequence(FireRight, HMSQT_MarineHUD, MHSS_Right_Out, -1);
 
 
3000
 
 
 
3001
        SECTION_DATA *casing = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum R Pistol round");
 
 
3002
 
 
 
3003
        if (casing)
 
 
3004
            MakePistolCasing(&casing->World_Offset, &casing->SecMat);
 
 
3005
 
 
 
3006
        firing = 1;
 
 
3007
    }
 
 
3008
 
 
 
3009
    if (PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
3010
    {
 
 
3011
        if (--PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
3012
            Start_Delta_Sequence(FireLeft, HMSQT_MarineHUD, MHSS_Secondary_Fire, -1);
 
 
3013
        else
 
 
3014
            Start_Delta_Sequence(FireLeft, HMSQT_MarineHUD, MHSS_Left_Out, -1);
 
 
3015
 
 
 
3016
        SECTION_DATA *casing = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum L Pistol round");
 
 
3017
 
 
 
3018
        if (casing)
 
 
3019
            MakePistolCasing(&casing->World_Offset, &casing->SecMat);
 
 
3020
 
 
 
3021
        firing = 1;
 
 
3022
    }
 
 
3023
 
 
 
3024
    //PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
3025
 
 
 
3026
    if(firing)
 
 
3027
    {
 
 
3028
        PlayerStatus.WeaponState = WEAPONSTATE_FIRING_SECONDARY;
 
 
3029
        AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
3030
        Sound_Play(SID_SHOTGUN, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
3031
        PlayerFireLineOfSightAmmo(AMMO_MARINE_PISTOL);
 
 
3032
        CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
3033
    }
 
 
3034
}
 
 
3035
 
 
 
3036
static void FireMarineTwoPistols()
 
 
3037
{
 
 
3038
    DELTA_CONTROLLER *FireRight = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireRight");
 
 
3039
    SECTION_DATA *casing;
 
 
3040
 
 
 
3041
    /* Deduce which pistol can fire, if either? */
 
 
3042
 
 
 
3043
    if (FireRight == NULL)
 
 
3044
    {
 
 
3045
        FireRight = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireRight", HMSQT_MarineHUD, MHSS_Standard_Fire, ONE_FIXED);
 
 
3046
        FireRight->Active = 0;
 
 
3047
    }
 
 
3048
 
 
 
3049
    DELTA_CONTROLLER *FireLeft = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft");
 
 
3050
 
 
 
3051
    if (FireLeft == NULL)
 
 
3052
    {
 
 
3053
        FireLeft = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft", HMSQT_MarineHUD, MHSS_Secondary_Fire, ONE_FIXED);
 
 
3054
        FireLeft->Active = 0;
 
 
3055
    }
 
 
3056
 
 
 
3057
    if (RightHand)
 
 
3058
    {
 
 
3059
        if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
3060
        {
 
 
3061
            RightHand = 0;
 
 
3062
            PWMFSDP = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum Flash");
 
 
3063
 
 
 
3064
            if (--PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
3065
                Start_Delta_Sequence(FireRight, HMSQT_MarineHUD, MHSS_Standard_Fire, -1);
 
 
3066
            else
 
 
3067
                Start_Delta_Sequence(FireRight, HMSQT_MarineHUD, MHSS_Right_Out, -1);
 
 
3068
        }
 
 
3069
 
 
 
3070
        casing = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum R Pistol round");
 
 
3071
    }
 
 
3072
    else
 
 
3073
    {
 
 
3074
        if (PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
3075
        {
 
 
3076
            RightHand = 1;
 
 
3077
            PWMFSDP = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum Flash L");
 
 
3078
 
 
 
3079
            if (--PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
3080
                Start_Delta_Sequence(FireLeft, HMSQT_MarineHUD, MHSS_Secondary_Fire, -1);
 
 
3081
            else
 
 
3082
                Start_Delta_Sequence(FireLeft, HMSQT_MarineHUD, MHSS_Left_Out, -1);
 
 
3083
        }
 
 
3084
 
 
 
3085
        casing = GetThisSectionData(PlayersWeaponHModelController.section_data, "Dum L Pistol round");
 
 
3086
    }
 
 
3087
 
 
 
3088
    PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
3089
    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
3090
 
 
 
3091
    MakePistolCasing(&casing->World_Offset, &casing->SecMat);
 
 
3092
    AddLightingEffectToObject(PlayerStatus.DisplayBlock, LFX_MUZZLEFLASH);
 
 
3093
    Sound_Play(SID_SHOTGUN, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
3094
 
 
 
3095
    PlayerFireLineOfSightAmmo(AMMO_MARINE_PISTOL);
 
 
3096
    CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
3097
}
 
 
3098
 
 
 
3099
void maintain_pistols()
 
 
3100
{
 
 
3101
    Weapon_ThisBurst = PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining;
 
 
3102
 
 
 
3103
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
3104
    {
 
 
3105
        case MHSS_Stationary:
 
 
3106
        case MHSS_Fidget:
 
 
3107
        {
 
 
3108
            if (!PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining && !PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining)
 
 
3109
            {
 
 
3110
                // Two pistols reloads BOTH primary and secondary.
 
 
3111
 
 
 
3112
                if (PlayerStatus.SelectedWeapon->MagazinesRemaining > 1)
 
 
3113
                {
 
 
3114
                    int time = DIV_FIXED(ONE_FIXED, 65536/3);
 
 
3115
                    time -= ONE_FIXED >> 4;
 
 
3116
 
 
 
3117
                    DELTA_CONTROLLER *FireRight = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireRight");
 
 
3118
                    DELTA_CONTROLLER *FireLeft = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft");
 
 
3119
                    FireRight->Active = 0;
 
 
3120
                    FireLeft->Active = 0;
 
 
3121
 
 
 
3122
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_MarineHUD, (int)MHSS_Standard_Reload, time, 0);
 
 
3123
                    PlayersWeaponHModelController.Looped = 0;
 
 
3124
                    PlayerStatus.WeaponStateTimeOutCounter = time;
 
 
3125
                    return;
 
 
3126
                }
 
 
3127
                else
 
 
3128
                {
 
 
3129
                    PlayerStatus.SwapToWeaponSlot = SlotForThisWeapon(WEAPON_MARINE_PISTOL);
 
 
3130
                    PlayerStatus.PreviouslySelectedWeaponSlot = PlayerStatus.SelectedWeaponSlot;
 
 
3131
                    PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_OUT;
 
 
3132
                    return;
 
 
3133
                }
 
 
3134
            }
 
 
3135
            else if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon && PlayerStatus.WeaponStateTimeOutCounter)
 
 
3136
            {
 
 
3137
                FireMarineTwoPistols();
 
 
3138
            }
 
 
3139
            else if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && PlayerStatus.WeaponStateTimeOutCounter)
 
 
3140
            {
 
 
3141
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Tertiary_Fire, -1, 0);
 
 
3142
                PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED >> 3;
 
 
3143
                return;
 
 
3144
            }
 
 
3145
            else
 
 
3146
            {
 
 
3147
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
3148
            }
 
 
3149
 
 
 
3150
            PlayerStatus.WeaponStateTimeOutCounter = !PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon;
 
 
3151
        }
 
 
3152
        break;
 
 
3153
        case MHSS_Standard_Reload:
 
 
3154
        {
 
 
3155
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
3156
             {
 
 
3157
                if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
3158
                {
 
 
3159
                    PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 12;
 
 
3160
                    PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
3161
                }
 
 
3162
 
 
 
3163
                if (PlayerStatus.SelectedWeapon->MagazinesRemaining)
 
 
3164
                {
 
 
3165
                    PlayerStatus.SelectedWeapon->SecondaryRoundsRemaining = 12;
 
 
3166
                    PlayerStatus.SelectedWeapon->MagazinesRemaining--;
 
 
3167
                }
 
 
3168
 
 
 
3169
                /* Pistol infinite ammo hack? */
 
 
3170
                if ((SinglePlayer != AvP.PlayMode) && netGameData.pistolInfiniteAmmo)
 
 
3171
                    PlayerStatus.SelectedWeapon->MagazinesRemaining += 2;
 
 
3172
 
 
 
3173
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 1), HMSQT_MarineHUD, (int)MHSS_Stationary, -1, 0);
 
 
3174
            }
 
 
3175
            else
 
 
3176
            {
 
 
3177
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3178
            }
 
 
3179
        }
 
 
3180
        break;
 
 
3181
    /*
 
 
3182
        case MHSS_Standard_Fire:
 
 
3183
        case MHSS_Secondary_Fire:
 
 
3184
        {
 
 
3185
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3186
 
 
 
3187
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
3188
            {
 
 
3189
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
3190
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 2), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
3191
            }
 
 
3192
        }
 
 
3193
        break;
 
 
3194
    */
 
 
3195
        case MHSS_Left_Out:
 
 
3196
        case MHSS_Right_Out:
 
 
3197
        break;
 
 
3198
        case MHSS_Tertiary_Fire:
 
 
3199
        {
 
 
3200
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
3201
            {
 
 
3202
                MarineTwoPistols_SecondaryFiring();
 
 
3203
 
 
 
3204
                if(!PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
3205
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 1), HMSQT_MarineHUD, (int)MHSS_Stationary, -1, 0);
 
 
3206
                else
 
 
3207
                    PlayerStatus.WeaponStateTimeOutCounter = PISTOL_RECOIL / 2;
 
 
3208
            }
 
 
3209
            else
 
 
3210
            {
 
 
3211
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3212
            }
 
 
3213
        }
 
 
3214
        break;
 
 
3215
        default:
 
 
3216
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
3217
            {
 
 
3218
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
3219
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 1), HMSQT_MarineHUD, (int)MHSS_Stationary, -1, 0);
 
 
3220
            }
 
 
3221
    }
 
 
3222
}
 
 
3223
 
 
 
3224
void MarineTwoPistols_Fidget()
 
 
3225
{
 
 
3226
    DELTA_CONTROLLER *FireLeft;
 
 
3227
    DELTA_CONTROLLER *FireRight = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireRight");
 
 
3228
 
 
 
3229
    if (FireRight == NULL)
 
 
3230
    {
 
 
3231
        FireRight = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireRight", HMSQT_MarineHUD, MHSS_Standard_Fire, ONE_FIXED);
 
 
3232
        FireRight->Active = 0;
 
 
3233
    }
 
 
3234
 
 
 
3235
    FireLeft = Get_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft");
 
 
3236
 
 
 
3237
    if (FireLeft == NULL)
 
 
3238
    {
 
 
3239
        FireLeft = Add_Delta_Sequence(&PlayersWeaponHModelController, "FireLeft", HMSQT_MarineHUD, MHSS_Secondary_Fire, ONE_FIXED);
 
 
3240
        FireLeft->Active = 0;
 
 
3241
    }
 
 
3242
 
 
 
3243
    if (!DeltaAnimation_IsFinished(FireRight))
 
 
3244
    {
 
 
3245
        /* Just leave it alone... */
 
 
3246
        return;
 
 
3247
    }
 
 
3248
 
 
 
3249
    /* If we're in Tertiary Fire, leave it alone for a moment. */
 
 
3250
    if (PlayersWeaponHModelController.Sub_Sequence == MHSS_Tertiary_Fire)
 
 
3251
    {
 
 
3252
        if (PlayersWeaponHModelController.Tweening)
 
 
3253
            return;
 
 
3254
 
 
 
3255
        if (PlayerStatus.WeaponStateTimeOutCounter < (ONE_FIXED >> 2))
 
 
3256
            return;
 
 
3257
    }
 
 
3258
 
 
 
3259
    if ((PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary) && (PlayersWeaponHModelController.Sub_Sequence != MHSS_Fidget))
 
 
3260
    {
 
 
3261
        if (PlayersWeaponHModelController.Sub_Sequence == MHSS_Tertiary_Fire)
 
 
3262
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>1), HMSQT_MarineHUD, (int)MHSS_Stationary, -1, 0);
 
 
3263
        else
 
 
3264
            InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
3265
    }
 
 
3266
 
 
 
3267
    marine_weapon_idle();
 
 
3268
}
 
 
3269
 
 
 
3270
#define FRISBEE_RECOIL ((65536*2000)/1625)
 
 
3271
#define FRISBEE_RELOAD 65536
 
 
3272
 
 
 
3273
void maintain_frisbee()
 
 
3274
{
 
 
3275
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
3276
    {
 
 
3277
        case MHSS_Stationary:
 
 
3278
        case MHSS_Fidget:
 
 
3279
        {
 
 
3280
            if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
3281
            {
 
 
3282
                if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
3283
                {
 
 
3284
                    if(PlayerStatus.WeaponStateTimeOutCounter) // this stops atomatic fire
 
 
3285
                    {
 
 
3286
                        PlayerStatus.WeaponStateTimeOutCounter = FRISBEE_RECOIL;
 
 
3287
                        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Secondary_Fire, -1, 0);
 
 
3288
                    }
 
 
3289
                }
 
 
3290
                else
 
 
3291
                {
 
 
3292
                    PlayerStatus.WeaponStateTimeOutCounter = FRISBEE_RECOIL;
 
 
3293
 
 
 
3294
                    marine_weapon_idle();
 
 
3295
                }
 
 
3296
            }
 
 
3297
            else
 
 
3298
            {
 
 
3299
                MarineZeroAmmoFunctionality();
 
 
3300
            }
 
 
3301
        }
 
 
3302
        break;
 
 
3303
        case MHSS_Standard_Fire:
 
 
3304
        {
 
 
3305
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3306
 
 
 
3307
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
3308
            {
 
 
3309
                if (PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
3310
                {
 
 
3311
                    PlayerStatus.WeaponStateTimeOutCounter = FRISBEE_RELOAD;
 
 
3312
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Standard_Reload, FRISBEE_RELOAD,
0);
 
 
3313
                }
 
 
3314
                else
 
 
3315
                {
 
 
3316
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
3317
                }
 
 
3318
            }
 
 
3319
        }
 
 
3320
        break;
 
 
3321
        case MHSS_Secondary_Fire:
 
 
3322
        {
 
 
3323
            if (PlayerStatus.WeaponStateTimeOutCounter > 0)
 
 
3324
            {
 
 
3325
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3326
            }
 
 
3327
            else
 
 
3328
            {
 
 
3329
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 6), HMSQT_MarineHUD, (int)MHSS_Standard_Fire, -1, 0);
 
 
3330
                PlayersWeaponHModelController.Looped = 0;
 
 
3331
                PlayerStatus.WeaponStateTimeOutCounter = FRISBEE_RECOIL;
 
 
3332
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
3333
                CreateFrisbeeKernel(&PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat, 1);
 
 
3334
                CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
3335
            }
 
 
3336
        }
 
 
3337
        break;
 
 
3338
        case MHSS_Standard_Reload:
 
 
3339
        {
 
 
3340
            PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
3341
 
 
 
3342
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
3343
            {
 
 
3344
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 3), HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED, 1);
 
 
3345
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
3346
            }
 
 
3347
        }
 
 
3348
        break;
 
 
3349
        default:
 
 
3350
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
3351
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Stationary, ONE_FIXED);
 
 
3352
    }
 
 
3353
}
 
 
3354
 
 
 
3355
static void PlayCudgelSound() 
 
 
3356
{
 
 
3357
    extern int oldRandomValue;
 
 
3358
 
 
 
3359
    int rand = FastRandom() % 4;
 
 
3360
 
 
 
3361
    if (rand == oldRandomValue)
 
 
3362
        rand = (rand + 1) % 4;
 
 
3363
 
 
 
3364
    oldRandomValue = rand;
 
 
3365
 
 
 
3366
    switch (rand)
 
 
3367
    {
 
 
3368
        case 0:
 
 
3369
              Sound_Play(SID_PULSE_SWIPE01, "ehp", &weaponHandle, (FastRandom()&255)-128);                    
 
 
3370
          break;
 
 
3371
          case 1:
 
 
3372
              Sound_Play(SID_PULSE_SWIPE02, "ehp", &weaponHandle, (FastRandom()&255)-128);                    
 
 
3373
          break;
 
 
3374
          case 2:
 
 
3375
               Sound_Play(SID_PULSE_SWIPE03, "ehp", &weaponHandle, (FastRandom()&255)-128);                    
 
 
3376
             break;
 
 
3377
        case 3:
 
 
3378
              Sound_Play(SID_PULSE_SWIPE04, "ehp", &weaponHandle, (FastRandom()&255)-128);                    
 
 
3379
         default:
 
 
3380
             break;
 
 
3381
    }
 
 
3382
}
 
 
3383
 
 
 
3384
static void GoGoGadgetCudgelPrimaryAttackAnimation()
 
 
3385
{
 
 
3386
    /* Standard_Fire is the default. */
 
 
3387
 
 
 
3388
    if ((FastRandom() & 65535) < 21645)
 
 
3389
    {
 
 
3390
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Standard_Fire))
 
 
3391
        {
 
 
3392
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_MarineHUD, (int)MHSS_Standard_Fire, -1, 0);
 
 
3393
 
 
 
3394
            StaffAttack = !PlayerStatus.Crouching;
 
 
3395
 
 
 
3396
        return;
 
 
3397
        }
 
 
3398
    }
 
 
3399
 
 
 
3400
    if ((FastRandom() & 65535) < 32767)
 
 
3401
    {
 
 
3402
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_MarineHUD, (int)MHSS_Secondary_Fire))
 
 
3403
        {
 
 
3404
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_MarineHUD, (int)MHSS_Secondary_Fire, -1, 0);
 
 
3405
 
 
 
3406
            StaffAttack = PlayerStatus.Crouching ?  2 : 3;
 
 
3407
        return;
 
 
3408
        }
 
 
3409
    }
 
 
3410
 
 
 
3411
    /* Still here? Use default. */
 
 
3412
 
 
 
3413
    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_MarineHUD, (int)MHSS_Standard_Fire, -1, 0);
 
 
3414
 
 
 
3415
    StaffAttack = !PlayerStatus.Crouching;
 
 
3416
}
 
 
3417
 
 
 
3418
static enum
 
 
3419
{
 
 
3420
    HAM_Centre = 0,
 
 
3421
    HAM_Front,
 
 
3422
    HAM_Back,
 
 
3423
    HAM_Top,
 
 
3424
    HAM_Base,
 
 
3425
    HAM_Left,
 
 
3426
    HAM_Right,
 
 
3427
    HAM_TopLeft,
 
 
3428
    HAM_TopRight,
 
 
3429
    HAM_BaseLeft,
 
 
3430
    HAM_BaseRight,
 
 
3431
    HAM_end
 
 
3432
 
 
 
3433
} HitZone, HitAspect;
 
 
3434
 
 
 
3435
static const VECTORCH HitAreaArray[HAM_end] =
 
 
3436
{
 
 
3437
    {0,0,0},
 
 
3438
    {0,0,1000},
 
 
3439
    {0,0,-1000},
 
 
3440
    {0,-1000,0},
 
 
3441
    {0,1000,0},
 
 
3442
    {-1000,0,0},
 
 
3443
    {1000,0,0},
 
 
3444
    {-1000,-1000,0},
 
 
3445
    {1000,-1000,0},
 
 
3446
    {-1000,1000,0},
 
 
3447
    {1000,1000,0},    
 
 
3448
};
 
 
3449
 
 
 
3450
static void FindHitArea(DISPLAYBLOCK *dptr) 
 
 
3451
{
 
 
3452
    int a;
 
 
3453
    int nearest = -1;
 
 
3454
    int fbnearest = -1;
 
 
3455
    int neardist = 1000000;
 
 
3456
    int fbneardist = 1000000;
 
 
3457
    VECTORCH Local_HitAreaArray[HAM_end];
 
 
3458
    MATRIXCH LtoV; 
 
 
3459
 
 
 
3460
    MatrixMultiply(&Global_VDB.VDB_Mat, &dptr->ObMat, &LtoV);
 
 
3461
 
 
 
3462
    for (a=0; a < HAM_end; a++)
 
 
3463
    {
 
 
3464
        RotateAndCopyVector(&HitAreaArray[a], &Local_HitAreaArray[a], &LtoV);
 
 
3465
 
 
 
3466
        Local_HitAreaArray[a].vx += dptr->ObView.vx;
 
 
3467
        Local_HitAreaArray[a].vy += dptr->ObView.vy;
 
 
3468
        Local_HitAreaArray[a].vz += dptr->ObView.vz;
 
 
3469
 
 
 
3470
        int dist = Approximate3dMagnitude(&Local_HitAreaArray[a]);
 
 
3471
 
 
 
3472
        if ( (a != HAM_Front) && (a != HAM_Back) )
 
 
3473
        {
 
 
3474
            if (dist < neardist)
 
 
3475
            {
 
 
3476
                nearest = a;
 
 
3477
                neardist = dist;
 
 
3478
            }
 
 
3479
        } 
 
 
3480
 
 
 
3481
        if ( (a == HAM_Front) || (a == HAM_Back) || (a == HAM_Centre) )
 
 
3482
        {
 
 
3483
            if (dist < fbneardist)
 
 
3484
            {
 
 
3485
                fbnearest = a;
 
 
3486
                fbneardist = dist;
 
 
3487
            }
 
 
3488
        }
 
 
3489
    }
 
 
3490
 
 
 
3491
    assert(nearest != -1);
 
 
3492
    assert( (fbnearest == HAM_Front) || (fbnearest == HAM_Back) || (fbnearest == HAM_Centre) );
 
 
3493
 
 
 
3494
    HitZone = nearest;
 
 
3495
    HitAspect = fbnearest;
 
 
3496
 
 
 
3497
    switch(nearest)
 
 
3498
    {
 
 
3499
        case HAM_Centre:
 
 
3500
            printf("Nearest = Centre\n");
 
 
3501
        break;
 
 
3502
        case HAM_Top:
 
 
3503
            printf("Nearest = Top\n");
 
 
3504
        break;
 
 
3505
        case HAM_Base:
 
 
3506
            printf("Nearest = Base\n");
 
 
3507
        break;
 
 
3508
        case HAM_Left:
 
 
3509
            printf("Nearest = Left\n");
 
 
3510
        break;
 
 
3511
        case HAM_Right:
 
 
3512
            printf("Nearest = Right\n");
 
 
3513
        break;
 
 
3514
        case HAM_TopLeft:
 
 
3515
            printf("Nearest = TopLeft\n");
 
 
3516
        break;
 
 
3517
        case HAM_TopRight:
 
 
3518
            printf("Nearest = TopRight\n");
 
 
3519
        break;
 
 
3520
        case HAM_BaseLeft:
 
 
3521
            printf("Nearest = BaseLeft\n");
 
 
3522
        break;
 
 
3523
        case HAM_BaseRight:
 
 
3524
            printf("Nearest = BaseRight\n");
 
 
3525
        break;
 
 
3526
        default:
 
 
3527
            assert(0);
 
 
3528
    }
 
 
3529
 
 
 
3530
    switch (fbnearest)
 
 
3531
    {
 
 
3532
        case HAM_Centre:
 
 
3533
            printf("Aspect Centre\n");
 
 
3534
        break;
 
 
3535
        case HAM_Front:
 
 
3536
            printf("Aspect Front\n");
 
 
3537
        break;
 
 
3538
        case HAM_Back:
 
 
3539
            printf("Aspect Back\n");
 
 
3540
    }
 
 
3541
}
 
 
3542
 
 
 
3543
HITLOCATIONTABLE *GetThisHitLocationTable(char *id) 
 
 
3544
{
 
 
3545
    int a=0;
 
 
3546
    extern HITLOCATIONTABLE Global_Hitlocation_Tables[];
 
 
3547
 
 
 
3548
    while (Global_Hitlocation_Tables[a].id != NULL) 
 
 
3549
    {
 
 
3550
        if (!strcmp(id,Global_Hitlocation_Tables[a].id)) 
 
 
3551
            return(&Global_Hitlocation_Tables[a]);
 
 
3552
        a++;
 
 
3553
    }
 
 
3554
 
 
 
3555
return NULL;
 
 
3556
}
 
 
3557
 
 
 
3558
static HITLOCATIONTABLEENTRY *Get_Sublocation(STRATEGYBLOCK *sbPtr) 
 
 
3559
{
 
 
3560
    HITLOCATIONTABLE *hltable = NULL;
 
 
3561
 
 
 
3562
    /* Identify table... */
 
 
3563
    switch (sbPtr->type)
 
 
3564
    {
 
 
3565
        case I_BehaviourAlienPlayer:
 
 
3566
            hltable = GetThisHitLocationTable("alien");
 
 
3567
        break;
 
 
3568
case I_BehaviourMarinePlayer: // jadda fix this
 
 
3569
break;
 
 
3570
case I_BehaviourPredatorPlayer:
 
 
3571
break;
 
 
3572
        case I_BehaviourMarine:
 
 
3573
        {
 
 
3574
            MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3575
 
 
 
3576
            hltable = GetThisHitLocationTable(marineStatusPointer->My_Weapon->HitLocationTableName);            
 
 
3577
        }
 
 
3578
        break;
 
 
3579
        case I_BehaviourAlien:
 
 
3580
        {
 
 
3581
            ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3582
 
 
 
3583
            switch (alienStatusPointer->Type)
 
 
3584
            {
 
 
3585
                case Standard:
 
 
3586
                default:
 
 
3587
                    hltable = GetThisHitLocationTable("alien");
 
 
3588
                break;
 
 
3589
                case Predalien:
 
 
3590
                    hltable = GetThisHitLocationTable("predalien");
 
 
3591
                break;
 
 
3592
                case Praetorian:
 
 
3593
                    hltable = GetThisHitLocationTable("praetorian");
 
 
3594
            }
 
 
3595
        }
 
 
3596
        break;
 
 
3597
        case I_BehaviourPredator:
 
 
3598
        {
 
 
3599
            PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3600
 
 
 
3601
            hltable = GetThisHitLocationTable(predatorStatusPointer->Selected_Weapon->HitLocationTableName);
 
 
3602
        }
 
 
3603
        break;
 
 
3604
        case I_BehaviourXenoborg:
 
 
3605
            hltable = GetThisHitLocationTable("xenoborg");
 
 
3606
        break;
 
 
3607
        case I_BehaviourAutoGun:
 
 
3608
            hltable = GetThisHitLocationTable("sentrygun");
 
 
3609
        break;
 
 
3610
        case I_BehaviourCorpse:
 
 
3611
        {
 
 
3612
            CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)(sbPtr->dataptr);    
 
 
3613
 
 
 
3614
            hltable = corpseDataPtr->hltable;
 
 
3615
            /* Special corpse case. */
 
 
3616
            HitZone = HAM_Centre;
 
 
3617
            HitAspect = HAM_Centre;
 
 
3618
        }
 
 
3619
        break;
 
 
3620
        case I_BehaviourNetGhost:
 
 
3621
        {
 
 
3622
            NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr;
 
 
3623
            hltable = ghostData->hltable;
 
 
3624
 
 
 
3625
            if(ghostData->type == I_BehaviourCorpse)    
 
 
3626
            {
 
 
3627
                //special corpse case here as well , I should imagine
 
 
3628
                HitZone = HAM_Centre;
 
 
3629
                HitAspect = HAM_Centre;
 
 
3630
            }
 
 
3631
        }
 
 
3632
        break;
 
 
3633
        default:
 
 
3634
            printf("No hit table!\n");
 
 
3635
            return NULL;
 
 
3636
            /* See ChrisF */
 
 
3637
    }
 
 
3638
 
 
 
3639
    if (hltable == NULL)
 
 
3640
    {
 
 
3641
        /* Hey ho... */
 
 
3642
        return NULL;
 
 
3643
    }
 
 
3644
 
 
 
3645
    /* Now the fun bit. */
 
 
3646
    int dice = FastRandom() & 65535;
 
 
3647
 
 
 
3648
    HITLOCATIONTABLEENTRY *subtable;
 
 
3649
 
 
 
3650
    switch (HitZone)
 
 
3651
    {
 
 
3652
        case HAM_Centre:
 
 
3653
            subtable = hltable->CentreLocs;
 
 
3654
        break;
 
 
3655
        case HAM_Top:
 
 
3656
            subtable = hltable->TopLocs;
 
 
3657
        break;
 
 
3658
        case HAM_Base:
 
 
3659
            subtable = hltable->BaseLocs;
 
 
3660
        break;
 
 
3661
        case HAM_Left:
 
 
3662
            subtable = hltable->LeftLocs;
 
 
3663
        break;
 
 
3664
        case HAM_Right:
 
 
3665
            subtable = hltable->RightLocs;
 
 
3666
        break;
 
 
3667
        case HAM_TopLeft:
 
 
3668
            subtable = hltable->TopLeftLocs;
 
 
3669
        break;
 
 
3670
        case HAM_TopRight:
 
 
3671
            subtable = hltable->TopRightLocs;
 
 
3672
        break;
 
 
3673
        case HAM_BaseLeft:
 
 
3674
            subtable = hltable->BaseLeftLocs;
 
 
3675
        break;
 
 
3676
        case HAM_BaseRight:
 
 
3677
            subtable = hltable->BaseRightLocs;
 
 
3678
        break;
 
 
3679
        default:
 
 
3680
            assert(0);
 
 
3681
            return NULL;
 
 
3682
    }
 
 
3683
 
 
 
3684
    /* Now, get location. */
 
 
3685
 
 
 
3686
    HITLOCATIONTABLEENTRY *entry = subtable;
 
 
3687
 
 
 
3688
    while (entry->section_name != NULL)
 
 
3689
    {
 
 
3690
        if (dice < entry->cprob)
 
 
3691
        {
 
 
3692
            if (!( ( (HitAspect == HAM_Front) && (entry->aspect & back_aspect) )
 
 
3693
                ||( (HitAspect == HAM_Back) && (entry->aspect & front_aspect) ) ))
 
 
3694
            {
 
 
3695
                /* Okay! */
 
 
3696
                break;
 
 
3697
            }
 
 
3698
        }
 
 
3699
 
 
 
3700
        dice -= entry->cprob;
 
 
3701
        entry++;
 
 
3702
    }
 
 
3703
 
 
 
3704
return entry;
 
 
3705
}
 
 
3706
 
 
 
3707
DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir) 
 
 
3708
{
 
 
3709
    if (NULL != sbPtr->DisplayBlock)
 
 
3710
    {
 
 
3711
        if ((source == NULL) || (source == PlayerStatus.sbptr))
 
 
3712
        {
 
 
3713
            FindHitArea(sbPtr->DisplayBlock);
 
 
3714
        }
 
 
3715
        else
 
 
3716
        {
 
 
3717
            HitZone = HAM_Top;
 
 
3718
            HitAspect = HAM_Centre;
 
 
3719
        }
 
 
3720
 
 
 
3721
        HITLOCATIONTABLEENTRY *entry = Get_Sublocation(sbPtr);
 
 
3722
 
 
 
3723
        if ((NULL != entry) && entry->section_name)
 
 
3724
        {
 
 
3725
            /* Valid hit. */
 
 
3726
            SECTION_DATA *target = GetThisSectionData(sbPtr->DisplayBlock->HModelControlBlock->section_data, entry->section_name);
 
 
3727
 
 
 
3728
            if (target)
 
 
3729
            {
 
 
3730
                /* Success! */
 
 
3731
                //printf("Damaged %s!\n", entry->section_name);
 
 
3732
                return CauseDamageToHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr, damage, multiple, target, attack_dir, NULL, 0);
 
 
3733
            }
 
 
3734
        }
 
 
3735
    }
 
 
3736
 
 
 
3737
    /* Far case?  Hey ho... */
 
 
3738
    /* Failure!  Never mind. */
 
 
3739
 
 
 
3740
    CauseDamageToObject(sbPtr, damage, multiple,attack_dir);
 
 
3741
 
 
 
3742
return NULL;
 
 
3743
}
 
 
3744
 
 
 
3745
static int MeleeWeapon_90Degree_Front_Core(const DAMAGE_PROFILE *damage, int range, int wristblade_secondary_strong)
 
 
3746
{
 
 
3747
    int numberOfObjects = numVisObjs;
 
 
3748
    int numhits = 0;
 
 
3749
 
 
 
3750
    while (numberOfObjects--)
 
 
3751
    {
 
 
3752
        DISPLAYBLOCK* objectPtr = VisibleObjects[numberOfObjects].DispPtr;
 
 
3753
        VECTORCH targetpos,targetposW;
 
 
3754
        STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
 
 
3755
 
 
 
3756
        /* does object have a strategy block? */
 
 
3757
        if (sbPtr)
 
 
3758
        {        
 
 
3759
            GetTargetingPointOfObject(objectPtr,&targetpos);
 
 
3760
            targetposW = targetpos;
 
 
3761
            targetpos.vx -= Global_VDB.VDB_World.vx;
 
 
3762
            targetpos.vy -= Global_VDB.VDB_World.vy;
 
 
3763
            targetpos.vz -= Global_VDB.VDB_World.vz;
 
 
3764
            RotateVector(&targetpos,&Global_VDB.VDB_Mat);
 
 
3765
 
 
 
3766
            /* is it in the frustrum? */
 
 
3767
            if ( (targetpos.vz > 0) 
 
 
3768
                && (targetpos.vz >  targetpos.vx) 
 
 
3769
                && (targetpos.vz > -targetpos.vx) 
 
 
3770
                && (targetpos.vz >  targetpos.vy) 
 
 
3771
                && (targetpos.vz > -targetpos.vy) )
 
 
3772
                {
 
 
3773
 
 
 
3774
                int dist = Approximate3dMagnitude(&targetpos);
 
 
3775
 
 
 
3776
                /* HACKAHACKAHACKA */
 
 
3777
 
 
 
3778
                if (objectPtr->HModelControlBlock == NULL)
 
 
3779
                    dist -= objectPtr->extent.radius >> 1;
 
 
3780
 
 
 
3781
                if (dist < range)
 
 
3782
                {
 
 
3783
                    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
3784
 
 
 
3785
                        if (dynPtr)
 
 
3786
                    {
 
 
3787
                        if (IsThisObjectVisibleFromThisPosition_WithIgnore(PlayerStatus.DisplayBlock, objectPtr, &targetposW))
 
 
3788
                        {
 
 
3789
                            int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
 
 
3790
                                dynPtr->LinImpulse.vx += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat31, magnitudeOfForce);
 
 
3791
                            dynPtr->LinImpulse.vy += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat32, magnitudeOfForce);
 
 
3792
                                dynPtr->LinImpulse.vz += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat33, magnitudeOfForce);
 
 
3793
                              /* Consider player's target. */
 
 
3794
 
 
 
3795
                            /* Consider target aspect. */
 
 
3796
                            {
 
 
3797
                                int real_multiple = ONE_FIXED;
 
 
3798
                                VECTORCH attack_dir,displacement;
 
 
3799
 
 
 
3800
                                displacement.vx = dynPtr->Position.vx - PlayerStatus.sbptr->DynPtr->Position.vx;
 
 
3801
                                displacement.vy = dynPtr->Position.vy - PlayerStatus.sbptr->DynPtr->Position.vy;
 
 
3802
                                displacement.vz = dynPtr->Position.vz - PlayerStatus.sbptr->DynPtr->Position.vz;
 
 
3803
 
 
 
3804
                                GetDirectionOfAttack(sbPtr, &displacement, &attack_dir);
 
 
3805
 
 
 
3806
                                if (attack_dir.vz > 0)
 
 
3807
                                    real_multiple <<= 1;
 
 
3808
 
 
 
3809
                                if (sbPtr->DisplayBlock->HModelControlBlock)
 
 
3810
                                {
 
 
3811
                                    if(wristblade_secondary_strong && (sbPtr->type == I_BehaviourAlien))
 
 
3812
                                    {
 
 
3813
                                        ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
3814
 
 
 
3815
                                        if((Standard == alienStatusPointer->Type) && !alienStatusPointer->IAmCrouched && ((FastRandom()
& 65535) < 3000))
 
 
3816
                                        {
 
 
3817
                                        InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 5), (int)HMSQT_AlienStand,
(int)ASSS_Boom_Fall_Back, -1, 0);
 
 
3818
                                        alienStatusPointer->unconscious = ONE_FIXED * 5 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
3819
                                        }
 
 
3820
                                        else
 
 
3821
                                        {
 
 
3822
                                            SECTION_DATA *chest = GetThisSectionData(sbPtr->DisplayBlock->HModelControlBlock->section_data,
"head");
 
 
3823
                                            CauseDamageToHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr, damage, real_multiple, chest,
&attack_dir, NULL, 0);
 
 
3824
                                        }
 
 
3825
                                    }
 
 
3826
                                    else
 
 
3827
                                    {
 
 
3828
                                        HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir);
 
 
3829
                                    }
 
 
3830
                                }
 
 
3831
                                else
 
 
3832
                                {
 
 
3833
                                    CauseDamageToObject(sbPtr, damage, real_multiple, &attack_dir);
 
 
3834
                                }
 
 
3835
                            }
 
 
3836
 
 
 
3837
                            numhits++;
 
 
3838
                        }
 
 
3839
                    }
 
 
3840
                  }
 
 
3841
            }
 
 
3842
        }
 
 
3843
    }
 
 
3844
 
 
 
3845
return numhits;
 
 
3846
}
 
 
3847
 
 
 
3848
void maintain_cudgel()
 
 
3849
{
 
 
3850
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
3851
    {
 
 
3852
        case MHSS_Stationary:
 
 
3853
        case MHSS_Fidget:
 
 
3854
        {
 
 
3855
            StaffAttack = -1;
 
 
3856
 
 
 
3857
            if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
3858
                GoGoGadgetCudgelPrimaryAttackAnimation();
 
 
3859
            else
 
 
3860
            {
 
 
3861
                MarineZeroAmmoFunctionality();
 
 
3862
                marine_weapon_idle();
 
 
3863
            }
 
 
3864
        }
 
 
3865
        break;
 
 
3866
        case MHSS_Standard_Fire:
 
 
3867
        case MHSS_Secondary_Fire:
 
 
3868
        {
 
 
3869
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
3870
            {
 
 
3871
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_MarineHUD, MHSS_Stationary, ONE_FIXED, 1);
 
 
3872
            }
 
 
3873
            else if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
3874
            {
 
 
3875
                MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AMMO_CUDGEL].MaxDamage, 2500, 0);
 
 
3876
                PlayCudgelSound();
 
 
3877
            }
 
 
3878
        }
 
 
3879
        break;
 
 
3880
        default:
 
 
3881
            if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Stationary)
 
 
3882
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_MarineHUD, MHSS_Stationary, ONE_FIXED, 1);
 
 
3883
    }
 
 
3884
}
 
 
3885
 
 
 
3886
void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr)
 
 
3887
{
 
 
3888
    VECTORCH XVector;
 
 
3889
    VECTORCH YVector;
 
 
3890
 
 
 
3891
       if (!directionPtr->vx)
 
 
3892
    {
 
 
3893
        XVector.vx = 65536;
 
 
3894
        XVector.vy = 0;
 
 
3895
        XVector.vz = 0;
 
 
3896
    }
 
 
3897
    else if (!directionPtr->vy)
 
 
3898
    {
 
 
3899
        XVector.vx = 0;
 
 
3900
        XVector.vy = 65536;
 
 
3901
        XVector.vz = 0;
 
 
3902
    }
 
 
3903
    else if (!directionPtr->vz)
 
 
3904
    {
 
 
3905
        XVector.vx = 0;
 
 
3906
        XVector.vy = 0;
 
 
3907
        XVector.vz = 65536;
 
 
3908
    }
 
 
3909
    else
 
 
3910
    {
 
 
3911
        XVector.vx = directionPtr->vz;
 
 
3912
        XVector.vy = 0;
 
 
3913
        XVector.vz = -directionPtr->vx;
 
 
3914
        Normalise(&XVector);
 
 
3915
    }
 
 
3916
 
 
 
3917
    CrossProduct(directionPtr, &XVector, &YVector);
 
 
3918
 
 
 
3919
    matrixPtr->mat11 = XVector.vx;
 
 
3920
    matrixPtr->mat12 = XVector.vy;
 
 
3921
    matrixPtr->mat13 = XVector.vz;
 
 
3922
 
 
 
3923
    matrixPtr->mat21 = YVector.vx;
 
 
3924
    matrixPtr->mat22 = YVector.vy;
 
 
3925
    matrixPtr->mat23 = YVector.vz;
 
 
3926
 
 
 
3927
    matrixPtr->mat31 = directionPtr->vx;
 
 
3928
    matrixPtr->mat32 = directionPtr->vy;
 
 
3929
    matrixPtr->mat33 = directionPtr->vz;
 
 
3930
}
 
 
3931
 
 
 
3932
static void LimbRip_AwardHealth() 
 
 
3933
{
 
 
3934
    int health_bonus;
 
 
3935
    const NPC_DATA *NpcData = &NpcDataList[I_PC_Alien_MaxStats];
 
 
3936
 
 
 
3937
    switch (AvP.Difficulty)
 
 
3938
    {
 
 
3939
        case I_Easy:
 
 
3940
            health_bonus = 5;
 
 
3941
        break;
 
 
3942
        case I_Medium:
 
 
3943
        default:
 
 
3944
            health_bonus = 2;
 
 
3945
        break;
 
 
3946
        case I_Hard:
 
 
3947
            health_bonus = 1;
 
 
3948
    }
 
 
3949
 
 
 
3950
    /* Now add some health. */
 
 
3951
    PlayerStatus.sbptr->DamageBlock.Health += health_bonus << ONE_FIXED_SHIFT;
 
 
3952
 
 
 
3953
    if (PlayerStatus.sbptr->DamageBlock.Health > NpcData->StartingStats.Health << ONE_FIXED_SHIFT)
 
 
3954
    {
 
 
3955
        PlayerStatus.sbptr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
3956
    }
 
 
3957
 
 
 
3958
    PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
3959
}
 
 
3960
 
 
 
3961
const int tail_xcal = 120;
 
 
3962
const int tail_ycal = 220;
 
 
3963
 
 
 
3964
static void ComputeTailDeltaValues(DELTA_CONTROLLER *XDelta, DELTA_CONTROLLER *YDelta) 
 
 
3965
{
 
 
3966
    VECTORCH target_pos;
 
 
3967
 
 
 
3968
    GetTargetingPointOfObject(Alien_Tail_Target->DisplayBlock, &target_pos);
 
 
3969
    TranslatePointIntoViewspace(&target_pos);
 
 
3970
    int screenX = WideMulNarrowDiv (target_pos.vx, Global_VDB.VDB_ProjX, target_pos.vz );
 
 
3971
    int screenY = WideMulNarrowDiv (target_pos.vy, Global_VDB.VDB_ProjY, target_pos.vz );
 
 
3972
 
 
 
3973
    if (CHEATMODE_MIRROR == UserProfile.active_bonus)
 
 
3974
        screenX = -screenX;
 
 
3975
 
 
 
3976
    int temp_timer = screenX * -tail_xcal;
 
 
3977
    temp_timer += 32767;
 
 
3978
 
 
 
3979
    if (temp_timer < 0)
 
 
3980
        temp_timer = 0;
 
 
3981
    else if (temp_timer > 65535)
 
 
3982
        temp_timer = 65535;
 
 
3983
 
 
 
3984
    XDelta->timer = temp_timer;
 
 
3985
 
 
 
3986
    temp_timer = screenY* tail_ycal;
 
 
3987
    temp_timer += 32767;
 
 
3988
 
 
 
3989
    if (temp_timer < 0)
 
 
3990
        temp_timer = 0;
 
 
3991
    else if (temp_timer > 65535)
 
 
3992
        temp_timer = 65535;
 
 
3993
 
 
 
3994
    YDelta->timer = temp_timer;
 
 
3995
 
 
 
3996
    //printf("Target Screen X,Y %d %d\n", screenX, screenY);
 
 
3997
}
 
 
3998
 
 
 
3999
static int Tail_TargetFilter(STRATEGYBLOCK *candidate) 
 
 
4000
{
 
 
4001
    switch (candidate->type)
 
 
4002
    {
 
 
4003
        case I_BehaviourMarine:
 
 
4004
        case I_BehaviourPredator:
 
 
4005
        case I_BehaviourInanimateObject:
 
 
4006
        case I_BehaviourPlacedLight:
 
 
4007
        case I_BehaviourMarinePlayer:
 
 
4008
        case I_BehaviourPredatorPlayer:
 
 
4009
        case I_BehaviourAlien:
 
 
4010
        case I_BehaviourAutoGun:
 
 
4011
        case I_BehaviourVideoScreen:
 
 
4012
        case I_BehaviourAlienPlayer:
 
 
4013
        case I_BehaviourFaceHugger:
 
 
4014
        case I_BehaviourXenoborg:
 
 
4015
        case I_BehaviourQueenAlien:
 
 
4016
            return 1;
 
 
4017
        case I_BehaviourNetGhost:
 
 
4018
        {
 
 
4019
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
4020
            switch (dataptr->type)
 
 
4021
            {
 
 
4022
                case I_BehaviourPredator:
 
 
4023
                case I_BehaviourMarine:
 
 
4024
                case I_BehaviourAutoGun:
 
 
4025
                case I_BehaviourPlacedLight:
 
 
4026
                case I_BehaviourInanimateObject:
 
 
4027
                case I_BehaviourMarinePlayer:
 
 
4028
                case I_BehaviourPredatorPlayer:
 
 
4029
                case I_BehaviourXenoborg:
 
 
4030
                    return 1;
 
 
4031
                case I_BehaviourAlienPlayer:
 
 
4032
                {
 
 
4033
                    switch (netGameData.gameType) 
 
 
4034
                    {
 
 
4035
                        case NGT_Individual:
 
 
4036
                            return 1;
 
 
4037
                        case NGT_CoopDeathmatch:
 
 
4038
                            return 0;
 
 
4039
                        case NGT_LastManStanding:
 
 
4040
                            return 0;
 
 
4041
                        case NGT_PredatorTag:
 
 
4042
                            return 1;
 
 
4043
                        case NGT_Coop:
 
 
4044
                            return 0;
 
 
4045
                        case NGT_AlienTag:
 
 
4046
                            return 1; //However, there shouldn't be more than one alien in alien tag anyway.
 
 
4047
                        default:
 
 
4048
                            return 0;
 
 
4049
                    }
 
 
4050
                }
 
 
4051
                default:
 
 
4052
                    return 0;
 
 
4053
            }
 
 
4054
        }
 
 
4055
        default:
 
 
4056
            return 0;
 
 
4057
    }
 
 
4058
}
 
 
4059
 
 
 
4060
#define ALIEN_TAIL_RANGE (4000)
 
 
4061
 
 
 
4062
static void AlienTail_TargetSelect()
 
 
4063
{
 
 
4064
    int numberOfObjects = numVisObjs;
 
 
4065
    DISPLAYBLOCK *nearest = NULL;
 
 
4066
    int neardist = 100000;
 
 
4067
 
 
 
4068
    while (numberOfObjects--)
 
 
4069
    {
 
 
4070
        DISPLAYBLOCK* objectPtr = VisibleObjects[numberOfObjects].DispPtr;
 
 
4071
        STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
 
 
4072
 
 
 
4073
        /* does object have a strategy block? */
 
 
4074
        if (sbPtr && Tail_TargetFilter(sbPtr))
 
 
4075
        {
 
 
4076
            /* is it in the frustrum? */
 
 
4077
            if ( (objectPtr->ObView.vz > 0) 
 
 
4078
                && (objectPtr->ObView.vz >  (objectPtr->ObView.vx>>1)) 
 
 
4079
                && (objectPtr->ObView.vz > -(objectPtr->ObView.vx>>1)) 
 
 
4080
                && (objectPtr->ObView.vz >  (objectPtr->ObView.vy>>1)) 
 
 
4081
                && (objectPtr->ObView.vz > -(objectPtr->ObView.vy>>1)) )
 
 
4082
            {
 
 
4083
                int dist = Approximate3dMagnitude(&objectPtr->ObView);
 
 
4084
 
 
 
4085
                if (dist < ALIEN_TAIL_RANGE)
 
 
4086
                {
 
 
4087
                    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
4088
 
 
 
4089
                    if (IsThisObjectVisibleFromThisPosition_WithIgnore(PlayerStatus.DisplayBlock, objectPtr, &dynPtr->Position))
 
 
4090
                    {
 
 
4091
                        /* Consider target validity here? */
 
 
4092
 
 
 
4093
                        if (dist < neardist)
 
 
4094
                        {
 
 
4095
                            nearest = objectPtr;
 
 
4096
                            neardist = dist;
 
 
4097
                        }
 
 
4098
                    }
 
 
4099
                }
 
 
4100
            }
 
 
4101
        }
 
 
4102
    }
 
 
4103
 
 
 
4104
    if(NULL != nearest)
 
 
4105
    {
 
 
4106
        Alien_Tail_Target = nearest->ObStrategyBlock;
 
 
4107
        COPY_NAME(Alien_Tail_Target_SBname, Alien_Tail_Target->SBname);
 
 
4108
    }
 
 
4109
    else
 
 
4110
    {
 
 
4111
        Alien_Tail_Target = NULL;
 
 
4112
    }
 
 
4113
}
 
 
4114
 
 
 
4115
#define BITE_RANGE     ((CHEATMODE_SNIPERMUNCH == UserProfile.active_bonus) ? 100000 : 1500)
 
 
4116
#define BITE_RADIUS    ((CHEATMODE_SNIPERMUNCH == UserProfile.active_bonus) ? 1500 : 200)
 
 
4117
 
 
 
4118
static SECTION_DATA *CheckBiteIntegrity() 
 
 
4119
{
 
 
4120
    VECTORCH targetpos;
 
 
4121
 
 
 
4122
    if (!NAME_ISEQUAL(Biting->SBname, Biting_SBname) || !Biting->DisplayBlock) 
 
 
4123
        return NULL;
 
 
4124
 
 
 
4125
    DISPLAYBLOCK *objectPtr = Biting->DisplayBlock;
 
 
4126
 
 
 
4127
    GetTargetingPointOfObject(objectPtr, &targetpos);
 
 
4128
    targetpos.vx -= Global_VDB.VDB_World.vx;
 
 
4129
    targetpos.vy -= Global_VDB.VDB_World.vy;
 
 
4130
    targetpos.vz -= Global_VDB.VDB_World.vz;
 
 
4131
    RotateVector(&targetpos, &Global_VDB.VDB_Mat);
 
 
4132
 
 
 
4133
    /* is it in the range band? */
 
 
4134
    if ((targetpos.vz > 0) && (targetpos.vz <  (BITE_RANGE << 1))) 
 
 
4135
    {
 
 
4136
        if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr, PlayerStatus.DisplayBlock, &Global_VDB.VDB_World)) 
 
 
4137
        {
 
 
4138
            /* The minute his *head* is in view... */
 
 
4139
            SECTION_DATA *head = GetThisSectionData(objectPtr->HModelControlBlock->section_data, "head");
 
 
4140
 
 
 
4141
            /* Is it still attached? */
 
 
4142
 
 
 
4143
            if (head && !(head->flags & section_data_notreal))
 
 
4144
            {
 
 
4145
                /* We'll have the head now if at all. */
 
 
4146
                VECTORCH temp_view = head->View_Offset;
 
 
4147
                /* I assume if we're alive, we have a head. */
 
 
4148
                temp_view.vz = 0;
 
 
4149
                /* Scale radius with FOV here? */
 
 
4150
 
 
 
4151
                if (Approximate3dMagnitude(&temp_view) < (BITE_RADIUS << 1)) 
 
 
4152
                    return head; // Aw, okay.
 
 
4153
            }
 
 
4154
        }
 
 
4155
    }
 
 
4156
 
 
 
4157
/* If you got here, you failed. */
 
 
4158
return NULL;
 
 
4159
}
 
 
4160
 
 
 
4161
static int AlienBite_TargetFilter(STRATEGYBLOCK *sbPtr) 
 
 
4162
{
 
 
4163
    /* Is it tasty, mm?  Is it... crunchable? */
 
 
4164
 
 
 
4165
    switch(sbPtr->type)
 
 
4166
    {
 
 
4167
        case I_BehaviourMarine:
 
 
4168
        {
 
 
4169
            MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
4170
 
 
 
4171
            return (!marineStatusPointer->Android && !NPC_IsDead(sbPtr));
 
 
4172
        }
 
 
4173
        break;
 
 
4174
        case I_BehaviourCorpse:
 
 
4175
        {
 
 
4176
            CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)sbPtr->dataptr;
 
 
4177
            assert(corpseDataPtr);
 
 
4178
 
 
 
4179
            if (((corpseDataPtr->timer / 2) < ONE_FIXED) || (-1 == corpseDataPtr->subtype)) // android
 
 
4180
            {
 
 
4181
                return 0; // Already fading.
 
 
4182
            }
 
 
4183
            else
 
 
4184
            {
 
 
4185
                switch(corpseDataPtr->Type)
 
 
4186
                {
 
 
4187
                    case I_BehaviourMarine:
 
 
4188
                    case I_BehaviourPredator:
 
 
4189
                        return 1; // Of course it's dead!
 
 
4190
                    default:
 
 
4191
                    break;
 
 
4192
                }
 
 
4193
            }
 
 
4194
        }
 
 
4195
        break;
 
 
4196
        case I_BehaviourNetGhost:
 
 
4197
        {
 
 
4198
            NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr;
 
 
4199
            assert(ghostData);
 
 
4200
 
 
 
4201
            //check for opponent in network game
 
 
4202
            switch(ghostData->type)
 
 
4203
            {
 
 
4204
                case I_BehaviourCorpse:
 
 
4205
                {
 
 
4206
                    switch(ghostData->subtype)
 
 
4207
                    {
 
 
4208
                        case I_BehaviourMarinePlayer:
 
 
4209
                        case I_BehaviourPredatorPlayer:
 
 
4210
                            return 1;
 
 
4211
                        default:
 
 
4212
                            break;
 
 
4213
                    }
 
 
4214
                }
 
 
4215
                break;
 
 
4216
                case I_BehaviourMarinePlayer:
 
 
4217
                case I_BehaviourPredatorPlayer:
 
 
4218
                {
 
 
4219
                    // We don't want to allow bite attacks against players
 
 
4220
                    // that have respawn invulnerability
 
 
4221
 
 
 
4222
                    if(!ghostData->invulnerable)
 
 
4223
                        return 1;
 
 
4224
                }
 
 
4225
                default:
 
 
4226
                break;
 
 
4227
            }
 
 
4228
        }
 
 
4229
        break;
 
 
4230
        case I_BehaviourPredator: 
 
 
4231
        {
 
 
4232
            /* There's always got to be a difficult one! */
 
 
4233
 
 
 
4234
            /* The minute his *head* is in view... */
 
 
4235
            SECTION_DATA *head = GetThisSectionData(sbPtr->DisplayBlock->HModelControlBlock->section_data, "head");
 
 
4236
 
 
 
4237
            /* Is it still attached? */
 
 
4238
            if (head && !(head->flags & section_data_notreal))
 
 
4239
            {
 
 
4240
                /* We'll have the head now if at all. */
 
 
4241
 
 
 
4242
                DAMAGEBLOCK temp_damage = head->current_damage;
 
 
4243
 
 
 
4244
                DamageDamageBlock(&temp_damage, &TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage, ONE_FIXED);
 
 
4245
 
 
 
4246
                if (temp_damage.Health <= 0)
 
 
4247
                    return 1; /* Killed the head, that'll do. */
 
 
4248
 
 
 
4249
                /* So the head lived, huh?  Let's try the body. */
 
 
4250
                temp_damage = sbPtr->DamageBlock;
 
 
4251
 
 
 
4252
                DamageDamageBlock(&temp_damage, &TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage, ONE_FIXED);
 
 
4253
 
 
 
4254
                if (temp_damage.Health <= 0) 
 
 
4255
                    return 1; /* Killed the body, that'll do too. */
 
 
4256
            }
 
 
4257
        }
 
 
4258
        default:
 
 
4259
        break;
 
 
4260
    }
 
 
4261
 
 
 
4262
return 0;
 
 
4263
}
 
 
4264
 
 
 
4265
static void BiteAttack_AwardHealth(STRATEGYBLOCK *sbPtr)
 
 
4266
{
 
 
4267
    /* Have all your armour back? */
 
 
4268
    const NPC_DATA *NpcData = &NpcDataList[I_PC_Alien_MaxStats];
 
 
4269
 
 
 
4270
    switch(sbPtr->type)
 
 
4271
    {
 
 
4272
        case I_BehaviourMarine:
 
 
4273
        case I_BehaviourPredator:
 
 
4274
        {
 
 
4275
            /* Add some armour... */
 
 
4276
            PlayerStatus.sbptr->DamageBlock.Armour += (BITE_ARMOUR_RECOVERY << ONE_FIXED_SHIFT);
 
 
4277
 
 
 
4278
            if (PlayerStatus.sbptr->DamageBlock.Armour > (NpcData->StartingStats.Armour << ONE_FIXED_SHIFT))
 
 
4279
                PlayerStatus.sbptr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
4280
 
 
 
4281
            PlayerStatus.Armour = PlayerStatus.sbptr->DamageBlock.Armour;
 
 
4282
 
 
 
4283
            /* And some health, too. */
 
 
4284
            PlayerStatus.sbptr->DamageBlock.Health += BITE_HEALTH_RECOVERY << ONE_FIXED_SHIFT;
 
 
4285
 
 
 
4286
            if (PlayerStatus.sbptr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT))
 
 
4287
                PlayerStatus.sbptr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
4288
 
 
 
4289
            PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
4290
        }
 
 
4291
        break;
 
 
4292
        case I_BehaviourCorpse:
 
 
4293
        {
 
 
4294
            /* It probably is still a corpse now... */
 
 
4295
            CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)sbPtr->dataptr;
 
 
4296
 
 
 
4297
            assert(corpseDataPtr);
 
 
4298
 
 
 
4299
            switch(corpseDataPtr->Type)
 
 
4300
            {
 
 
4301
                case I_BehaviourMarine:
 
 
4302
                case I_BehaviourPredator:
 
 
4303
                {
 
 
4304
                    /* No armour, just a bit of health. */
 
 
4305
                    PlayerStatus.sbptr->DamageBlock.Health += (20 << ONE_FIXED_SHIFT);
 
 
4306
 
 
 
4307
                    if (PlayerStatus.sbptr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT))
 
 
4308
                        PlayerStatus.sbptr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
4309
 
 
 
4310
                    PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
4311
                }
 
 
4312
                default:
 
 
4313
                break;
 
 
4314
            }
 
 
4315
        }
 
 
4316
        break;
 
 
4317
        case I_BehaviourNetGhost:    
 
 
4318
        {
 
 
4319
            //rather higher health awards for getting network opponents
 
 
4320
            NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr;
 
 
4321
            assert(ghostData);
 
 
4322
 
 
 
4323
            switch(ghostData->type)
 
 
4324
            {
 
 
4325
                case I_BehaviourCorpse:
 
 
4326
                {
 
 
4327
                    switch(ghostData->subtype)
 
 
4328
                    {
 
 
4329
                        case I_BehaviourMarinePlayer:
 
 
4330
                        case I_BehaviourPredatorPlayer:
 
 
4331
                        {
 
 
4332
                            /* Add some armour... */
 
 
4333
                            PlayerStatus.sbptr->DamageBlock.Armour += (BITE_ARMOUR_RECOVERY << ONE_FIXED_SHIFT);
 
 
4334
 
 
 
4335
                            if (PlayerStatus.sbptr->DamageBlock.Armour > (NpcData->StartingStats.Armour << ONE_FIXED_SHIFT))
 
 
4336
                                PlayerStatus.sbptr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
4337
 
 
 
4338
                            PlayerStatus.Armour = PlayerStatus.sbptr->DamageBlock.Armour;
 
 
4339
 
 
 
4340
                            /* And some health, too. */
 
 
4341
                            PlayerStatus.sbptr->DamageBlock.Health += (20 << ONE_FIXED_SHIFT);
 
 
4342
 
 
 
4343
                            if (PlayerStatus.sbptr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT))
 
 
4344
                            {
 
 
4345
                                PlayerStatus.sbptr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
4346
                            }
 
 
4347
                            else if(PlayerStatus.sbptr->DamageBlock.Health < (PlayerStatus.StartingHealth << ONE_FIXED_SHIFT))
 
 
4348
                            {
 
 
4349
                                //make sure player has at least starting health
 
 
4350
                                PlayerStatus.sbptr->DamageBlock.Health = PlayerStatus.StartingHealth << ONE_FIXED_SHIFT;
 
 
4351
                            }
 
 
4352
 
 
 
4353
                            PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
4354
                        }
 
 
4355
                        default:
 
 
4356
                        break;
 
 
4357
                    }
 
 
4358
                }
 
 
4359
                break;
 
 
4360
                case I_BehaviourMarinePlayer:
 
 
4361
                case I_BehaviourPredatorPlayer:
 
 
4362
                {
 
 
4363
                    //killed player character with a bite attack
 
 
4364
 
 
 
4365
                    /* Add some armour... */
 
 
4366
                    PlayerStatus.sbptr->DamageBlock.Armour += PlayerStatus.StartingArmour << ONE_FIXED_SHIFT;
 
 
4367
 
 
 
4368
                    if (PlayerStatus.sbptr->DamageBlock.Armour > (NpcData->StartingStats.Armour << ONE_FIXED_SHIFT))
 
 
4369
                        PlayerStatus.sbptr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
4370
 
 
 
4371
                    PlayerStatus.Armour = PlayerStatus.sbptr->DamageBlock.Armour;
 
 
4372
 
 
 
4373
                    /* And some health, too. */
 
 
4374
                    PlayerStatus.sbptr->DamageBlock.Health += PlayerStatus.StartingHealth << ONE_FIXED_SHIFT;
 
 
4375
 
 
 
4376
                    if (PlayerStatus.sbptr->DamageBlock.Health > (NpcData->StartingStats.Health<<ONE_FIXED_SHIFT))
 
 
4377
                        PlayerStatus.sbptr->DamageBlock.Health = NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
 
 
4378
 
 
 
4379
                    PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
4380
                }
 
 
4381
                default:
 
 
4382
                break;
 
 
4383
            }
 
 
4384
        }
 
 
4385
        default:
 
 
4386
        break;
 
 
4387
    }
 
 
4388
}
 
 
4389
 
 
 
4390
static void FixAlienStrikeSpeed(int time)
 
 
4391
{
 
 
4392
    ACStrikeTime = MUL_FIXED(time, ONE_FIXED);
 
 
4393
    //TemplateWeapon[WEAPON_ALIEN_CLAW].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY] = DIV_FIXED(ONE_FIXED, ACStrikeTime);
 
 
4394
}
 
 
4395
 
 
 
4396
STRATEGYBLOCK *GetBitingTarget() 
 
 
4397
{
 
 
4398
    int numberOfObjects = numVisObjs;
 
 
4399
 
 
 
4400
    while (numberOfObjects--)
 
 
4401
    {
 
 
4402
        DISPLAYBLOCK* objectPtr = VisibleObjects[numberOfObjects].DispPtr;
 
 
4403
        STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
 
 
4404
 
 
 
4405
        if (sbPtr == PlayerStatus.sbptr)
 
 
4406
            continue;
 
 
4407
 
 
 
4408
        /* does object have a strategy block? */
 
 
4409
        if (sbPtr && AlienBite_TargetFilter(sbPtr))
 
 
4410
        {
 
 
4411
            VECTORCH targetpos;
 
 
4412
 
 
 
4413
            GetTargetingPointOfObject(objectPtr, &targetpos);
 
 
4414
            targetpos.vx -= Global_VDB.VDB_World.vx;
 
 
4415
            targetpos.vy -= Global_VDB.VDB_World.vy;
 
 
4416
            targetpos.vz -= Global_VDB.VDB_World.vz;
 
 
4417
            RotateVector(&targetpos, &Global_VDB.VDB_Mat);
 
 
4418
 
 
 
4419
            /* is it in the range band? */
 
 
4420
            if ((targetpos.vz > 0) && (targetpos.vz < BITE_RANGE))
 
 
4421
            {
 
 
4422
                if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr, PlayerStatus.DisplayBlock, &Global_VDB.VDB_World))
 
 
4423
                {
 
 
4424
                    /* The minute his *head* is in view... */
 
 
4425
                    SECTION_DATA *head = GetThisSectionData(objectPtr->HModelControlBlock->section_data, "head");
 
 
4426
 
 
 
4427
                    /* Is it still attached? */
 
 
4428
                    if (head && !(head->flags & section_data_notreal))
 
 
4429
                    {
 
 
4430
                        /* We'll have the head now if at all. */
 
 
4431
                        VECTORCH temp_view = head->View_Offset;
 
 
4432
                        /* I assume if we're alive, we have a head. */
 
 
4433
                        temp_view.vz = 0;
 
 
4434
 
 
 
4435
                        if (Approximate3dMagnitude(&temp_view) < BITE_RADIUS)
 
 
4436
                        {
 
 
4437
                            Biting = sbPtr;
 
 
4438
                            /* Fix the name. */
 
 
4439
                            COPY_NAME(Biting_SBname, Biting->SBname);
 
 
4440
                            FixAlienStrikeSpeed(ONE_FIXED / 3);
 
 
4441
                            /* Init attack. */
 
 
4442
                            Bit = 0;
 
 
4443
                            return Biting;
 
 
4444
                        }
 
 
4445
                    }
 
 
4446
                }
 
 
4447
            }
 
 
4448
        }
 
 
4449
    }
 
 
4450
 
 
 
4451
return (Biting = NULL);
 
 
4452
}
 
 
4453
 
 
 
4454
static int alien_claw(DAMAGE_PROFILE *damage, int multiple, int range)
 
 
4455
{
 
 
4456
    int numberOfObjects = numVisObjs;
 
 
4457
    int numhits = 0;
 
 
4458
 
 
 
4459
    while (numberOfObjects--)
 
 
4460
    {
 
 
4461
        VECTORCH targetpos,targetposW;
 
 
4462
        DISPLAYBLOCK* objectPtr = VisibleObjects[numberOfObjects].DispPtr;
 
 
4463
        STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
 
 
4464
 
 
 
4465
        /* does object have a strategy block? */
 
 
4466
        if (sbPtr)
 
 
4467
        {
 
 
4468
            GetTargetingPointOfObject(objectPtr, &targetpos);
 
 
4469
            targetposW = targetpos;
 
 
4470
            targetpos.vx -= Global_VDB.VDB_World.vx;
 
 
4471
            targetpos.vy -= Global_VDB.VDB_World.vy;
 
 
4472
            targetpos.vz -= Global_VDB.VDB_World.vz;
 
 
4473
            RotateVector(&targetpos, &Global_VDB.VDB_Mat);
 
 
4474
 
 
 
4475
            /* is it in range? */
 
 
4476
            if (targetpos.vz > 0)
 
 
4477
            {
 
 
4478
                int dist = Approximate3dMagnitude(&targetpos);
 
 
4479
 
 
 
4480
                if (dist < range)
 
 
4481
                {
 
 
4482
                    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
4483
 
 
 
4484
                        if (dynPtr)
 
 
4485
                    {
 
 
4486
                        /* KJL 19:10:49 25/01/99 - I'm going to try changing this to
 
 
4487
                        see if I can have an Alien that doesn't kill multiple things in one frame */
 
 
4488
 
 
 
4489
                        /* CDF 30/3/99 - I'm going to change it back with modifications,
 
 
4490
                        since people evidently can't make up their minds. */
 
 
4491
 
 
 
4492
                        if (IsThisObjectVisibleFromThisPosition_WithIgnore(PlayerStatus.DisplayBlock, objectPtr, &targetposW))
 
 
4493
                        {
 
 
4494
                            int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass;
 
 
4495
                                dynPtr->LinImpulse.vx += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat31, magnitudeOfForce);
 
 
4496
                            dynPtr->LinImpulse.vy += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat32, magnitudeOfForce);
 
 
4497
                                dynPtr->LinImpulse.vz += MUL_FIXED(PlayerStatus.DisplayBlock->ObMat.mat33, magnitudeOfForce);
 
 
4498
                            /* Consider target aspect. */
 
 
4499
                            {
 
 
4500
                                VECTORCH attack_dir,displacement;
 
 
4501
                                int real_multiple = multiple;
 
 
4502
 
 
 
4503
                                displacement.vx = dynPtr->Position.vx - PlayerStatus.sbptr->DynPtr->Position.vx;
 
 
4504
                                displacement.vy = dynPtr->Position.vy - PlayerStatus.sbptr->DynPtr->Position.vy;
 
 
4505
                                displacement.vz = dynPtr->Position.vz - PlayerStatus.sbptr->DynPtr->Position.vz;
 
 
4506
 
 
 
4507
                                GetDirectionOfAttack(sbPtr, &displacement, &attack_dir);
 
 
4508
 
 
 
4509
                                if (attack_dir.vz > 0)
 
 
4510
                                    real_multiple <<= 1;
 
 
4511
 
 
 
4512
                                if (sbPtr->DisplayBlock->HModelControlBlock)
 
 
4513
                                {
 
 
4514
                                    DISPLAYBLOCK *frag = HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir);
 
 
4515
 
 
 
4516
                                    if(NULL != frag)
 
 
4517
                                    {
 
 
4518
                                        switch(sbPtr->type)
 
 
4519
                                        {
 
 
4520
                                            case I_BehaviourMarine:
 
 
4521
                                            {
 
 
4522
                                                MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
4523
 
 
 
4524
                                                if (!marineStatusPointer->Android)
 
 
4525
                                                    LimbRip_AwardHealth(); /* Took off a limb! */
 
 
4526
                                            }
 
 
4527
                                            break;
 
 
4528
                                            case I_BehaviourCorpse:
 
 
4529
                                            {
 
 
4530
                                                CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)(sbPtr->dataptr);
 
 
4531
 
 
 
4532
                                                if (-1 != corpseDataPtr->subtype) // android
 
 
4533
                                                    LimbRip_AwardHealth(); /* Took off a limb! */
 
 
4534
                                            }
 
 
4535
                                            default:
 
 
4536
                                            break;
 
 
4537
                                        }
 
 
4538
                                    }
 
 
4539
                                }
 
 
4540
                                else
 
 
4541
                                {
 
 
4542
                                    CauseDamageToObject(sbPtr, damage, real_multiple, &attack_dir);
 
 
4543
                                }
 
 
4544
                            }
 
 
4545
 
 
 
4546
                            numhits++;
 
 
4547
                        }
 
 
4548
                    }
 
 
4549
                  }
 
 
4550
            }
 
 
4551
        }
 
 
4552
    }
 
 
4553
 
 
 
4554
return numhits;
 
 
4555
}
 
 
4556
 
 
 
4557
void maintain_alien_weapons()
 
 
4558
{
 
 
4559
    if (Biting && (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon || PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon))
 
 
4560
    {
 
 
4561
        if (PlayerStatus.WeaponStateTimeOutCounter < (ONE_FIXED >> 1))
 
 
4562
        {
 
 
4563
            if (!Bit)
 
 
4564
            {
 
 
4565
                SECTION_DATA *head_sec = CheckBiteIntegrity();
 
 
4566
                Bit = 1;
 
 
4567
 
 
 
4568
                /* Try the bite. */
 
 
4569
                if (head_sec)
 
 
4570
                {
 
 
4571
                    CurrentGameStats_HeadBitten(Biting);
 
 
4572
 
 
 
4573
                    /* Munch! */
 
 
4574
                    if (CHEATMODE_SUPERGORE == UserProfile.active_bonus)
 
 
4575
CauseDamageToHModel(Biting->DisplayBlock->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION_SUPER].MaxDamage, ONE_FIXED, head_sec,
NULL, NULL, 0);
 
 
4576
                    else
 
 
4577
CauseDamageToHModel(Biting->DisplayBlock->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage, ONE_FIXED, head_sec, NULL,
NULL,0);
 
 
4578
 
 
 
4579
                    /* Side effects, anyone? */
 
 
4580
                    BiteAttack_AwardHealth(Biting);
 
 
4581
 
 
 
4582
                    if (PlayerStatus.sound_mouth != SOUND_NOACTIVEINDEX)
 
 
4583
                        Sound_Stop(PlayerStatus.sound_mouth);
 
 
4584
 
 
 
4585
                    Sound_Play(SID_ALIEN_JAW_ATTACK, "de", &PlayerStatus.sbptr->DynPtr->Position, &PlayerStatus.sound_mouth);
 
 
4586
 
 
 
4587
                    {
 
 
4588
                    extern int AlienTongueOffset;
 
 
4589
                    extern int AlienTeethOffset;
 
 
4590
                    extern int AlienBiteAttackInProgress;
 
 
4591
                    extern float CameraZoomScale;
 
 
4592
 
 
 
4593
                    AlienBiteAttackInProgress = 1;
 
 
4594
                    CameraZoomScale = 0.25f;
 
 
4595
                    AlienTongueOffset = ONE_FIXED;
 
 
4596
                    AlienTeethOffset = 0;
 
 
4597
                    }
 
 
4598
                }
 
 
4599
            }
 
 
4600
        }
 
 
4601
    return;
 
 
4602
    }
 
 
4603
 
 
 
4604
    PositionPlayersWeapon();
 
 
4605
 
 
 
4606
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
4607
    {
 
 
4608
        //case AHSS_Eat:
 
 
4609
        case AHSS_end:
 
 
4610
        default:
 
 
4611
        break;
 
 
4612
        case AHSS_LeftSwipeDown:
 
 
4613
        case AHSS_RightSwipeDown:
 
 
4614
        case AHSS_LeftSwipeIn:
 
 
4615
        case AHSS_RightSwipeIn:
 
 
4616
        case AHSS_Both_In:
 
 
4617
        case AHSS_Both_Down:
 
 
4618
        case AHSS_PounceIn:
 
 
4619
        case AHSS_PounceDown:
 
 
4620
        {
 
 
4621
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
4622
            {
 
 
4623
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_AlienHUD, (int)AHSS_end, ACStrikeTime, 0);
 
 
4624
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
4625
            }
 
 
4626
            else
 
 
4627
            {
 
 
4628
                int hits = (PlayersWeaponHModelController.keyframe_flags & 1) + (PlayersWeaponHModelController.keyframe_flags & 2);
 
 
4629
 
 
 
4630
                if (hits)
 
 
4631
                {
 
 
4632
                    alien_claw(&Player_Weapon_Damage, ONE_FIXED * hits, 2500);
 
 
4633
                    SpeciesSound(0, ASC_Swipe, ((FastRandom() & 255) - 128), &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position,
ALIEN_SOUND);
 
 
4634
                }
 
 
4635
 
 
 
4636
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
4637
            }
 
 
4638
        }
 
 
4639
        return;
 
 
4640
        case AHSS_TailHold:
 
 
4641
                //printf("Tail Max. Pen. Damage = %d - Poised.\n", Player_Weapon_Damage.Penetrative);
 
 
4642
        case AHSS_Hor_Delta:
 
 
4643
        case AHSS_Ver_Delta:
 
 
4644
        case AHSS_TailCome:
 
 
4645
        {
 
 
4646
            if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
4647
            {
 
 
4648
                if (!PlayersWeaponHModelController.Tweening && (PlayersWeaponHModelController.sequence_timer == (ONE_FIXED-1))) 
 
 
4649
                {
 
 
4650
                    /* Finished poise move. */
 
 
4651
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_AlienHUD, (int)AHSS_TailHold, ONE_FIXED, 1);
 
 
4652
                    //printf("Tail Max. Pen. Damage = %d\n", Player_Weapon_Damage.Penetrative);
 
 
4653
                    Alien_Tail_Clock = -1;
 
 
4654
                }
 
 
4655
                else if ( -1 != Alien_Tail_Clock)
 
 
4656
                {
 
 
4657
                    Alien_Tail_Clock += NormalFrameTime;
 
 
4658
 
 
 
4659
                    while (Alien_Tail_Clock >= 1000)
 
 
4660
                    {
 
 
4661
                        Player_Weapon_Damage.Penetrative += 1;
 
 
4662
                        Alien_Tail_Clock -= 1000;
 
 
4663
                    }
 
 
4664
 
 
 
4665
                    //printf("Tail Pen. Damage = %d\n", Player_Weapon_Damage.Penetrative);
 
 
4666
                }
 
 
4667
 
 
 
4668
            }
 
 
4669
            else
 
 
4670
            {
 
 
4671
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_AlienHUD, (int)AHSS_TailStrike, (ONE_FIXED/6), 0);
 
 
4672
            }
 
 
4673
 
 
 
4674
            DELTA_CONTROLLER *XDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "XDelta");
 
 
4675
            DELTA_CONTROLLER *YDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "YDelta");
 
 
4676
 
 
 
4677
            AlienTail_TargetSelect();
 
 
4678
 
 
 
4679
            if(NULL == Alien_Tail_Target)
 
 
4680
                XDelta->timer = YDelta->timer = 32767;
 
 
4681
            else
 
 
4682
                ComputeTailDeltaValues(XDelta, YDelta);
 
 
4683
        }
 
 
4684
        return;
 
 
4685
        case AHSS_TailStrike:
 
 
4686
        {
 
 
4687
            if (Alien_Tail_Target)
 
 
4688
            {
 
 
4689
                switch(Alien_Tail_Target->type)
 
 
4690
                {
 
 
4691
                    case I_BehaviourInanimateObject:
 
 
4692
                    case I_BehaviourPowerCable:
 
 
4693
                    case I_BehaviourVideoScreen:
 
 
4694
                        if(Alien_Tail_Target->DamageBlock.Health <= 0)
 
 
4695
                            Alien_Tail_Target = NULL;
 
 
4696
                    break;
 
 
4697
                    default:
 
 
4698
                    if (NPC_IsDead(Alien_Tail_Target) || !NAME_ISEQUAL(Alien_Tail_Target->SBname, Alien_Tail_Target_SBname) ||
!Alien_Tail_Target->DisplayBlock)
 
 
4699
                        Alien_Tail_Target = NULL;
 
 
4700
                }
 
 
4701
 
 
 
4702
                if (Alien_Tail_Target)
 
 
4703
                {
 
 
4704
                    /* Do we still have a target?  Correct for aiming. */
 
 
4705
                    DELTA_CONTROLLER *XDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "XDelta");
 
 
4706
                    DELTA_CONTROLLER *YDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "YDelta");
 
 
4707
                    ComputeTailDeltaValues(XDelta, YDelta);
 
 
4708
                }
 
 
4709
            }
 
 
4710
 
 
 
4711
            if (PlayersWeaponHModelController.keyframe_flags & 1) 
 
 
4712
            {
 
 
4713
                /* Just for now, do damage anyway... */
 
 
4714
                if (Alien_Tail_Target)
 
 
4715
                {
 
 
4716
                    int multiple = ONE_FIXED;
 
 
4717
 
 
 
4718
                    /* Consider target aspect. */
 
 
4719
                    VECTORCH attack_dir, displacement;
 
 
4720
 
 
 
4721
                    displacement.vx = Alien_Tail_Target->DynPtr->Position.vx - PlayerStatus.sbptr->DynPtr->Position.vx;
 
 
4722
                    displacement.vy = Alien_Tail_Target->DynPtr->Position.vy - PlayerStatus.sbptr->DynPtr->Position.vy;
 
 
4723
                    displacement.vz = Alien_Tail_Target->DynPtr->Position.vz - PlayerStatus.sbptr->DynPtr->Position.vz;
 
 
4724
 
 
 
4725
                    GetDirectionOfAttack(Alien_Tail_Target, &displacement, &attack_dir);
 
 
4726
 
 
 
4727
                    if (attack_dir.vz > 0) 
 
 
4728
                        multiple <<= 1;
 
 
4729
 
 
 
4730
                    if (Alien_Tail_Target->DisplayBlock->HModelControlBlock) 
 
 
4731
                        HtoHDamageToHModel(Alien_Tail_Target, &Player_Weapon_Damage, multiple, NULL, &attack_dir);
 
 
4732
                    else 
 
 
4733
                        CauseDamageToObject(Alien_Tail_Target, &Player_Weapon_Damage, multiple, &attack_dir);
 
 
4734
                }
 
 
4735
 
 
 
4736
                SpeciesSound(0, ASC_TailSound, ((FastRandom() & 255) - 128), &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position,
ALIEN_SOUND);
 
 
4737
                /* Slower recoil... */
 
 
4738
                HModel_ChangeSpeed(&PlayersWeaponHModelController, ONE_FIXED);
 
 
4739
            }
 
 
4740
            else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
4741
            {
 
 
4742
                PlayersWeaponHModelController.Sub_Sequence = AHSS_end;
 
 
4743
            }
 
 
4744
        }
 
 
4745
        return;
 
 
4746
    };
 
 
4747
 
 
 
4748
    if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
4749
    {
 
 
4750
        PlayerStatus.twPtr = &TemplateWeapon[WEAPON_ALIEN_CLAW];
 
 
4751
        int alien_speed = Approximate3dMagnitude(&PlayerStatus.sbptr->DynPtr->LinVelocity);
 
 
4752
 
 
 
4753
        /* Speed: < 5000 = standing.  > 22000 = jumping.  In practice, walk/fall = 18000 ish, jump = 27000 ish. */
 
 
4754
 
 
 
4755
        /* Check we've got the claws. */
 
 
4756
 
 
 
4757
        if (Alien_Visible_Weapon)
 
 
4758
        {
 
 
4759
            GetHierarchicalWeapon("alien_HUD", "claws", (int)HMSQT_AlienHUD, (int)AHSS_LeftSwipeDown);
 
 
4760
            ProveHModel(&PlayersWeaponHModelController, &PlayerStatus.weapon);
 
 
4761
 
 
 
4762
            Alien_Visible_Weapon = 0;
 
 
4763
        }
 
 
4764
 
 
 
4765
        /* Setup base damage. */
 
 
4766
 
 
 
4767
        Player_Weapon_Damage = TemplateAmmo[AMMO_ALIEN_CLAW].MaxDamage;
 
 
4768
 
 
 
4769
        /* Choose attack type and speed. */
 
 
4770
 
 
 
4771
        if ((alien_speed < 5000) && !PlayerStatus.Crouching && (PlayerStatus.sbptr->DynPtr->IsInContactWithFloor))
 
 
4772
        {
 
 
4773
            /* Standing on solid ground. */
 
 
4774
 
 
 
4775
            FixAlienStrikeSpeed(ONE_FIXED / 3);
 
 
4776
 
 
 
4777
            //printf("Standing Claw, Speed %d\n", alien_speed);
 
 
4778
 
 
 
4779
            if ((FastRandom() & 65536) > 32768)
 
 
4780
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4),HMSQT_AlienHUD, (int)AHSS_Both_In, ACStrikeTime, 0);
 
 
4781
            else
 
 
4782
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4),HMSQT_AlienHUD, (int)AHSS_Both_Down, ACStrikeTime, 0);
 
 
4783
        }
 
 
4784
        else
 
 
4785
        {
 
 
4786
            if (PlayerStatus.Crouching)
 
 
4787
            {
 
 
4788
                /* If crouching, falling or no, slower strike. */
 
 
4789
                if (  /* Gravity points vaguely down... */
 
 
4790
                    (PlayerStatus.sbptr->DynPtr->GravityDirection.vx < 46341)
 
 
4791
                    && (PlayerStatus.sbptr->DynPtr->GravityDirection.vx > -46341)
 
 
4792
                    && (PlayerStatus.sbptr->DynPtr->GravityDirection.vy > 46341)
 
 
4793
                    && (PlayerStatus.sbptr->DynPtr->GravityDirection.vz < 46341)
 
 
4794
                    && (PlayerStatus.sbptr->DynPtr->GravityDirection.vz > -46341)
 
 
4795
                   )
 
 
4796
                {
 
 
4797
                    FixAlienStrikeSpeed(ONE_FIXED / 4);
 
 
4798
                }
 
 
4799
                else
 
 
4800
                {
 
 
4801
                    FixAlienStrikeSpeed(ONE_FIXED / 3);
 
 
4802
                }
 
 
4803
            }
 
 
4804
            else
 
 
4805
            {
 
 
4806
                FixAlienStrikeSpeed(ONE_FIXED / 5);
 
 
4807
            }
 
 
4808
 
 
 
4809
            /* Speed test here, for jumping? */
 
 
4810
 
 
 
4811
            if (!PlayerStatus.sbptr->DynPtr->IsInContactWithFloor && (PlayerStatus.sbptr->DynPtr->TimeNotInContactWithFloor <= 0)
&& (alien_speed > 22000) )
 
 
4812
            {
 
 
4813
                /* Must be jumping. */
 
 
4814
                FixAlienStrikeSpeed(ONE_FIXED / 3);
 
 
4815
                /* Extra damage for pounce. */
 
 
4816
                Player_Weapon_Damage.Impact += 10;
 
 
4817
                Player_Weapon_Damage.Cutting += 10;
 
 
4818
 
 
 
4819
                if ((FastRandom() & 65536) > 32768)
 
 
4820
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_AlienHUD, (int)AHSS_PounceIn, ACStrikeTime, 0);
 
 
4821
                else
 
 
4822
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_AlienHUD, (int)AHSS_PounceDown, ACStrikeTime, 0);
 
 
4823
            }
 
 
4824
            else if (RightHand)
 
 
4825
            {
 
 
4826
                if ((FastRandom() & 65536) > 32768)
 
 
4827
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_AlienHUD, (int)AHSS_LeftSwipeIn, (ONE_FIXED/6), 0);
 
 
4828
                else
 
 
4829
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_AlienHUD, (int)AHSS_LeftSwipeDown, (ONE_FIXED/6), 0);
 
 
4830
 
 
 
4831
                RightHand = 0;
 
 
4832
            }
 
 
4833
            else
 
 
4834
            {
 
 
4835
                if ((FastRandom() & 65536) > 32768)
 
 
4836
                    InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED >> 4),HMSQT_AlienHUD, (int)AHSS_RightSwipeIn, (ONE_FIXED/6) , 0);
 
 
4837
                else
 
 
4838
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4),HMSQT_AlienHUD, (int)AHSS_RightSwipeDown, (ONE_FIXED/6) , 0);
 
 
4839
 
 
 
4840
                RightHand = 1;
 
 
4841
            }
 
 
4842
        }
 
 
4843
 
 
 
4844
        PlayerStatus.WeaponStateTimeOutCounter = ACStrikeTime;
 
 
4845
        PlayersWeaponHModelController.Playing = 1;
 
 
4846
    }
 
 
4847
    else if (PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
4848
    {
 
 
4849
        PlayerStatus.twPtr = &TemplateWeapon[WEAPON_ALIEN_TAIL];
 
 
4850
        DELTA_CONTROLLER *XDelta,*YDelta;
 
 
4851
 
 
 
4852
        if (!Alien_Visible_Weapon) 
 
 
4853
        {
 
 
4854
            GetHierarchicalWeapon("alien_HUD", "tail", (int)HMSQT_AlienHUD, (int)AHSS_TailCome);
 
 
4855
            ProveHModel(&PlayersWeaponHModelController, &PlayerStatus.weapon);
 
 
4856
 
 
 
4857
            Alien_Visible_Weapon = 1;
 
 
4858
            /* Create delta sequences. */
 
 
4859
            XDelta = Add_Delta_Sequence(&PlayersWeaponHModelController, "XDelta", (int)HMSQT_AlienHUD, (int)AHSS_Hor_Delta, 0);
 
 
4860
            YDelta = Add_Delta_Sequence(&PlayersWeaponHModelController, "YDelta", (int)HMSQT_AlienHUD, (int)AHSS_Ver_Delta, 0);
 
 
4861
        }
 
 
4862
        else
 
 
4863
        {
 
 
4864
            XDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "XDelta");
 
 
4865
            YDelta = Get_Delta_Sequence(&PlayersWeaponHModelController, "YDelta");
 
 
4866
        }
 
 
4867
 
 
 
4868
        XDelta->timer = 32767;
 
 
4869
        YDelta->timer = 32767;
 
 
4870
 
 
 
4871
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_AlienHUD, (int)AHSS_TailCome, ONE_FIXED, 0);
 
 
4872
 
 
 
4873
        Player_Weapon_Damage = TemplateAmmo[AMMO_ALIEN_TAIL].MaxDamage;
 
 
4874
 
 
 
4875
        Alien_Tail_Clock = 0;
 
 
4876
    }
 
 
4877
}
 
 
4878
 
 
 
4879
void GenericPredatorWeapon_Idle()
 
 
4880
{
 
 
4881
        //    if (!HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
4882
        if(0)
 
 
4883
    if ((PlayersWeaponHModelController.Sub_Sequence != (int)PlayerStatus.twPtr->InitialSubSequence) || ((PlayersWeaponHModelController.Sub_Sequence !=
PHSS_Fidget) || (PlayersWeaponHModelController.Sub_Sequence != PHSS_Run)))
 
 
4884
    {
 
 
4885
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PlayerStatus.twPtr->InitialSubSequence,
ONE_FIXED, 1);
 
 
4886
        puts("INIT");
 
 
4887
    }
 
 
4888
 
 
 
4889
    /* Are we running? */
 
 
4890
 
 
 
4891
    if (PlayerStatus.sbptr->DynPtr->LinVelocity.vx || PlayerStatus.sbptr->DynPtr->LinVelocity.vy ||
PlayerStatus.sbptr->DynPtr->LinVelocity.vz)
 
 
4892
    {
 
 
4893
        /* Were we running? */
 
 
4894
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Run))
 
 
4895
        {
 
 
4896
            if (PlayersWeaponHModelController.Sub_Sequence != (int)PHSS_Run)
 
 
4897
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Run, ONE_FIXED, 1);
 
 
4898
        }
 
 
4899
        else
 
 
4900
        {
 
 
4901
            if (PlayersWeaponHModelController.Sub_Sequence != (int)PHSS_Stand)
 
 
4902
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), PHSS_Stand, (int)PHSS_Stand, ONE_FIXED, 1);
 
 
4903
        }
 
 
4904
    }
 
 
4905
    else
 
 
4906
    {
 
 
4907
        if ((PlayersWeaponHModelController.Sub_Sequence != (int)PHSS_Stand) && (PlayersWeaponHModelController.Sub_Sequence != PHSS_Fidget))
 
 
4908
        {
 
 
4909
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Stand, ONE_FIXED, 1);
 
 
4910
        }
 
 
4911
        else if (PlayerStatus.WeaponStateTimeOutCounter > ONE_FIXED)
 
 
4912
        {
 
 
4913
            if (PlayersWeaponHModelController.Sub_Sequence == PHSS_Fidget)
 
 
4914
            {
 
 
4915
                if (PlayersWeaponHModelController.sequence_timer == (ONE_FIXED-1))
 
 
4916
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Stand, ONE_FIXED, 1);
 
 
4917
            }
 
 
4918
            else if (!(FastRandom() & 255))
 
 
4919
            {
 
 
4920
                /* Start animation. */
 
 
4921
                if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Fidget))
 
 
4922
                {
 
 
4923
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>2), HMSQT_PredatorHUD, (int)PHSS_Fidget, -1, 0);
 
 
4924
                    PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
4925
                }
 
 
4926
            }
 
 
4927
 
 
 
4928
            PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
4929
        }
 
 
4930
        else
 
 
4931
        {
 
 
4932
            PlayerStatus.WeaponStateTimeOutCounter += NormalFrameTime;
 
 
4933
        }
 
 
4934
    }
 
 
4935
 
 
 
4936
    PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
4937
}
 
 
4938
 
 
 
4939
void WristBlade_Readying()
 
 
4940
{
 
 
4941
    const SECTION *root_section = GetNamedHierarchyFromLibrary("pred_HUD", "wrist blade");
 
 
4942
    assert(root_section);
 
 
4943
 
 
 
4944
    PlayersWeaponHModelController.Sequence_Type = (int)HMSQT_PredatorHUD;
 
 
4945
    PlayersWeaponHModelController.Sub_Sequence = (int)PHSS_Come;
 
 
4946
    PlayersWeaponHModelController.Seconds_For_Sequence = (ONE_FIXED >> 1);
 
 
4947
    /* That to get the new sections right. */
 
 
4948
    Transmogrify_HModels(NULL, &PlayersWeaponHModelController, root_section, 0, 1, 0);
 
 
4949
    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Come, (ONE_FIXED>>1), 0);
 
 
4950
}
 
 
4951
 
 
 
4952
static void ThrowSecondaryWeakStrike()
 
 
4953
{
 
 
4954
    int attack;
 
 
4955
 
 
 
4956
    if ((FastRandom() & 65535) < 32767)
 
 
4957
        attack = !HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_One);
 
 
4958
    else
 
 
4959
        attack = HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_Two);
 
 
4960
 
 
 
4961
    switch (attack)
 
 
4962
    {
 
 
4963
        default:
 
 
4964
        case 0:
 
 
4965
            assert(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_One));
 
 
4966
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_One, -1, 0);
 
 
4967
        break;
 
 
4968
        case 1:
 
 
4969
            assert(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_Two));
 
 
4970
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Weak_Two, -1, 0);
 
 
4971
    }
 
 
4972
 
 
 
4973
    StaffAttack = PlayerStatus.Crouching ? 4 : 5;
 
 
4974
}
 
 
4975
 
 
 
4976
static void ThrowSecondaryStrongStrike()
 
 
4977
{
 
 
4978
    int attack;    
 
 
4979
 
 
 
4980
    if ((FastRandom() & 65535) < 32767)
 
 
4981
        attack = !HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_One);
 
 
4982
    else
 
 
4983
        attack = HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_Two);
 
 
4984
 
 
 
4985
    switch (attack)
 
 
4986
    {
 
 
4987
        default:
 
 
4988
        case 0:
 
 
4989
            assert(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_One));
 
 
4990
            InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_One,-1,0);
 
 
4991
        break;
 
 
4992
        case 1:
 
 
4993
            assert(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_Two));
 
 
4994
            InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary_Strong_Two,-1,0);
 
 
4995
    }
 
 
4996
 
 
 
4997
    StaffAttack = PlayerStatus.Crouching ? 2 : 3;
 
 
4998
}
 
 
4999
 
 
 
5000
static int Trophy_TargetFilter(STRATEGYBLOCK *sbPtr) 
 
 
5001
{
 
 
5002
    /* Only works on dead'uns. */
 
 
5003
 
 
 
5004
    switch(sbPtr->type)
 
 
5005
    {
 
 
5006
        case I_BehaviourCorpse:
 
 
5007
        {
 
 
5008
            CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)sbPtr->dataptr;
 
 
5009
            assert(corpseDataPtr);
 
 
5010
 
 
 
5011
            if ((corpseDataPtr->timer / 2) < ONE_FIXED)
 
 
5012
            {
 
 
5013
                /* Already fading. */
 
 
5014
                return 0;
 
 
5015
            }
 
 
5016
            else
 
 
5017
            {
 
 
5018
                switch(corpseDataPtr->Type)
 
 
5019
                {
 
 
5020
                    case I_BehaviourMarine:
 
 
5021
                    {
 
 
5022
                        MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
5023
 
 
 
5024
                        if(!marineStatusPointer->My_Weapon->ARealMarine)
 
 
5025
                            return 0;
 
 
5026
                    }
 
 
5027
                    case I_BehaviourAlien:
 
 
5028
                    case I_BehaviourPredator:
 
 
5029
                        return 1; // Of course it's dead!
 
 
5030
                    default:
 
 
5031
                        return 0;
 
 
5032
                }
 
 
5033
            }
 
 
5034
        }
 
 
5035
        case I_BehaviourNetGhost:
 
 
5036
        {
 
 
5037
            NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr;
 
 
5038
            assert(ghostData);
 
 
5039
 
 
 
5040
            //check for opponent in network game
 
 
5041
            if(ghostData->type == I_BehaviourCorpse)
 
 
5042
            {
 
 
5043
                switch(ghostData->subtype)
 
 
5044
                {
 
 
5045
                    case I_BehaviourMarinePlayer:
 
 
5046
                    {
 
 
5047
                        MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
5048
 
 
 
5049
                        if(!marineStatusPointer->My_Weapon->ARealMarine)
 
 
5050
                            return 0;
 
 
5051
                    }
 
 
5052
                    case I_BehaviourPredatorPlayer:
 
 
5053
                    case I_BehaviourAlienPlayer:
 
 
5054
                        return 1;
 
 
5055
                    default:
 
 
5056
                    return 0;
 
 
5057
                }
 
 
5058
            }
 
 
5059
        }
 
 
5060
        return 0;
 
 
5061
        case I_BehaviourHierarchicalFragment:
 
 
5062
        {
 
 
5063
            HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->dataptr;
 
 
5064
            assert(debrisDataPtr);
 
 
5065
 
 
 
5066
            switch(debrisDataPtr->Type)
 
 
5067
            {
 
 
5068
                case I_BehaviourMarine:
 
 
5069
                {
 
 
5070
                    MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
5071
 
 
 
5072
                    if(!marineStatusPointer->My_Weapon->ARealMarine)
 
 
5073
                        return 0;
 
 
5074
                }
 
 
5075
                case I_BehaviourAlien:
 
 
5076
                case I_BehaviourPredator:
 
 
5077
                {
 
 
5078
                    DISPLAYBLOCK *objectPtr = sbPtr->DisplayBlock;
 
 
5079
 
 
 
5080
                    if (objectPtr && objectPtr->HModelControlBlock)
 
 
5081
                    {
 
 
5082
                        /* Test for the head... */
 
 
5083
                        SECTION_DATA *head = GetThisSectionData(objectPtr->HModelControlBlock->section_data, "head");
 
 
5084
                        /* Is it still attached? */
 
 
5085
 
 
 
5086
                        if (head && !(head->flags & section_data_notreal))
 
 
5087
                        {
 
 
5088
                            if (!HModel_DepthTest(objectPtr->HModelControlBlock, head,1))
 
 
5089
                                return 1; // Fragment is big enough.
 
 
5090
                        }
 
 
5091
                    }
 
 
5092
                }
 
 
5093
                default:
 
 
5094
                return 0;
 
 
5095
            }
 
 
5096
        }
 
 
5097
        return 0;
 
 
5098
        case I_BehaviourSpeargunBolt:
 
 
5099
        {
 
 
5100
            SPEAR_BEHAV_BLOCK *spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->dataptr;
 
 
5101
            assert(spearDataPtr);
 
 
5102
 
 
 
5103
            switch(spearDataPtr->Type)
 
 
5104
            {
 
 
5105
                case I_BehaviourMarine:
 
 
5106
                {
 
 
5107
                    MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
5108
 
 
 
5109
                    if(!marineStatusPointer->My_Weapon->ARealMarine)
 
 
5110
                        return 0;
 
 
5111
                }
 
 
5112
                case I_BehaviourAlien:
 
 
5113
                case I_BehaviourPredator:
 
 
5114
                {
 
 
5115
                    DISPLAYBLOCK *objectPtr = sbPtr->DisplayBlock;
 
 
5116
 
 
 
5117
                    if (objectPtr && objectPtr->HModelControlBlock)
 
 
5118
                    {
 
 
5119
                        /* Test for the head... */
 
 
5120
                        SECTION_DATA *head = GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
 
 
5121
                        /* Is it still attached? */
 
 
5122
 
 
 
5123
                        if (head && !(head->flags & section_data_notreal))
 
 
5124
                        {
 
 
5125
                            if (!HModel_DepthTest(objectPtr->HModelControlBlock,head,1))
 
 
5126
                                return 1; // Fragment is big enough.
 
 
5127
                        }
 
 
5128
                    }
 
 
5129
                }
 
 
5130
                default:
 
 
5131
                return 0;
 
 
5132
            }
 
 
5133
        }
 
 
5134
        default:
 
 
5135
        return 0;
 
 
5136
    }
 
 
5137
}
 
 
5138
 
 
 
5139
#define TROPHY_RANGE     (3000)
 
 
5140
#define TROPHY_RADIUS    (200)
 
 
5141
 
 
 
5142
static STRATEGYBLOCK *GetTrophyTarget(SECTION_DATA **head_section_data) 
 
 
5143
{
 
 
5144
    int numberOfObjects = numVisObjs;
 
 
5145
 
 
 
5146
    *head_section_data = NULL;
 
 
5147
 
 
 
5148
    while (numberOfObjects--)
 
 
5149
    {
 
 
5150
        DISPLAYBLOCK* objectPtr = VisibleObjects[numberOfObjects].DispPtr;
 
 
5151
        assert(objectPtr);
 
 
5152
        STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock;
 
 
5153
 
 
 
5154
        /* does object have a strategy block? */
 
 
5155
        if (sbPtr && Trophy_TargetFilter(sbPtr))
 
 
5156
        {
 
 
5157
            VECTORCH targetpos;
 
 
5158
            assert(objectPtr->HModelControlBlock);
 
 
5159
 
 
 
5160
            GetTargetingPointOfObject(objectPtr,&targetpos);
 
 
5161
            targetpos.vx -= Global_VDB.VDB_World.vx;
 
 
5162
            targetpos.vy -= Global_VDB.VDB_World.vy;
 
 
5163
            targetpos.vz -= Global_VDB.VDB_World.vz;
 
 
5164
            RotateVector(&targetpos, &Global_VDB.VDB_Mat);
 
 
5165
 
 
 
5166
            /* is it in the range band? */
 
 
5167
            if ((targetpos.vz > 0) && (targetpos.vz < TROPHY_RANGE))
 
 
5168
            {
 
 
5169
                DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
5170
 
 
 
5171
                if (dynPtr)
 
 
5172
                {
 
 
5173
                    if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr, PlayerStatus.DisplayBlock, &Global_VDB.VDB_World))
 
 
5174
                    {
 
 
5175
                        /* The minute his *head* is in view... */
 
 
5176
                        SECTION_DATA *head = GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head");
 
 
5177
                        /* Is it still attached? */
 
 
5178
 
 
 
5179
                        if (head && !(head->flags & section_data_notreal))
 
 
5180
                        {
 
 
5181
                            /* We'll have the head now if at all. */
 
 
5182
                            /* I assume if we're alive, we have a head. */
 
 
5183
                            VECTORCH temp_view = head->View_Offset;
 
 
5184
                            temp_view.vz = 0;
 
 
5185
 
 
 
5186
                            if (Approximate3dMagnitude(&temp_view) < TROPHY_RADIUS)
 
 
5187
                            {
 
 
5188
                                /* Aw, okay. */
 
 
5189
                                *head_section_data = head;
 
 
5190
                                return sbPtr;
 
 
5191
                            }
 
 
5192
                        }
 
 
5193
                    }
 
 
5194
                }
 
 
5195
            }
 
 
5196
        }
 
 
5197
    }
 
 
5198
 
 
 
5199
return NULL;
 
 
5200
}
 
 
5201
 
 
 
5202
static void WristbladePrimaryAttackAnimation()
 
 
5203
{
 
 
5204
    /* Attack_Jab is the default. */
 
 
5205
 
 
 
5206
    if ((FastRandom() & 65535) < 21645)
 
 
5207
    {
 
 
5208
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Attack_Primary))
 
 
5209
        {
 
 
5210
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, -1, 0);
 
 
5211
 
 
 
5212
            StaffAttack = PlayerStatus.Crouching ? 6 : 7;
 
 
5213
            return;
 
 
5214
        }
 
 
5215
    }
 
 
5216
 
 
 
5217
    if ((FastRandom() & 65535) < 32767)
 
 
5218
    {
 
 
5219
        if (HModelSequence_Exists(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary))
 
 
5220
        {
 
 
5221
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary, -1, 0);
 
 
5222
 
 
 
5223
            StaffAttack = PlayerStatus.Crouching ? 8 : 9;
 
 
5224
            return;
 
 
5225
        }
 
 
5226
    }
 
 
5227
 
 
 
5228
    /* Still here? Use default. */
 
 
5229
 
 
 
5230
    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Jab, -1, 0);
 
 
5231
    StaffAttack = !PlayerStatus.Crouching;
 
 
5232
}
 
 
5233
 
 
 
5234
void maintain_wristblade()
 
 
5235
{
 
 
5236
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
5237
    {
 
 
5238
        case PHSS_Attack_Secondary_Weak_One:
 
 
5239
        case PHSS_Attack_Secondary_Weak_Two:
 
 
5240
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5241
            {
 
 
5242
                GenericPredatorWeapon_Idle();
 
 
5243
                StaffAttack = -1;
 
 
5244
            }
 
 
5245
            else if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
5246
            {
 
 
5247
                MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AMMO_PRED_WRISTBLADE].MaxDamage, 2500, 0);
 
 
5248
                SpeciesSound(0, PSC_Swipe, ((FastRandom() & 255) - 128), &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position,
PREDATOR_SOUND);
 
 
5249
            }
 
 
5250
 
 
 
5251
            PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
5252
        break;
 
 
5253
        case PHSS_Attack_Secondary_Strong_One:
 
 
5254
        case PHSS_Attack_Secondary_Strong_Two:
 
 
5255
        {
 
 
5256
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5257
            {
 
 
5258
                GenericPredatorWeapon_Idle();
 
 
5259
                StaffAttack = -1;
 
 
5260
            }
 
 
5261
            else if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
5262
            {
 
 
5263
                SECTION_DATA *head_sec;
 
 
5264
 
 
 
5265
                STRATEGYBLOCK *Trophy = GetTrophyTarget(&head_sec);
 
 
5266
 
 
 
5267
                if (Trophy)
 
 
5268
                {
 
 
5269
                    CauseDamageToHModel(Trophy->DisplayBlock->HModelControlBlock, Trophy, &TemplateAmmo[AMMO_PRED_TROPHY_KILLSECTION].MaxDamage,
ONE_FIXED, head_sec, NULL, NULL, 0);
 
 
5270
 
 
 
5271
                    if (PlayerStatus.sound_mouth == SOUND_NOACTIVEINDEX)
 
 
5272
                        SpeciesSound(0, PSC_Taunt, 0, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND);
 
 
5273
 
 
 
5274
                    CurrentGameStats_TrophyCollected(Trophy);
 
 
5275
                }
 
 
5276
                else
 
 
5277
                {
 
 
5278
                    MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage, 2500, 1);
 
 
5279
                }
 
 
5280
 
 
 
5281
                SpeciesSound(0, PSC_Swipe, ((FastRandom()&255)-128), &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND);
 
 
5282
            }
 
 
5283
            PlayerStatus.WeaponState = WEAPONSTATE_FIRING_SECONDARY;
 
 
5284
        }
 
 
5285
        break;
 
 
5286
        case PHSS_PullBack:
 
 
5287
        {
 
 
5288
            if(PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
5289
            {
 
 
5290
                if (!PlayersWeaponHModelController.Tweening && (PlayersWeaponHModelController.sequence_timer == (ONE_FIXED-1)))
 
 
5291
                {
 
 
5292
                    /* Finished poise move. */
 
 
5293
                    InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Hold, -1, 1);
 
 
5294
                }
 
 
5295
                else
 
 
5296
                {
 
 
5297
                    Alien_Tail_Clock += NormalFrameTime;
 
 
5298
                }
 
 
5299
            }
 
 
5300
            else
 
 
5301
            {
 
 
5302
                ThrowSecondaryWeakStrike();
 
 
5303
            }
 
 
5304
        }
 
 
5305
        break;
 
 
5306
        case PHSS_Hold:
 
 
5307
        {
 
 
5308
            /* Windup finished and holding... timeout? */
 
 
5309
            Alien_Tail_Clock -= NormalFrameTime;
 
 
5310
 
 
 
5311
            if (Alien_Tail_Clock < -(ONE_FIXED << 2))
 
 
5312
            {
 
 
5313
                InitHModelTweening_Backwards(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_PullBack, -1, 0);
 
 
5314
            }
 
 
5315
            else if(!PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
5316
            {
 
 
5317
                ThrowSecondaryStrongStrike();
 
 
5318
            }
 
 
5319
        }
 
 
5320
        break;
 
 
5321
        case PHSS_Attack_Jab:
 
 
5322
        case PHSS_Attack_Primary:
 
 
5323
        case PHSS_Attack_Secondary:
 
 
5324
        {
 
 
5325
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5326
            {
 
 
5327
                StaffAttack = -1;
 
 
5328
                GenericPredatorWeapon_Idle();
 
 
5329
            }
 
 
5330
            else if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
5331
            {
 
 
5332
                MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AMMO_PRED_WRISTBLADE].MaxDamage, 2500, 0);
 
 
5333
                SpeciesSound(0, PSC_Swipe, ((FastRandom()&255)-128), &weaponHandle, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND);
 
 
5334
            }
 
 
5335
            PlayerStatus.WeaponState = WEAPONSTATE_FIRING_PRIMARY;
 
 
5336
        }
 
 
5337
        break;
 
 
5338
        default:
 
 
5339
            if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
5340
            {
 
 
5341
                WristbladePrimaryAttackAnimation();
 
 
5342
            }
 
 
5343
            else if(PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
5344
            {
 
 
5345
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_PullBack, -1, 0);
 
 
5346
                Alien_Tail_Clock = 0;
 
 
5347
            }
 
 
5348
            else
 
 
5349
            {
 
 
5350
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
5351
                GenericPredatorWeapon_Idle();
 
 
5352
            }
 
 
5353
    }
 
 
5354
 
 
 
5355
}
 
 
5356
 
 
 
5357
void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr)
 
 
5358
{
 
 
5359
    if (dispPtr)
 
 
5360
    {
 
 
5361
        STRATEGYBLOCK *sbPtr = dispPtr->ObStrategyBlock;
 
 
5362
        assert(sbPtr);
 
 
5363
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
5364
        assert(dynPtr);
 
 
5365
 
 
 
5366
        switch(sbPtr->type)
 
 
5367
        {
 
 
5368
            case I_BehaviourHierarchicalFragment:
 
 
5369
            {
 
 
5370
                SPEAR_BEHAV_BLOCK *newBehaviourDataBlock = malloc(sizeof(SPEAR_BEHAV_BLOCK));
 
 
5371
 
 
 
5372
                Splice_HModels(&newBehaviourDataBlock->HierarchicalFragment, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).section_data);
 
 
5373
 
 
 
5374
                AVP_BEHAVIOUR_TYPE Type = ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type;
 
 
5375
                int SubType = ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType;
 
 
5376
 
 
 
5377
                int android = ((I_BehaviourMarine == Type) && (-1 == SubType));
 
 
5378
 
 
 
5379
                /* we don't need the old extra sb data */
 
 
5380
                Dispel_HModel(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController));
 
 
5381
                free(sbPtr->dataptr);
 
 
5382
 
 
 
5383
                dispPtr->HModelControlBlock = &newBehaviourDataBlock->HierarchicalFragment;
 
 
5384
 
 
 
5385
                sbPtr->dataptr = (void*) newBehaviourDataBlock;
 
 
5386
 
 
 
5387
                if (!sbPtr->dataptr) 
 
 
5388
                {
 
 
5389
                    // Failed to allocate a strategy block data pointer
 
 
5390
                    RemoveBehaviourStrategy(sbPtr);
 
 
5391
                    return;
 
 
5392
                }
 
 
5393
 
 
 
5394
                sbPtr->type = I_BehaviourSpeargunBolt;
 
 
5395
 
 
 
5396
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->counter = 5 * ONE_FIXED;
 
 
5397
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Stuck = 0;
 
 
5398
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->SpearThroughFragment = 1;
 
 
5399
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Android = android;
 
 
5400
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Type = Type;
 
 
5401
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->SubType = SubType;
 
 
5402
 
 
 
5403
                dynPtr->LinVelocity.vx = spearDirectionPtr->vx / 4;
 
 
5404
                dynPtr->LinVelocity.vy = spearDirectionPtr->vy / 4;
 
 
5405
                dynPtr->LinVelocity.vz = spearDirectionPtr->vz / 4;
 
 
5406
                dynPtr->LinImpulse.vx = 0;
 
 
5407
                dynPtr->LinImpulse.vy = 0;
 
 
5408
                dynPtr->LinImpulse.vz = 0;
 
 
5409
                dynPtr->AngVelocity.EulerX = 0;
 
 
5410
                dynPtr->AngVelocity.EulerY = 0;
 
 
5411
                dynPtr->AngVelocity.EulerZ = 0;
 
 
5412
                dynPtr->GravityOn = 1;
 
 
5413
                dynPtr->StopOnCollision = 1;
 
 
5414
 
 
 
5415
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Position.vx = spearPositionPtr->vx - dynPtr->Position.vx;
 
 
5416
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Position.vy = spearPositionPtr->vy - dynPtr->Position.vy;
 
 
5417
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Position.vz = spearPositionPtr->vz - dynPtr->Position.vz;
 
 
5418
                {
 
 
5419
                    MATRIXCH mat;
 
 
5420
                    MakeMatrixFromDirection(spearDirectionPtr,&mat);
 
 
5421
                    ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->Orient = mat;
 
 
5422
                }
 
 
5423
 
 
 
5424
                /* Ooooh!  Not initialised at all! CDF 23/9/98, hassled about an assert */
 
 
5425
                /* KJL 10:37:56 05/10/98 - Just keeping you on your toes :) */
 
 
5426
 
 
 
5427
                InitHModelTweening(&(((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->HierarchicalFragment),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
 
 
5428
                ProveHModel(dispPtr->HModelControlBlock,dispPtr);
 
 
5429
                /* And just for now... */
 
 
5430
                ((SPEAR_BEHAV_BLOCK *)sbPtr->dataptr)->HierarchicalFragment.Playing=0;
 
 
5431
 
 
 
5432
                /* Baaaad Kevin!  And why couldn't you have called the HModelController 'HModelController' like God intended? */
 
 
5433
                /* KJL 10:38:17 05/10/98 - Hey, I was trying to be descriptive. */
 
 
5434
 
 
 
5435
                Sound_Play(SID_PLASMABOLT_HIT, "d", &dynPtr->Position);  
 
 
5436
            }
 
 
5437
            break;
 
 
5438
            case I_BehaviourVideoScreen:
 
 
5439
                puts("VIDEO");
 
 
5440
            break;
 
 
5441
            case I_BehaviourDummy:
 
 
5442
            case I_BehaviourMarine:
 
 
5443
            break;
 
 
5444
            default: // we have hit static dynamic object; not the same as hitting the environment.
 
 
5445
            printf("hitting default %d\n", sbPtr->type);
 
 
5446
            break;
 
 
5447
        }
 
 
5448
    }
 
 
5449
}
 
 
5450
 
 
 
5451
#define SPEAR_NPC_IMPULSE    (2000)
 
 
5452
 
 
 
5453
static void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, VECTORCH *directionPtr, SECTION_DATA *this_section_data) 
 
 
5454
{
 
 
5455
    if(sbPtr)
 
 
5456
    {
 
 
5457
        VECTORCH incoming;
 
 
5458
        VECTORCH *invec = NULL;
 
 
5459
        DISPLAYBLOCK *fragged_section = NULL;
 
 
5460
 
 
 
5461
        if (sbPtr->DynPtr)
 
 
5462
        {
 
 
5463
            MATRIXCH WtoLMat = sbPtr->DynPtr->OrientMat;
 
 
5464
            /* Consider incoming hit direction. */
 
 
5465
            TransposeMatrixCH(&WtoLMat);
 
 
5466
            RotateAndCopyVector(directionPtr, &incoming, &WtoLMat);
 
 
5467
            invec = &incoming;
 
 
5468
 
 
 
5469
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
5470
            /* Forget torque for the moment. */
 
 
5471
 
 
 
5472
            /* Knock the character back - unless it is the alien queen.  */
 
 
5473
            if(sbPtr->type != I_BehaviourQueenAlien)
 
 
5474
            {
 
 
5475
                dynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx, SPEAR_NPC_IMPULSE);
 
 
5476
                dynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy, SPEAR_NPC_IMPULSE);
 
 
5477
                dynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz, SPEAR_NPC_IMPULSE);
 
 
5478
            }
 
 
5479
        }
 
 
5480
 
 
 
5481
        if (this_section_data && sbPtr->DisplayBlock && sbPtr->DisplayBlock->HModelControlBlock)
 
 
5482
        {
 
 
5483
            AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point, this_section_data);
 
 
5484
 
 
 
5485
            assert(sbPtr->DisplayBlock->HModelControlBlock == this_section_data->my_controller);
 
 
5486
            fragged_section = CauseDamageToHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr, &TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage, ONE_FIXED,
this_section_data, invec, positionPtr, 0);
 
 
5487
 
 
 
5488
            if (fragged_section)
 
 
5489
            {
 
 
5490
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx, SPEAR_NPC_IMPULSE);
 
 
5491
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy, SPEAR_NPC_IMPULSE);
 
 
5492
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz, SPEAR_NPC_IMPULSE);
 
 
5493
                CreateSpearPossiblyWithFragment(fragged_section, &LOS_Point, directionPtr);
 
 
5494
            } 
 
 
5495
        }
 
 
5496
        else
 
 
5497
        {
 
 
5498
            CauseDamageToObject(sbPtr, &TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage, ONE_FIXED, invec);
 
 
5499
            if (I_BehaviourInanimateObject == sbPtr->type)
 
 
5500
            {
 
 
5501
            //puts("TAAAAAAA");
 
 
5502
            }
 
 
5503
        }
 
 
5504
    }
 
 
5505
}
 
 
5506
 
 
 
5507
void ShotPredRifleArrow(const VECTORCH *start_position, const MATRIXCH *orient)
 
 
5508
{
 
 
5509
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourSpeargunBolt);
 
 
5510
 
 
 
5511
    if (NULL != sbPtr)
 
 
5512
    {
 
 
5513
        sbPtr->shapeIndex = GetLoadedShapeMSL("spear");
 
 
5514
        DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(sbPtr->shapeIndex); 
 
 
5515
        DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
5516
        sbPtr->dataptr = malloc(sizeof(SPEAR_BEHAV_BLOCK));
 
 
5517
 
 
 
5518
        if((NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == dispPtr))
 
 
5519
        {
 
 
5520
            RemoveBehaviourStrategy(sbPtr);
 
 
5521
            return;
 
 
5522
        }
 
 
5523
 
 
 
5524
        dispPtr->ObStrategyBlock = sbPtr;
 
 
5525
        dispPtr->ObStrategyBlock->DynPtr = dynPtr;
 
 
5526
        dispPtr->ObWorld = *start_position;
 
 
5527
 
 
 
5528
        dispPtr->extent.max_x = 10;
 
 
5529
        dispPtr->extent.max_y = 10;
 
 
5530
        dispPtr->extent.max_z = 10;
 
 
5531
        dispPtr->extent.min_x = -10;
 
 
5532
        dispPtr->extent.min_y = -10;
 
 
5533
        dispPtr->extent.min_z = -10;
 
 
5534
 
 
 
5535
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 50 * ONE_FIXED;
 
 
5536
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->Stuck = 0;
 
 
5537
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->FromPlayer = 1;
 
 
5538
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->SpearThroughFragment = 0;
 
 
5539
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->Android = 0;
 
 
5540
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->Type = I_BehaviourSpeargunBolt;
 
 
5541
        ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->SubType = 0;
 
 
5542
 
 
 
5543
        dynPtr->Position = dynPtr->PrevPosition = *start_position;
 
 
5544
        dynPtr->OrientMat = dynPtr->PrevOrientMat = *orient;
 
 
5545
        dynPtr->Mass = 1;
 
 
5546
 
 
 
5547
        #define PREDATOR_ARROW_SPEED 900000
 
 
5548
        dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, PREDATOR_ARROW_SPEED);
 
 
5549
        dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, PREDATOR_ARROW_SPEED);
 
 
5550
        dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, PREDATOR_ARROW_SPEED);
 
 
5551
 
 
 
5552
        //send location here , so as to avoid having to update it every frame
 
 
5553
        if(SinglePlayer != AvP.PlayMode)
 
 
5554
            AddNetMsg_LocalObjectState(dispPtr->ObStrategyBlock);
 
 
5555
    }
 
 
5556
}
 
 
5557
 
 
 
5558
#define SPEAR_PLAYER_IMPULSE     (-6000)
 
 
5559
 
 
 
5560
void maintain_speargun()
 
 
5561
{
 
 
5562
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
5563
    {
 
 
5564
    case PHSS_Stand:
 
 
5565
    case PHSS_Run:
 
 
5566
    case PHSS_Fidget:
 
 
5567
        if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon && PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
5568
        {
 
 
5569
            CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
5570
 
 
 
5571
            if (CHEATMODE_PIGSTICKING != UserProfile.active_bonus)
 
 
5572
            {
 
 
5573
                PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining--;
 
 
5574
                ShotPredRifleArrow(&PWMFSDP->World_Offset, &PlayerStatus.weapon.ObMat);
 
 
5575
                Sound_Play(SID_PRED_LASER, "hpd", (FastRandom() & 255)-128, &PlayerStatus.sbptr->DynPtr->Position);
 
 
5576
            }
 
 
5577
            else
 
 
5578
            {
 
 
5579
                int i;
 
 
5580
                for (i = 0; i < 10; i++)
 
 
5581
                {
 
 
5582
                    VECTORCH start_position = PWMFSDP->World_Offset;
 
 
5583
                    start_position.vx += FastRandom() & 2024;// + (i * 2);
 
 
5584
                    start_position.vy += FastRandom() & 2024;// + (i * 2);
 
 
5585
                    start_position.vz += FastRandom() & 2024;// + (i * 2);
 
 
5586
                    ShotPredRifleArrow(&start_position, &PlayerStatus.weapon.ObMat);
 
 
5587
                /*
 
 
5588
                    MATRIXCH ObMat = PlayerStatus.weapon.ObMat;
 
 
5589
                    ObMat.mat31 += FastRandom() & 2048 + i*2;
 
 
5590
                    ObMat.mat32 += FastRandom() & 2048 + i*2;
 
 
5591
                    ObMat.mat33 += FastRandom() & 2048 + i*2;
 
 
5592
 
 
 
5593
                    ShotPredRifleArrow(&PWMFSDP->World_Offset, &ObMat);
 
 
5594
                */
 
 
5595
                }
 
 
5596
            }
 
 
5597
 
 
 
5598
            if(DynamicObjectIsMoving(PlayerStatus.sbptr->DynPtr) || !PlayerStatus.sbptr->DynPtr->IsInContactWithFloor)
 
 
5599
            {
 
 
5600
                /* Kickback! */
 
 
5601
                PlayerStatus.sbptr->DynPtr->LinImpulse.vx += MUL_FIXED(PlayerStatus.weapon.ObMat.mat31, SPEAR_PLAYER_IMPULSE);
 
 
5602
                PlayerStatus.sbptr->DynPtr->LinImpulse.vy += MUL_FIXED(PlayerStatus.weapon.ObMat.mat32, SPEAR_PLAYER_IMPULSE);
 
 
5603
                PlayerStatus.sbptr->DynPtr->LinImpulse.vz += MUL_FIXED(PlayerStatus.weapon.ObMat.mat33, SPEAR_PLAYER_IMPULSE);
 
 
5604
            }
 
 
5605
 
 
 
5606
            int time = DIV_FIXED(ONE_FIXED, 65536*2);
 
 
5607
            time -= (ONE_FIXED>>4);
 
 
5608
 
 
 
5609
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, time, 0);
 
 
5610
        return;
 
 
5611
        }
 
 
5612
        else if (!PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining)
 
 
5613
        {
 
 
5614
            PredatorZeroAmmoFunctionality();
 
 
5615
        }
 
 
5616
        break;
 
 
5617
        case PHSS_Attack_Primary:
 
 
5618
            if (!HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5619
                return;
 
 
5620
        default:
 
 
5621
        break;
 
 
5622
    }
 
 
5623
 
 
 
5624
    GenericPredatorWeapon_Idle();
 
 
5625
}
 
 
5626
 
 
 
5627
static const int Caster_PCKill = 49151;
 
 
5628
static const int Caster_NPCKill = 16384;
 
 
5629
 
 
 
5630
static void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage, int factor)
 
 
5631
{
 
 
5632
    VECTORCH position = {-300,0,0};
 
 
5633
    VECTORCH targetDirection;
 
 
5634
    MATRIXCH orient;
 
 
5635
 
 
 
5636
    /* calculate the position */
 
 
5637
    MATRIXCH matrix = Global_VDB.VDB_Mat;
 
 
5638
    TransposeMatrixCH(&matrix);
 
 
5639
 
 
 
5640
    RotateVector(&position, &matrix);
 
 
5641
 
 
 
5642
    position.vx += PlayerStatus.DisplayBlock->ObWorld.vx;
 
 
5643
    position.vy += PlayerStatus.DisplayBlock->ObWorld.vy;
 
 
5644
    position.vz += PlayerStatus.DisplayBlock->ObWorld.vz;
 
 
5645
 
 
 
5646
    if(SmartTarget_Object)
 
 
5647
    {
 
 
5648
        targetDirection.vx = PlayerStatus.Target.Position.vx - position.vx;
 
 
5649
        targetDirection.vy = PlayerStatus.Target.Position.vy - position.vy;
 
 
5650
        targetDirection.vz = PlayerStatus.Target.Position.vz - position.vz;
 
 
5651
    }
 
 
5652
    else
 
 
5653
    {
 
 
5654
        targetDirection.vx = 0;
 
 
5655
        targetDirection.vy = 0;
 
 
5656
        targetDirection.vz = 65535;
 
 
5657
        RotateVector(&targetDirection, &matrix);
 
 
5658
    }
 
 
5659
 
 
 
5660
    Normalise(&targetDirection);
 
 
5661
    MakeMatrixFromDirection(&targetDirection, &orient);
 
 
5662
 
 
 
5663
    {
 
 
5664
        SECTION_DATA *muzzle = GetThisSectionData(PlayerStatus.HModelController.section_data, "dum flash");
 
 
5665
        InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat, 1, damage, factor);
 
 
5666
    }
 
 
5667
    //InitialiseEnergyBoltBehaviourKernel(&position, &orient, 1, damage, factor);
 
 
5668
}
 
 
5669
 
 
 
5670
static void fire_shouldercannon()
 
 
5671
{
 
 
5672
    PlayersWeaponHModelController.Playing = 1;
 
 
5673
 
 
 
5674
    if (PlayerStatus.PlasmaCasterCharge < 0)
 
 
5675
    {
 
 
5676
        /* Don't fire at all! */
 
 
5677
        Sound_Play(SID_PREDATOR_PLASMACASTER_EMPTY, "h");
 
 
5678
    }
 
 
5679
    else
 
 
5680
    {
 
 
5681
        int jumpcharge = MUL_FIXED(Caster_Jumpstart, Caster_ChargeRatio);
 
 
5682
 
 
 
5683
        if ((PlayerStatus.FieldCharge < jumpcharge) && (PlayerStatus.PlasmaCasterCharge < Caster_NPCKill))
 
 
5684
            return;
 
 
5685
        {
 
 
5686
            PlayerStatus.PlasmaCasterCharge = Caster_Jumpstart;
 
 
5687
            PlayerStatus.FieldCharge -= jumpcharge;
 
 
5688
            CurrentGameStats_ChargeUsed(jumpcharge);
 
 
5689
            CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
5690
 
 
 
5691
            /* Fix plasmacaster damage. */
 
 
5692
            Player_Weapon_Damage = TemplateAmmo[AMMO_PLASMACASTER].MaxDamage;
 
 
5693
 
 
 
5694
            /* At least we can theoretically work it. */
 
 
5695
 
 
 
5696
            if (PlayerStatus.PlasmaCasterCharge >= Caster_NPCKill)
 
 
5697
            {
 
 
5698
                /* In the upper graph. */
 
 
5699
                int factor = PlayerStatus.PlasmaCasterCharge - Caster_NPCKill;
 
 
5700
                factor = DIV_FIXED(factor, (Caster_PCKill - Caster_NPCKill));
 
 
5701
 
 
 
5702
                Player_Weapon_Damage.Impact += MUL_FIXED(30, factor);
 
 
5703
                Player_Weapon_Damage.Penetrative += MUL_FIXED(65, factor);
 
 
5704
                Player_Weapon_Damage.Fire += MUL_FIXED(15, factor);
 
 
5705
                Player_Weapon_Damage.Electrical += MUL_FIXED(30, factor);
 
 
5706
            }
 
 
5707
            else
 
 
5708
            {
 
 
5709
                /* In the lower graph. */
 
 
5710
                int factor = DIV_FIXED(PlayerStatus.PlasmaCasterCharge, Caster_NPCKill);
 
 
5711
                Player_Weapon_Damage.Penetrative = MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER].MaxDamage.Penetrative, factor);
 
 
5712
            }
 
 
5713
 
 
 
5714
            InitialiseEnergyBoltBehaviour(&Player_Weapon_Damage, PlayerStatus.PlasmaCasterCharge);
 
 
5715
        }
 
 
5716
    }
 
 
5717
}
 
 
5718
 
 
 
5719
void maintain_shouldercannon()
 
 
5720
{
 
 
5721
    if(PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon && (PlayerStatus.PlasmaCasterCharge < ONE_FIXED) && (PlayerStatus.FieldCharge >
0))
 
 
5722
    {
 
 
5723
        int chargerate;
 
 
5724
        int optimumchargerate = DIV_FIXED(NormalFrameTime, Caster_Chargetime);
 
 
5725
 
 
 
5726
        /* optimumchargerate is for the CASTER. */
 
 
5727
 
 
 
5728
        if (PlayerStatus.FieldCharge >= MUL_FIXED(optimumchargerate, Caster_ChargeRatio))
 
 
5729
            chargerate = optimumchargerate;
 
 
5730
        else
 
 
5731
            chargerate = DIV_FIXED(PlayerStatus.FieldCharge, Caster_ChargeRatio);
 
 
5732
 
 
 
5733
        if (PlayerStatus.PlasmaCasterCharge + chargerate > ONE_FIXED)
 
 
5734
            chargerate = ONE_FIXED - PlayerStatus.PlasmaCasterCharge;
 
 
5735
 
 
 
5736
        PlayerStatus.FieldCharge -= MUL_FIXED(chargerate, Caster_ChargeRatio);
 
 
5737
        CurrentGameStats_ChargeUsed(MUL_FIXED(chargerate, Caster_ChargeRatio));
 
 
5738
        assert(PlayerStatus.FieldCharge >= 0);
 
 
5739
        PlayerStatus.PlasmaCasterCharge += chargerate;
 
 
5740
        assert(PlayerStatus.PlasmaCasterCharge <= ONE_FIXED);
 
 
5741
 
 
 
5742
        if (chargerate)
 
 
5743
        {
 
 
5744
            /* Play a charging sound! */
 
 
5745
            if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
5746
            {
 
 
5747
                if (ActiveSounds[weaponHandle].soundIndex != SID_PREDATOR_PLASMACASTER_CHARGING)
 
 
5748
                    Sound_Stop(weaponHandle); // Stop other sounds...
 
 
5749
            }
 
 
5750
 
 
 
5751
            if(weaponHandle == SOUND_NOACTIVEINDEX)
 
 
5752
                Sound_Play(SID_PREDATOR_PLASMACASTER_CHARGING, "ehl", &weaponHandle);
 
 
5753
        }
 
 
5754
    }
 
 
5755
    else
 
 
5756
    {
 
 
5757
        /* Be very quiet... we're hunting wabbits! */
 
 
5758
        if(weaponHandle != SOUND_NOACTIVEINDEX)
 
 
5759
               Sound_Stop(weaponHandle);
 
 
5760
    }
 
 
5761
 
 
 
5762
 
 
 
5763
    //printf("Plasma Caster Charge = %d\n", PlayerStatus.PlasmaCasterCharge);
 
 
5764
 
 
 
5765
    /* Now anim control. */
 
 
5766
 
 
 
5767
    if (PlayersWeaponHModelController.Sub_Sequence == PHSS_Attack_Primary)
 
 
5768
    {
 
 
5769
        if (PlayersWeaponHModelController.Tweening)
 
 
5770
        {
 
 
5771
            PlayersWeaponHModelController.Playing = 1;
 
 
5772
            return;
 
 
5773
        }
 
 
5774
 
 
 
5775
        assert(PlayersWeaponHModelController.Looped == 0);
 
 
5776
 
 
 
5777
        if (!HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5778
            return;
 
 
5779
    }
 
 
5780
    else if (PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
5781
    {
 
 
5782
        /* Start Animation. */
 
 
5783
        assert(PlayersWeaponHModelController.section_data);
 
 
5784
        assert(PlayersWeaponHModelController.Playing == 1);
 
 
5785
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, -1, 0);
 
 
5786
        fire_shouldercannon();
 
 
5787
        return;
 
 
5788
    }
 
 
5789
 
 
 
5790
    GenericPredatorWeapon_Idle();
 
 
5791
}
 
 
5792
 
 
 
5793
void FireExtinguisher()
 
 
5794
{
 
 
5795
    /* Ha ha ha.  I made a funny! */
 
 
5796
 
 
 
5797
    if (PlayerStatus.sbptr->DamageBlock.IsOnFire && (PlayerStatus.FieldCharge > EXTINGUISHER_USE_THRESHOLD))
 
 
5798
    {
 
 
5799
        /* No longer will we do that wussey instant healing thing! */
 
 
5800
        PlayerStatus.FieldCharge -= EXTINGUISHER_USE_THRESHOLD;
 
 
5801
        CurrentGameStats_ChargeUsed(EXTINGUISHER_USE_THRESHOLD);
 
 
5802
 
 
 
5803
        assert(PlayersWeaponHModelController.section_data);
 
 
5804
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED >> 4), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, -1, 0);
 
 
5805
    }
 
 
5806
}
 
 
5807
 
 
 
5808
void Extinguisher_Use()
 
 
5809
{
 
 
5810
    if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
5811
        PlayerStatus.sbptr->DamageBlock.IsOnFire = 0;
 
 
5812
 
 
 
5813
    /* That's all, folks. */
 
 
5814
}
 
 
5815
 
 
 
5816
void FireSpikeyThing()
 
 
5817
{
 
 
5818
    if ((PlayerStatus.sbptr->DamageBlock.Health == PlayerStatus.StartingHealth << ONE_FIXED_SHIFT) &&
!PlayerStatus.sbptr->DamageBlock.IsOnFire)
 
 
5819
        return;
 
 
5820
 
 
 
5821
    if (PlayerStatus.FieldCharge > MEDICOMP_USE_THRESHOLD)
 
 
5822
    {
 
 
5823
        /* No longer will we do that wussey instant healing thing! */
 
 
5824
        PlayerStatus.FieldCharge -= MEDICOMP_USE_THRESHOLD - 1;
 
 
5825
        CurrentGameStats_ChargeUsed(MEDICOMP_USE_THRESHOLD - 1);
 
 
5826
 
 
 
5827
        assert(PlayersWeaponHModelController.section_data);
 
 
5828
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Attack_Secondary, -1, 0);
 
 
5829
    }
 
 
5830
}
 
 
5831
 
 
 
5832
void SpikeyThing_Use()
 
 
5833
{
 
 
5834
    /* We must be in the animation. */
 
 
5835
 
 
 
5836
    /* Maintain this state... */
 
 
5837
    PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED >> 1;
 
 
5838
 
 
 
5839
    if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
5840
    {
 
 
5841
        if (PlayerStatus.sbptr->DamageBlock.IsOnFire)
 
 
5842
            PlayerStatus.sbptr->DamageBlock.IsOnFire = 0;
 
 
5843
    }
 
 
5844
 
 
 
5845
    if (PlayersWeaponHModelController.keyframe_flags & 2)
 
 
5846
    {
 
 
5847
        PlayerStatus.sbptr->DamageBlock.Health = PlayerStatus.StartingHealth << ONE_FIXED_SHIFT;
 
 
5848
        PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health;
 
 
5849
 
 
 
5850
        /* Now yell a bit? */
 
 
5851
        if (PlayerStatus.sound_mouth != SOUND_NOACTIVEINDEX)
 
 
5852
            Sound_Stop(PlayerStatus.sound_mouth);
 
 
5853
 
 
 
5854
        Sound_Play(SID_PRED_ROAR, "hed", &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position);
 
 
5855
 
 
 
5856
        if(SinglePlayer != AvP.PlayMode)
 
 
5857
            netGameData.myLastScream = PSC_Medicomp_Special;
 
 
5858
 
 
 
5859
        if (GREENFLASH_INTENSITY > PlayerStatus.DamagedOverlayIntensity)
 
 
5860
            PlayerStatus.DamagedOverlayIntensity = GREENFLASH_INTENSITY;
 
 
5861
 
 
 
5862
        {
 
 
5863
            /* Auto change to wristblade? */
 
 
5864
            int slot = PlayerStatus.PreviouslySelectedWeaponSlot;
 
 
5865
 
 
 
5866
            /* Try flashback weapon... */
 
 
5867
            if (slot == -1)
 
 
5868
                slot = SlotForThisWeapon(WEAPON_PRED_WRISTBLADE);
 
 
5869
 
 
 
5870
            PlayerStatus.SwapToWeaponSlot = slot;
 
 
5871
            PlayerStatus.WeaponState = WEAPONSTATE_UNREADYING;
 
 
5872
            PlayerStatus.WeaponStateTimeOutCounter = ONE_FIXED;
 
 
5873
        }
 
 
5874
    }
 
 
5875
}
 
 
5876
 
 
 
5877
void maintain_medicomp()
 
 
5878
{
 
 
5879
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
5880
    {
 
 
5881
        case PHSS_Attack_Primary:
 
 
5882
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5883
                GenericPredatorWeapon_Idle();
 
 
5884
            else
 
 
5885
                Extinguisher_Use();
 
 
5886
        break;
 
 
5887
        case PHSS_Attack_Secondary:
 
 
5888
            if (!HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5889
            {
 
 
5890
                SpikeyThing_Use();
 
 
5891
                break;
 
 
5892
            }
 
 
5893
        //case PHSS_Stand:
 
 
5894
        //break;
 
 
5895
        default:
 
 
5896
            if(PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
5897
            {
 
 
5898
                FireSpikeyThing();
 
 
5899
            }
 
 
5900
            else if(PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon)
 
 
5901
            {
 
 
5902
                FireExtinguisher();
 
 
5903
            }
 
 
5904
            else
 
 
5905
            {
 
 
5906
                GenericPredatorWeapon_Idle();
 
 
5907
            }
 
 
5908
    }
 
 
5909
}
 
 
5910
 
 
 
5911
#define NEAR_WEAPON_FUDGE 1
 
 
5912
 
 
 
5913
void maintain_predpistol() 
 
 
5914
{
 
 
5915
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
5916
    {
 
 
5917
        case PHSS_Attack_Primary:
 
 
5918
            if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
5919
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Stand, ONE_FIXED, 1);
 
 
5920
        break;
 
 
5921
        default:
 
 
5922
            if(PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon && (PlayerStatus.FieldCharge >= PredPistol_ShotCost))
 
 
5923
            {
 
 
5924
                PlayerStatus.FieldCharge -= PredPistol_ShotCost;
 
 
5925
                CurrentGameStats_ChargeUsed(PredPistol_ShotCost);
 
 
5926
 
 
 
5927
                /* calculate the position */
 
 
5928
                VECTORCH position = PWMFSDP->World_Offset;
 
 
5929
 
 
 
5930
                #if NEAR_WEAPON_FUDGE
 
 
5931
                {
 
 
5932
                    VECTORCH fudgeFactor;
 
 
5933
 
 
 
5934
                    fudgeFactor.vx = position.vx - Global_VDB.VDB_World.vx;
 
 
5935
                    fudgeFactor.vy = position.vy - Global_VDB.VDB_World.vy;
 
 
5936
                    fudgeFactor.vz = position.vz - Global_VDB.VDB_World.vz;
 
 
5937
 
 
 
5938
                    Crunch_Position_For_Players_Weapon(&fudgeFactor);
 
 
5939
 
 
 
5940
                    position = fudgeFactor;
 
 
5941
                }
 
 
5942
                #endif
 
 
5943
 
 
 
5944
                Pred_Pistol_Bolt(&position, &PlayerStatus.weapon.ObMat, 1);
 
 
5945
 
 
 
5946
                CurrentGameStats_WeaponFired(PlayerStatus.SelectedWeaponSlot, 1);
 
 
5947
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, ONE_FIXED, 0);
 
 
5948
                Sound_Play(SID_PRED_PISTOL, "hd", &PlayerStatus.sbptr->DynPtr->Position);
 
 
5949
            }
 
 
5950
            else
 
 
5951
            {
 
 
5952
                GenericPredatorWeapon_Idle();
 
 
5953
            }
 
 
5954
    }
 
 
5955
}
 
 
5956
 
 
 
5957
static void InitialiseDiscBehaviour(SECTION_DATA *disc_section)
 
 
5958
{
 
 
5959
    assert(disc_section);
 
 
5960
 
 
 
5961
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourPredatorDisc_SeekTrack);
 
 
5962
 
 
 
5963
    if (NULL == sbPtr)
 
 
5964
        return;
 
 
5965
 
 
 
5966
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
5967
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
5968
    sbPtr->dataptr = malloc(sizeof(PC_PRED_DISC_BEHAV_BLOCK));
 
 
5969
 
 
 
5970
    if ((NULL == dispPtr) || (NULL == dynPtr) || (NULL == sbPtr->dataptr))
 
 
5971
    {
 
 
5972
        RemoveBehaviourStrategy(sbPtr);
 
 
5973
        return;
 
 
5974
    }
 
 
5975
 
 
 
5976
    dispPtr->ObStrategyBlock = sbPtr;
 
 
5977
    dispPtr->ObMat = IdentityMatrix;
 
 
5978
    dispPtr->ObWorld = disc_section->World_Offset;
 
 
5979
    dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
5980
 
 
 
5981
    dispPtr->extent.min_x = -30;
 
 
5982
    dispPtr->extent.min_y = -30;
 
 
5983
    dispPtr->extent.min_z = -30;
 
 
5984
    dispPtr->extent.max_x = 30;
 
 
5985
    dispPtr->extent.max_y = 30;
 
 
5986
    dispPtr->extent.max_z = 30;
 
 
5987
 
 
 
5988
    dispPtr->ObStrategyBlock->DynPtr = dynPtr;
 
 
5989
    dispPtr->ObStrategyBlock->DamageBlock.Indestructable = 1;
 
 
5990
 
 
 
5991
    {
 
 
5992
        MATRIXCH matrix    = Global_VDB.VDB_Mat;
 
 
5993
 
 
 
5994
    /*
 
 
5995
        if (PlayerStatus.Target.Distance < 1400)
 
 
5996
        {
 
 
5997
            // Yuck!
 
 
5998
            dynPtr->Position = Global_VDB.VDB_World;
 
 
5999
            // Nudge down a wee tad bit.
 
 
6000
            dynPtr->Position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat21, 200);
 
 
6001
            dynPtr->Position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat22, 200);
 
 
6002
            dynPtr->Position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat23, 200);
 
 
6003
 
 
 
6004
            dynPtr->Position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat11, 200);
 
 
6005
            dynPtr->Position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat12, 200);
 
 
6006
            dynPtr->Position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat13, 200);
 
 
6007
        }
 
 
6008
        else
 
 
6009
    */
 
 
6010
        dynPtr->Position = disc_section->World_Offset;
 
 
6011
 
 
 
6012
        dynPtr->IgnoreThePlayer = 1;
 
 
6013
 
 
 
6014
        dynPtr->PrevPosition = dynPtr->Position;
 
 
6015
        TransposeMatrixCH(&matrix);
 
 
6016
        /* dynPtr->OrientMat = PlayerStatus.DisplayBlock->ObMat; */
 
 
6017
        dynPtr->PrevOrientMat = dynPtr->OrientMat = matrix;
 
 
6018
        /* I added this next line for networking: Patrick */
 
 
6019
        MatrixToEuler(&matrix, &PlayerStatus.weapon.ObEuler);
 
 
6020
 
 
 
6021
        dynPtr->OrientEuler.EulerX = PlayerStatus.weapon.ObEuler.EulerX;
 
 
6022
        dynPtr->OrientEuler.EulerY = PlayerStatus.weapon.ObEuler.EulerY;
 
 
6023
        dynPtr->OrientEuler.EulerZ = PlayerStatus.weapon.ObEuler.EulerZ;
 
 
6024
 
 
 
6025
        /* align velocity too */
 
 
6026
        dynPtr->LinVelocity.vx = MUL_FIXED(matrix.mat31, DISC_SPEED);
 
 
6027
        dynPtr->LinVelocity.vy = MUL_FIXED(matrix.mat32, DISC_SPEED);
 
 
6028
        dynPtr->LinVelocity.vz = MUL_FIXED(matrix.mat33, DISC_SPEED);
 
 
6029
    }
 
 
6030
 
 
 
6031
      PC_PRED_DISC_BEHAV_BLOCK *bblk = (PC_PRED_DISC_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr;
 
 
6032
 
 
 
6033
    bblk->counter = SmartTarget_Object ? DISC_LIFETIME : DISC_FREETIME;
 
 
6034
    bblk->bounces = 0;
 
 
6035
    bblk->Destruct = 0;
 
 
6036
    bblk->Stuck = 0;
 
 
6037
    bblk->Bounced = 0;
 
 
6038
    bblk->soundHandle = SOUND_NOACTIVEINDEX;
 
 
6039
    bblk->Target = NULL;
 
 
6040
 
 
 
6041
    {
 
 
6042
    int a;
 
 
6043
    for (a=0; a < SB_NAME_LENGTH; a++)
 
 
6044
        bblk->Target_SBname[a] = bblk->Prev_Target_SBname[a] = '\0';
 
 
6045
    }
 
 
6046
 
 
 
6047
    if (SmartTarget_Object)
 
 
6048
    {
 
 
6049
        bblk->Target = SmartTarget_Object->ObStrategyBlock;
 
 
6050
        COPY_NAME(bblk->Prev_Target_SBname, bblk->Target_SBname);
 
 
6051
        COPY_NAME(bblk->Target_SBname, bblk->Target->SBname);
 
 
6052
    }
 
 
6053
 
 
 
6054
    /* Create HModel. */
 
 
6055
    {
 
 
6056
        const SECTION *root_section = GetNamedHierarchyFromLibrary("disk", "Disk");
 
 
6057
 
 
 
6058
        assert(root_section);
 
 
6059
 
 
 
6060
        Create_HModel(&bblk->HModelController, root_section);
 
 
6061
        InitHModelSequence(&bblk->HModelController, HMSQT_MarineStand, MSSS_Minigun_Delta, ONE_FIXED);
 
 
6062
 
 
 
6063
        ProveHModel(&bblk->HModelController, dispPtr);
 
 
6064
 
 
 
6065
        dispPtr->HModelControlBlock = &bblk->HModelController;
 
 
6066
    }
 
 
6067
 
 
 
6068
    if(SinglePlayer != AvP.PlayMode)
 
 
6069
        AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
6070
 
 
 
6071
    disc_section->flags |= section_data_notreal;
 
 
6072
}
 
 
6073
 
 
 
6074
void maintain_preddisc()
 
 
6075
{
 
 
6076
    switch(PlayersWeaponHModelController.Sub_Sequence)
 
 
6077
    {
 
 
6078
    default:
 
 
6079
        if(PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon)
 
 
6080
            InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Attack_Primary, -1, 0);
 
 
6081
    break;
 
 
6082
    case PHSS_Attack_Primary:
 
 
6083
        if (PlayersWeaponHModelController.keyframe_flags & 1)
 
 
6084
        {
 
 
6085
            SECTION_DATA *disc_section = GetThisSectionData(PlayersWeaponHModelController.section_data, "disk");
 
 
6086
            InitialiseDiscBehaviour(disc_section);
 
 
6087
            disc_section->flags |= section_data_notreal;
 
 
6088
            PlayerStatus.SelectedWeapon->PrimaryRoundsRemaining = 0;
 
 
6089
            PredatorZeroAmmoFunctionality();
 
 
6090
        }
 
 
6091
    }
 
 
6092
}
 
 
6093
 
 
 
6094
void WristConsole_Unreadying()
 
 
6095
{
 
 
6096
    //if (PlayerStatus.WeaponStateTimeOutCounter == ONE_FIXED)
 
 
6097
    {
 
 
6098
        assert(PlayersWeaponHModelController.section_data);
 
 
6099
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Go, 96666, 0); /* 1.6s */
 
 
6100
    }
 
 
6101
}
 
 
6102
 
 
 
6103
void GenericPredatorWeapon_SwapOut()
 
 
6104
{
 
 
6105
    if (PlayerStatus.WeaponStateTimeOutCounter == ONE_FIXED)
 
 
6106
    {
 
 
6107
        //int time = DIV_FIXED(ONE_FIXED, PlayerStatus.twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]);
 
 
6108
        int time = DIV_FIXED(ONE_FIXED, ONE_FIXED);
 
 
6109
        time -= (ONE_FIXED>>4);
 
 
6110
 
 
 
6111
        InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>4), HMSQT_PredatorHUD, (int)PHSS_Go, time, 0);
 
 
6112
        PlayersWeaponHModelController.Looped = 0;
 
 
6113
    }
 
 
6114
}
 
 
6115
 
 
 
6116
void GenericPredatorWeapon_Reload()
 
 
6117
{
 
 
6118
    if (PlayerStatus.WeaponStateTimeOutCounter == ONE_FIXED)
 
 
6119
    {
 
 
6120
        int time = DIV_FIXED(ONE_FIXED, 65536*4);
 
 
6121
 
 
 
6122
        time -= ONE_FIXED >> 4;
 
 
6123
 
 
 
6124
        InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Program,time,0);
 
 
6125
        PlayersWeaponHModelController.Looped = 0;
 
 
6126
    }
 
 
6127
}
 
 
6128
 
 
 
6129
void WristConsole_Readying()
 
 
6130
{
 
 
6131
    const SECTION *root_section = GetNamedHierarchyFromLibrary("pred_HUD","wrist display");
 
 
6132
    assert(root_section);
 
 
6133
 
 
 
6134
    PlayersWeaponHModelController.Sequence_Type = HMSQT_PredatorHUD;
 
 
6135
    PlayersWeaponHModelController.Sub_Sequence = PHSS_Come;
 
 
6136
    Transmogrify_HModels(NULL,&PlayersWeaponHModelController, root_section, 0, 1, 1);
 
 
6137
    InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Come,129434,0);    /* 2.1s */
 
 
6138
}
 
 
6139
 
 
 
6140
int SimilarPredWeapons(struct PLAYER_WEAPON_DATA *nwp, struct PLAYER_WEAPON_DATA *owp)
 
 
6141
{
 
 
6142
 
 
 
6143
//if (nwp->WeaponIDNumber == WEAPON_PRED_WRISTBLADE || nwp->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON || nwp->WeaponIDNumber ==
WEAPON_PRED_MEDICOMP)
 
 
6144
if (nwp->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON || nwp->WeaponIDNumber == WEAPON_PRED_MEDICOMP)
 
 
6145
{
 
 
6146
    //if (owp->WeaponIDNumber == WEAPON_PRED_WRISTBLADE || owp->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON || owp->WeaponIDNumber ==
WEAPON_PRED_MEDICOMP)
 
 
6147
    if (owp->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON || owp->WeaponIDNumber == WEAPON_PRED_MEDICOMP)
 
 
6148
    {
 
 
6149
        if (nwp->WeaponIDNumber != owp->WeaponIDNumber)
 
 
6150
            return 1;
 
 
6151
    }
 
 
6152
}
 
 
6153
 
 
 
6154
return 0;
 
 
6155
}
 
 
6156
/*
 
 
6157
{
 
 
6158
    VECTORCH shotvector = {0, 0, 65535};
 
 
6159
    RotateVector(&shotvector, &PWMFSDP->SecMat);
 
 
6160
    FindPolygonInLineOfSight(&shotvector, &PWMFSDP->World_Offset, PlayerStatus.DisplayBlock);
 
 
6161
    MakeParticle(&PWMFSDP->World_Offset, &shotvector, PARTICLE_PLASMATRAIL);
 
 
6162
}
 
 
6163
*/
 
 
6164
 
 
 
6165
void maintain_predator_weapons()
 
 
6166
{
 
 
6167
    PositionPlayersWeapon();
 
 
6168
 
 
 
6169
    switch(PlayerStatus.WeaponState)
 
 
6170
    {
 
 
6171
        case WEAPONSTATE_IDLE:
 
 
6172
        case WEAPONSTATE_FIRING_PRIMARY:
 
 
6173
        case WEAPONSTATE_FIRING_SECONDARY:
 
 
6174
            PlayerStatus.twPtr->maintain_weapon();
 
 
6175
        break;
 
 
6176
        case WEAPONSTATE_READYING:
 
 
6177
        {
 
 
6178
            //if (HModelAnimation_IsFinished(&PlayersWeaponHModelController))
 
 
6179
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
6180
            {
 
 
6181
                PlayerStatus.WeaponState = WEAPONSTATE_IDLE;
 
 
6182
                PlayerStatus.WeaponStateTimeOutCounter = 0;
 
 
6183
 
 
 
6184
                switch(PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
6185
                {
 
 
6186
                    case WEAPON_PRED_WRISTBLADE:
 
 
6187
                        WristBlade_Readying();
 
 
6188
                    break;
 
 
6189
                    case WEAPON_PRED_MEDICOMP:
 
 
6190
                    case WEAPON_PRED_SHOULDERCANNON:
 
 
6191
                        WristConsole_Readying();
 
 
6192
                    break;
 
 
6193
                    case WEAPON_PRED_RIFLE:
 
 
6194
                    default:
 
 
6195
                    break;
 
 
6196
                }
 
 
6197
            }
 
 
6198
            else
 
 
6199
            {
 
 
6200
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
6201
            }
 
 
6202
        }
 
 
6203
        break;
 
 
6204
        case WEAPONSTATE_UNREADYING:
 
 
6205
        {
 
 
6206
            if (PlayerStatus.WeaponStateTimeOutCounter < 0)
 
 
6207
            {
 
 
6208
                PlayerStatus.SelectedWeaponSlot = PlayerStatus.SwapToWeaponSlot;
 
 
6209
                PlayerStatus.SelectedWeapon = &PlayerStatus.WeaponSlot[PlayerStatus.SwapToWeaponSlot];
 
 
6210
                PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_IN;
 
 
6211
            }
 
 
6212
            else
 
 
6213
            {
 
 
6214
                PlayerStatus.WeaponStateTimeOutCounter -= NormalFrameTime;
 
 
6215
            }
 
 
6216
        }
 
 
6217
        break;
 
 
6218
        case WEAPONSTATE_SWAPPING_IN:
 
 
6219
        {
 
 
6220
            PlayerStatus.WeaponStateTimeOutCounter = PlayerStatus.twPtr->swap_in_out;
 
 
6221
 
 
 
6222
            if(!SimilarPredWeapons(PlayerStatus.SelectedWeapon, &PlayerStatus.WeaponSlot[PlayerStatus.SwapToWeaponSlot]))
 
 
6223
            {
 
 
6224
                GrabWeaponShape();
 
 
6225
 
 
 
6226
                assert(PlayersWeaponHModelController.section_data);
 
 
6227
                //InitHModelSequence(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Come, ONE_FIXED/3);
 
 
6228
                InitHModelSequence(&PlayersWeaponHModelController, HMSQT_PredatorHUD, (int)PHSS_Come, PlayerStatus.WeaponStateTimeOutCounter);
 
 
6229
                PlayersWeaponHModelController.Looped = 0;
 
 
6230
 
 
 
6231
            }
 
 
6232
 
 
 
6233
            PlayerStatus.WeaponState = WEAPONSTATE_READYING;
 
 
6234
        }
 
 
6235
        break;
 
 
6236
        case WEAPONSTATE_SWAPPING_OUT:
 
 
6237
        {
 
 
6238
            if(predHUDSoundHandle != SOUND_NOACTIVEINDEX)
 
 
6239
                Sound_Stop(predHUDSoundHandle);
 
 
6240
 
 
 
6241
            if(!SimilarPredWeapons(PlayerStatus.SelectedWeapon, &PlayerStatus.WeaponSlot[PlayerStatus.SwapToWeaponSlot]))
 
 
6242
            {
 
 
6243
            //SECTION *root_section = GetNamedHierarchyFromLibrary("pred_HUD", "Template");
 
 
6244
            //assert(root_section);
 
 
6245
                PlayerStatus.WeaponStateTimeOutCounter = PlayerStatus.twPtr->swap_in_out;
 
 
6246
 
 
 
6247
                PlayersWeaponHModelController.Sequence_Type = (int)HMSQT_PredatorHUD;
 
 
6248
                PlayersWeaponHModelController.Sub_Sequence = (int)PHSS_Go;
 
 
6249
                //PlayersWeaponHModelController.Seconds_For_Sequence = (ONE_FIXED/3);
 
 
6250
                PlayersWeaponHModelController.Seconds_For_Sequence = PlayerStatus.WeaponStateTimeOutCounter;
 
 
6251
                // That to get the new sections right. 
 
 
6252
            //Transmogrify_HModels(NULL, &PlayersWeaponHModelController, root_section, 0, 1, 0);
 
 
6253
                //InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Go, (ONE_FIXED/3), 0);
 
 
6254
                InitHModelTweening(&PlayersWeaponHModelController, (ONE_FIXED>>3), HMSQT_PredatorHUD, (int)PHSS_Go,
PlayerStatus.WeaponStateTimeOutCounter, 0);
 
 
6255
            }
 
 
6256
 
 
 
6257
            PlayerStatus.WeaponState = WEAPONSTATE_UNREADYING;
 
 
6258
        }
 
 
6259
        default:
 
 
6260
        break;
 
 
6261
    }
 
 
6262
}
 
 
6263
 
 
 
6264
int AreTwoPistolsInTertiaryFire()
 
 
6265
{
 
 
6266
    if (PlayersWeaponHModelController.Sub_Sequence != MHSS_Tertiary_Fire)
 
 
6267
    {
 
 
6268
        switch(PlayerStatus.SelectedWeapon->WeaponIDNumber)
 
 
6269
        {
 
 
6270
        case WEAPON_MARINE_PISTOL:
 
 
6271
            switch(PlayerStatus.WeaponState)
 
 
6272
            {
 
 
6273
                case WEAPONSTATE_FIRING_PRIMARY:
 
 
6274
                case WEAPONSTATE_FIRING_SECONDARY:
 
 
6275
                    /* This to trap single player's reflection. */
 
 
6276
                    return 1;
 
 
6277
                default:
 
 
6278
                    return 0;
 
 
6279
            }
 
 
6280
        default:
 
 
6281
        return 0;
 
 
6282
        }
 
 
6283
    }
 
 
6284
 
 
 
6285
return 1;
 
 
6286
}
 
 
6287
 
 
 
6288
SECTION_DATA *HitLocationRoll(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *source)
 
 
6289
{
 
 
6290
    if (sbPtr->DisplayBlock == NULL)
 
 
6291
    {
 
 
6292
        /* Far case?  Hey ho... */
 
 
6293
        return NULL;
 
 
6294
    }
 
 
6295
 
 
 
6296
    if (sbPtr->DisplayBlock->HModelControlBlock == NULL)
 
 
6297
    {
 
 
6298
        /* Not a hierarchy. */
 
 
6299
        return NULL;
 
 
6300
    }
 
 
6301
 
 
 
6302
    if ((source == NULL) || (source == PlayerStatus.sbptr))
 
 
6303
    {
 
 
6304
        /* Why not?  This shouldn't get called, really... */
 
 
6305
        FindHitArea(sbPtr->DisplayBlock);
 
 
6306
    }
 
 
6307
    else
 
 
6308
    {
 
 
6309
        HitZone = HAM_Top;
 
 
6310
        HitAspect = HAM_Centre;
 
 
6311
    }
 
 
6312
 
 
 
6313
    HITLOCATIONTABLEENTRY *entry = Get_Sublocation(sbPtr);
 
 
6314
 
 
 
6315
    if (NULL != entry && entry->section_name)
 
 
6316
        return GetThisSectionData(sbPtr->DisplayBlock->HModelControlBlock->section_data, entry->section_name);
 
 
6317
 
 
 
6318
return NULL;
 
 
6319
}
 
 
6320
 
 
 
6321
/*-------------------**
 
 
6322
** Load/Save Globals **
 
 
6323
**-------------------*/
 
 
6324
#include "savegame.h"
 
 
6325
 
 
 
6326
typedef struct weapons_c_save_block
 
 
6327
{
 
 
6328
    SAVE_BLOCK_HEADER header;
 
 
6329
 
 
 
6330
    int Alien_Visible_Weapon;
 
 
6331
    int Alien_Tail_Clock;
 
 
6332
    DAMAGE_PROFILE Player_Weapon_Damage;
 
 
6333
    int PlayerDamagedOverlayIntensity;
 
 
6334
    int WeaponFidgetPlaying;
 
 
6335
    int Old_Minigun_SpinSpeed;
 
 
6336
    int Minigun_SpinSpeed;
 
 
6337
    int Weapon_ThisBurst;
 
 
6338
    EULER Minigun_MaxHeadJolt;
 
 
6339
    EULER Minigun_HeadJolt;
 
 
6340
    int StaffAttack;
 
 
6341
    int RightHand;
 
 
6342
 
 
 
6343
} WEAPONS_C_SAVE_BLOCK;
 
 
6344
 
 
 
6345
void Load_WeaponsCGlobals(SAVE_BLOCK_HEADER* header)
 
 
6346
{
 
 
6347
    WEAPONS_C_SAVE_BLOCK* block = (WEAPONS_C_SAVE_BLOCK*) header;
 
 
6348
 
 
 
6349
    //check the size of the save block
 
 
6350
    if(header->size != sizeof(*block))
 
 
6351
        return;
 
 
6352
 
 
 
6353
    Alien_Visible_Weapon = block->Alien_Visible_Weapon;
 
 
6354
    Alien_Tail_Clock = block->Alien_Tail_Clock;
 
 
6355
    Player_Weapon_Damage = block->Player_Weapon_Damage;
 
 
6356
    PlayerStatus.DamagedOverlayIntensity = block->PlayerDamagedOverlayIntensity;
 
 
6357
    WeaponFidgetPlaying = block->WeaponFidgetPlaying;
 
 
6358
    Old_Minigun_SpinSpeed = block->Old_Minigun_SpinSpeed;
 
 
6359
    Minigun_SpinSpeed = block->Minigun_SpinSpeed;
 
 
6360
    Weapon_ThisBurst = block->Weapon_ThisBurst;
 
 
6361
    Minigun_MaxHeadJolt = block->Minigun_MaxHeadJolt;
 
 
6362
    Minigun_HeadJolt = block->Minigun_HeadJolt;
 
 
6363
    StaffAttack = block->StaffAttack;
 
 
6364
    RightHand = block->RightHand;
 
 
6365
 
 
 
6366
    Load_SoundState(&weaponHandle);
 
 
6367
}
 
 
6368
 
 
 
6369
void Save_WeaponsCGlobals()
 
 
6370
{
 
 
6371
    WEAPONS_C_SAVE_BLOCK* block;
 
 
6372
 
 
 
6373
    GET_SAVE_BLOCK_POINTER(block);
 
 
6374
 
 
 
6375
    //fill in the header
 
 
6376
    block->header.size = sizeof(*block);
 
 
6377
    block->header.type = SaveBlock_WeaponsCGlobals;
 
 
6378
 
 
 
6379
    block->Alien_Visible_Weapon = Alien_Visible_Weapon;
 
 
6380
    block->Alien_Tail_Clock = Alien_Tail_Clock;
 
 
6381
    block->Player_Weapon_Damage = Player_Weapon_Damage;
 
 
6382
    block->PlayerDamagedOverlayIntensity = PlayerStatus.DamagedOverlayIntensity;
 
 
6383
    block->WeaponFidgetPlaying = WeaponFidgetPlaying;
 
 
6384
    block->Old_Minigun_SpinSpeed = Old_Minigun_SpinSpeed;
 
 
6385
    block->Minigun_SpinSpeed = Minigun_SpinSpeed;
 
 
6386
    block->Weapon_ThisBurst = Weapon_ThisBurst;
 
 
6387
    block->Minigun_MaxHeadJolt = Minigun_MaxHeadJolt;
 
 
6388
    block->Minigun_HeadJolt = Minigun_HeadJolt;
 
 
6389
    block->StaffAttack = StaffAttack;
 
 
6390
    block->RightHand = RightHand;
 
 
6391
 
 
 
6392
    Save_SoundState(&weaponHandle);
 
 
6393
}