4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
#include "npc_common.h"
 
 
2
#include "weaponbehaviour.h"
 
 
3
#include "debris.h"
 
 
4
#include "dynamics.h"
 
 
5
#include "lighting.h"
 
 
6
#include "game_statistics.h"
 
 
7
#include "sfx.h"
 
 
8
#include "savegame.h"
 
 
9
#include "userprofile.h"
 
 
10
#include <stdlib.h>
 
 
11
#include <string.h>
 
 
12
 
 
 
13
#define FLAMETHROWER_PARTICLES_PER_FRAME (MUL_FIXED(120,NormalFrameTime))
 
 
14
 
 
 
15
#define FRISBEE_SPEED 20000
 
 
16
#define ENERGY_BOLT_SPEED (ONE_FIXED * 4)
 
 
17
 
 
 
18
extern int SlotForThisWeapon(enum WEAPON_ID weaponID);
 
 
19
extern void AutoSwapToDisc();
 
 
20
extern int GetLoadedShapeMSL(char const * shapename);
 
 
21
 
 
 
22
extern MATRIXCH IdentityMatrix;
 
 
23
 
 
 
24
int PredPistolBoltGravity = 80000;
 
 
25
int PredPistolBoltSpeed = 32767;
 
 
26
int Caster_BlastRadius = 5000;
 
 
27
 
 
 
28
SOUND3DDATA Explosion_SoundData =
 
 
29
{
 
 
30
    {0,0,0,},
 
 
31
    {0,0,0,},
 
 
32
    15000,
 
 
33
    150000,
 
 
34
};
 
 
35
 
 
 
36
static void RubberDuckBehaviour(STRATEGYBLOCK *sbPtr)
 
 
37
{
 
 
38
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
39
 
 
 
40
    if (!sbPtr->DisplayBlock)
 
 
41
        return;
 
 
42
 
 
 
43
    int newLevel = EffectOfRipples(&dynPtr->Position);
 
 
44
 
 
 
45
    {
 
 
46
        int minusDeltaX,plusDeltaX,minusDeltaZ,plusDeltaZ;
 
 
47
        VECTORCH delta;
 
 
48
        delta.vx = dynPtr->Position.vx;
 
 
49
        delta.vz = dynPtr->Position.vz;
 
 
50
 
 
 
51
        delta.vx -= 50;
 
 
52
        minusDeltaX = EffectOfRipples(&delta)-newLevel;
 
 
53
        delta.vx += 100;
 
 
54
        plusDeltaX = EffectOfRipples(&delta)-newLevel;
 
 
55
        delta.vx -= 50;
 
 
56
 
 
 
57
        delta.vz -= 50;
 
 
58
        minusDeltaZ = EffectOfRipples(&delta)-newLevel;
 
 
59
        delta.vz += 100;
 
 
60
        plusDeltaZ = EffectOfRipples(&delta)-newLevel;
 
 
61
 
 
 
62
        {
 
 
63
            int scale = NormalFrameTime<<1;
 
 
64
 
 
 
65
            if(scale > ONE_FIXED)
 
 
66
                scale = ONE_FIXED;
 
 
67
 
 
 
68
            scale = ONE_FIXED;
 
 
69
               dynPtr->LinImpulse.vx -= MUL_FIXED(scale,dynPtr->LinImpulse.vx);
 
 
70
               dynPtr->LinImpulse.vz -= MUL_FIXED(scale,dynPtr->LinImpulse.vz);
 
 
71
        }
 
 
72
 
 
 
73
        if (minusDeltaX > plusDeltaX)
 
 
74
        {
 
 
75
            if (minusDeltaX > 0)
 
 
76
                dynPtr->LinImpulse.vx = -minusDeltaX*256;
 
 
77
        }
 
 
78
        else
 
 
79
        {
 
 
80
            if (plusDeltaX > 0)
 
 
81
                dynPtr->LinImpulse.vx = plusDeltaX*256;
 
 
82
        }
 
 
83
 
 
 
84
        if (minusDeltaZ > plusDeltaZ)
 
 
85
        {
 
 
86
            if (minusDeltaZ > 0)
 
 
87
                dynPtr->LinImpulse.vz = -minusDeltaZ*256;
 
 
88
        }
 
 
89
        else
 
 
90
        {
 
 
91
            if (plusDeltaZ > 0)
 
 
92
                dynPtr->LinImpulse.vz = plusDeltaZ*256;
 
 
93
        }
 
 
94
    }
 
 
95
 
 
 
96
    dynPtr->LinImpulse.vy = 0;
 
 
97
 
 
 
98
    {
 
 
99
        int level=0;
 
 
100
/*
 
 
101
        switch(AvP.level)
 
 
102
        {
 
 
103
            case AVP_ENVIRONMENT_INVASION_A:
 
 
104
                level = -35800;
 
 
105
            break;
 
 
106
            case AVP_ENVIRONMENT_COLONY:
 
 
107
                level = 2656;
 
 
108
            break;
 
 
109
            case AVP_ENVIRONMENT_WATERFALL_M:
 
 
110
            case AVP_ENVIRONMENT_WATERFALL:
 
 
111
                level = 12925;
 
 
112
            break;
 
 
113
            case AVP_ENVIRONMENT_DERELICT:
 
 
114
                level = 32000;
 
 
115
            break;
 
 
116
            case AVP_ENVIRONMENT_E3DEMOSP:
 
 
117
            case AVP_ENVIRONMENT_MASSACRE:
 
 
118
                level = 3300;
 
 
119
            break;
 
 
120
            default:
 
 
121
            level = 0;
 
 
122
        }
 
 
123
 
 
 
124
*/
 
 
125
        dynPtr->Position.vy = newLevel + level;
 
 
126
    }
 
 
127
 
 
 
128
    dynPtr->AngVelocity.EulerY -= MUL_FIXED(dynPtr->AngVelocity.EulerY,NormalFrameTime);
 
 
129
    dynPtr->AngVelocity.EulerY += (dynPtr->LinImpulse.vz + dynPtr->LinImpulse.vx+(FastRandom()&255)-128)/16;
 
 
130
    dynPtr->AngVelocity.EulerZ = (dynPtr->LinImpulse.vz/256);
 
 
131
    dynPtr->AngVelocity.EulerX = (dynPtr->LinImpulse.vx/256);
 
 
132
 
 
 
133
    if (dynPtr->AngVelocity.EulerY > 8192)
 
 
134
        dynPtr->AngVelocity.EulerY = 8192;
 
 
135
    else if (dynPtr->AngVelocity.EulerY < -8192)
 
 
136
        dynPtr->AngVelocity.EulerY = -8192;
 
 
137
 
 
 
138
    DynamicallyRotateObject(dynPtr);
 
 
139
}
 
 
140
 
 
 
141
DISPLAYBLOCK *MakeObject(AVP_BEHAVIOUR_TYPE bhvr, const VECTORCH *positionPtr) 
 
 
142
{
 
 
143
    int shapeIndex;
 
 
144
 
 
 
145
    switch (bhvr)
 
 
146
    {
 
 
147
        case I_BehaviourRocket:
 
 
148
            shapeIndex = GetLoadedShapeMSL("missile");
 
 
149
        break;
 
 
150
        case I_BehaviourPulseGrenade:
 
 
151
        case I_BehaviourGrenade:
 
 
152
            shapeIndex = GetLoadedShapeMSL("Shell");
 
 
153
        break;
 
 
154
        case I_BehaviourFragmentationGrenade:
 
 
155
            shapeIndex = GetLoadedShapeMSL("Cluster");
 
 
156
        break;
 
 
157
        case I_BehaviourProximityGrenade:
 
 
158
            shapeIndex = GetLoadedShapeMSL("Proxmine");
 
 
159
        break;
 
 
160
        case I_BehaviourFlare:
 
 
161
            shapeIndex = GetLoadedShapeMSL("Flare");
 
 
162
        break;
 
 
163
        default:
 
 
164
        shapeIndex = 0;
 
 
165
    }
 
 
166
 
 
 
167
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(bhvr);
 
 
168
 
 
 
169
    if(NULL == sbPtr)
 
 
170
    return NULL;
 
 
171
 
 
 
172
    sbPtr->DisplayBlock = AllocateNewObject(shapeIndex); 
 
 
173
 
 
 
174
    if (sbPtr->DisplayBlock)
 
 
175
    {
 
 
176
        sbPtr->DisplayBlock->ObStrategyBlock = sbPtr;
 
 
177
        sbPtr->DisplayBlock->ObWorld = *positionPtr;
 
 
178
        sbPtr->shapeIndex = shapeIndex;
 
 
179
        sbPtr->maintainVisibility = 1;
 
 
180
        sbPtr->containingModule = ModuleFromPosition(positionPtr, NULL); // JADDA add sbPtr->containingModule = ModuleFromPosition(positionPtr, NULL) for
the rest
 
 
181
        if(NULL != sbPtr->containingModule)
 
 
182
        return sbPtr->DisplayBlock;
 
 
183
    }
 
 
184
 
 
 
185
    RemoveBehaviourStrategy(sbPtr);
 
 
186
 
 
 
187
return NULL;
 
 
188
}
 
 
189
 
 
 
190
STRATEGYBLOCK* CreateRocketKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) 
 
 
191
{
 
 
192
    DISPLAYBLOCK *dispPtr = MakeObject(I_BehaviourRocket, position);
 
 
193
 
 
 
194
    if (NULL != dispPtr)
 
 
195
    {
 
 
196
        /* make displayblock a dynamic module object */
 
 
197
        dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
198
 
 
 
199
        AddLightingEffectToObject(dispPtr, LFX_ROCKETJET);
 
 
200
 
 
 
201
        DYNAMICSBLOCK *dynPtr = dispPtr->ObStrategyBlock->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
202
        dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(PREDPISTOL_BEHAV_BLOCK));
 
 
203
 
 
 
204
        if ((NULL != dynPtr) && (NULL != dispPtr->ObStrategyBlock->dataptr))
 
 
205
        {
 
 
206
            dynPtr->IgnoreThePlayer = fromplayer;
 
 
207
 
 
 
208
            ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 5 * ONE_FIXED * 100;
 
 
209
            ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->player = fromplayer;
 
 
210
 
 
 
211
            /* align rocket to launcher */
 
 
212
            dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
213
 
 
 
214
            dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
215
            /* I added this next line for networking: Patrick */
 
 
216
            MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
217
 
 
 
218
            /* align velocity too */
 
 
219
            #define MISSILE_SPEED 80000
 
 
220
            dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, MISSILE_SPEED);
 
 
221
            dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, MISSILE_SPEED);
 
 
222
            dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, MISSILE_SPEED);
 
 
223
 
 
 
224
            if(SinglePlayer != AvP.PlayMode)
 
 
225
                AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
226
 
 
 
227
            return dispPtr->ObStrategyBlock; 
 
 
228
        }
 
 
229
 
 
 
230
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
231
    }
 
 
232
 
 
 
233
return NULL;
 
 
234
}
 
 
235
 
 
 
236
STRATEGYBLOCK* CreateGrenadeKernel(AVP_BEHAVIOUR_TYPE behaviourID, VECTORCH *position, MATRIXCH *orient, int fromplayer)
 
 
237
{
 
 
238
    DISPLAYBLOCK *dispPtr = MakeObject(behaviourID, position);
 
 
239
 
 
 
240
    if (NULL != dispPtr)
 
 
241
    {
 
 
242
        DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
243
 
 
 
244
        if (NULL != dynPtr)
 
 
245
        {
 
 
246
            switch(behaviourID)
 
 
247
            {
 
 
248
                case I_BehaviourProximityGrenade:
 
 
249
                {
 
 
250
                    dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(PROX_GRENADE_BEHAV_BLOCK));
 
 
251
                    dispPtr->extent.min_x = -20;
 
 
252
                    dispPtr->extent.min_y = -20;
 
 
253
                    dispPtr->extent.min_z = -20;
 
 
254
                    dispPtr->extent.max_x = 20;
 
 
255
                    dispPtr->extent.max_y = 20;
 
 
256
                    dispPtr->extent.max_z = 20;
 
 
257
 
 
 
258
                    if (NULL != dispPtr->ObStrategyBlock->dataptr)
 
 
259
                    {
 
 
260
                        dynPtr->StopOnCollision = 1;
 
 
261
                        ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 2 * ONE_FIXED;
 
 
262
                        ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->SoundHandle = SOUND_NOACTIVEINDEX;
 
 
263
                        ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->SoundGenerationTimer = 0;
 
 
264
                    }
 
 
265
                }
 
 
266
                break;
 
 
267
                default:
 
 
268
                {
 
 
269
                    dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(GRENADE_BEHAV_BLOCK));
 
 
270
                    dynPtr->StopOnCollision = 1;
 
 
271
 
 
 
272
                    if (NULL != dispPtr->ObStrategyBlock->dataptr)
 
 
273
                    {
 
 
274
                        ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 2 * ONE_FIXED;
 
 
275
                        ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->bouncelastframe = 0;
 
 
276
                    }
 
 
277
                }
 
 
278
            }
 
 
279
 
 
 
280
            if (NULL != dispPtr->ObStrategyBlock->dataptr)
 
 
281
            {
 
 
282
                dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
283
                dispPtr->ObStrategyBlock->DynPtr = dynPtr;
 
 
284
                dynPtr->IgnoreThePlayer = fromplayer;
 
 
285
 
 
 
286
                /* align grenade to launcher */
 
 
287
                dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
288
                dynPtr->OrientMat = dynPtr->PrevOrientMat = *orient;
 
 
289
                MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
290
 
 
 
291
                #define GRENADE_SPEED 70000
 
 
292
                /* align velocity too */    
 
 
293
                dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->OrientMat.mat31, GRENADE_SPEED);
 
 
294
                dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->OrientMat.mat32, GRENADE_SPEED);
 
 
295
                dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->OrientMat.mat33, GRENADE_SPEED);
 
 
296
                dynPtr->IgnoresNotVisPolys = 1;
 
 
297
 
 
 
298
                if(SinglePlayer != AvP.PlayMode)
 
 
299
                    AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
300
 
 
 
301
                return dispPtr->ObStrategyBlock;
 
 
302
            }
 
 
303
        }
 
 
304
 
 
 
305
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
306
    }
 
 
307
 
 
 
308
return NULL;
 
 
309
}
 
 
310
 
 
 
311
static STRATEGYBLOCK* CreateFlare(const VECTORCH *position, const MATRIXCH *orient)
 
 
312
{
 
 
313
    DISPLAYBLOCK *dispPtr = MakeObject(I_BehaviourFlare, position);
 
 
314
 
 
 
315
    if (NULL != dispPtr)
 
 
316
    {
 
 
317
        dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
318
 
 
 
319
        DYNAMICSBLOCK *dynPtr = dispPtr->ObStrategyBlock->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
320
        dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(FLARE_BEHAV_BLOCK));
 
 
321
 
 
 
322
        if ((NULL != dynPtr) && (NULL != dispPtr->ObStrategyBlock->dataptr))
 
 
323
        {
 
 
324
            FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * )dispPtr->ObStrategyBlock->dataptr;
 
 
325
            AddLightingEffectToObject(dispPtr, LFX_FLARE);
 
 
326
 
 
 
327
            dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
328
            dynPtr->OrientMat = dynPtr->PrevOrientMat = *orient;
 
 
329
            MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
330
 
 
 
331
            dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->OrientMat.mat31, 30000);
 
 
332
            dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->OrientMat.mat32, 30000);
 
 
333
            dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->OrientMat.mat33, 30000);
 
 
334
            dynPtr->IgnoresNotVisPolys = dynPtr->StopOnCollision = 1;
 
 
335
            dynPtr->StopOnCollision = 0;
 
 
336
 
 
 
337
            bbPtr->LifeTimeRemaining = FLARE_LIFETIME * ONE_FIXED;
 
 
338
            bbPtr->ParticleGenerationTimer = 0;
 
 
339
            bbPtr->SoundHandle = SOUND_NOACTIVEINDEX;
 
 
340
            bbPtr->becomeStuck = 0;
 
 
341
 
 
 
342
            if(SinglePlayer != AvP.PlayMode)
 
 
343
                AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
344
 
 
 
345
            return dispPtr->ObStrategyBlock;
 
 
346
        }
 
 
347
 
 
 
348
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
349
    }
 
 
350
 
 
 
351
return NULL;
 
 
352
}
 
 
353
 
 
 
354
int FlareDebounced = 0;
 
 
355
 
 
 
356
void ThrowAFlare()
 
 
357
{
 
 
358
    if (FlareDebounced)
 
 
359
    {
 
 
360
        FlareDebounced = 0;
 
 
361
 
 
 
362
        MATRIXCH mat = Global_VDB.VDB_Mat;
 
 
363
        VECTORCH position = Global_VDB.VDB_World;
 
 
364
 
 
 
365
        TransposeMatrixCH(&mat);
 
 
366
 
 
 
367
        CreateFlare(&position, &mat);
 
 
368
        Sound_Play(SID_THROW_FLARE, "h");
 
 
369
        PlayerStatus.FlaresLeft--;
 
 
370
    }
 
 
371
}
 
 
372
 
 
 
373
STRATEGYBLOCK* InitialisePulseGrenadeBehaviour(const VECTORCH *position, const MATRIXCH *orient)
 
 
374
{
 
 
375
    DISPLAYBLOCK *dispPtr = MakeObject(I_BehaviourPulseGrenade, position);
 
 
376
 
 
 
377
    if (NULL != dispPtr)
 
 
378
    {
 
 
379
        DYNAMICSBLOCK *dynPtr = dispPtr->ObStrategyBlock->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
380
        dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(PREDPISTOL_BEHAV_BLOCK));
 
 
381
 
 
 
382
        if ((NULL != dynPtr) && (NULL != dispPtr->ObStrategyBlock->dataptr))
 
 
383
        {
 
 
384
            //AddLightingEffectToObject(dispPtr, LFX_ROCKETJET);
 
 
385
            dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
386
 
 
 
387
            ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 5 * ONE_FIXED;
 
 
388
            ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->player = 1;
 
 
389
 
 
 
390
            dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
391
            dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
392
 
 
 
393
            dynPtr->StopOnCollision = 1;
 
 
394
            #define PULSEGRENADE_SPEED 100000
 
 
395
 
 
 
396
            dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, PULSEGRENADE_SPEED);
 
 
397
            dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, PULSEGRENADE_SPEED);
 
 
398
            dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, PULSEGRENADE_SPEED);
 
 
399
 
 
 
400
            if(SinglePlayer != AvP.PlayMode)
 
 
401
                AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
402
 
 
 
403
            return dispPtr->ObStrategyBlock; 
 
 
404
        }
 
 
405
 
 
 
406
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
407
    }
 
 
408
 
 
 
409
return NULL;
 
 
410
}
 
 
411
 
 
 
412
STRATEGYBLOCK* Pred_Pistol_Bolt(VECTORCH *position, MATRIXCH *orient, int player)
 
 
413
{
 
 
414
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourPPPlasmaBolt);
 
 
415
 
 
 
416
    if(NULL == sbPtr)
 
 
417
        return NULL;
 
 
418
 
 
 
419
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
420
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
421
    sbPtr->dataptr = malloc(sizeof(PREDPISTOL_BEHAV_BLOCK));
 
 
422
    SFXBLOCK* sfx_ptr = AllocateSfxBlock();
 
 
423
 
 
 
424
    if ((NULL == dispPtr) || (NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == sfx_ptr))
 
 
425
    {
 
 
426
        RemoveBehaviourStrategy(sbPtr);
 
 
427
        return NULL;
 
 
428
    }
 
 
429
 
 
 
430
    dispPtr->ObStrategyBlock = sbPtr;
 
 
431
    dispPtr->SfxPtr = sfx_ptr;
 
 
432
 
 
 
433
    dispPtr->SfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT;
 
 
434
    /* make displayblock a dynamic module object */
 
 
435
    dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
436
    dispPtr->ObMat = IdentityMatrix;
 
 
437
    dispPtr->ObWorld = *position;
 
 
438
 
 
 
439
    AddLightingEffectToObject(dispPtr, LFX_PLASMA_BOLT);
 
 
440
 
 
 
441
    dispPtr->extent.min_x = -50;
 
 
442
    dispPtr->extent.min_y = -50;
 
 
443
    dispPtr->extent.min_y = -50;
 
 
444
    dispPtr->extent.max_x = 50;
 
 
445
    dispPtr->extent.max_y = 50;
 
 
446
    dispPtr->extent.max_z = 50;
 
 
447
 
 
 
448
    ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 5 * ONE_FIXED;
 
 
449
    ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->player = player;
 
 
450
 
 
 
451
    /* align rocket to launcher */
 
 
452
    dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
453
 
 
 
454
    /* align velocity too */    
 
 
455
    dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
456
    /* I added this next line for networking: Patrick */
 
 
457
    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
458
 
 
 
459
    /* align velocity too */    
 
 
460
 
 
 
461
    dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->OrientMat.mat31, PredPistolBoltSpeed);
 
 
462
    dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->OrientMat.mat32, PredPistolBoltSpeed);
 
 
463
    dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->OrientMat.mat33, PredPistolBoltSpeed);
 
 
464
 
 
 
465
    dynPtr->UseStandardGravity = 0;
 
 
466
    dynPtr->GravityDirection.vy = PredPistolBoltGravity; /* Half gravity! */
 
 
467
    dynPtr->StopOnCollision = 1;
 
 
468
    dynPtr->IgnoreThePlayer = player;
 
 
469
    sbPtr->maintainVisibility = 1;
 
 
470
 
 
 
471
    if(SinglePlayer != AvP.PlayMode)
 
 
472
        AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
473
 
 
 
474
return sbPtr;
 
 
475
}
 
 
476
 
 
 
477
void Crunch_Position_For_Players_Weapon(VECTORCH *position) 
 
 
478
{
 
 
479
    position->vx += PlayerStatus.weapon.ObWorld.vx - Global_VDB.VDB_World.vx;
 
 
480
    position->vx = position->vx/4 + Global_VDB.VDB_World.vx;
 
 
481
 
 
 
482
    position->vy += PlayerStatus.weapon.ObWorld.vy - Global_VDB.VDB_World.vy;
 
 
483
    position->vy = position->vy/4 + Global_VDB.VDB_World.vy;
 
 
484
 
 
 
485
    position->vz += PlayerStatus.weapon.ObWorld.vz - Global_VDB.VDB_World.vz;
 
 
486
    position->vz = position->vz/4 + Global_VDB.VDB_World.vz;
 
 
487
}
 
 
488
 
 
 
489
STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position, MATRIXCH *orient, int player, const DAMAGE_PROFILE *damage, int factor) 
 
 
490
{
 
 
491
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourPredatorEnergyBolt);
 
 
492
 
 
 
493
    if(NULL == sbPtr)
 
 
494
        return NULL;
 
 
495
 
 
 
496
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
497
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
498
    sbPtr->dataptr = malloc(sizeof(CASTER_BOLT_BEHAV_BLOCK));
 
 
499
    SFXBLOCK* sfx_ptr = AllocateSfxBlock();
 
 
500
 
 
 
501
    if((NULL == dispPtr) || (NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == sfx_ptr))
 
 
502
    {
 
 
503
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
504
        return NULL;
 
 
505
    }
 
 
506
 
 
 
507
    dispPtr->ObStrategyBlock = sbPtr;
 
 
508
    dispPtr->SfxPtr = sfx_ptr;
 
 
509
 
 
 
510
    dispPtr->SfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT;
 
 
511
    dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
512
    dispPtr->ObMat = IdentityMatrix;
 
 
513
    dispPtr->ObWorld = *position;
 
 
514
 
 
 
515
    dispPtr->extent.min_x = -50;
 
 
516
    dispPtr->extent.min_y = -50;
 
 
517
    dispPtr->extent.min_y = -50;
 
 
518
    dispPtr->extent.max_x = 50;
 
 
519
    dispPtr->extent.max_y = 50;
 
 
520
    dispPtr->extent.max_z = 50;
 
 
521
 
 
 
522
    dynPtr->Mass = 1;
 
 
523
 
 
 
524
    AddLightingEffectToObject(dispPtr, LFX_PLASMA_BOLT);
 
 
525
 
 
 
526
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 5 * ONE_FIXED * 50;
 
 
527
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->damage = *damage;            
 
 
528
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->blast_radius = MUL_FIXED(factor, Caster_BlastRadius);            
 
 
529
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->player = player;
 
 
530
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->soundHandle = SOUND_NOACTIVEINDEX;
 
 
531
 
 
 
532
    /* align rocket to launcher */
 
 
533
    dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
534
 
 
 
535
    /* align velocity too */    
 
 
536
    dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
537
    /* I added this next line for networking: Patrick */
 
 
538
    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
539
 
 
 
540
    /* align velocity too */
 
 
541
 
 
 
542
    dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, ENERGY_BOLT_SPEED);
 
 
543
    dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, ENERGY_BOLT_SPEED);
 
 
544
    dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, ENERGY_BOLT_SPEED);
 
 
545
 
 
 
546
    if(SinglePlayer != AvP.PlayMode)
 
 
547
        AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
548
 
 
 
549
    Sound_Play(SID_PRED_LAUNCHER, "hpd",(FastRandom() & 255)-128, &dynPtr->Position);
 
 
550
    dynPtr->IgnoreThePlayer = player;
 
 
551
    sbPtr->maintainVisibility = 1;
 
 
552
 
 
 
553
return sbPtr;
 
 
554
}
 
 
555
 
 
 
556
STRATEGYBLOCK* CreateFrisbeeKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) 
 
 
557
{
 
 
558
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFrisbee);
 
 
559
 
 
 
560
    if(NULL == sbPtr)
 
 
561
        return NULL;
 
 
562
 
 
 
563
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
564
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
565
    sbPtr->dataptr = malloc(sizeof(FRISBEE_BEHAV_BLOCK));
 
 
566
 
 
 
567
    if ((NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == dispPtr))
 
 
568
    {
 
 
569
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
570
        return NULL;
 
 
571
    }
 
 
572
 
 
 
573
    dispPtr->ObStrategyBlock = sbPtr;
 
 
574
    dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
575
    dispPtr->ObMat = IdentityMatrix;
 
 
576
    dispPtr->ObWorld = *position;
 
 
577
 
 
 
578
    dispPtr->extent.min_x = -50;
 
 
579
    dispPtr->extent.min_y = -50;
 
 
580
    dispPtr->extent.min_y = -50;
 
 
581
    dispPtr->extent.max_x = 50;
 
 
582
    dispPtr->extent.max_y = 50;
 
 
583
    dispPtr->extent.max_z = 50;
 
 
584
 
 
 
585
    dynPtr->Mass = 3;
 
 
586
 
 
 
587
    AddLightingEffectToObject(dispPtr, LFX_ROCKETJET);
 
 
588
 
 
 
589
    dynPtr->IgnoreThePlayer = fromplayer;
 
 
590
 
 
 
591
    FRISBEE_BEHAV_BLOCK *fblk = ((FRISBEE_BEHAV_BLOCK *)sbPtr->dataptr);
 
 
592
 
 
 
593
    fblk->counter = 5 * ONE_FIXED;
 
 
594
    fblk->soundHandle = SOUND_NOACTIVEINDEX;
 
 
595
    fblk->Bounced = 0;
 
 
596
    fblk->bounces = 0;
 
 
597
 
 
 
598
    fblk->Laser.SourcePosition = *position;
 
 
599
    fblk->Laser.SourcePosition = *position;
 
 
600
    fblk->Laser.BeamHasHitPlayer = 0;
 
 
601
    fblk->Laser.BeamIsOn = 0;
 
 
602
 
 
 
603
    /* Create HModel. */
 
 
604
    {
 
 
605
        SECTION *root_section = GetNamedHierarchyFromLibrary("mdisk", "Mdisk");
 
 
606
 
 
 
607
        assert(root_section);
 
 
608
 
 
 
609
        Create_HModel(&fblk->HModelController, root_section);
 
 
610
        InitHModelSequence(&fblk->HModelController, HMSQT_MarineStand, MSSS_Minigun_Delta, (ONE_FIXED>>1));
 
 
611
 
 
 
612
        ProveHModel(&fblk->HModelController,dispPtr);
 
 
613
        fblk->HModelController.Looped = 1;
 
 
614
 
 
 
615
        dispPtr->HModelControlBlock = &fblk->HModelController;
 
 
616
    }
 
 
617
 
 
 
618
    /* align rocket to launcher */
 
 
619
    dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
620
    dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
621
 
 
 
622
    /* I added this next line for networking: Patrick */
 
 
623
    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
624
 
 
 
625
    /* align velocity too */    
 
 
626
 
 
 
627
    dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, FRISBEE_SPEED);
 
 
628
    dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, FRISBEE_SPEED);
 
 
629
    dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, FRISBEE_SPEED);
 
 
630
    sbPtr->maintainVisibility = 1;
 
 
631
 
 
 
632
    if(SinglePlayer != AvP.PlayMode)
 
 
633
        AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
634
 
 
 
635
return sbPtr; 
 
 
636
}
 
 
637
 
 
 
638
static int Frisbee_TargetFilter(STRATEGYBLOCK *candidate)
 
 
639
{
 
 
640
    switch (candidate->type)
 
 
641
    {
 
 
642
        case I_BehaviourAlien:
 
 
643
        case I_BehaviourPredator:
 
 
644
        case I_BehaviourPredatorPlayer:
 
 
645
        case I_BehaviourAlienPlayer:
 
 
646
        case I_BehaviourFaceHugger:
 
 
647
        case I_BehaviourXenoborg:
 
 
648
        case I_BehaviourQueenAlien:
 
 
649
            return 1;
 
 
650
        case I_BehaviourMarine:
 
 
651
        case I_BehaviourMarinePlayer:
 
 
652
            return 0;
 
 
653
        case I_BehaviourNetGhost:
 
 
654
        {
 
 
655
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
656
            switch (dataptr->type)
 
 
657
            {
 
 
658
                case I_BehaviourAlienPlayer:
 
 
659
                case I_BehaviourPredatorPlayer:
 
 
660
                case I_BehaviourMarinePlayer:
 
 
661
                {
 
 
662
                    switch (netGameData.gameType)
 
 
663
                    {
 
 
664
                        default:
 
 
665
                        case NGT_Coop:
 
 
666
                        case NGT_CoopDeathmatch:
 
 
667
                        case NGT_LastManStanding:
 
 
668
                            return 0;
 
 
669
                        case NGT_Individual:
 
 
670
                        case NGT_PredatorTag:
 
 
671
                        case NGT_AlienTag:
 
 
672
                            return 1; //However, there shouldn't be more than one alien in alien tag anyway.
 
 
673
                    }
 
 
674
                }
 
 
675
                case I_BehaviourAlien:
 
 
676
                    return 1;
 
 
677
                default:
 
 
678
                    return 0;
 
 
679
            }
 
 
680
        }
 
 
681
        case I_BehaviourDummy:
 
 
682
        {
 
 
683
            switch (AvP.PlayerType)
 
 
684
            {
 
 
685
                default:
 
 
686
                case I_Marine:
 
 
687
                    return 0;
 
 
688
                case I_Predator:
 
 
689
                case I_Alien:
 
 
690
                    return 1;
 
 
691
            }
 
 
692
        }
 
 
693
        default:
 
 
694
            return 0;
 
 
695
    }
 
 
696
}
 
 
697
 
 
 
698
void FrisbeeEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
699
{
 
 
700
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
701
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
702
    CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
703
 
 
 
704
    MakeDewlineTrailParticles(dynPtr, 32);
 
 
705
 
 
 
706
    /* check for a collision with something */
 
 
707
    if (bbPtr->counter <= 0)
 
 
708
    {
 
 
709
        /* for net game support: send a message saying we've blown up... */
 
 
710
        if(SinglePlayer != AvP.PlayMode)
 
 
711
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
712
 
 
 
713
        sbPtr->please_destroy_me = 1;
 
 
714
    }
 
 
715
    else if (reportPtr)
 
 
716
    {
 
 
717
          if(reportPtr->ObstacleSBPtr)
 
 
718
          {
 
 
719
             VECTORCH attack_dir;
 
 
720
            /* Accuracy snipped again! */
 
 
721
             GetDirectionOfAttack(reportPtr->ObstacleSBPtr, &dynPtr->LinVelocity, &attack_dir);
 
 
722
            CauseDamageToObject(reportPtr->ObstacleSBPtr, &bbPtr->damage, ONE_FIXED, &attack_dir);
 
 
723
        }
 
 
724
 
 
 
725
        if(SinglePlayer != AvP.PlayMode)
 
 
726
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
727
 
 
 
728
        /* Splash damage? */
 
 
729
        MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_PULSEGRENADE);
 
 
730
        sbPtr->please_destroy_me = 1;
 
 
731
    }
 
 
732
    else
 
 
733
    {
 
 
734
        VECTORCH direction;
 
 
735
        direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx;
 
 
736
        direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy;
 
 
737
        direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz;
 
 
738
        Normalise(&direction);
 
 
739
        MakeMatrixFromDirection(&direction, &dynPtr->OrientMat);
 
 
740
        bbPtr->counter -= NormalFrameTime;
 
 
741
    }
 
 
742
}
 
 
743
 
 
 
744
//Function only does minimal frisbee setup , the rest will be done by the load function
 
 
745
static const VECTORCH zeroVect = {0,0,0};
 
 
746
 
 
 
747
static STRATEGYBLOCK* InitialiseFrisbeeBehaviour_ForLoad()
 
 
748
{
 
 
749
    DISPLAYBLOCK *dispPtr = MakeObject(I_BehaviourFrisbee, &zeroVect);
 
 
750
 
 
 
751
    if (NULL != dispPtr)
 
 
752
    {
 
 
753
        DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
754
        dispPtr->ObStrategyBlock->dataptr = malloc(sizeof(FRISBEE_BEHAV_BLOCK));
 
 
755
 
 
 
756
        if ((NULL != dynPtr) && (NULL != dispPtr->ObStrategyBlock->dataptr))
 
 
757
        {
 
 
758
            /* make displayblock a dynamic module object */
 
 
759
            dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
760
 
 
 
761
            dispPtr->ObStrategyBlock->DynPtr = dynPtr;
 
 
762
 
 
 
763
            FRISBEE_BEHAV_BLOCK *bblk = dispPtr->ObStrategyBlock->dataptr;
 
 
764
 
 
 
765
            bblk->soundHandle = SOUND_NOACTIVEINDEX;
 
 
766
            bblk->Laser.SourcePosition = zeroVect;
 
 
767
            bblk->Laser.SourcePosition = zeroVect;
 
 
768
            bblk->Laser.BeamHasHitPlayer = 0;
 
 
769
            bblk->Laser.BeamIsOn = 0;
 
 
770
 
 
 
771
            dispPtr->HModelControlBlock = &bblk->HModelController;
 
 
772
 
 
 
773
            return dispPtr->ObStrategyBlock;
 
 
774
        }
 
 
775
 
 
 
776
        RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
 
 
777
    }
 
 
778
 
 
 
779
return NULL;
 
 
780
}
 
 
781
 
 
 
782
static STRATEGYBLOCK* InitialiseFrisbeeBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, const DAMAGE_PROFILE *damage, int factor) 
 
 
783
{
 
 
784
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFrisbeeEnergyBolt);
 
 
785
 
 
 
786
    if(NULL == sbPtr)
 
 
787
        return NULL;
 
 
788
 
 
 
789
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
790
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
 
 
791
    sbPtr->dataptr = malloc(sizeof(CASTER_BOLT_BEHAV_BLOCK));
 
 
792
    SFXBLOCK* sfx_ptr = AllocateSfxBlock();
 
 
793
 
 
 
794
    if((NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == dispPtr) || (NULL == sfx_ptr))
 
 
795
    {
 
 
796
        RemoveBehaviourStrategy(sbPtr);
 
 
797
        return NULL;
 
 
798
    }
 
 
799
 
 
 
800
    dispPtr->ObStrategyBlock = sbPtr;
 
 
801
    dispPtr->SfxPtr = sfx_ptr;
 
 
802
 
 
 
803
    dispPtr->SfxPtr->SfxID = SFX_FRISBEE_PLASMA_BOLT;
 
 
804
    dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
 
 
805
    dispPtr->ObMat = IdentityMatrix;
 
 
806
    dispPtr->ObWorld = *position;
 
 
807
 
 
 
808
    dispPtr->extent.min_x = -50;
 
 
809
    dispPtr->extent.min_y = -50;
 
 
810
    dispPtr->extent.min_y = -50;
 
 
811
    dispPtr->extent.max_x = 50;
 
 
812
    dispPtr->extent.max_y = 50;
 
 
813
    dispPtr->extent.max_z = 50;
 
 
814
 
 
 
815
    dynPtr->Mass = 1;
 
 
816
 
 
 
817
    AddLightingEffectToObject(dispPtr, LFX_PLASMA_BOLT);
 
 
818
 
 
 
819
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->counter = 5 * ONE_FIXED;
 
 
820
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->damage = *damage;            
 
 
821
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->blast_radius = MUL_FIXED(factor,Caster_BlastRadius);            
 
 
822
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->player = player;
 
 
823
    ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->dataptr)->soundHandle = SOUND_NOACTIVEINDEX;
 
 
824
 
 
 
825
    /* align rocket to launcher */
 
 
826
    dynPtr->Position = dynPtr->PrevPosition = *position;
 
 
827
    dynPtr->IgnoreSameObjectsAsYou = 1;
 
 
828
 
 
 
829
    /* align velocity too */
 
 
830
    dynPtr->PrevOrientMat = dynPtr->OrientMat = *orient;
 
 
831
    /* I added this next line for networking: Patrick */
 
 
832
    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
833
 
 
 
834
    dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31, ENERGY_BOLT_SPEED);
 
 
835
    dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32, ENERGY_BOLT_SPEED);
 
 
836
    dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33, ENERGY_BOLT_SPEED);
 
 
837
 
 
 
838
    if(SinglePlayer != AvP.PlayMode)
 
 
839
        AddNetGameObjectID(dispPtr->ObStrategyBlock);
 
 
840
 
 
 
841
    Sound_Play(SID_PRED_LAUNCHER, "hpd", (FastRandom() & 255)-128, &dynPtr->Position);
 
 
842
 
 
 
843
    dynPtr->IgnoreThePlayer = player;
 
 
844
    sbPtr->maintainVisibility = 1;
 
 
845
 
 
 
846
return sbPtr;
 
 
847
}
 
 
848
 
 
 
849
static int Reflect(VECTORCH *Incident, VECTORCH *Normal, EULER *Output)
 
 
850
{
 
 
851
    MATRIXCH tempMat;
 
 
852
    VECTORCH outVec;
 
 
853
    /* Ah, the wonders of better math support. */
 
 
854
 
 
 
855
    assert(Incident);
 
 
856
    assert(Normal);
 
 
857
    assert(Output);
 
 
858
 
 
 
859
    VECTORCH normInc = *Incident;
 
 
860
    Normalise(&normInc);
 
 
861
    int retval = DotProduct(&normInc,Normal);
 
 
862
 
 
 
863
    /* Hold that thought. */
 
 
864
    int dot = retval*(-2);
 
 
865
 
 
 
866
    /* Yeah, okay, and a better algorithm. */    
 
 
867
    outVec.vx = normInc.vx + MUL_FIXED(dot, Normal->vx);
 
 
868
    outVec.vy = normInc.vy + MUL_FIXED(dot, Normal->vy);
 
 
869
    outVec.vz = normInc.vz + MUL_FIXED(dot, Normal->vz);
 
 
870
 
 
 
871
    MakeMatrixFromDirection(&outVec,&tempMat);
 
 
872
    MatrixToEuler(&tempMat,Output);
 
 
873
    /* But bear in mind, most of the early one was coping with *
 
 
874
     * bad functions and junk inputs... that's my excuse.      */
 
 
875
 
 
 
876
return retval;
 
 
877
}
 
 
878
 
 
 
879
#define DISC_MAX_BOUNCES    (10)
 
 
880
 
 
 
881
void Frisbee_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr)
 
 
882
{
 
 
883
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
884
    FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
885
    MATRIXCH mat;
 
 
886
 
 
 
887
    /* Hit the environment.  Bounce? */
 
 
888
    int dp = Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
 
 
889
 
 
 
890
    dynPtr->OrientEuler.EulerZ = 0;
 
 
891
    dynPtr->IgnoreThePlayer = 0;
 
 
892
 
 
 
893
    /* Always bounce.  Reference Disc_Hit_Environment for sticking conditions. */
 
 
894
    MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
 
 
895
    //Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
 
 
896
 
 
 
897
    CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
 
 
898
    TransposeMatrixCH(&mat);
 
 
899
 
 
 
900
    dynPtr->OrientMat = mat;
 
 
901
 
 
 
902
    dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31, FRISBEE_SPEED);
 
 
903
    dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32, FRISBEE_SPEED);
 
 
904
    dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33, FRISBEE_SPEED);
 
 
905
 
 
 
906
    dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;
 
 
907
 
 
 
908
    // Record that the disc has bounced - for use in network game
 
 
909
    fbPtr->Bounced = 1;
 
 
910
    fbPtr->bounces++;
 
 
911
}
 
 
912
 
 
 
913
static int SBForcesBounce(STRATEGYBLOCK *sbPtr)
 
 
914
{
 
 
915
    switch (sbPtr->type)
 
 
916
    {
 
 
917
        case I_BehaviourInanimateObject:
 
 
918
            return sbPtr->DamageBlock.Indestructable;
 
 
919
        case I_BehaviourProximityDoor:
 
 
920
        case I_BehaviourTrackObject:
 
 
921
        case I_BehaviourLiftDoor:
 
 
922
        case I_BehaviourSwitchDoor:
 
 
923
        case I_BehaviourLinkSwitch:
 
 
924
        case I_BehaviourBinarySwitch:
 
 
925
        case I_BehaviourLift:
 
 
926
        case I_BehaviourPlatform:
 
 
927
        case I_BehaviourPredatorDisc_SeekTrack:
 
 
928
            return 1;
 
 
929
        case I_BehaviourNetGhost:
 
 
930
        {
 
 
931
            NETGHOSTDATABLOCK *dataptr = sbPtr->dataptr;
 
 
932
 
 
 
933
            switch (dataptr->type)
 
 
934
            {
 
 
935
                case I_BehaviourPredatorDisc_SeekTrack:
 
 
936
                    return 1;
 
 
937
                default:
 
 
938
                    return 0;
 
 
939
            }
 
 
940
        }
 
 
941
        default:
 
 
942
            return 0;
 
 
943
    }
 
 
944
}
 
 
945
 
 
 
946
static void MatrixFromZVector(VECTORCH *v, MATRIXCH *m)
 
 
947
{
 
 
948
    VECTORCH XVector;
 
 
949
    VECTORCH YVector;
 
 
950
    VECTORCH zero = {0, 0, 0};
 
 
951
 
 
 
952
    XVector.vx = v->vz;
 
 
953
    XVector.vy = 0;
 
 
954
    XVector.vz = -v->vx;
 
 
955
 
 
 
956
    Normalise(&XVector);
 
 
957
 
 
 
958
    MakeNormal(&zero, &XVector, v, &YVector);
 
 
959
 
 
 
960
    m->mat11 = XVector.vx;
 
 
961
    m->mat12 = XVector.vy;
 
 
962
    m->mat13 = XVector.vz;
 
 
963
 
 
 
964
    m->mat21 = -YVector.vx;
 
 
965
    m->mat22 = -YVector.vy;
 
 
966
    m->mat23 = -YVector.vz;
 
 
967
 
 
 
968
    m->mat31 = v->vx;
 
 
969
    m->mat32 = v->vy;
 
 
970
    m->mat33 = v->vz;
 
 
971
}
 
 
972
 
 
 
973
void FrisbeeBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
974
{
 
 
975
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
976
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
977
    FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
978
    int explodeNow = 0;    
 
 
979
 
 
 
980
    if (fbPtr->counter <= 0)
 
 
981
    {
 
 
982
        explodeNow = 1;
 
 
983
    }
 
 
984
    else
 
 
985
    {        
 
 
986
        if (reportPtr)
 
 
987
        {
 
 
988
            if (NULL == reportPtr->ObstacleSBPtr)
 
 
989
            {
 
 
990
                Frisbee_Hit_Environment(sbPtr, reportPtr);
 
 
991
            }
 
 
992
            else if (SBForcesBounce(reportPtr->ObstacleSBPtr))
 
 
993
            {
 
 
994
                MATRIXCH mat;
 
 
995
                /* Bounce. */
 
 
996
                Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
 
 
997
                dynPtr->OrientEuler.EulerZ = 0;
 
 
998
                dynPtr->IgnoreThePlayer = 0;
 
 
999
 
 
 
1000
                MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
 
 
1001
                //Sound_Play(SID_ED_SKEETERDISC_HITWALL, "dp", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
1002
 
 
 
1003
                fbPtr->bounces++;
 
 
1004
                /*
 
 
1005
                Record that the disc has bounced - for use in network game
 
 
1006
                */
 
 
1007
 
 
 
1008
                fbPtr->Bounced = 1;
 
 
1009
 
 
 
1010
                CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
 
 
1011
                TransposeMatrixCH(&mat);
 
 
1012
 
 
 
1013
                dynPtr->OrientMat = mat;
 
 
1014
 
 
 
1015
                dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31, FRISBEE_SPEED);
 
 
1016
                dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32, FRISBEE_SPEED);
 
 
1017
                dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33, FRISBEE_SPEED);
 
 
1018
 
 
 
1019
                dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;
 
 
1020
            }
 
 
1021
            else
 
 
1022
            {
 
 
1023
                /* Hit a creature? */
 
 
1024
                VECTORCH attack_dir;
 
 
1025
 
 
 
1026
                /* Accuracy snipped. */
 
 
1027
                GetDirectionOfAttack(reportPtr->ObstacleSBPtr, &dynPtr->LinVelocity, &attack_dir);
 
 
1028
                CauseDamageToObject(reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_FRISBEE].MaxDamage, ONE_FIXED,&attack_dir);
 
 
1029
                explodeNow = 1;
 
 
1030
            }
 
 
1031
        }
 
 
1032
    }
 
 
1033
 
 
 
1034
    if (explodeNow)
 
 
1035
    {
 
 
1036
        if (sbPtr->containingModule)
 
 
1037
        {
 
 
1038
            MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_PULSEGRENADE);
 
 
1039
            Explosion_SoundData.position = dynPtr->Position;
 
 
1040
            Sound_Play(SID_NICE_EXPLOSION, "nh", &Explosion_SoundData);
 
 
1041
        }
 
 
1042
 
 
 
1043
        /* for net game support: send a message saying we've blown up... */
 
 
1044
        if(SinglePlayer != AvP.PlayMode)
 
 
1045
        {
 
 
1046
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1047
             AddNetMsg_SpotOtherSound(SID_NICE_EXPLOSION, &dynPtr->Position, 1);
 
 
1048
        }
 
 
1049
 
 
 
1050
        sbPtr->please_destroy_me = 1;
 
 
1051
    }
 
 
1052
    else
 
 
1053
    {
 
 
1054
        /* We must be flying.  Maintain sound. */
 
 
1055
 
 
 
1056
        if(fbPtr->soundHandle != SOUND_NOACTIVEINDEX)
 
 
1057
        {
 
 
1058
            Sound_Update3d(fbPtr->soundHandle, &sbPtr->DynPtr->Position);
 
 
1059
 
 
 
1060
            if (ActiveSounds[fbPtr->soundHandle].soundIndex != SID_PREDATOR_DISK_FLYING)
 
 
1061
            {
 
 
1062
                Sound_Stop(fbPtr->soundHandle);
 
 
1063
                 //Sound_Play(SID_ED_SKEETERDISC_SPIN, "del", &sbPtr->DynPtr->Position, &fbPtr->soundHandle);
 
 
1064
            }
 
 
1065
        }
 
 
1066
        //else Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&fbPtr->soundHandle);
 
 
1067
 
 
 
1068
        SECTION_DATA *disc_section = GetThisSectionData(fbPtr->HModelController.section_data, "Mdisk");
 
 
1069
 
 
 
1070
        if (disc_section)
 
 
1071
        {
 
 
1072
            VECTORCH line;
 
 
1073
            line.vx = disc_section->SecMat.mat11;
 
 
1074
            line.vy = disc_section->SecMat.mat12;
 
 
1075
            line.vz = disc_section->SecMat.mat13;
 
 
1076
 
 
 
1077
            /* Make a laser? */
 
 
1078
            // KJL 12:32:40 08/02/00 - Fox want the laser beam removed
 
 
1079
            fbPtr->Laser.BeamIsOn = 0;
 
 
1080
 
 
 
1081
            {
 
 
1082
                int l = 0;
 
 
1083
                for (;l < 4; l++)
 
 
1084
                    MakeFlareParticle(dynPtr);
 
 
1085
            }    
 
 
1086
 
 
 
1087
            /* Now do the target sweep. */
 
 
1088
            if (fbPtr->counter < (4* (ONE_FIXED)))
 
 
1089
            {
 
 
1090
                int a = 0;
 
 
1091
                STRATEGYBLOCK *nearest = NULL;
 
 
1092
                VECTORCH offset;
 
 
1093
 
 
 
1094
                MODULE *dmod = ModuleFromPosition(&sbPtr->DynPtr->Position, PlayerStatus.sbptr->containingModule);
 
 
1095
 
 
 
1096
                for (; a < NumActiveStBlocks; a++)
 
 
1097
                 {
 
 
1098
                    STRATEGYBLOCK *candidate = ActiveStBlockList[a];
 
 
1099
 
 
 
1100
                    if (candidate != sbPtr)
 
 
1101
                    {
 
 
1102
                        if (candidate->DynPtr)
 
 
1103
                        {
 
 
1104
                            if (Frisbee_TargetFilter(candidate))
 
 
1105
                            {
 
 
1106
                                /* Check visibility? */
 
 
1107
 
 
 
1108
                                if (!NPC_IsDead(candidate))
 
 
1109
                                {
 
 
1110
                                    if (candidate->DisplayBlock && sbPtr->DisplayBlock)
 
 
1111
                                    {
 
 
1112
                                        /* Near case. */
 
 
1113
                                        if (NPCCanSeeTarget(sbPtr, candidate))
 
 
1114
                                        {
 
 
1115
                                            VECTORCH targetPos;
 
 
1116
                                            nearest = candidate;
 
 
1117
 
 
 
1118
                                            /* Shoot it, */
 
 
1119
                                            GetTargetingPointOfObject_Far(nearest, &targetPos);
 
 
1120
 
 
 
1121
                                            if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position,
 
 
1122
                                                &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset))
 
 
1123
                                            {
 
 
1124
                                                /* Use this. */
 
 
1125
                                            }
 
 
1126
                                            else
 
 
1127
                                            {
 
 
1128
                                                offset.vx = targetPos.vx-sbPtr->DynPtr->Position.vx;
 
 
1129
                                                offset.vy = targetPos.vy-sbPtr->DynPtr->Position.vy;
 
 
1130
                                                offset.vz = targetPos.vz-sbPtr->DynPtr->Position.vz;
 
 
1131
                                                Normalise(&offset);
 
 
1132
                                            }
 
 
1133
 
 
 
1134
                                            {
 
 
1135
                                                MATRIXCH mat;
 
 
1136
                                                MatrixFromZVector(&offset,&mat);
 
 
1137
                                                InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0, 
 
 
1138
                                                    &TemplateAmmo[AMMO_FRISBEE].MaxDamage, 65536);
 
 
1139
                                            }
 
 
1140
                                        }
 
 
1141
                                    }
 
 
1142
                                    else
 
 
1143
                                    {
 
 
1144
                                        if (dmod)
 
 
1145
                                        {
 
 
1146
                                            if (IsModuleVisibleFromModule(dmod,candidate->containingModule))
 
 
1147
                                            {
 
 
1148
                                                VECTORCH targetPos;
 
 
1149
                                                nearest = candidate;
 
 
1150
 
 
 
1151
                                                /* Shoot it, */
 
 
1152
                                                GetTargetingPointOfObject_Far(nearest,&targetPos);
 
 
1153
 
 
 
1154
                                            if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position,
 
 
1155
                                                    &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset))
 
 
1156
                                            {
 
 
1157
                                                    /* Use this. */
 
 
1158
                                            }
 
 
1159
                                            else
 
 
1160
                                            {
 
 
1161
                                                    offset.vx = targetPos.vx-sbPtr->DynPtr->Position.vx;
 
 
1162
                                                    offset.vy = targetPos.vy-sbPtr->DynPtr->Position.vy;
 
 
1163
                                                    offset.vz = targetPos.vz-sbPtr->DynPtr->Position.vz;
 
 
1164
                                                    Normalise(&offset);
 
 
1165
                                            }
 
 
1166
 
 
 
1167
                                                {
 
 
1168
                                                MATRIXCH mat;
 
 
1169
                                                MatrixFromZVector(&offset,&mat);
 
 
1170
                                                InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0, 
 
 
1171
                                                    &TemplateAmmo[AMMO_FRISBEE].MaxDamage, 65536);
 
 
1172
                                                }
 
 
1173
                                            }
 
 
1174
                                        }
 
 
1175
                                    }
 
 
1176
                                }
 
 
1177
                            }
 
 
1178
                        }
 
 
1179
                    }
 
 
1180
                }
 
 
1181
 
 
 
1182
                if (nearest)
 
 
1183
                {
 
 
1184
                    /* And explode. */
 
 
1185
 
 
 
1186
                    if (sbPtr->containingModule)
 
 
1187
                    {
 
 
1188
                        MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_PULSEGRENADE);
 
 
1189
                        Explosion_SoundData.position = dynPtr->Position;
 
 
1190
                        //Sound_Play(SID_ED_SKEETERPLASMAFIRE, "n", &Explosion_SoundData);
 
 
1191
                    }
 
 
1192
 
 
 
1193
                    /* for net game support: send a message saying we've blown up... */
 
 
1194
                    if(SinglePlayer != AvP.PlayMode)
 
 
1195
                    {
 
 
1196
                        AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1197
                        //AddNetMsg_SpotOtherSound(SID_ED_SKEETERPLASMAFIRE, &dynPtr->Position,1);
 
 
1198
                    }
 
 
1199
 
 
 
1200
                    /* destroy rocket */
 
 
1201
                    sbPtr->please_destroy_me = 1;
 
 
1202
                }
 
 
1203
            }
 
 
1204
        }
 
 
1205
 
 
 
1206
        fbPtr->counter -= NormalFrameTime;
 
 
1207
    }
 
 
1208
}
 
 
1209
 
 
 
1210
void RocketBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1211
{
 
 
1212
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1213
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1214
    PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
1215
 
 
 
1216
    if (reportPtr || (bbPtr->counter <= 0) )
 
 
1217
    {
 
 
1218
        if (reportPtr && reportPtr->ObstacleSBPtr)
 
 
1219
        {
 
 
1220
            if (bbPtr->player && AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr))
 
 
1221
            {
 
 
1222
                /* Log accuracy! */
 
 
1223
                int slot = SlotForThisWeapon(WEAPON_SADAR);
 
 
1224
 
 
 
1225
                if (slot != -1)
 
 
1226
                    CurrentGameStats_WeaponHit(slot, 1);
 
 
1227
            }
 
 
1228
        }
 
 
1229
 
 
 
1230
        if (sbPtr->containingModule)
 
 
1231
        {
 
 
1232
            MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_SADAR_BLAST);
 
 
1233
            Explosion_SoundData.position = dynPtr->Position;
 
 
1234
            Sound_Play(SID_NICE_EXPLOSION, "nh", &Explosion_SoundData);
 
 
1235
        }
 
 
1236
 
 
 
1237
        /* for net game support: send a message saying we've blown up... */
 
 
1238
        if(SinglePlayer != AvP.PlayMode)
 
 
1239
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1240
 
 
 
1241
        /* destroy rocket */
 
 
1242
        sbPtr->please_destroy_me = 1;
 
 
1243
    }
 
 
1244
    else
 
 
1245
    {
 
 
1246
        bbPtr->counter -= NormalFrameTime;
 
 
1247
        MakeRocketTrailParticles(&dynPtr->PrevPosition, &dynPtr->Position);
 
 
1248
    }
 
 
1249
}
 
 
1250
 
 
 
1251
void GrenadeBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
1252
{
 
 
1253
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1254
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1255
    GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
1256
 
 
 
1257
    if (reportPtr == NULL) 
 
 
1258
    {
 
 
1259
        bbPtr->bouncelastframe = !DynamicObjectIsMoving(dynPtr);
 
 
1260
    }
 
 
1261
    else
 
 
1262
    {
 
 
1263
        if(reportPtr->ObstacleSBPtr)
 
 
1264
        {
 
 
1265
            switch(reportPtr->ObstacleSBPtr->type)
 
 
1266
            {
 
 
1267
                case I_BehaviourAlien:
 
 
1268
                case I_BehaviourMarinePlayer:
 
 
1269
                case I_BehaviourAlienPlayer:
 
 
1270
                case I_BehaviourPredatorPlayer:
 
 
1271
                case I_BehaviourPredator:
 
 
1272
                case I_BehaviourXenoborg:
 
 
1273
                case I_BehaviourMarine:
 
 
1274
                case I_BehaviourQueenAlien:
 
 
1275
                    bbPtr->counter = 0;
 
 
1276
                break;
 
 
1277
                case I_BehaviourInanimateObject:
 
 
1278
                    CauseDamageToObject(reportPtr->ObstacleSBPtr, &damage_profiles[FALLINGDAMAGE], 100 * NormalFrameTime, NULL);
 
 
1279
                    //CauseDamageToObject(reportPtr->ObstacleSBPtr, &damage_profiles[CERTAINDEATH], 100 * NormalFrameTime, NULL);
 
 
1280
                break;
 
 
1281
                case I_BehaviourNetGhost:
 
 
1282
                {
 
 
1283
                    NETGHOSTDATABLOCK *ghostData = reportPtr->ObstacleSBPtr->dataptr;
 
 
1284
 
 
 
1285
                    switch(ghostData->type)
 
 
1286
                    {
 
 
1287
                        case I_BehaviourMarinePlayer:
 
 
1288
                        case I_BehaviourPredatorPlayer:
 
 
1289
                        case I_BehaviourAlienPlayer:
 
 
1290
                        case I_BehaviourAlien:
 
 
1291
                            bbPtr->counter = 0;
 
 
1292
                        default:
 
 
1293
                        break;
 
 
1294
                    }
 
 
1295
                }
 
 
1296
                default:
 
 
1297
                break;
 
 
1298
            }
 
 
1299
        }
 
 
1300
 
 
 
1301
        if (bbPtr->counter && !bbPtr->bouncelastframe)
 
 
1302
        {
 
 
1303
            Sound_Play(SID_GRENADE_BOUNCE, "dph", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
1304
            bbPtr->bouncelastframe = 1;
 
 
1305
        }
 
 
1306
    }
 
 
1307
 
 
 
1308
    if (bbPtr->counter <= 0)
 
 
1309
    {
 
 
1310
        if (sbPtr->containingModule)
 
 
1311
        {
 
 
1312
            MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_GRENADE_BLAST);
 
 
1313
            Explosion_SoundData.position = dynPtr->Position;
 
 
1314
            Sound_Play(SID_GRENADE_EXPLOSION, "nh", &Explosion_SoundData);
 
 
1315
        }
 
 
1316
 
 
 
1317
        if(SinglePlayer != AvP.PlayMode)
 
 
1318
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1319
 
 
 
1320
        sbPtr->please_destroy_me = 1;
 
 
1321
    }
 
 
1322
    else
 
 
1323
    {
 
 
1324
        bbPtr->counter -= NormalFrameTime;
 
 
1325
        MakeGrenadeTrailParticles(&dynPtr->PrevPosition, &dynPtr->Position);
 
 
1326
        DynamicallyRotateObject(dynPtr);
 
 
1327
    }
 
 
1328
}
 
 
1329
 
 
 
1330
void FragGrenadeBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
1331
{
 
 
1332
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1333
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1334
    GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
1335
 
 
 
1336
    if (reportPtr == NULL)
 
 
1337
    {
 
 
1338
        bbPtr->bouncelastframe = !DynamicObjectIsMoving(dynPtr);
 
 
1339
    }
 
 
1340
    else
 
 
1341
    {
 
 
1342
        do
 
 
1343
        {
 
 
1344
            if (reportPtr->ObstacleSBPtr)
 
 
1345
            {
 
 
1346
                switch(reportPtr->ObstacleSBPtr->type)
 
 
1347
                {
 
 
1348
                    case I_BehaviourAlien:
 
 
1349
                    case I_BehaviourMarinePlayer:
 
 
1350
                    case I_BehaviourAlienPlayer:
 
 
1351
                    case I_BehaviourPredatorPlayer:
 
 
1352
                    case I_BehaviourPredator:
 
 
1353
                    case I_BehaviourXenoborg:
 
 
1354
                    case I_BehaviourMarine:
 
 
1355
                    case I_BehaviourQueenAlien:
 
 
1356
                        bbPtr->counter = 0;
 
 
1357
                    break;
 
 
1358
                    case I_BehaviourNetGhost:
 
 
1359
                    {
 
 
1360
                        NETGHOSTDATABLOCK *ghostData = reportPtr->ObstacleSBPtr->dataptr;
 
 
1361
 
 
 
1362
                        switch(ghostData->type)
 
 
1363
                        {
 
 
1364
                            case I_BehaviourMarinePlayer:
 
 
1365
                            case I_BehaviourPredatorPlayer:
 
 
1366
                            case I_BehaviourAlienPlayer:
 
 
1367
                            case I_BehaviourAlien:
 
 
1368
                                bbPtr->counter = 0;
 
 
1369
                            default:
 
 
1370
                            break;
 
 
1371
                        }
 
 
1372
                    }
 
 
1373
                    default:
 
 
1374
                    break;
 
 
1375
                }
 
 
1376
            }
 
 
1377
            else
 
 
1378
            {
 
 
1379
                dynPtr->IgnoreThePlayer = 0;
 
 
1380
            }
 
 
1381
 
 
 
1382
            reportPtr = reportPtr->NextCollisionReportPtr;
 
 
1383
 
 
 
1384
        } while (reportPtr);
 
 
1385
 
 
 
1386
        if (bbPtr->counter && !bbPtr->bouncelastframe)
 
 
1387
        {
 
 
1388
            Sound_Play(SID_GRENADE_BOUNCE, "dph", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
1389
            bbPtr->bouncelastframe = 1;
 
 
1390
        }
 
 
1391
    }
 
 
1392
 
 
 
1393
    if (bbPtr->counter <= 0)
 
 
1394
    {
 
 
1395
        if (sbPtr->containingModule)
 
 
1396
        {
 
 
1397
            Explosion_SoundData.position = dynPtr->Position;
 
 
1398
            Sound_Play(SID_NADEEXPLODE, "nh", &Explosion_SoundData);
 
 
1399
            MakeFlechetteExplosionAt(&dynPtr->Position, 0);
 
 
1400
        }
 
 
1401
 
 
 
1402
        /* for net game support: send a message saying we've blown up... */
 
 
1403
        if(SinglePlayer != AvP.PlayMode)
 
 
1404
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1405
 
 
 
1406
        sbPtr->please_destroy_me = 1;
 
 
1407
    }
 
 
1408
    else
 
 
1409
    {
 
 
1410
        VECTORCH velocity;
 
 
1411
        velocity.vx = (FastRandom()&255) - 128;
 
 
1412
        velocity.vy = -1000-(FastRandom()&255);
 
 
1413
        velocity.vz = (FastRandom()&255) - 128;
 
 
1414
        MakeParticle(&dynPtr->Position, &velocity, PARTICLE_BLACKSMOKE);
 
 
1415
 
 
 
1416
        bbPtr->counter -= NormalFrameTime;
 
 
1417
        DynamicallyRotateObject(dynPtr);
 
 
1418
    }
 
 
1419
}
 
 
1420
 
 
 
1421
int ValidTargetForProxMine(const STRATEGYBLOCK *sbPtr)
 
 
1422
{
 
 
1423
    int i = NumActiveStBlocks;
 
 
1424
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1425
 
 
 
1426
    while(i)
 
 
1427
    {
 
 
1428
        STRATEGYBLOCK *obstaclePtr = ActiveStBlockList[--i];
 
 
1429
        DYNAMICSBLOCK *obstacleDynPtr = obstaclePtr->DynPtr;
 
 
1430
 
 
 
1431
        if(NULL != obstaclePtr->DynPtr)
 
 
1432
        switch(obstaclePtr->type)
 
 
1433
        {
 
 
1434
            case I_BehaviourAlien:
 
 
1435
            case I_BehaviourMarinePlayer:
 
 
1436
            case I_BehaviourAlienPlayer:
 
 
1437
            case I_BehaviourPredatorPlayer:
 
 
1438
            case I_BehaviourPredator:
 
 
1439
            case I_BehaviourXenoborg:
 
 
1440
            case I_BehaviourMarine:
 
 
1441
            case I_BehaviourQueenAlien:
 
 
1442
            case I_BehaviourFaceHugger:
 
 
1443
            {
 
 
1444
                VECTORCH disp = obstacleDynPtr->Position;
 
 
1445
                disp.vx -= dynPtr->Position.vx;
 
 
1446
                disp.vy -= dynPtr->Position.vy;
 
 
1447
                disp.vz -= dynPtr->Position.vz;
 
 
1448
 
 
 
1449
                if (Approximate3dMagnitude(&disp) <= PROX_GRENADE_RANGE)
 
 
1450
                    return 1;
 
 
1451
            }
 
 
1452
            break;
 
 
1453
            case I_BehaviourNetGhost:
 
 
1454
            {
 
 
1455
                NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)obstaclePtr->dataptr;
 
 
1456
 
 
 
1457
                switch(ghostDataPtr->type)
 
 
1458
                {
 
 
1459
                    case I_BehaviourAlienPlayer:
 
 
1460
                    case I_BehaviourMarinePlayer:
 
 
1461
                    case I_BehaviourPredatorPlayer:
 
 
1462
                    case I_BehaviourAlien:
 
 
1463
                    {
 
 
1464
                        VECTORCH disp = obstacleDynPtr->Position;
 
 
1465
                        disp.vx -= dynPtr->Position.vx;
 
 
1466
                        disp.vy -= dynPtr->Position.vy;
 
 
1467
                        disp.vz -= dynPtr->Position.vz;
 
 
1468
 
 
 
1469
                        if (Approximate3dMagnitude(&disp) <= PROX_GRENADE_RANGE)
 
 
1470
                            return 1;
 
 
1471
                    }
 
 
1472
                    default:
 
 
1473
                    continue;
 
 
1474
                }
 
 
1475
            }
 
 
1476
            default:
 
 
1477
            continue;
 
 
1478
        }
 
 
1479
    }
 
 
1480
 
 
 
1481
return 0;
 
 
1482
}
 
 
1483
 
 
 
1484
void ProximityGrenadeBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1485
{
 
 
1486
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1487
    PROX_GRENADE_BEHAV_BLOCK *bbPtr = (PROX_GRENADE_BEHAV_BLOCK *)sbPtr->dataptr;
 
 
1488
 
 
 
1489
    if (bbPtr->counter <= 0)
 
 
1490
    {
 
 
1491
        if (bbPtr->SoundHandle != SOUND_NOACTIVEINDEX)
 
 
1492
        {
 
 
1493
            Sound_Stop(bbPtr->SoundHandle);
 
 
1494
            bbPtr->SoundHandle = SOUND_NOACTIVEINDEX;
 
 
1495
        }
 
 
1496
 
 
 
1497
        MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_GRENADE_BLAST);
 
 
1498
 
 
 
1499
        if (sbPtr->containingModule)
 
 
1500
        {
 
 
1501
            Explosion_SoundData.position = dynPtr->Position;
 
 
1502
            Sound_Play(SID_GRENADE_PROXEXPLOSION, "np", &Explosion_SoundData);
 
 
1503
        }
 
 
1504
 
 
 
1505
        /* for net game support: send a message saying we've blown up... */
 
 
1506
        if(SinglePlayer != AvP.PlayMode)
 
 
1507
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1508
 
 
 
1509
        sbPtr->please_destroy_me = 1;
 
 
1510
    }
 
 
1511
    else
 
 
1512
    {
 
 
1513
        if (dynPtr->IsStatic)
 
 
1514
        {
 
 
1515
            if(bbPtr->counter > PROX_GRENADE_TRIGGER_TIME)
 
 
1516
            {
 
 
1517
                // scan for objects in proximity
 
 
1518
 
 
 
1519
                if (ValidTargetForProxMine(sbPtr))
 
 
1520
                {
 
 
1521
                    bbPtr->counter = PROX_GRENADE_TRIGGER_TIME;
 
 
1522
                    Sound_Play(SID_PROX_GRENADE_READYTOBLOW, "deh", &dynPtr->Position, &bbPtr->SoundHandle);
 
 
1523
                }
 
 
1524
                else
 
 
1525
                {
 
 
1526
                    int scale = ONE_FIXED - bbPtr->counter / PROX_GRENADE_LIFETIME;
 
 
1527
                    scale = MUL_FIXED(scale, scale);
 
 
1528
                    scale = MUL_FIXED(scale, scale) * 8;
 
 
1529
                    bbPtr->SoundGenerationTimer += NormalFrameTime + MUL_FIXED(NormalFrameTime, scale);
 
 
1530
 
 
 
1531
                    while (bbPtr->SoundGenerationTimer >= PROX_GRENADE_SOUND_GENERATION_TIME)
 
 
1532
                    {
 
 
1533
                        bbPtr->SoundGenerationTimer -= PROX_GRENADE_SOUND_GENERATION_TIME;
 
 
1534
                        Sound_Play(SID_PROX_GRENADE_ACTIVE, "dh", &dynPtr->Position);
 
 
1535
                    }
 
 
1536
                }
 
 
1537
            }
 
 
1538
        }
 
 
1539
        else
 
 
1540
        {
 
 
1541
            COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1542
 
 
 
1543
            if (reportPtr)
 
 
1544
            {
 
 
1545
                char stickWhereYouAre = 0;
 
 
1546
 
 
 
1547
                STRATEGYBLOCK *obstaclePtr = reportPtr->ObstacleSBPtr;
 
 
1548
 
 
 
1549
                if (obstaclePtr)
 
 
1550
                {
 
 
1551
                    DISPLAYBLOCK *dispPtr = obstaclePtr->DisplayBlock;
 
 
1552
 
 
 
1553
                    if (dispPtr && dispPtr->Module)
 
 
1554
                    {
 
 
1555
                        if(NULL != dispPtr->ObMorphCtrl)
 
 
1556
                            stickWhereYouAre = 1;
 
 
1557
                    }
 
 
1558
                    else
 
 
1559
                    {
 
 
1560
                        switch(obstaclePtr->type)
 
 
1561
                        {
 
 
1562
                            case I_BehaviourAlien:
 
 
1563
                            case I_BehaviourMarinePlayer:
 
 
1564
                            case I_BehaviourAlienPlayer:
 
 
1565
                            case I_BehaviourPredatorPlayer:
 
 
1566
                            case I_BehaviourPredator:
 
 
1567
                            case I_BehaviourXenoborg:
 
 
1568
                            case I_BehaviourMarine:
 
 
1569
                            case I_BehaviourQueenAlien:
 
 
1570
                            case I_BehaviourFaceHugger:
 
 
1571
                                // best blow up then
 
 
1572
                                bbPtr->counter = 0;
 
 
1573
                            return;
 
 
1574
                            case I_BehaviourNetGhost:
 
 
1575
                            {
 
 
1576
                                NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)obstaclePtr->dataptr;
 
 
1577
 
 
 
1578
                                switch(ghostDataPtr->type)
 
 
1579
                                {
 
 
1580
                                    case I_BehaviourAlienPlayer:
 
 
1581
                                    case I_BehaviourMarinePlayer:
 
 
1582
                                    case I_BehaviourPredatorPlayer:
 
 
1583
                                    case I_BehaviourAlien:
 
 
1584
                                        // best blow up then
 
 
1585
                                        bbPtr->counter = 0;
 
 
1586
                                    return;
 
 
1587
                                    default:
 
 
1588
                                    break;
 
 
1589
                                }
 
 
1590
                            }
 
 
1591
                            default:
 
 
1592
                            break;
 
 
1593
                        }
 
 
1594
                    }
 
 
1595
                }
 
 
1596
                else
 
 
1597
                {
 
 
1598
                    stickWhereYouAre = 1;
 
 
1599
                }
 
 
1600
 
 
 
1601
                if(stickWhereYouAre)
 
 
1602
                {
 
 
1603
                    dynPtr->IsStatic = 1;
 
 
1604
                    dynPtr->PrevPosition = dynPtr->Position;
 
 
1605
                    MakeMatrixFromDirection(&reportPtr->ObstacleNormal, &dynPtr->OrientMat);
 
 
1606
                    /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */
 
 
1607
                    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
1608
                    bbPtr->counter = PROX_GRENADE_LIFETIME * ONE_FIXED;
 
 
1609
                }
 
 
1610
            }
 
 
1611
 
 
 
1612
            MakeGrenadeTrailParticles(&dynPtr->PrevPosition, &dynPtr->Position);
 
 
1613
        }
 
 
1614
 
 
 
1615
        bbPtr->counter -= NormalFrameTime;
 
 
1616
    }
 
 
1617
}
 
 
1618
 
 
 
1619
void FlareBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
1620
{
 
 
1621
    FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
1622
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1623
    DISPLAYBLOCK *dptr = sbPtr->DisplayBlock;
 
 
1624
 
 
 
1625
    if (bbPtr->SoundHandle != SOUND_NOACTIVEINDEX)
 
 
1626
        ActiveSounds[bbPtr->SoundHandle].threedeedata.position = dynPtr->Position;
 
 
1627
 
 
 
1628
    if (bbPtr->LifeTimeRemaining <= 0)
 
 
1629
    {        
 
 
1630
        if (bbPtr->SoundHandle != SOUND_NOACTIVEINDEX)
 
 
1631
        {
 
 
1632
            Sound_Stop(bbPtr->SoundHandle);
 
 
1633
            bbPtr->SoundHandle = SOUND_NOACTIVEINDEX;
 
 
1634
        }
 
 
1635
 
 
 
1636
        /* for net game support: send a message saying we've blown up... */
 
 
1637
        if(SinglePlayer != AvP.PlayMode)
 
 
1638
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1639
 
 
 
1640
        sbPtr->please_destroy_me = 1;
 
 
1641
 
 
 
1642
        return;
 
 
1643
    }
 
 
1644
    else if (bbPtr->LifeTimeRemaining > ONE_FIXED * 4)
 
 
1645
        bbPtr->ParticleGenerationTimer += NormalFrameTime;
 
 
1646
    else
 
 
1647
        bbPtr->ParticleGenerationTimer += MUL_FIXED(NormalFrameTime, bbPtr->LifeTimeRemaining)/4;
 
 
1648
 
 
 
1649
    while (bbPtr->ParticleGenerationTimer >= FLARE_PARTICLE_GENERATION_TIME)
 
 
1650
    {
 
 
1651
        bbPtr->ParticleGenerationTimer -= FLARE_PARTICLE_GENERATION_TIME;
 
 
1652
        MakeFlareParticle(dynPtr);
 
 
1653
    }
 
 
1654
 
 
 
1655
    /* add lighting effect */
 
 
1656
    if(NULL != dptr)
 
 
1657
    {
 
 
1658
        if(!dptr->ObNumLights)
 
 
1659
            AddLightingEffectToObject(dptr, LFX_FLARE);
 
 
1660
 
 
 
1661
        LIGHTBLOCK *lightPtr = dptr->ObLights[0];
 
 
1662
 
 
 
1663
        if(NULL != lightPtr)
 
 
1664
        {
 
 
1665
            lightPtr->LightBright = 1 + MUL_FIXED( (ONE_FIXED*4-(FastRandom()&32767)), bbPtr->LifeTimeRemaining / FLARE_LIFETIME);
 
 
1666
        }
 
 
1667
    }
 
 
1668
 
 
 
1669
       bbPtr->LifeTimeRemaining -= NormalFrameTime;
 
 
1670
 
 
 
1671
    if (dynPtr->IsFloating)
 
 
1672
    {
 
 
1673
        RubberDuckBehaviour(sbPtr);
 
 
1674
    }
 
 
1675
    else if(!dynPtr->IsStatic)
 
 
1676
    {
 
 
1677
        COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1678
 
 
 
1679
        if (NULL != reportPtr)
 
 
1680
        {
 
 
1681
            char stickWhereYouAre = 0;
 
 
1682
 
 
 
1683
            if (NULL != reportPtr->ObstacleSBPtr)
 
 
1684
            {
 
 
1685
                DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->DisplayBlock;
 
 
1686
 
 
 
1687
                if (NULL != dispPtr)
 
 
1688
                {
 
 
1689
                    STRATEGYBLOCK* hit_sbptr = reportPtr->ObstacleSBPtr;
 
 
1690
 
 
 
1691
                    if (NULL != dispPtr->Module)
 
 
1692
                    {
 
 
1693
                        if(NULL != dispPtr->ObMorphCtrl) stickWhereYouAre = 1;
 
 
1694
                    }
 
 
1695
                    else
 
 
1696
                    {
 
 
1697
                        switch(hit_sbptr->type)
 
 
1698
                        {
 
 
1699
                            case I_BehaviourAlien:
 
 
1700
                            {
 
 
1701
                                ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(hit_sbptr->dataptr);
 
 
1702
                                CauseDamageToObject(hit_sbptr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL);
 
 
1703
                                NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
1704
                                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
1705
                                NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
1706
                                alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
1707
                                alienStatusPointer->StateTimer = ONE_FIXED / 8;
 
 
1708
                            }
 
 
1709
                            break;
 
 
1710
                            default:
 
 
1711
                                CauseDamageToObject(hit_sbptr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL);
 
 
1712
                        }
 
 
1713
                    }
 
 
1714
                }
 
 
1715
            }
 
 
1716
            else if(-1 != reportPtr->ModuleIndex) // morphable object such as doors
 
 
1717
            {
 
 
1718
                stickWhereYouAre = 1;
 
 
1719
            }
 
 
1720
 
 
 
1721
            if(stickWhereYouAre)
 
 
1722
            {
 
 
1723
                dynPtr->IsStatic = 1;
 
 
1724
                dynPtr->OnlyCollideWithEnvironment = 1;
 
 
1725
                dynPtr->PrevPosition = dynPtr->Position;
 
 
1726
                MakeMatrixFromDirection(&reportPtr->ObstacleNormal, &dynPtr->OrientMat);
 
 
1727
                /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */
 
 
1728
                 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
1729
                //set flag, so appropriate net message gets sent
 
 
1730
                bbPtr->becomeStuck = 1;
 
 
1731
                Sound_Play(SID_BURNING_FLARE, "dlev", &dynPtr->Position, &bbPtr->SoundHandle, 50);
 
 
1732
            }
 
 
1733
        }
 
 
1734
    }
 
 
1735
}
 
 
1736
 
 
 
1737
void PulseGrenadeBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
1738
{
 
 
1739
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1740
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1741
    PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
1742
 
 
 
1743
    if (NULL != reportPtr)
 
 
1744
    {
 
 
1745
        if(NULL != reportPtr->ObstacleSBPtr)
 
 
1746
        {
 
 
1747
            if(bbPtr->player && AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr))
 
 
1748
            {
 
 
1749
                int slot = SlotForThisWeapon(WEAPON_PULSERIFLE);
 
 
1750
 
 
 
1751
                if (slot != -1)
 
 
1752
                    CurrentGameStats_WeaponHit(slot, 1);
 
 
1753
            }
 
 
1754
        }
 
 
1755
    }
 
 
1756
    else
 
 
1757
    {
 
 
1758
        bbPtr->counter -= NormalFrameTime;
 
 
1759
 
 
 
1760
        if (bbPtr->counter > 0)
 
 
1761
        {
 
 
1762
            MakeRocketTrailParticles(&dynPtr->PrevPosition, &dynPtr->Position);
 
 
1763
            return;
 
 
1764
        }
 
 
1765
    }
 
 
1766
 
 
 
1767
    MakeVolumetricExplosionAt(&dynPtr->Position, EXPLOSION_PULSEGRENADE);
 
 
1768
 
 
 
1769
    //if (sbPtr->containingModule)
 
 
1770
    {
 
 
1771
        Explosion_SoundData.position = dynPtr->Position;
 
 
1772
        Sound_Play(SID_NADEEXPLODE, "nh", &Explosion_SoundData);
 
 
1773
    }
 
 
1774
 
 
 
1775
    /* for net game support: send a message saying we've blown up... */
 
 
1776
    if(SinglePlayer != AvP.PlayMode)
 
 
1777
        AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1778
 
 
 
1779
    sbPtr->please_destroy_me = 1;
 
 
1780
}
 
 
1781
 
 
 
1782
void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1783
{
 
 
1784
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1785
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1786
    PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
1787
 
 
 
1788
    if (reportPtr)
 
 
1789
    {
 
 
1790
          if(reportPtr->ObstacleSBPtr && bbPtr->player && AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr))
 
 
1791
        {
 
 
1792
            int slot = SlotForThisWeapon(WEAPON_PRED_PISTOL);
 
 
1793
 
 
 
1794
            if (slot != -1)
 
 
1795
                CurrentGameStats_WeaponHit(slot,1);
 
 
1796
        }
 
 
1797
    }
 
 
1798
    else if (bbPtr->counter > 0) 
 
 
1799
    {
 
 
1800
        bbPtr->counter -= NormalFrameTime;
 
 
1801
        return;
 
 
1802
    }
 
 
1803
 
 
 
1804
    MakeElectricalExplosion(&dynPtr->Position);
 
 
1805
 
 
 
1806
    if(SinglePlayer != AvP.PlayMode)
 
 
1807
        AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1808
 
 
 
1809
    sbPtr->please_destroy_me = 1;
 
 
1810
}
 
 
1811
 
 
 
1812
static DISPLAYBLOCK* InitialiseSpeargunBoltBehaviour_ForLoad()
 
 
1813
{
 
 
1814
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourSpeargunBolt);
 
 
1815
 
 
 
1816
    if(NULL == sbPtr)
 
 
1817
    return NULL;
 
 
1818
 
 
 
1819
    int shapeIndex = GetLoadedShapeMSL("spear");
 
 
1820
 
 
 
1821
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(shapeIndex); 
 
 
1822
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
1823
    sbPtr->dataptr = malloc(sizeof(SPEAR_BEHAV_BLOCK));
 
 
1824
 
 
 
1825
    if ((NULL == dynPtr) || (NULL == sbPtr->dataptr) || (NULL == dispPtr)) 
 
 
1826
    {
 
 
1827
        RemoveBehaviourStrategy(sbPtr);
 
 
1828
        return NULL;
 
 
1829
    }
 
 
1830
 
 
 
1831
    dispPtr->ObWorld.vx = dispPtr->ObWorld.vy = dispPtr->ObWorld.vz = 0;
 
 
1832
 
 
 
1833
    dispPtr->ObStrategyBlock = sbPtr;
 
 
1834
    sbPtr->shapeIndex = shapeIndex;
 
 
1835
 
 
 
1836
    dispPtr->extent.min_x = -10;
 
 
1837
    dispPtr->extent.min_y = -10;
 
 
1838
    dispPtr->extent.min_y = -10;
 
 
1839
    dispPtr->extent.max_x = 10;
 
 
1840
    dispPtr->extent.max_y = 10;
 
 
1841
    dispPtr->extent.max_z = 10;
 
 
1842
    sbPtr->maintainVisibility = 1;
 
 
1843
 
 
 
1844
return dispPtr;
 
 
1845
}
 
 
1846
 
 
 
1847
void SpeargunBoltBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1848
{
 
 
1849
    SPEAR_BEHAV_BLOCK *bbPtr = (SPEAR_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
1850
 
 
 
1851
    if (bbPtr->counter > 0) 
 
 
1852
    {
 
 
1853
        bbPtr->counter -= NormalFrameTime;
 
 
1854
 
 
 
1855
        if (!bbPtr->Stuck)
 
 
1856
        {
 
 
1857
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1858
            COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
1859
 
 
 
1860
            if (reportPtr)
 
 
1861
            {
 
 
1862
                int normDotBeta = DotProduct(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal);
 
 
1863
 
 
 
1864
                char stickWhereYouAre = 0;
 
 
1865
 
 
 
1866
                if (reportPtr->ObstacleSBPtr)
 
 
1867
                {
 
 
1868
                    DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->DisplayBlock;
 
 
1869
 
 
 
1870
                    if (dispPtr && dispPtr->Module && !dispPtr->ObMorphCtrl)
 
 
1871
                    {
 
 
1872
                        stickWhereYouAre = 1;
 
 
1873
                    }
 
 
1874
                    else
 
 
1875
                    {
 
 
1876
                        STRATEGYBLOCK * victim = reportPtr->ObstacleSBPtr;
 
 
1877
                        //reportPtr->ObstacleNormal;
 
 
1878
                        //reportPtr->ObstaclePoint;
 
 
1879
 
 
 
1880
                        if(bbPtr->FromPlayer && AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr))
 
 
1881
                            CurrentGameStats_WeaponHit(PlayerStatus.SelectedWeaponSlot, 1);
 
 
1882
 
 
 
1883
if(0)
 
 
1884
                        if (victim->DisplayBlock)
 
 
1885
                        {
 
 
1886
                            if (victim->DisplayBlock->HModelControlBlock)
 
 
1887
                            {
 
 
1888
                            //bbPtr->SpearThroughFragment = 1;
 
 
1889
DISPLAYBLOCK *fragged_section = CauseDamageToHModel(victim->DisplayBlock->HModelControlBlock, victim, &TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage,
ONE_FIXED,
 
 
1890
//this_section_data,
 
 
1891
victim->DisplayBlock->HModelControlBlock->section_data,
 
 
1892
&reportPtr->ObstacleNormal, &reportPtr->ObstaclePoint, 0);
 
 
1893
 
 
 
1894
            if (fragged_section)
 
 
1895
            {
 
 
1896
                #define SPEAR_NPC_IMPULSE       (2000)
 
 
1897
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vx += MUL_FIXED(reportPtr->ObstacleNormal.vx, SPEAR_NPC_IMPULSE);
 
 
1898
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vy += MUL_FIXED(reportPtr->ObstacleNormal.vy, SPEAR_NPC_IMPULSE);
 
 
1899
                fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vz += MUL_FIXED(reportPtr->ObstacleNormal.vz, SPEAR_NPC_IMPULSE);
 
 
1900
                CreateSpearPossiblyWithFragment(fragged_section, &reportPtr->ObstaclePoint, &reportPtr->ObstacleNormal);
 
 
1901
            } 
 
 
1902
 
 
 
1903
                            /*
 
 
1904
                                switch(victim->type)
 
 
1905
                                {
 
 
1906
                                case I_BehaviourMarinePlayer:
 
 
1907
                                case I_BehaviourPredatorPlayer:
 
 
1908
                                case I_BehaviourAlienPlayer:
 
 
1909
                                case I_BehaviourAlien:
 
 
1910
                                case I_BehaviourQueenAlien:
 
 
1911
                                case I_BehaviourFaceHugger:
 
 
1912
                                case I_BehaviourPredator:
 
 
1913
                                case I_BehaviourXenoborg:
 
 
1914
                                case I_BehaviourMarine:
 
 
1915
                                case I_BehaviourAutoGun:
 
 
1916
                                case I_BehaviourHierarchicalFragment:
 
 
1917
                                case I_BehaviourCorpse:
 
 
1918
                                case I_BehaviourDummy:
 
 
1919
 
 
 
1920
                                }
 
 
1921
                            */
 
 
1922
 
 
 
1923
                            }
 
 
1924
                        }
 
 
1925
 
 
 
1926
                        VECTORCH attack_dir;
 
 
1927
                        GetDirectionOfAttack(reportPtr->ObstacleSBPtr, &dynPtr->LinVelocity, &attack_dir);
 
 
1928
                        //CauseDamageToObject(reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage, ONE_FIXED, NULL);
 
 
1929
                    }
 
 
1930
                }
 
 
1931
                else
 
 
1932
                {
 
 
1933
                    stickWhereYouAre = 1;
 
 
1934
                }
 
 
1935
 
 
 
1936
                if(stickWhereYouAre && normDotBeta)
 
 
1937
                {
 
 
1938
                    /* Sink in... */
 
 
1939
                    Sound_Play(SID_SPEARGUN_HITTING_WALL, "d", &dynPtr->Position);  
 
 
1940
                    bbPtr->Stuck = 1;
 
 
1941
                    /* Counter at 20s. */
 
 
1942
                    bbPtr->counter = (20 * ONE_FIXED);
 
 
1943
                    dynPtr->GravityOn = 0;
 
 
1944
                    dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS;
 
 
1945
 
 
 
1946
                    {
 
 
1947
                        /* get a pt in the poly */
 
 
1948
                        VECTORCH pop = reportPtr->ObstaclePoint;                                  
 
 
1949
                        pop.vx -= dynPtr->Position.vx;
 
 
1950
                        pop.vy -= dynPtr->Position.vy;
 
 
1951
                        pop.vz -= dynPtr->Position.vz;
 
 
1952
 
 
 
1953
                        /* hmm, what about double sided polys? */
 
 
1954
                        int d = DotProduct(&reportPtr->ObstacleNormal, &pop);
 
 
1955
 
 
 
1956
                        int lambda = DIV_FIXED(d, normDotBeta);
 
 
1957
 
 
 
1958
                        dynPtr->Position.vx += MUL_FIXED(lambda, dynPtr->LinVelocity.vx);
 
 
1959
                        dynPtr->Position.vy += MUL_FIXED(lambda, dynPtr->LinVelocity.vy);
 
 
1960
                        dynPtr->Position.vz += MUL_FIXED(lambda, dynPtr->LinVelocity.vz);
 
 
1961
                    }
 
 
1962
 
 
 
1963
                    dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0;
 
 
1964
                    dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;
 
 
1965
            //dynPtr->IsStatic = 1;
 
 
1966
 
 
 
1967
                    MakeFocusedExplosion(&dynPtr->PrevPosition, &dynPtr->Position, 20, PARTICLE_SPARK);
 
 
1968
                    MakeLightElement(&dynPtr->Position, LIGHTELEMENT_ELECTRICAL_SPARKS);
 
 
1969
                }
 
 
1970
 
 
 
1971
                bbPtr->Stuck = 1;
 
 
1972
            }
 
 
1973
        }
 
 
1974
    }
 
 
1975
    else
 
 
1976
    {
 
 
1977
        /* for net game support: send a message saying we've blown up... */
 
 
1978
        if(SinglePlayer != AvP.PlayMode)
 
 
1979
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
1980
 
 
 
1981
        sbPtr->please_destroy_me = 1;
 
 
1982
    }
 
 
1983
}
 
 
1984
 
 
 
1985
#define TIME_FOR_FLAMETHROWER_PARTICLE    (ONE_FIXED/120)
 
 
1986
 
 
 
1987
void FireFlameThrower(VECTORCH *base_position, const VECTORCH *base_offset, MATRIXCH *orientmat, int player, int *timer)
 
 
1988
{
 
 
1989
    /* Simple function containing flamethrower function. */
 
 
1990
 
 
 
1991
    VECTORCH position;
 
 
1992
 
 
 
1993
    *timer += NormalFrameTime;
 
 
1994
 
 
 
1995
    while (*timer >= TIME_FOR_FLAMETHROWER_PARTICLE) 
 
 
1996
    {
 
 
1997
        VECTORCH velocity;
 
 
1998
        (*timer) -= TIME_FOR_FLAMETHROWER_PARTICLE;
 
 
1999
 
 
 
2000
        /* calculate the position */
 
 
2001
 
 
 
2002
        {
 
 
2003
            int offset = MUL_FIXED(FastRandom()&16383, NormalFrameTime);
 
 
2004
 
 
 
2005
            position = *base_offset;
 
 
2006
 
 
 
2007
            position.vz += offset;
 
 
2008
            position.vy += (FastRandom() % (offset/8+1)) - offset/16;
 
 
2009
            position.vx += (FastRandom() % (offset/8+1)) - offset/16;
 
 
2010
        }
 
 
2011
 
 
 
2012
        RotateVector(&position, orientmat);
 
 
2013
 
 
 
2014
        if (player)
 
 
2015
        {
 
 
2016
            Crunch_Position_For_Players_Weapon(&position);        
 
 
2017
        }
 
 
2018
        else
 
 
2019
        {
 
 
2020
            position.vx += base_position->vx;
 
 
2021
            position.vy += base_position->vy;
 
 
2022
            position.vz += base_position->vz;
 
 
2023
        }
 
 
2024
 
 
 
2025
        velocity.vx = ((FastRandom()&1023) - 512);//*2;
 
 
2026
        velocity.vy = ((FastRandom()&1023) - 512);//*2;
 
 
2027
        velocity.vz = ((FastRandom()&511) + 200+512)*16;
 
 
2028
        RotateVector(&velocity, orientmat);
 
 
2029
        MakeParticle(&position, &velocity, PARTICLE_FLAME);
 
 
2030
    }
 
 
2031
}
 
 
2032
 
 
 
2033
void FireNetGhostFlameThrower(VECTORCH *positionPtr, MATRIXCH *orientMatPtr)
 
 
2034
{
 
 
2035
    /* KJL 16:31:42 27/01/98 - these particles aren't colliding, so I'll
 
 
2036
    see what happens if I use more... */
 
 
2037
    int i = FLAMETHROWER_PARTICLES_PER_FRAME * 2;
 
 
2038
 
 
 
2039
    VECTORCH position;
 
 
2040
 
 
 
2041
    while(i--)
 
 
2042
    /* calculate the position */
 
 
2043
    {
 
 
2044
        VECTORCH velocity;
 
 
2045
 
 
 
2046
        {
 
 
2047
            int offset = MUL_FIXED(FastRandom()&16383, NormalFrameTime);
 
 
2048
 
 
 
2049
            position.vz = offset;
 
 
2050
            position.vy = (FastRandom()%(offset/8+1)) - offset/16;
 
 
2051
            position.vx = (FastRandom()%(offset/8+1)) - offset/16;
 
 
2052
        }
 
 
2053
 
 
 
2054
        velocity.vx = ((FastRandom()&1023) - 512);//*2;
 
 
2055
        velocity.vy = ((FastRandom()&1023) - 512);//*2;
 
 
2056
        velocity.vz = ((FastRandom()&511) + 200+512)*16;
 
 
2057
 
 
 
2058
        RotateVector(&position, orientMatPtr);
 
 
2059
        RotateVector(&velocity, orientMatPtr);
 
 
2060
 
 
 
2061
        position.vx += positionPtr->vx;
 
 
2062
        position.vy += positionPtr->vy;
 
 
2063
        position.vz += positionPtr->vz;
 
 
2064
 
 
 
2065
        if (!LocalDetailLevels.GhostFlameThrowerCollisions)
 
 
2066
            MakeParticle(&position, &velocity, PARTICLE_NONCOLLIDINGFLAME);
 
 
2067
        else
 
 
2068
            MakeParticle(&position, &velocity, PARTICLE_NONDAMAGINGFLAME);
 
 
2069
    }
 
 
2070
}
 
 
2071
 
 
 
2072
/*----------------------Patrick 4/3/97--------------------------
 
 
2073
  Stuff for predator (and xenoborg) projectiles...
 
 
2074
  NB will need a creation function for player (AIs have their own)
 
 
2075
  --------------------------------------------------------------*/
 
 
2076
void PredatorEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr)
 
 
2077
{
 
 
2078
    CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
2079
 
 
 
2080
    if (bbPtr->counter > 0)
 
 
2081
    {
 
 
2082
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
2083
        COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
2084
 
 
 
2085
        bbPtr->counter -= NormalFrameTime;
 
 
2086
 
 
 
2087
        if (reportPtr)
 
 
2088
        {
 
 
2089
            if(reportPtr->ObstacleSBPtr)
 
 
2090
            {
 
 
2091
                DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->DisplayBlock;
 
 
2092
 
 
 
2093
                if (bbPtr->player && AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr))
 
 
2094
                {
 
 
2095
                    int slot = SlotForThisWeapon(WEAPON_PRED_SHOULDERCANNON);
 
 
2096
 
 
 
2097
                    if (slot != -1)
 
 
2098
                        CurrentGameStats_WeaponHit(slot, 1);
 
 
2099
                }
 
 
2100
 
 
 
2101
                switch (reportPtr->ObstacleSBPtr->type)
 
 
2102
                {
 
 
2103
                    case I_BehaviourMarine:
 
 
2104
                    case I_BehaviourAlien:
 
 
2105
                    {
 
 
2106
                        if(dispPtr)
 
 
2107
                        {
 
 
2108
                            /* look for the object's torso in preference */
 
 
2109
                            SECTION_DATA *chest_section =  GetThisSectionData(dispPtr->HModelControlBlock->section_data, "chest");
 
 
2110
 
 
 
2111
                            if (chest_section)
 
 
2112
                            {
 
 
2113
                                VECTORCH rel_pos = dynPtr->Position;
 
 
2114
 
 
 
2115
                                rel_pos.vx -= chest_section->World_Offset.vx;
 
 
2116
                                rel_pos.vy -= chest_section->World_Offset.vy;
 
 
2117
                                rel_pos.vz -= chest_section->World_Offset.vz;
 
 
2118
 
 
 
2119
                                Normalise(&rel_pos);
 
 
2120
 
 
 
2121
    CauseDamageToHModel(dispPtr->HModelControlBlock, reportPtr->ObstacleSBPtr, &bbPtr->damage, ONE_FIXED, chest_section, &rel_pos,
&chest_section->World_Offset, 0);
 
 
2122
                            }
 
 
2123
                            else
 
 
2124
                            {
 
 
2125
                                VECTORCH attack_dir;
 
 
2126
                                GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
 
 
2127
                                CauseDamageToObject(reportPtr->ObstacleSBPtr, &bbPtr->damage, ONE_FIXED, &attack_dir);
 
 
2128
                            }
 
 
2129
                        }
 
 
2130
                    }
 
 
2131
                    break;
 
 
2132
                    default:
 
 
2133
                    {
 
 
2134
                        VECTORCH attack_dir;
 
 
2135
                        GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
 
 
2136
                        CauseDamageToObject(reportPtr->ObstacleSBPtr, &bbPtr->damage, ONE_FIXED, &attack_dir);
 
 
2137
                    }
 
 
2138
                }
 
 
2139
 
 
 
2140
                MakePlasmaExplosion(&dynPtr->Position, &dynPtr->PrevPosition, EXPLOSION_FOCUSEDPLASMA);
 
 
2141
 
 
 
2142
                if(SinglePlayer != AvP.PlayMode)
 
 
2143
                {
 
 
2144
                    AddNetMsg_MakePlasmaExplosion(&dynPtr->Position, &dynPtr->PrevPosition, EXPLOSION_FOCUSEDPLASMA);
 
 
2145
                    AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
2146
                }
 
 
2147
            }
 
 
2148
            else
 
 
2149
            {
 
 
2150
                MakePlasmaExplosion(&dynPtr->Position, &dynPtr->PrevPosition, EXPLOSION_DISSIPATINGPLASMA);
 
 
2151
 
 
 
2152
                if(SinglePlayer != AvP.PlayMode)
 
 
2153
                {
 
 
2154
                    AddNetMsg_MakePlasmaExplosion(&dynPtr->Position, &dynPtr->PrevPosition, EXPLOSION_DISSIPATINGPLASMA);
 
 
2155
                    AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
2156
                }
 
 
2157
            }
 
 
2158
 
 
 
2159
            sbPtr->please_destroy_me = 1;
 
 
2160
        }
 
 
2161
        else
 
 
2162
        {
 
 
2163
            //MakePlasmaTrailParticles(dynPtr, (bbPtr->damage.Impact ? (bbPtr->damage.Impact * 5) : 20));
 
 
2164
            MakePlasmaTrailParticles(dynPtr, (bbPtr->damage.Impact ? (bbPtr->damage.Impact * 5) : 1));
 
 
2165
 
 
 
2166
            VECTORCH direction;
 
 
2167
            direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx;
 
 
2168
            direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy;
 
 
2169
            direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz;
 
 
2170
            Normalise(&direction);
 
 
2171
            MakeMatrixFromDirection(&direction, &dynPtr->OrientMat);
 
 
2172
        }
 
 
2173
    }
 
 
2174
    else
 
 
2175
    {
 
 
2176
        /* for net game support: send a message saying we've blown up... */
 
 
2177
 
 
 
2178
        if(SinglePlayer != AvP.PlayMode)
 
 
2179
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
2180
 
 
 
2181
        sbPtr->please_destroy_me = 1;
 
 
2182
    }
 
 
2183
}
 
 
2184
 
 
 
2185
static void EulerAnglesHoming(VECTORCH *source, VECTORCH *Target, EULER *eulr, int rate) 
 
 
2186
{
 
 
2187
    int offsetx = Target->vx - source->vx;
 
 
2188
    int offsety = Target->vz - source->vz;
 
 
2189
    int angle1 = ArcTan(offsetx, offsety);
 
 
2190
    int angle2 = eulr->EulerY;
 
 
2191
    int offsetz;
 
 
2192
 
 
 
2193
    if (angle1 != angle2)
 
 
2194
    {
 
 
2195
        int testangle = angle2 - angle1;
 
 
2196
 
 
 
2197
        if (abs(testangle) < (NormalFrameTime >> rate))
 
 
2198
        {
 
 
2199
            eulr->EulerY = angle1;
 
 
2200
            eulr->EulerY &= wrap360;
 
 
2201
        }
 
 
2202
        else if ( ((testangle > 0) && (testangle < deg180)) || (testangle < -deg180) )
 
 
2203
        {
 
 
2204
            eulr->EulerY -= NormalFrameTime >> rate;
 
 
2205
            eulr->EulerY &= wrap360;
 
 
2206
        }
 
 
2207
        else
 
 
2208
        {
 
 
2209
            eulr->EulerY += NormalFrameTime >> rate;
 
 
2210
            eulr->EulerY &= wrap360;
 
 
2211
        }
 
 
2212
    }
 
 
2213
 
 
 
2214
    /* That was for the first plane. Now the second. */
 
 
2215
 
 
 
2216
    offsetz = SqRoot32((offsetx*offsetx)+(offsety*offsety));
 
 
2217
    offsety = -(Target->vy - source->vy);
 
 
2218
 
 
 
2219
    angle1 = ArcTan(offsety, offsetz);
 
 
2220
    angle2 = eulr->EulerX;
 
 
2221
 
 
 
2222
    if (angle1 != angle2)
 
 
2223
    {
 
 
2224
        int testangle = angle2 - angle1;
 
 
2225
 
 
 
2226
        if (abs(testangle) < (NormalFrameTime>>rate))
 
 
2227
        {
 
 
2228
            eulr->EulerX = angle1;
 
 
2229
            eulr->EulerX &= wrap360;
 
 
2230
        }
 
 
2231
        else if ( ((testangle > 0) && (testangle < deg180)) || (testangle < -deg180) )
 
 
2232
        {
 
 
2233
            eulr->EulerX -= NormalFrameTime >> rate;
 
 
2234
            eulr->EulerX &= wrap360;
 
 
2235
        }
 
 
2236
        else
 
 
2237
        {
 
 
2238
            eulr->EulerX += NormalFrameTime >> rate;
 
 
2239
            eulr->EulerX &= wrap360;
 
 
2240
        }
 
 
2241
    }
 
 
2242
}
 
 
2243
 
 
 
2244
static void Convert_Disc_To_Pickup(STRATEGYBLOCK *sbPtr)
 
 
2245
{
 
 
2246
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
2247
    PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
2248
    SECTION_DATA *disc_section = GetThisSectionData(bbPtr->HModelController.section_data, "disk");
 
 
2249
    /* Transmogrify a disc behaviour to a disc ammo pickup! */
 
 
2250
 
 
 
2251
    assert(disc_section);
 
 
2252
 
 
 
2253
    dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0;
 
 
2254
    dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;
 
 
2255
 
 
 
2256
    dynPtr->IsPickupObject = 1;
 
 
2257
    dynPtr->OrientMat = disc_section->SecMat;
 
 
2258
    dynPtr->Position = disc_section->World_Offset;
 
 
2259
    MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
 
 
2260
 
 
 
2261
    sbPtr->shapeIndex = disc_section->sempai->ShapeNum;
 
 
2262
    sbPtr->DamageBlock.Indestructable = 1;
 
 
2263
 
 
 
2264
    if (sbPtr->DisplayBlock)
 
 
2265
    {
 
 
2266
        sbPtr->DisplayBlock->ObShape = disc_section->sempai->ShapeNum;
 
 
2267
        sbPtr->DisplayBlock->ShapeData = disc_section->sempai->Shape;
 
 
2268
        sbPtr->DisplayBlock->HModelControlBlock = NULL;
 
 
2269
    }
 
 
2270
 
 
 
2271
    INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = malloc(sizeof(INANIMATEOBJECT_STATUSBLOCK));
 
 
2272
 
 
 
2273
    objectStatusPtr->respawnTimer = 0; 
 
 
2274
 
 
 
2275
    objectStatusPtr->typeId = IOT_Weapon;
 
 
2276
    objectStatusPtr->subType = (int)WEAPON_PRED_DISC;
 
 
2277
    objectStatusPtr->event_target = NULL;
 
 
2278
    objectStatusPtr->fragments = NULL;
 
 
2279
    objectStatusPtr->num_frags = 0;
 
 
2280
    objectStatusPtr->inan_tac = NULL;
 
 
2281
    objectStatusPtr->ghosted_object = 1;
 
 
2282
    objectStatusPtr->explosionTimer = 0;
 
 
2283
    objectStatusPtr->lifespanTimer = 0;
 
 
2284
 
 
 
2285
    Sound_Stop(bbPtr->soundHandle);
 
 
2286
    Dispel_HModel(&bbPtr->HModelController);
 
 
2287
    free(bbPtr);
 
 
2288
    sbPtr->dataptr = (void *)objectStatusPtr;
 
 
2289
    sbPtr->type = I_BehaviourInanimateObject;
 
 
2290
}
 
 
2291
 
 
 
2292
static void Disc_Hit_Environment(STRATEGYBLOCK *sbPtr, COLLISIONREPORT *reportPtr)
 
 
2293
{
 
 
2294
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
2295
    PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
2296
    MATRIXCH mat;
 
 
2297
 
 
 
2298
    /* Hit the environment.  Bounce? */
 
 
2299
    int dp = Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
 
 
2300
 
 
 
2301
    dynPtr->OrientEuler.EulerZ = 0;
 
 
2302
    dynPtr->IgnoreThePlayer = 0;
 
 
2303
 
 
 
2304
    if ((-1 == reportPtr->ModuleIndex) || ((dp > -46341) && (bbPtr->counter > 0) && (bbPtr->bounces <= DISC_MAX_BOUNCES)))
 
 
2305
    { /* 65536/Rt2 */
 
 
2306
        /* Bounce. */
 
 
2307
        MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->Position);
 
 
2308
        Sound_Play(SID_PREDATOR_DISK_HITTING_WALL, "dp", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
2309
        /* Record that the disc has bounced - for use in network game */
 
 
2310
        bbPtr->Bounced = 1;
 
 
2311
        bbPtr->bounces++;
 
 
2312
    }
 
 
2313
    else
 
 
2314
    {
 
 
2315
        CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
 
 
2316
        TransposeMatrixCH(&mat);
 
 
2317
        /* very steep angle (or very long flight!) - stick. */
 
 
2318
        bbPtr->Stuck = 1;
 
 
2319
        bbPtr->HModelController.Playing = 0;
 
 
2320
        MakeSprayOfSparks(&mat, &dynPtr->Position);
 
 
2321
        Sound_Stop(bbPtr->soundHandle);
 
 
2322
        Sound_Play(SID_DISC_STICKSINWALL, "dp", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
2323
    }
 
 
2324
 
 
 
2325
    if (bbPtr->Target == NULL)
 
 
2326
    {
 
 
2327
        /* No target, so come home. */
 
 
2328
        bbPtr->Target = PlayerStatus.sbptr;
 
 
2329
        COPY_NAME(bbPtr->Target_SBname, bbPtr->Target->SBname);
 
 
2330
    }
 
 
2331
}
 
 
2332
 
 
 
2333
void DiscBehaviour_SeekTrack(STRATEGYBLOCK *sbPtr)
 
 
2334
{
 
 
2335
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
2336
    COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
2337
    PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->dataptr;
 
 
2338
 
 
 
2339
    ProveHModel_Far(&bbPtr->HModelController, sbPtr);
 
 
2340
 
 
 
2341
    if (bbPtr->Target)
 
 
2342
    {
 
 
2343
        if (bbPtr->Target == PlayerStatus.sbptr)
 
 
2344
        {
 
 
2345
            VECTORCH targetPos;
 
 
2346
            GetTargetingPointOfObject_Far(bbPtr->Target, &targetPos);
 
 
2347
            EulerAnglesHoming(&dynPtr->Position, &targetPos, &dynPtr->OrientEuler, ((bbPtr->counter > 0) ? 4 : 2));
 
 
2348
        }
 
 
2349
        else
 
 
2350
        {
 
 
2351
            if(NPC_IsDead(bbPtr->Target))// || !NAME_ISEQUAL(bbPtr->Target_SBname, bbPtr->Target->SBname))
 
 
2352
            {
 
 
2353
                bbPtr->Target = PlayerStatus.sbptr;
 
 
2354
                bbPtr->counter = DISC_LIFETIME;
 
 
2355
                COPY_NAME(bbPtr->Target_SBname, bbPtr->Target->SBname);
 
 
2356
            }
 
 
2357
            else
 
 
2358
            {
 
 
2359
                /* Our target lives! */
 
 
2360
                VECTORCH targetPos;
 
 
2361
                GetTargetingPointOfObject_Far(bbPtr->Target, &targetPos);
 
 
2362
                EulerAnglesHoming(&dynPtr->Position, &targetPos, &dynPtr->OrientEuler, 4);
 
 
2363
            }
 
 
2364
        }
 
 
2365
    }
 
 
2366
 
 
 
2367
    if(reportPtr)
 
 
2368
    {
 
 
2369
        dynPtr->IgnoreThePlayer = 0;
 
 
2370
 
 
 
2371
          if(reportPtr->ObstacleSBPtr)
 
 
2372
          {
 
 
2373
            switch (reportPtr->ObstacleSBPtr->type)
 
 
2374
            {
 
 
2375
                case I_BehaviourPredatorPlayer:
 
 
2376
                {
 
 
2377
                    if(reportPtr->ObstacleSBPtr == PlayerStatus.sbptr)
 
 
2378
                    {
 
 
2379
                        /* Hit the owner.  Catch it! */
 
 
2380
                        int a;
 
 
2381
 
 
 
2382
                        for (a=0; a < MAX_NO_OF_WEAPON_SLOTS; a++)
 
 
2383
                        {
 
 
2384
                            if (PlayerStatus.WeaponSlot[a].WeaponIDNumber == WEAPON_PRED_DISC)
 
 
2385
                            {
 
 
2386
                                if (!PlayerStatus.WeaponSlot[a].PrimaryRoundsRemaining)
 
 
2387
                                {
 
 
2388
                                    PlayerStatus.WeaponSlot[a].PrimaryRoundsRemaining = 1;
 
 
2389
                                    bbPtr->Target = NULL;
 
 
2390
                                    sbPtr->please_destroy_me = 1;
 
 
2391
                                    Sound_Stop(bbPtr->soundHandle);
 
 
2392
                                    Sound_Play(SID_PREDATOR_DISK_BEING_CAUGHT, "h");
 
 
2393
 
 
 
2394
                                    if(SinglePlayer != AvP.PlayMode)
 
 
2395
                                        AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
2396
 
 
 
2397
                                    AutoSwapToDisc();
 
 
2398
                                    return;
 
 
2399
                                }
 
 
2400
                            }
 
 
2401
                        }
 
 
2402
                    }
 
 
2403
                }
 
 
2404
                break;
 
 
2405
                case I_BehaviourInanimateObject:
 
 
2406
                    CauseDamageToObject(reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_PRED_DISC].MaxDamage, ONE_FIXED, NULL);
 
 
2407
                break;
 
 
2408
                case I_BehaviourNetGhost:
 
 
2409
                {
 
 
2410
                    NETGHOSTDATABLOCK *dataptr = sbPtr->dataptr;
 
 
2411
 
 
 
2412
                    if(I_BehaviourPredatorDisc_SeekTrack != dataptr->type)
 
 
2413
                    {
 
 
2414
                        CauseDamageToObject(reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_PRED_DISC].MaxDamage, ONE_FIXED, NULL);
 
 
2415
                        break;
 
 
2416
                    }
 
 
2417
                }
 
 
2418
                case I_BehaviourProximityDoor:
 
 
2419
                case I_BehaviourTrackObject:
 
 
2420
                case I_BehaviourLiftDoor:
 
 
2421
                case I_BehaviourSwitchDoor:
 
 
2422
                case I_BehaviourLinkSwitch:
 
 
2423
                case I_BehaviourBinarySwitch:
 
 
2424
                case I_BehaviourLift:
 
 
2425
                case I_BehaviourPlatform:
 
 
2426
                case I_BehaviourPredatorDisc_SeekTrack:
 
 
2427
                {
 
 
2428
                    Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
 
 
2429
                    dynPtr->OrientEuler.EulerZ = 0;
 
 
2430
                    MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->Position);
 
 
2431
                    Sound_Play(SID_PREDATOR_DISK_HITTING_WALL, "dp", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
2432
                    bbPtr->bounces++;
 
 
2433
                    bbPtr->Bounced = 1; // Record that the disc has bounced - for use in network game
 
 
2434
                }
 
 
2435
                break;
 
 
2436
                case I_BehaviourMarine:
 
 
2437
                case I_BehaviourAlien:
 
 
2438
                {
 
 
2439
                    DISPLAYBLOCK *objectPtr = reportPtr->ObstacleSBPtr->DisplayBlock;
 
 
2440
 
 
 
2441
                    if(objectPtr)
 
 
2442
                    {
 
 
2443
                        /* look for the object's torso in preference */
 
 
2444
                        SECTION_DATA *chest_section = GetThisSectionData(objectPtr->HModelControlBlock->section_data, "chest");
 
 
2445
 
 
 
2446
                        if (chest_section)
 
 
2447
                        {
 
 
2448
                            VECTORCH rel_pos = dynPtr->Position;
 
 
2449
 
 
 
2450
                            rel_pos.vx -= chest_section->World_Offset.vx;
 
 
2451
                            rel_pos.vy -= chest_section->World_Offset.vy;
 
 
2452
                            rel_pos.vz -= chest_section->World_Offset.vz;
 
 
2453
 
 
 
2454
                            Normalise(&rel_pos);
 
 
2455
 
 
 
2456
CauseDamageToHModel(objectPtr->HModelControlBlock, reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_PRED_DISC].MaxDamage, ONE_FIXED, chest_section,
&rel_pos, &chest_section->World_Offset, 0);
 
 
2457
                        break;
 
 
2458
                        }
 
 
2459
                    }
 
 
2460
                } // no break for you
 
 
2461
                default:
 
 
2462
                    CauseDamageToObject(reportPtr->ObstacleSBPtr, &TemplateAmmo[AMMO_PRED_DISC].MaxDamage, ONE_FIXED, NULL);
 
 
2463
            }
 
 
2464
 
 
 
2465
            Sound_Play(SID_PREDATOR_DISK_HITTING_TARGET, "dp", &dynPtr->Position, ((FastRandom()&511)-255));
 
 
2466
 
 
 
2467
            if (NAME_ISEQUAL(reportPtr->ObstacleSBPtr->SBname, bbPtr->Target_SBname))
 
 
2468
            {
 
 
2469
                /* Got him!  Seek the player. */
 
 
2470
                bbPtr->Target = PlayerStatus.sbptr;
 
 
2471
                bbPtr->counter = DISC_LIFETIME;
 
 
2472
                COPY_NAME(bbPtr->Target_SBname, bbPtr->Target->SBname);
 
 
2473
            }
 
 
2474
        }
 
 
2475
        else
 
 
2476
        {
 
 
2477
            Disc_Hit_Environment(sbPtr, reportPtr);
 
 
2478
        }
 
 
2479
        reportPtr = reportPtr->NextCollisionReportPtr;
 
 
2480
    }
 
 
2481
 
 
 
2482
    if (bbPtr->Stuck)
 
 
2483
    {
 
 
2484
        Convert_Disc_To_Pickup(sbPtr);
 
 
2485
    }
 
 
2486
    else
 
 
2487
    {
 
 
2488
        MATRIXCH mat;
 
 
2489
 
 
 
2490
        if(SOUND_NOACTIVEINDEX == bbPtr->soundHandle)
 
 
2491
            Sound_Play(SID_PREDATOR_DISK_FLYING, "del", &sbPtr->DynPtr->Position, &bbPtr->soundHandle);
 
 
2492
        else
 
 
2493
            Sound_Update3d(bbPtr->soundHandle, &sbPtr->DynPtr->Position);
 
 
2494
 
 
 
2495
        sbPtr->DamageBlock.IsOnFire = 0;
 
 
2496
        bbPtr->counter -= NormalFrameTime;
 
 
2497
 
 
 
2498
        if ((bbPtr->Target == NULL) && (bbPtr->counter <= 0))
 
 
2499
        {
 
 
2500
            bbPtr->Target = PlayerStatus.sbptr;
 
 
2501
            bbPtr->counter = DISC_LIFETIME;
 
 
2502
            COPY_NAME(bbPtr->Target_SBname, bbPtr->Target->SBname);
 
 
2503
        }
 
 
2504
 
 
 
2505
        CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
 
 
2506
        TransposeMatrixCH(&mat);
 
 
2507
 
 
 
2508
        dynPtr->OrientMat = mat;
 
 
2509
 
 
 
2510
        dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31, DISC_SPEED);
 
 
2511
        dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32, DISC_SPEED);
 
 
2512
        dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33, DISC_SPEED);
 
 
2513
 
 
 
2514
        dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;
 
 
2515
        NewTrailPoint(sbPtr->DynPtr);
 
 
2516
    }
 
 
2517
}
 
 
2518
 
 
 
2519
static int PredDisc_TargetFilter(STRATEGYBLOCK *candidate)
 
 
2520
{
 
 
2521
    switch (candidate->type)
 
 
2522
    {
 
 
2523
        case I_BehaviourAlien:
 
 
2524
        case I_BehaviourMarine:
 
 
2525
        case I_BehaviourMarinePlayer:
 
 
2526
        case I_BehaviourAlienPlayer:
 
 
2527
        case I_BehaviourPredator:
 
 
2528
        case I_BehaviourPredatorPlayer:
 
 
2529
        case I_BehaviourXenoborg:
 
 
2530
        case I_BehaviourQueenAlien:
 
 
2531
        case I_BehaviourFaceHugger:
 
 
2532
            return 1;
 
 
2533
        case I_BehaviourNetGhost:
 
 
2534
        {
 
 
2535
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
2536
 
 
 
2537
            switch (dataptr->type)
 
 
2538
            {
 
 
2539
                case I_BehaviourMarinePlayer:
 
 
2540
                case I_BehaviourAlienPlayer:
 
 
2541
                case I_BehaviourPredatorPlayer:
 
 
2542
                    return 1;
 
 
2543
                default:
 
 
2544
                    return 0;
 
 
2545
            }
 
 
2546
        }
 
 
2547
        default:
 
 
2548
            return 0;
 
 
2549
    }
 
 
2550
}
 
 
2551
 
 
 
2552
static int ObjectIsOnScreen(DISPLAYBLOCK *object) 
 
 
2553
{
 
 
2554
    extern struct KObject VisibleObjects[maxobjects];
 
 
2555
    extern int numVisObjs;
 
 
2556
    int a = 0;
 
 
2557
 
 
 
2558
    for (; a < numVisObjs; a++)
 
 
2559
    {
 
 
2560
        if (VisibleObjects[a].DispPtr == object)
 
 
2561
            return 1;
 
 
2562
    }
 
 
2563
 
 
 
2564
return 0;
 
 
2565
}
 
 
2566
 
 
 
2567
#define DISC_PROX_RANGE 90000
 
 
2568
 
 
 
2569
STRATEGYBLOCK *PredDisc_GetNewTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr,VECTORCH *discpos, STRATEGYBLOCK *prevtarg, int mine) 
 
 
2570
{
 
 
2571
    int a = 0;
 
 
2572
    STRATEGYBLOCK *nearest = NULL;
 
 
2573
 
 
 
2574
    for (; a < NumActiveStBlocks; a++)
 
 
2575
    {
 
 
2576
        STRATEGYBLOCK *candidate = ActiveStBlockList[a];
 
 
2577
 
 
 
2578
        if ((candidate != prevtarg) && (candidate != PlayerStatus.sbptr))
 
 
2579
        {
 
 
2580
            if (candidate->DynPtr && PredDisc_TargetFilter(candidate))
 
 
2581
            {
 
 
2582
                VECTORCH offset;
 
 
2583
 
 
 
2584
                offset.vx = discpos->vx-candidate->DynPtr->Position.vx;
 
 
2585
                offset.vy = discpos->vy-candidate->DynPtr->Position.vy;
 
 
2586
                offset.vz = discpos->vz-candidate->DynPtr->Position.vz;
 
 
2587
 
 
 
2588
                int dist = Approximate3dMagnitude(&offset);
 
 
2589
 
 
 
2590
                if (! ((mine == 1) && dist > DISC_PROX_RANGE))
 
 
2591
                {
 
 
2592
                    if (dist < ONE_FIXED)
 
 
2593
                    {
 
 
2594
                        /* Check visibility? */
 
 
2595
                        if (candidate->DisplayBlock && !NPC_IsDead(candidate))
 
 
2596
                        {
 
 
2597
                            /* Not the last one again! */
 
 
2598
                            if (!NAME_ISEQUAL(bptr->Prev_Target_SBname, candidate->SBname))
 
 
2599
                            {
 
 
2600
                                if (mine == 1)
 
 
2601
                                {
 
 
2602
                                    if (IsThisObjectVisibleFromThisPosition(candidate->DisplayBlock, discpos))
 
 
2603
                                        nearest = candidate;
 
 
2604
                                }
 
 
2605
                                else if (mine == 2)
 
 
2606
                                {
 
 
2607
                                    if (ObjectIsOnScreen(candidate->DisplayBlock))
 
 
2608
                                        nearest = candidate;
 
 
2609
                                }
 
 
2610
                                else if (candidate->containingModule)
 
 
2611
                                {
 
 
2612
                                    MODULE *dmod = ModuleFromPosition(discpos, PlayerStatus.sbptr->containingModule);
 
 
2613
 
 
 
2614
                                    if (IsModuleVisibleFromModule(dmod, candidate->containingModule))
 
 
2615
                                        nearest = candidate;
 
 
2616
                                }
 
 
2617
                            }
 
 
2618
                        }
 
 
2619
                    }
 
 
2620
                }
 
 
2621
            }
 
 
2622
        }
 
 
2623
    }
 
 
2624
 
 
 
2625
return nearest;
 
 
2626
}
 
 
2627
 
 
 
2628
DISPLAYBLOCK *SpawnMolotovCocktail(SECTION_DATA *root, MATRIXCH *master_orient)
 
 
2629
{
 
 
2630
    /* Doesn't really matter what shape gets generated... */
 
 
2631
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourMolotov);
 
 
2632
 
 
 
2633
    if(NULL == sbPtr)
 
 
2634
        return NULL;
 
 
2635
 
 
 
2636
    DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject();
 
 
2637
    sbPtr->dataptr = malloc(sizeof(MOLOTOV_BEHAV_BLOCK));
 
 
2638
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
 
 
2639
 
 
 
2640
    if ((NULL == sbPtr->dataptr) || (NULL == dynPtr) || (NULL == dispPtr))
 
 
2641
    {
 
 
2642
        RemoveBehaviourStrategy(sbPtr);
 
 
2643
        return NULL;
 
 
2644
    }
 
 
2645
 
 
 
2646
    if(root) //allow case root==NULL for loading
 
 
2647
        dispPtr->ObWorld = root->World_Offset;
 
 
2648
 
 
 
2649
    // 2. NOW set up the strategyblock-specific fields for
 
 
2650
    // the new displayblock. We won't go through the "AttachNew
 
 
2651
    // StrategyBlock" and "AssignRunTimeBehaviours" pair, since
 
 
2652
    // the first switches on ObShape and the second on bhvr;
 
 
2653
    // but, in this case, there isn't a particular connection
 
 
2654
    // between them.
 
 
2655
 
 
 
2656
    dispPtr->ObStrategyBlock = sbPtr;
 
 
2657
 
 
 
2658
    ((MOLOTOV_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = 65536;//32767;//FastRandom()&32767;
 
 
2659
 
 
 
2660
    if(root) //allow case root == NULL for loading
 
 
2661
    {
 
 
2662
        int woundflags = Splice_HModels(&(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), root);
 
 
2663
        InitHModelSequence( &(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), 0, 1, ONE_FIXED);
 
 
2664
    }
 
 
2665
 
 
 
2666
    dispPtr->HModelControlBlock = &(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController);
 
 
2667
 
 
 
2668
    if(root) //allow case root == NULL for loading
 
 
2669
    {
 
 
2670
        dispPtr->ObWorld = root->World_Offset;
 
 
2671
        dispPtr->ObMat = root->SecMat;
 
 
2672
    }
 
 
2673
 
 
 
2674
    assert(dispPtr->ObWorld.vx < 1000000 && dispPtr->ObWorld.vx > -1000000);
 
 
2675
    assert(dispPtr->ObWorld.vy < 1000000 && dispPtr->ObWorld.vy > -1000000);
 
 
2676
    assert(dispPtr->ObWorld.vz < 1000000 && dispPtr->ObWorld.vz > -1000000);
 
 
2677
 
 
 
2678
    ProveHModel(dispPtr->HModelControlBlock, dispPtr);
 
 
2679
 
 
 
2680
    if(root) //allow case root == NULL for loading
 
 
2681
    {
 
 
2682
        dynPtr->Position = root->World_Offset;
 
 
2683
        dynPtr->OrientMat = root->SecMat;
 
 
2684
    }
 
 
2685
 
 
 
2686
    // Give explosion fragments an angular velocity
 
 
2687
    dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
 
 
2688
    dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
 
 
2689
    dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
 
 
2690
 
 
 
2691
    dynPtr->IgnoreThePlayer = 0;
 
 
2692
 
 
 
2693
    /* Handle velocity... */
 
 
2694
    VECTORCH start = {0, -2000, 12000};
 
 
2695
    MATRIXCH tm = *master_orient;
 
 
2696
    sbPtr->maintainVisibility = 1;
 
 
2697
 
 
 
2698
    RotateAndCopyVector(&start, &dynPtr->LinImpulse, &tm);
 
 
2699
 
 
 
2700
return dispPtr;
 
 
2701
}
 
 
2702
 
 
 
2703
void MolotovBehaviour(STRATEGYBLOCK *sbPtr) 
 
 
2704
{
 
 
2705
    COLLISIONREPORT *reportPtr = sbPtr->DynPtr->CollisionReportPtr;
 
 
2706
    MOLOTOV_BEHAV_BLOCK *bbPtr = (MOLOTOV_BEHAV_BLOCK * )sbPtr->dataptr;
 
 
2707
 
 
 
2708
    if(reportPtr && reportPtr->ObstacleSBPtr)
 
 
2709
    {
 
 
2710
        reportPtr->ObstacleSBPtr->DamageBlock.IsOnFire = ONE_FIXED * 60;
 
 
2711
        reportPtr->ObstacleSBPtr->DamageBlock.Combustability = 2;
 
 
2712
    }
 
 
2713
 
 
 
2714
    if ((bbPtr->counter <= 0) || reportPtr)
 
 
2715
    {
 
 
2716
        MakeMolotovExplosionAt(&sbPtr->DynPtr->Position);
 
 
2717
 
 
 
2718
        if (sbPtr->containingModule)
 
 
2719
        {
 
 
2720
            Explosion_SoundData.position = sbPtr->DynPtr->Position;
 
 
2721
            Sound_Play(SID_MOLOTOV_EXPLOSION, "n", &Explosion_SoundData);
 
 
2722
        }
 
 
2723
 
 
 
2724
        if(SinglePlayer != AvP.PlayMode)
 
 
2725
            AddNetMsg_LocalObjectDestroyed(sbPtr);
 
 
2726
 
 
 
2727
        sbPtr->please_destroy_me = 1;
 
 
2728
    }
 
 
2729
    else
 
 
2730
    {
 
 
2731
        bbPtr->counter -= NormalFrameTime;
 
 
2732
        DynamicallyRotateObject(sbPtr->DynPtr);
 
 
2733
    }
 
 
2734
}
 
 
2735
 
 
 
2736
//defines for load/save macros
 
 
2737
#define SAVELOAD_BLOCK block
 
 
2738
#define SAVELOAD_BEHAV behav
 
 
2739
 
 
 
2740
/*-------------------**
 
 
2741
** Load/Save Flare Grenade **
 
 
2742
**-------------------*/
 
 
2743
typedef struct flare_grenade_save_block
 
 
2744
{
 
 
2745
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
2746
 
 
 
2747
    int LifeTimeRemaining;
 
 
2748
    int ParticleGenerationTimer;
 
 
2749
 
 
 
2750
    DYNAMICSBLOCK dynamics;
 
 
2751
 
 
 
2752
} FLARE_GRENADE_SAVE_BLOCK;
 
 
2753
 
 
 
2754
void LoadStrategy_Flare(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
2755
{
 
 
2756
    FLARE_GRENADE_SAVE_BLOCK* block = (FLARE_GRENADE_SAVE_BLOCK*) header;
 
 
2757
 
 
 
2758
    //check the size of the save block
 
 
2759
    if(header->size != sizeof(*block))
 
 
2760
        return;
 
 
2761
 
 
 
2762
    STRATEGYBLOCK* sbPtr = CreateFlare(&block->dynamics.Position, &block->dynamics.OrientMat);
 
 
2763
 
 
 
2764
    if(NULL != sbPtr)
 
 
2765
    {
 
 
2766
        FLARE_BEHAV_BLOCK* behav = (FLARE_BEHAV_BLOCK*) sbPtr->dataptr;
 
 
2767
 
 
 
2768
        COPYELEMENT_LOAD(LifeTimeRemaining)
 
 
2769
        COPYELEMENT_LOAD(ParticleGenerationTimer)
 
 
2770
 
 
 
2771
        *sbPtr->DynPtr = block->dynamics;
 
 
2772
 
 
 
2773
        Load_SoundState(&behav->SoundHandle);
 
 
2774
    }
 
 
2775
}
 
 
2776
 
 
 
2777
void SaveStrategy_Flare(STRATEGYBLOCK* sbPtr)
 
 
2778
{
 
 
2779
    FLARE_GRENADE_SAVE_BLOCK* block;
 
 
2780
    FLARE_BEHAV_BLOCK* behav = (FLARE_BEHAV_BLOCK*) sbPtr->dataptr;
 
 
2781
 
 
 
2782
    GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
 
 
2783
 
 
 
2784
    COPYELEMENT_SAVE(LifeTimeRemaining)
 
 
2785
    COPYELEMENT_SAVE(ParticleGenerationTimer)
 
 
2786
 
 
 
2787
    block->dynamics = *sbPtr->DynPtr;
 
 
2788
    block->dynamics.CollisionReportPtr=0;
 
 
2789
 
 
 
2790
    Save_SoundState(&behav->SoundHandle);
 
 
2791
}
 
 
2792
 
 
 
2793
/*-------------------**
 
 
2794
** Load/Save Prox Grenade **
 
 
2795
**-------------------*/
 
 
2796
typedef struct prox_grenade_save_block
 
 
2797
{
 
 
2798
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
2799
 
 
 
2800
    int counter;
 
 
2801
    int SoundGenerationTimer;
 
 
2802
 
 
 
2803
    DYNAMICSBLOCK dynamics;
 
 
2804
 
 
 
2805
} PROX_GRENADE_SAVE_BLOCK;
 
 
2806
 
 
 
2807
void LoadStrategy_ProxGrenade(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
2808
{
 
 
2809
    PROX_GRENADE_SAVE_BLOCK* block = (PROX_GRENADE_SAVE_BLOCK*) header;
 
 
2810
 
 
 
2811
    //check the size of the save block
 
 
2812
    if(header->size != sizeof(*block))
 
 
2813
        return;
 
 
2814
 
 
 
2815
    STRATEGYBLOCK* sbPtr = CreateGrenadeKernel(I_BehaviourProximityGrenade, &block->dynamics.Position, &block->dynamics.OrientMat, 0);
 
 
2816
 
 
 
2817
    if(NULL != sbPtr)
 
 
2818
    {
 
 
2819
        PROX_GRENADE_BEHAV_BLOCK* behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->dataptr;
 
 
2820
 
 
 
2821
        //copy stuff over
 
 
2822
        COPYELEMENT_LOAD(counter)
 
 
2823
        COPYELEMENT_LOAD(SoundGenerationTimer)
 
 
2824
 
 
 
2825
        *sbPtr->DynPtr = block->dynamics;
 
 
2826
 
 
 
2827
        Load_SoundState(&behav->SoundHandle);
 
 
2828
    }
 
 
2829
}
 
 
2830
 
 
 
2831
void SaveStrategy_ProxGrenade(STRATEGYBLOCK* sbPtr)
 
 
2832
{
 
 
2833
    PROX_GRENADE_SAVE_BLOCK* block;
 
 
2834
    PROX_GRENADE_BEHAV_BLOCK* behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->dataptr;
 
 
2835
 
 
 
2836
    GET_STRATEGY_SAVE_BLOCK(block, sbPtr);
 
 
2837
 
 
 
2838
    COPYELEMENT_SAVE(counter)
 
 
2839
    COPYELEMENT_SAVE(SoundGenerationTimer)
 
 
2840
 
 
 
2841
    block->dynamics = *sbPtr->DynPtr;
 
 
2842
    block->dynamics.CollisionReportPtr = NULL;
 
 
2843
 
 
 
2844
    Save_SoundState(&behav->SoundHandle);
 
 
2845
}
 
 
2846
 
 
 
2847
/*-------------------------**
 
 
2848
** Load/Save speargun bolt **
 
 
2849
**-------------------------*/
 
 
2850
 
 
 
2851
typedef struct spear_bolt_save_block
 
 
2852
{
 
 
2853
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
2854
 
 
 
2855
//behaviour block stuff
 
 
2856
    int counter;
 
 
2857
    MATRIXCH Orient;
 
 
2858
    VECTORCH Position;
 
 
2859
//    HMODELCONTROLLER HierarchicalFragment;
 
 
2860
    int Android;
 
 
2861
    AVP_BEHAVIOUR_TYPE Type;
 
 
2862
    int SubType;
 
 
2863
    unsigned int SpearThroughFragment;
 
 
2864
    unsigned int Stuck :1;
 
 
2865
 
 
 
2866
//strategy block stuff
 
 
2867
    DYNAMICSBLOCK dynamics;
 
 
2868
 
 
 
2869
} SPEAR_BOLT_SAVE_BLOCK;
 
 
2870
 
 
 
2871
void LoadStrategy_SpearBolt(SAVE_BLOCK_HEADER* header)
 
 
2872
{
 
 
2873
    SPEAR_BOLT_SAVE_BLOCK* block = (SPEAR_BOLT_SAVE_BLOCK*) header;
 
 
2874
 
 
 
2875
    //check the size of the save block
 
 
2876
    if(header->size != sizeof(*block))
 
 
2877
        return;
 
 
2878
 
 
 
2879
    //create default spear bolt
 
 
2880
    DISPLAYBLOCK* dPtr = InitialiseSpeargunBoltBehaviour_ForLoad();
 
 
2881
 
 
 
2882
    if(NULL != dPtr)
 
 
2883
    {
 
 
2884
        STRATEGYBLOCK* sbPtr = dPtr->ObStrategyBlock;
 
 
2885
 
 
 
2886
        SPEAR_BEHAV_BLOCK* behav = (SPEAR_BEHAV_BLOCK*)sbPtr->dataptr;
 
 
2887
 
 
 
2888
        COPYELEMENT_LOAD(counter)
 
 
2889
        COPYELEMENT_LOAD(Orient)
 
 
2890
        COPYELEMENT_LOAD(Position)
 
 
2891
        COPYELEMENT_LOAD(Android)
 
 
2892
        COPYELEMENT_LOAD(Type)
 
 
2893
        COPYELEMENT_LOAD(SubType)
 
 
2894
        COPYELEMENT_LOAD(SpearThroughFragment)
 
 
2895
        COPYELEMENT_LOAD(Stuck)
 
 
2896
 
 
 
2897
        *sbPtr->DynPtr = block->dynamics;
 
 
2898
 
 
 
2899
        {
 
 
2900
            SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
2901
 
 
 
2902
            if(hier_header)
 
 
2903
                LoadHierarchy(hier_header,&behav->HierarchicalFragment);
 
 
2904
        }
 
 
2905
 
 
 
2906
        //if there is a hierarchy  fill it in the displayblock
 
 
2907
        if(behav->HierarchicalFragment.Root_Section)
 
 
2908
            dPtr->HModelControlBlock = &behav->HierarchicalFragment;    
 
 
2909
    }
 
 
2910
}
 
 
2911
 
 
 
2912
void SaveStrategy_SpearBolt(STRATEGYBLOCK* sbPtr)
 
 
2913
{
 
 
2914
    SPEAR_BOLT_SAVE_BLOCK *block;
 
 
2915
    SPEAR_BEHAV_BLOCK *behav = (SPEAR_BEHAV_BLOCK*)sbPtr->dataptr;
 
 
2916
    GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
 
 
2917
 
 
 
2918
    COPYELEMENT_SAVE(counter)
 
 
2919
    COPYELEMENT_SAVE(Orient)
 
 
2920
    COPYELEMENT_SAVE(Position)
 
 
2921
    COPYELEMENT_SAVE(Android)
 
 
2922
    COPYELEMENT_SAVE(Type)
 
 
2923
    COPYELEMENT_SAVE(SubType)
 
 
2924
    COPYELEMENT_SAVE(SpearThroughFragment)
 
 
2925
    COPYELEMENT_SAVE(Stuck)
 
 
2926
 
 
 
2927
    block->dynamics = *sbPtr->DynPtr;
 
 
2928
    block->dynamics.CollisionReportPtr = NULL;
 
 
2929
 
 
 
2930
    //save the hierarchy
 
 
2931
    SaveHierarchy(&behav->HierarchicalFragment);
 
 
2932
}