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