4b825dc642cb6eb9a060e54bf8d69288fbee490494a6641b73026d662261604d7d192beae70b11dc
 
 
1
#include "system.h"
 
 
2
#include "prototyp.h"
 
 
3
#include "stratdef.h"
 
 
4
#include "bh_types.h"
 
 
5
#include "weapons.h"
 
 
6
#include "pheromon.h"
 
 
7
#include "npc_sentrygun.h"
 
 
8
#include "sequnces.h"
 
 
9
#include "npc_marine.h"
 
 
10
#include "targeting.h"
 
 
11
#include "los.h"
 
 
12
#include "psndplat.h"
 
 
13
#include "npc_dummy.h"
 
 
14
#include "lighting.h"
 
 
15
#include "corpse.h"
 
 
16
#include "particle.h"
 
 
17
#include "bh_ais.h"
 
 
18
#include "pldghost.h"
 
 
19
#include "extents.h"
 
 
20
#include <stdlib.h>
 
 
21
#include <assert.h>
 
 
22
 
 
 
23
#define SENTRYGUN_DRAMA 0
 
 
24
 
 
 
25
int SentrygunSpread = 5;
 
 
26
int sentrygun_infinity_ammo = 0;
 
 
27
int sentrygun_reload_ammo = 0;
 
 
28
 
 
 
29
extern uint8_t Null_Name[8];
 
 
30
extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
 
 
31
 
 
 
32
SOUND3DDATA SentryFire_SoundData =
 
 
33
{
 
 
34
    {0,0,0,},
 
 
35
    {0,0,0,},
 
 
36
    20000,
 
 
37
    40000,
 
 
38
};
 
 
39
 
 
 
40
SOUND3DDATA SentryWhirr_SoundData =
 
 
41
{
 
 
42
    {0,0,0,},
 
 
43
    {0,0,0,},
 
 
44
    0,
 
 
45
    32000,
 
 
46
};
 
 
47
 
 
 
48
static int make_new_sentrygun(STRATEGYBLOCK *sbPtr, int start_ammo, AG_STATE start_state)
 
 
49
{
 
 
50
    sbPtr->dataptr = malloc(sizeof(AUTOGUN_STATUS_BLOCK));
 
 
51
    sbPtr->maintainVisibility = 1;
 
 
52
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
53
 
 
 
54
    if((NULL == sbPtr->dataptr) || (NULL == sbPtr->DynPtr))
 
 
55
    {
 
 
56
        RemoveBehaviourStrategy(sbPtr);
 
 
57
        return 0;
 
 
58
    }
 
 
59
 
 
 
60
    sbPtr->DynPtr->Mass = 400;
 
 
61
    sbPtr->DynPtr->CanClimbStairs = 0;
 
 
62
    AUTOGUN_STATUS_BLOCK *new_sentrygun = sbPtr->dataptr;
 
 
63
    new_sentrygun->behaviourState = start_state;
 
 
64
 
 
 
65
    new_sentrygun->HModelController.Deltas = NULL;
 
 
66
    new_sentrygun->HModelController.Root_Section = NULL;
 
 
67
    new_sentrygun->HModelController.section_data = NULL;
 
 
68
    new_sentrygun->gun_pan = NULL;
 
 
69
    new_sentrygun->gun_tilt = NULL;
 
 
70
    new_sentrygun->Target = NULL;
 
 
71
    COPY_NAME(new_sentrygun->Target_SBname, Null_Name);
 
 
72
 
 
 
73
    new_sentrygun->targetTrackPos.vx = 0;
 
 
74
    new_sentrygun->targetTrackPos.vy = 0;
 
 
75
    new_sentrygun->targetTrackPos.vz = 0;
 
 
76
 
 
 
77
    new_sentrygun->Gun_Pan = 0;
 
 
78
    new_sentrygun->Gun_Tilt = 0;
 
 
79
    new_sentrygun->GunFlash = NULL;
 
 
80
 
 
 
81
    new_sentrygun->incidentFlag = 0;
 
 
82
    new_sentrygun->incidentTimer = 0;
 
 
83
 
 
 
84
    new_sentrygun->ammo = start_ammo;
 
 
85
    new_sentrygun->roundsFired = 0;
 
 
86
    new_sentrygun->volleyFired = 0;
 
 
87
 
 
 
88
      new_sentrygun->soundHandle = SOUND_NOACTIVEINDEX;
 
 
89
      new_sentrygun->soundHandle2 = SOUND_NOACTIVEINDEX;
 
 
90
    new_sentrygun->Firing = 0;
 
 
91
    new_sentrygun->WhirrSoundOn = 0;
 
 
92
    new_sentrygun->Drama = 0;
 
 
93
      new_sentrygun->createdByPlayer = 0;
 
 
94
    new_sentrygun->gunpandir = 0;
 
 
95
    new_sentrygun->guntiltdir = 0;
 
 
96
    new_sentrygun->OnTarget = 0;
 
 
97
    new_sentrygun->OnTarget_LastFrame = 0;
 
 
98
    new_sentrygun->death_target_sbptr = NULL;
 
 
99
    new_sentrygun->death_target_request = 0;
 
 
100
 
 
 
101
    {
 
 
102
        int i = 0;
 
 
103
        for(i=0; i < SB_NAME_LENGTH; i++)
 
 
104
            new_sentrygun->death_target_ID[i] = 0;
 
 
105
    }
 
 
106
 
 
 
107
    {
 
 
108
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_SentryGun];
 
 
109
        sbPtr->DamageBlock = NpcData->StartingStats;
 
 
110
        sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
111
        sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
112
    }
 
 
113
 
 
 
114
    SECTION *root_section = GetNamedHierarchyFromLibrary("sentry", "gun");
 
 
115
 
 
 
116
    if (!root_section)
 
 
117
    {
 
 
118
        RemoveBehaviourStrategy(sbPtr);
 
 
119
        return 0;
 
 
120
    }
 
 
121
 
 
 
122
    Create_HModel(&new_sentrygun->HModelController,root_section);
 
 
123
    InitHModelSequence(&new_sentrygun->HModelController, HMSQT_Xenoborg, XBSS_Powered_Up_Standard, ONE_FIXED);
 
 
124
 
 
 
125
    {
 
 
126
        DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_sentrygun->HModelController, "GunTilt", (int)HMSQT_Xenoborg,
(int)XBSS_Head_Vertical_Delta, 0);
 
 
127
        assert(delta);
 
 
128
        delta->timer = 32767;
 
 
129
        delta->Active = 0;
 
 
130
 
 
 
131
        delta = Add_Delta_Sequence(&new_sentrygun->HModelController, "GunPan", (int)HMSQT_Xenoborg, (int)XBSS_Head_Horizontal_Delta, 0);
 
 
132
        assert(delta);
 
 
133
        delta->timer = 32767;
 
 
134
        delta->Active = 0;
 
 
135
    }
 
 
136
 
 
 
137
return 1;
 
 
138
}
 
 
139
 
 
 
140
void MakeSentrygunNear(STRATEGYBLOCK *sbPtr)
 
 
141
{
 
 
142
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
143
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
144
 
 
 
145
    DISPLAYBLOCK *dPtr = CreateActiveObject();
 
 
146
 
 
 
147
    if(dPtr == NULL)
 
 
148
        return; /* if cannot create displayblock, leave far */
 
 
149
 
 
 
150
    sbPtr->DisplayBlock = dPtr;
 
 
151
    dPtr->ObStrategyBlock = sbPtr;
 
 
152
 
 
 
153
    /* need to initialise positional information in the new display block */ 
 
 
154
    dPtr->ObWorld = dynPtr->Position;
 
 
155
    dPtr->ObEuler = dynPtr->OrientEuler;
 
 
156
    dPtr->ObMat = dynPtr->OrientMat;
 
 
157
 
 
 
158
       /* state and sequence init */
 
 
159
    dPtr->HModelControlBlock = &agunStatusPointer->HModelController;
 
 
160
 
 
 
161
    ProveHModel(dPtr->HModelControlBlock, dPtr);
 
 
162
}
 
 
163
 
 
 
164
void CreateSentrygun(VECTORCH *Position)
 
 
165
{
 
 
166
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourAutoGun);
 
 
167
 
 
 
168
    if((NULL != sbPtr) && make_new_sentrygun(sbPtr, 500, I_tracking))
 
 
169
    {
 
 
170
        AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
171
        agunStatus->createdByPlayer = 1;
 
 
172
 
 
 
173
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
174
        dynPtr->PrevPosition = dynPtr->Position = *Position;
 
 
175
        dynPtr->OrientEuler.EulerY = PlayerStatus.DisplayBlock->ObEuler.EulerY;
 
 
176
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
177
        TransposeMatrixCH(&dynPtr->OrientMat);
 
 
178
        AssignNewSBName(sbPtr);
 
 
179
        //if(AvP.Network != I_No_Network) AddNetGameObjectID(sbPtr);
 
 
180
        sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
181
 
 
 
182
        if(!sbPtr->containingModule)
 
 
183
            RemoveBehaviourStrategy(sbPtr);
 
 
184
    }
 
 
185
}
 
 
186
 
 
 
187
void CastSentrygunBot() 
 
 
188
{
 
 
189
    #define BOTRANGE 2000
 
 
190
 
 
 
191
    VECTORCH position;
 
 
192
 
 
 
193
    position = PlayerStatus.sbptr->DynPtr->Position;
 
 
194
    position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE);
 
 
195
    position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE);
 
 
196
    position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE);
 
 
197
 
 
 
198
    CreateSentrygun(&position);
 
 
199
}
 
 
200
 
 
 
201
void AutoGunBehaveInit(void *bhdata, STRATEGYBLOCK *sbPtr)
 
 
202
{
 
 
203
    int i;
 
 
204
 
 
 
205
    AUTOGUN_TOOLS_TEMPLATE *toolsData = (AUTOGUN_TOOLS_TEMPLATE *)bhdata; 
 
 
206
 
 
 
207
    for(i=0; i < SB_NAME_LENGTH; i++)
 
 
208
        sbPtr->SBname[i] = toolsData->nameID[i];
 
 
209
 
 
 
210
    if(make_new_sentrygun(sbPtr, toolsData->ammo, (toolsData->startInactive ? I_inactive : I_tracking)))
 
 
211
    {
 
 
212
        AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
213
        agunStatus->death_target_request = toolsData->death_target_request;
 
 
214
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
215
        dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
 
 
216
        dynPtr->OrientEuler = toolsData->orientation;
 
 
217
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
218
        TransposeMatrixCH(&dynPtr->OrientMat);
 
 
219
        sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
220
 
 
 
221
        if(!sbPtr->containingModule)
 
 
222
            RemoveBehaviourStrategy(sbPtr);
 
 
223
    }
 
 
224
}
 
 
225
 
 
 
226
void MakeSentrygunFar(STRATEGYBLOCK *sbPtr)
 
 
227
{
 
 
228
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
229
    assert(agunStatusPointer);
 
 
230
 
 
 
231
    DestroyActiveObject(&sbPtr->DisplayBlock);
 
 
232
    DestroyActiveObject(&agunStatusPointer->GunFlash);
 
 
233
 
 
 
234
    /* agun data block init */
 
 
235
    if(agunStatusPointer->behaviourState != I_disabled)
 
 
236
           agunStatusPointer->stateTimer = 0;
 
 
237
 
 
 
238
    /* zero linear velocity in dynamics block */
 
 
239
    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;    
 
 
240
}
 
 
241
 
 
 
242
static void Autogun_VerifyDeltaControllers(STRATEGYBLOCK *sbPtr)
 
 
243
{
 
 
244
    assert(sbPtr);
 
 
245
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
246
    assert(agunStatusPointer);                      
 
 
247
 
 
 
248
    /* Nothing has deltas like a xenoborg does. */
 
 
249
    /* But sentryguns try their best. */
 
 
250
 
 
 
251
    agunStatusPointer->gun_pan = Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunPan");
 
 
252
    assert(agunStatusPointer->gun_pan);
 
 
253
 
 
 
254
    agunStatusPointer->gun_tilt = Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunTilt");
 
 
255
    assert(agunStatusPointer->gun_tilt);
 
 
256
}
 
 
257
 
 
 
258
static void AGun_ComputeDeltaValues(STRATEGYBLOCK *sbPtr)
 
 
259
{
 
 
260
    assert(sbPtr);
 
 
261
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
262
    assert(agunStatusPointer);
 
 
263
 
 
 
264
    /* Interpret all status block values, and apply to deltas. */
 
 
265
    /* Gun Pan first. */
 
 
266
 
 
 
267
    int angle = agunStatusPointer->Gun_Pan >> 4;
 
 
268
 
 
 
269
    if (angle >= 3072)
 
 
270
        angle -= 4096;
 
 
271
 
 
 
272
    if (angle >= 2048)
 
 
273
        angle -= 4096;
 
 
274
 
 
 
275
    assert(agunStatusPointer->gun_pan);
 
 
276
 
 
 
277
    /* Now, we have an angle. */
 
 
278
 
 
 
279
    if (angle > SGUN_PAN_GIMBALL)
 
 
280
    {
 
 
281
        angle = SGUN_PAN_GIMBALL;
 
 
282
    }
 
 
283
    else if (angle < -SGUN_PAN_GIMBALL)
 
 
284
    {
 
 
285
        angle = -SGUN_PAN_GIMBALL;
 
 
286
    }
 
 
287
 
 
 
288
    {
 
 
289
        int fake_timer;
 
 
290
 
 
 
291
        if (angle > 0)
 
 
292
        {
 
 
293
            fake_timer = DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1));
 
 
294
            fake_timer += 32767;
 
 
295
 
 
 
296
            if (fake_timer > 65536)
 
 
297
                fake_timer = 65535;
 
 
298
            else if (fake_timer < 0)
 
 
299
                fake_timer = 0;
 
 
300
        }
 
 
301
        else
 
 
302
        {
 
 
303
            fake_timer = DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1));
 
 
304
            fake_timer += 32767;
 
 
305
 
 
 
306
            if (fake_timer > 65536)
 
 
307
                fake_timer = 65535;
 
 
308
            else if (fake_timer < 0)
 
 
309
                fake_timer = 0;
 
 
310
        }
 
 
311
 
 
 
312
        if (agunStatusPointer->gun_pan->timer != fake_timer)
 
 
313
            agunStatusPointer->WhirrSoundOn = 1;
 
 
314
 
 
 
315
        agunStatusPointer->gun_pan->timer = fake_timer;
 
 
316
    }
 
 
317
 
 
 
318
    /* Gun Tilt... */
 
 
319
 
 
 
320
    angle = agunStatusPointer->Gun_Tilt>>4;
 
 
321
 
 
 
322
    if (angle >= 3072)
 
 
323
        angle -= 4096;
 
 
324
 
 
 
325
    if (angle >= 2048)
 
 
326
        angle = angle - 3072;
 
 
327
 
 
 
328
    if (angle > 1024)
 
 
329
        angle = 2048-angle;
 
 
330
 
 
 
331
    assert(agunStatusPointer->gun_tilt);
 
 
332
 
 
 
333
    /* Now, we have an angle. */
 
 
334
 
 
 
335
    if (angle > SGUN_PITCH_GIMBALL)
 
 
336
    {
 
 
337
        angle = SGUN_PITCH_GIMBALL;
 
 
338
    }
 
 
339
    else if (angle < -SGUN_PITCH_GIMBALL)
 
 
340
    {
 
 
341
        angle = -SGUN_PITCH_GIMBALL;
 
 
342
    }
 
 
343
 
 
 
344
    assert(angle >= -1024);
 
 
345
    assert(angle <= 1024);
 
 
346
 
 
 
347
    {
 
 
348
        int fake_timer = 1024 - angle;
 
 
349
 
 
 
350
        fake_timer <<= 5;
 
 
351
 
 
 
352
        if (fake_timer == 65536)
 
 
353
            fake_timer = 65535;
 
 
354
 
 
 
355
        fake_timer = 65536 - fake_timer;
 
 
356
 
 
 
357
        assert(fake_timer >= 0);
 
 
358
        assert(fake_timer < 65536);
 
 
359
 
 
 
360
        if (agunStatusPointer->gun_tilt->timer != fake_timer)
 
 
361
            agunStatusPointer->WhirrSoundOn = 1;
 
 
362
 
 
 
363
        agunStatusPointer->gun_tilt->timer = fake_timer;
 
 
364
    }
 
 
365
}
 
 
366
 
 
 
367
static int Autogun_TargetFilter(STRATEGYBLOCK *candidate)
 
 
368
{
 
 
369
    // Reject NULLs and far targets.
 
 
370
    if (candidate->DisplayBlock == NULL)
 
 
371
        return 0;
 
 
372
 
 
 
373
    // Shoot pretty much anything.
 
 
374
    switch (candidate->type)
 
 
375
    {
 
 
376
        case I_BehaviourAlien:
 
 
377
        case I_BehaviourPredator:
 
 
378
        case I_BehaviourFaceHugger:
 
 
379
        case I_BehaviourAlienPlayer:
 
 
380
        case I_BehaviourPredatorPlayer:
 
 
381
        case I_BehaviourXenoborg:
 
 
382
        case I_BehaviourQueenAlien:
 
 
383
            return 1;
 
 
384
        case I_BehaviourDummy:
 
 
385
        {
 
 
386
            DUMMY_STATUS_BLOCK *dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->dataptr);    
 
 
387
            assert(dummyStatusPointer);
 
 
388
            switch (dummyStatusPointer->PlayerType)
 
 
389
            {
 
 
390
                case I_Alien:
 
 
391
                case I_Predator:
 
 
392
                    return 1;
 
 
393
                default:
 
 
394
                    return 0;
 
 
395
            }
 
 
396
        }
 
 
397
        default:
 
 
398
        return 0;
 
 
399
    }
 
 
400
}
 
 
401
 
 
 
402
static STRATEGYBLOCK *Autogun_GetNewTarget(STRATEGYBLOCK *sbPtr)
 
 
403
{
 
 
404
    int neardist = ONE_FIXED;
 
 
405
    int a;
 
 
406
    STRATEGYBLOCK *nearest = NULL;
 
 
407
 
 
 
408
    for (a=0; a < NumActiveStBlocks; a++)
 
 
409
    {
 
 
410
        STRATEGYBLOCK *candidate = ActiveStBlockList[a];
 
 
411
 
 
 
412
        if ((candidate != sbPtr) && candidate->DynPtr && Autogun_TargetFilter(candidate))
 
 
413
        {
 
 
414
            VECTORCH offset;
 
 
415
 
 
 
416
            offset.vx = (&sbPtr->DynPtr->Position)->vx - candidate->DynPtr->Position.vx;
 
 
417
            offset.vy = (&sbPtr->DynPtr->Position)->vy - candidate->DynPtr->Position.vy;
 
 
418
            offset.vz = (&sbPtr->DynPtr->Position)->vz - candidate->DynPtr->Position.vz;
 
 
419
 
 
 
420
            int dist = Approximate3dMagnitude(&offset);
 
 
421
 
 
 
422
            if ((dist < neardist) && NPCCanSeeTarget(sbPtr, candidate) && !NPC_IsDead(candidate))
 
 
423
            {
 
 
424
                MODULE *dmod = ModuleFromPosition(&sbPtr->DynPtr->Position, PlayerStatus.sbptr->containingModule);
 
 
425
                assert(dmod);
 
 
426
 
 
 
427
                if (IsModuleVisibleFromModule(dmod, candidate->containingModule))
 
 
428
                    nearest = candidate;
 
 
429
            }
 
 
430
        }
 
 
431
    }
 
 
432
 
 
 
433
return(nearest);
 
 
434
}
 
 
435
 
 
 
436
int AGunSight_FrustrumReject(VECTORCH *localOffset)
 
 
437
{
 
 
438
    VECTORCH fixed_offset = *localOffset;
 
 
439
 
 
 
440
//    printf("Local Offset: %d %d %d\n",localOffset->vx,localOffset->vy,localOffset->vz);
 
 
441
 
 
 
442
    fixed_offset.vy -= 300; /* ish */
 
 
443
 
 
 
444
    return (((fixed_offset.vz < 0) && ( ((fixed_offset.vy) < (-fixed_offset.vz)) && (fixed_offset.vy >= 0)))
 
 
445
         ||((fixed_offset.vy < 0) && ((-fixed_offset.vy) < (-fixed_offset.vz))));
 
 
446
    /*
 
 
447
        return 1; // 180 horizontal, 90 vertical.
 
 
448
    else
 
 
449
        return 0;
 
 
450
    */
 
 
451
}
 
 
452
 
 
 
453
void AGunMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate)
 
 
454
{
 
 
455
    assert(sbPtr);
 
 
456
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
457
    assert(agunStatusPointer);
 
 
458
 
 
 
459
    /* Let's wave the gun around, half full tracking. */
 
 
460
    if (agunStatusPointer->gunpandir)
 
 
461
    {
 
 
462
        agunStatusPointer->Gun_Pan += (NormalFrameTime >> rate);
 
 
463
 
 
 
464
        if (agunStatusPointer->Gun_Pan > (SGUN_PAN_GIMBALL << 3))
 
 
465
        {
 
 
466
            agunStatusPointer->Gun_Pan = (SGUN_PAN_GIMBALL << 3);
 
 
467
            agunStatusPointer->gunpandir = 0;
 
 
468
        }
 
 
469
    }
 
 
470
    else
 
 
471
    {
 
 
472
        agunStatusPointer->Gun_Pan -= (NormalFrameTime >> rate);
 
 
473
 
 
 
474
        if (agunStatusPointer->Gun_Pan < -(SGUN_PAN_GIMBALL << 3))
 
 
475
        {
 
 
476
            agunStatusPointer->Gun_Pan = -(SGUN_PAN_GIMBALL << 3);
 
 
477
            agunStatusPointer->gunpandir = 1;
 
 
478
        }
 
 
479
    }
 
 
480
 
 
 
481
    if (agunStatusPointer->gun_pan)
 
 
482
        agunStatusPointer->gun_pan->Active = 1;
 
 
483
 
 
 
484
    /* And centre tilt. */
 
 
485
    if (agunStatusPointer->Gun_Tilt < 0)
 
 
486
    {
 
 
487
        agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>rate);
 
 
488
 
 
 
489
        if (agunStatusPointer->Gun_Tilt > (SGUN_PAN_GIMBALL << 3))
 
 
490
        {
 
 
491
            agunStatusPointer->Gun_Tilt = (SGUN_PAN_GIMBALL << 3);
 
 
492
        }
 
 
493
        else if (agunStatusPointer->Gun_Tilt > 0)
 
 
494
        {
 
 
495
            agunStatusPointer->Gun_Tilt = 0;
 
 
496
        }
 
 
497
 
 
 
498
    }
 
 
499
    else if (agunStatusPointer->Gun_Tilt > 0)
 
 
500
    {
 
 
501
        agunStatusPointer->Gun_Tilt -= (NormalFrameTime >> rate);
 
 
502
 
 
 
503
        if (agunStatusPointer->Gun_Tilt < -(SGUN_PAN_GIMBALL << 3))
 
 
504
        {
 
 
505
            agunStatusPointer->Gun_Tilt = -(SGUN_PAN_GIMBALL << 3);
 
 
506
 
 
 
507
        }
 
 
508
        else if (agunStatusPointer->Gun_Tilt < 0)
 
 
509
        {
 
 
510
            agunStatusPointer->Gun_Tilt = 0;
 
 
511
        }
 
 
512
    }
 
 
513
 
 
 
514
    if (agunStatusPointer->gun_tilt)
 
 
515
        agunStatusPointer->gun_tilt->Active = 1;
 
 
516
}
 
 
517
 
 
 
518
void AGunMovement_Centre(STRATEGYBLOCK *sbPtr,int rate)
 
 
519
{
 
 
520
    assert(sbPtr);
 
 
521
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
522
    assert(agunStatusPointer);
 
 
523
 
 
 
524
    /* Let's centre pan... */
 
 
525
    if (agunStatusPointer->Gun_Pan < 0)
 
 
526
    {
 
 
527
        agunStatusPointer->Gun_Pan += (NormalFrameTime >> rate);
 
 
528
 
 
 
529
        if (agunStatusPointer->Gun_Pan > (SGUN_PAN_GIMBALL << 3))
 
 
530
        {
 
 
531
            agunStatusPointer->Gun_Pan = (SGUN_PAN_GIMBALL << 3);
 
 
532
 
 
 
533
        }
 
 
534
        else if (agunStatusPointer->Gun_Pan > 0)
 
 
535
        {
 
 
536
            agunStatusPointer->Gun_Pan = 0;
 
 
537
        }
 
 
538
    }
 
 
539
    else if (agunStatusPointer->Gun_Pan > 0)
 
 
540
    {
 
 
541
        agunStatusPointer->Gun_Pan -= (NormalFrameTime >> rate);
 
 
542
 
 
 
543
        if (agunStatusPointer->Gun_Pan < -(SGUN_PAN_GIMBALL << 3))
 
 
544
        {
 
 
545
            agunStatusPointer->Gun_Pan = -(SGUN_PAN_GIMBALL << 3);
 
 
546
        }
 
 
547
        else if (agunStatusPointer->Gun_Pan < 0)
 
 
548
        {
 
 
549
            agunStatusPointer->Gun_Pan = 0;
 
 
550
        }
 
 
551
    }
 
 
552
 
 
 
553
    if (agunStatusPointer->gun_pan)
 
 
554
        agunStatusPointer->gun_pan->Active = 1;
 
 
555
 
 
 
556
    /* And centre tilt. */
 
 
557
    if (agunStatusPointer->Gun_Tilt < 0)
 
 
558
    {
 
 
559
        agunStatusPointer->Gun_Tilt += (NormalFrameTime >> rate);
 
 
560
 
 
 
561
        if (agunStatusPointer->Gun_Tilt > (SGUN_PAN_GIMBALL << 3))
 
 
562
        {
 
 
563
            agunStatusPointer->Gun_Tilt = (SGUN_PAN_GIMBALL << 3);
 
 
564
 
 
 
565
        }
 
 
566
        else if (agunStatusPointer->Gun_Tilt > 0)
 
 
567
        {
 
 
568
            agunStatusPointer->Gun_Tilt = 0;
 
 
569
        }
 
 
570
    }
 
 
571
    else if (agunStatusPointer->Gun_Tilt > 0)
 
 
572
    {
 
 
573
        agunStatusPointer->Gun_Tilt -= (NormalFrameTime >> rate);
 
 
574
 
 
 
575
        if (agunStatusPointer->Gun_Tilt < -(SGUN_PAN_GIMBALL << 3))
 
 
576
        {
 
 
577
            agunStatusPointer->Gun_Tilt = -(SGUN_PAN_GIMBALL << 3);
 
 
578
 
 
 
579
        }
 
 
580
        else if (agunStatusPointer->Gun_Tilt < 0)
 
 
581
        {
 
 
582
            agunStatusPointer->Gun_Tilt = 0;
 
 
583
        }
 
 
584
    }
 
 
585
 
 
 
586
    if (agunStatusPointer->gun_tilt)
 
 
587
        agunStatusPointer->gun_tilt->Active = 1;
 
 
588
}
 
 
589
 
 
 
590
void AGun_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) 
 
 
591
{
 
 
592
    VECTORCH targetPos;
 
 
593
 
 
 
594
    assert(sbPtr);
 
 
595
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
596
    assert(agunStatusPointer);
 
 
597
 
 
 
598
    /* First, extract relative angle. */
 
 
599
 
 
 
600
    MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
601
    TransposeMatrixCH(&WtoL);
 
 
602
    targetPos = agunStatusPointer->targetTrackPos;
 
 
603
    targetPos.vx -= pivotPoint->vx;
 
 
604
    targetPos.vy -= pivotPoint->vy;
 
 
605
    targetPos.vz -= pivotPoint->vz;
 
 
606
    RotateVector(&targetPos,&WtoL);
 
 
607
 
 
 
608
    /* Now... */
 
 
609
    {
 
 
610
        int offsetx = targetPos.vx;
 
 
611
        int offsety = targetPos.vz;
 
 
612
        int offseta = -(targetPos.vy);
 
 
613
 
 
 
614
        while( (offsetx > (ONE_FIXED>>2))
 
 
615
            ||(offsety > (ONE_FIXED>>2))
 
 
616
            ||(offseta > (ONE_FIXED>>2))
 
 
617
            ||(offsetx < -(ONE_FIXED>>2))
 
 
618
            ||(offsety < -(ONE_FIXED>>2))
 
 
619
            ||(offseta < -(ONE_FIXED>>2)))
 
 
620
        {
 
 
621
            offsetx >>= 1;
 
 
622
            offsety >>= 1;
 
 
623
            offseta >>= 1;
 
 
624
        }
 
 
625
 
 
 
626
        int offsetz = SqRoot32((offsetx*offsetx)+(offsety*offsety));
 
 
627
 
 
 
628
        if (angley)
 
 
629
        {
 
 
630
            *angley = ArcTan(offseta, offsetz);
 
 
631
 
 
 
632
            if (*angley >= 3072)
 
 
633
                *angley -= 4096;
 
 
634
 
 
 
635
            if (*angley >= 2048)
 
 
636
                *angley = (*angley) - 3072;
 
 
637
 
 
 
638
            if (*angley > 1024)
 
 
639
                *angley = 2048 - *angley;
 
 
640
        }
 
 
641
 
 
 
642
        if (anglex)
 
 
643
        {
 
 
644
            *anglex = ArcTan(offsetx, offsety);
 
 
645
 
 
 
646
            if (*anglex >= 3072)
 
 
647
                *anglex -= 4096;
 
 
648
 
 
 
649
            if (*anglex >= 2048)
 
 
650
                *anglex = *anglex - 4096;
 
 
651
        }
 
 
652
    }
 
 
653
}
 
 
654
 
 
 
655
int AGunMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley)
 
 
656
{
 
 
657
    int real_anglex = in_anglex;
 
 
658
    int angley = in_angley;
 
 
659
    int online = 0;
 
 
660
 
 
 
661
    assert(sbPtr);
 
 
662
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
663
    assert(agunStatusPointer);
 
 
664
 
 
 
665
    /* Now fix multiples. */
 
 
666
    while ((real_anglex > 4095) || (real_anglex < 0))
 
 
667
    {
 
 
668
        if (real_anglex <0)
 
 
669
        {
 
 
670
            real_anglex += 4096;
 
 
671
        }
 
 
672
        else if (real_anglex > 4095)
 
 
673
        {
 
 
674
            real_anglex -= 4096;
 
 
675
        }
 
 
676
    }
 
 
677
 
 
 
678
    if (real_anglex >= 3072)
 
 
679
        real_anglex -= 4096;
 
 
680
 
 
 
681
    if (real_anglex >= 2048)
 
 
682
        real_anglex = real_anglex - 3072;
 
 
683
 
 
 
684
    if (real_anglex > 1024)
 
 
685
        real_anglex = 2048 - real_anglex;
 
 
686
 
 
 
687
    if (angley >= 3072)
 
 
688
        angley -= 4096;
 
 
689
 
 
 
690
    if (angley >= 2048)
 
 
691
        angley = angley-3072;
 
 
692
 
 
 
693
    if (angley > 1024)
 
 
694
        angley = 2048-angley;
 
 
695
 
 
 
696
    real_anglex <<= 4;
 
 
697
    angley <<= 4;
 
 
698
 
 
 
699
    if (agunStatusPointer->Gun_Pan<real_anglex)
 
 
700
    {
 
 
701
        agunStatusPointer->Gun_Pan += (NormalFrameTime >> rate);
 
 
702
 
 
 
703
        if (agunStatusPointer->Gun_Pan > (SGUN_PAN_GIMBALL << 4))
 
 
704
        {
 
 
705
            agunStatusPointer->Gun_Pan = (SGUN_PAN_GIMBALL << 4);
 
 
706
        }
 
 
707
        else if (agunStatusPointer->Gun_Pan > real_anglex)
 
 
708
        {
 
 
709
            agunStatusPointer->Gun_Pan = real_anglex;
 
 
710
            online++;
 
 
711
        }
 
 
712
    }
 
 
713
    else if (agunStatusPointer->Gun_Pan > real_anglex)
 
 
714
    {
 
 
715
        agunStatusPointer->Gun_Pan -= (NormalFrameTime >> rate);
 
 
716
 
 
 
717
        if (agunStatusPointer->Gun_Pan < -(SGUN_PAN_GIMBALL << 4))
 
 
718
        {
 
 
719
            agunStatusPointer->Gun_Pan = -(SGUN_PAN_GIMBALL << 4);
 
 
720
        }
 
 
721
        else if (agunStatusPointer->Gun_Pan < real_anglex)
 
 
722
        {
 
 
723
            agunStatusPointer->Gun_Pan = real_anglex;
 
 
724
            online++;
 
 
725
        }
 
 
726
    }
 
 
727
    else
 
 
728
    {
 
 
729
        online++;
 
 
730
    }
 
 
731
 
 
 
732
    if (agunStatusPointer->gun_pan)
 
 
733
        agunStatusPointer->gun_pan->Active = 1;
 
 
734
 
 
 
735
    /* Now y. */
 
 
736
    angley = -angley;
 
 
737
    /* Oops. */
 
 
738
 
 
 
739
    /* Note that Sentryguns now only track vertically HALF their full traverse. */
 
 
740
    /* Those shifts used to be <<4. */
 
 
741
 
 
 
742
    if (agunStatusPointer->Gun_Tilt < angley)
 
 
743
    {
 
 
744
        agunStatusPointer->Gun_Tilt += (NormalFrameTime >> rate);
 
 
745
 
 
 
746
        if (agunStatusPointer->Gun_Tilt > (SGUN_PITCH_GIMBALL << 3))
 
 
747
        {
 
 
748
            agunStatusPointer->Gun_Tilt = (SGUN_PITCH_GIMBALL << 3);
 
 
749
        }
 
 
750
        else if (agunStatusPointer->Gun_Tilt > angley)
 
 
751
        {
 
 
752
            agunStatusPointer->Gun_Tilt = angley;
 
 
753
            online++;
 
 
754
        }
 
 
755
    }
 
 
756
    else if (agunStatusPointer->Gun_Tilt > angley)
 
 
757
    {
 
 
758
        agunStatusPointer->Gun_Tilt -= (NormalFrameTime >> rate);
 
 
759
 
 
 
760
        if (agunStatusPointer->Gun_Tilt < -(SGUN_PITCH_GIMBALL << 3))
 
 
761
        {
 
 
762
            agunStatusPointer->Gun_Tilt = -(SGUN_PITCH_GIMBALL << 3);
 
 
763
        }
 
 
764
        else if (agunStatusPointer->Gun_Tilt < angley)
 
 
765
        {
 
 
766
            agunStatusPointer->Gun_Tilt = angley;
 
 
767
            online++;
 
 
768
        }
 
 
769
    }
 
 
770
    else
 
 
771
    {
 
 
772
        online++;
 
 
773
    }
 
 
774
 
 
 
775
    if (agunStatusPointer->gun_tilt)
 
 
776
        agunStatusPointer->gun_tilt->Active = 1;
 
 
777
 
 
 
778
return (online > 1);
 
 
779
}
 
 
780
 
 
 
781
void Execute_AGun_Target(STRATEGYBLOCK *sbPtr) 
 
 
782
{
 
 
783
    int anglex,angley;
 
 
784
 
 
 
785
    assert(sbPtr);
 
 
786
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
787
    assert(agunStatusPointer);
 
 
788
 
 
 
789
    {
 
 
790
        SECTION_DATA *gun_section = GetThisSectionData(agunStatusPointer->HModelController.section_data,"gun");
 
 
791
        assert(gun_section);
 
 
792
 
 
 
793
        AGun_GetRelativeAngles(sbPtr,&anglex,&angley,&gun_section->World_Offset);
 
 
794
    }
 
 
795
 
 
 
796
    agunStatusPointer->OnTarget_LastFrame = agunStatusPointer->OnTarget;
 
 
797
 
 
 
798
    if (AGunMovement_TrackToAngles(sbPtr,2,anglex,angley))
 
 
799
    {
 
 
800
        /* Pointing at target! */
 
 
801
        agunStatusPointer->OnTarget = 1;
 
 
802
 
 
 
803
        if (!agunStatusPointer->OnTarget_LastFrame)
 
 
804
        {
 
 
805
            /* Newly aquired! */
 
 
806
            //Sound_Play(SID_SENTRYGUN_LOCK,"d",&sbPtr->DynPtr->Position);
 
 
807
            agunStatusPointer->Drama = SENTRYGUN_DRAMA;
 
 
808
        }
 
 
809
 
 
 
810
        if (agunStatusPointer->Drama <= 0)
 
 
811
        {
 
 
812
            if (!agunStatusPointer->Firing)
 
 
813
            {
 
 
814
                /* Renew firing. */
 
 
815
                agunStatusPointer->Firing = ONE_FIXED >> 1;
 
 
816
            }
 
 
817
        }
 
 
818
        else
 
 
819
        {
 
 
820
            agunStatusPointer->Firing = 0;
 
 
821
            agunStatusPointer->Drama -= NormalFrameTime;
 
 
822
 
 
 
823
            if (agunStatusPointer->Drama < 0)
 
 
824
                agunStatusPointer->Drama = 0;
 
 
825
        }
 
 
826
    }
 
 
827
    else
 
 
828
    {
 
 
829
        agunStatusPointer->OnTarget = 0;
 
 
830
    }
 
 
831
}
 
 
832
 
 
 
833
static void AGun_MaintainGun(STRATEGYBLOCK *sbPtr)
 
 
834
{
 
 
835
    VECTORCH alpha;
 
 
836
    VECTORCH beta;
 
 
837
 
 
 
838
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
839
 
 
 
840
    SECTION_DATA *dum = GetThisSectionData(agunStatusPointer->HModelController.section_data, "flash dummy");
 
 
841
 
 
 
842
    if (!agunStatusPointer->Firing || (dum == NULL) || !sbPtr->DisplayBlock)
 
 
843
    {
 
 
844
        DestroyActiveObject(&agunStatusPointer->GunFlash);
 
 
845
        return;
 
 
846
    }
 
 
847
 
 
 
848
    if (sentrygun_reload_ammo)
 
 
849
    {
 
 
850
        agunStatusPointer->ammo = 500;
 
 
851
        sentrygun_reload_ammo = 0;
 
 
852
    }
 
 
853
 
 
 
854
    /* Okay, must be firing.  Did we get anyone? */
 
 
855
 
 
 
856
    int volley_section = AGUN_ROF * NormalFrameTime;
 
 
857
 
 
 
858
    agunStatusPointer->volleyFired += volley_section;
 
 
859
 
 
 
860
    if (agunStatusPointer->volleyFired > (AGUN_VOLLEYSIZE << ONE_FIXED_SHIFT))
 
 
861
        agunStatusPointer->volleyFired = (AGUN_VOLLEYSIZE << ONE_FIXED_SHIFT);
 
 
862
 
 
 
863
    int totalrounds = agunStatusPointer->volleyFired >> ONE_FIXED_SHIFT;
 
 
864
    assert(totalrounds >= agunStatusPointer->roundsFired);
 
 
865
    int multiple = totalrounds-agunStatusPointer->roundsFired;
 
 
866
 
 
 
867
    if (multiple && !agunStatusPointer->ammo) 
 
 
868
    {
 
 
869
        /* Click ineffectually. */
 
 
870
        if (agunStatusPointer->soundHandle != SOUND_NOACTIVEINDEX) 
 
 
871
        {
 
 
872
            if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex != SID_NOAMMO)
 
 
873
                Sound_Stop(agunStatusPointer->soundHandle);
 
 
874
        }
 
 
875
        else
 
 
876
        //if (agunStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) 
 
 
877
        {
 
 
878
            Sound_Play(SID_NOAMMO, "del", &sbPtr->DynPtr->Position, &agunStatusPointer->soundHandle);
 
 
879
        }
 
 
880
 
 
 
881
        DestroyActiveObject(&agunStatusPointer->GunFlash);
 
 
882
    return;
 
 
883
    }
 
 
884
 
 
 
885
    if (!sentrygun_infinity_ammo)
 
 
886
    {
 
 
887
        if (multiple > agunStatusPointer->ammo)
 
 
888
        {
 
 
889
            multiple = agunStatusPointer->ammo;
 
 
890
            agunStatusPointer->ammo = 0;
 
 
891
        }
 
 
892
        else
 
 
893
            agunStatusPointer->ammo -= multiple;
 
 
894
    }
 
 
895
 
 
 
896
    agunStatusPointer->roundsFired += multiple;
 
 
897
 
 
 
898
    /* End of volley? */
 
 
899
    if (agunStatusPointer->volleyFired == (AGUN_VOLLEYSIZE << ONE_FIXED_SHIFT))
 
 
900
    {
 
 
901
        agunStatusPointer->volleyFired= 0;
 
 
902
        agunStatusPointer->roundsFired = 0;
 
 
903
        agunStatusPointer->Target= NULL;
 
 
904
    }
 
 
905
 
 
 
906
    while (multiple)
 
 
907
    {
 
 
908
        /* Set up LOS. */
 
 
909
        //get a random rotation , for error in firing direction
 
 
910
        MATRIXCH rotate;
 
 
911
 
 
 
912
        multiple--;
 
 
913
 
 
 
914
        {
 
 
915
            EULER e;
 
 
916
            //convert angle from degrees to the engine units
 
 
917
            int spread = (SentrygunSpread* 4096) / 360;
 
 
918
            e.EulerX = (MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360;
 
 
919
            e.EulerY =(MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360;
 
 
920
            e.EulerZ = 0;
 
 
921
            CreateEulerMatrix(&e,&rotate);
 
 
922
        }
 
 
923
 
 
 
924
        alpha = dum->World_Offset;
 
 
925
        beta.vx = dum->SecMat.mat31;
 
 
926
        beta.vy = dum->SecMat.mat32;
 
 
927
        beta.vz = dum->SecMat.mat33;
 
 
928
 
 
 
929
        RotateVector(&beta, &rotate);
 
 
930
 
 
 
931
        FindPolygonInLineOfSight(&beta, &alpha, 0, sbPtr->DisplayBlock);
 
 
932
 
 
 
933
        if (LOS_ObjectHitPtr)
 
 
934
        {
 
 
935
            #if DEBUG
 
 
936
            if (LOS_HModel_Section && LOS_ObjectHitPtr->ObStrategyBlock && LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock)
 
 
937
            {
 
 
938
                assert(LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->HModelControlBlock == LOS_HModel_Section->my_controller);
 
 
939
            }
 
 
940
            #endif
 
 
941
 
 
 
942
            /*Don't allow the sentrygun to destroy 'special' inanimate objects.  Doing so ruins some puzzles*/
 
 
943
 
 
 
944
            if (LOS_ObjectHitPtr->Module)
 
 
945
            {
 
 
946
                /* bad idea to put bullethole on a morphing object */
 
 
947
                if(!LOS_ObjectHitPtr->ObMorphCtrl)
 
 
948
                    MakeDecal(DECAL_BULLETHOLE, &LOS_ObjectNormal, &LOS_Point, LOS_ObjectHitPtr->Module->m_index);
 
 
949
 
 
 
950
                /* cause a ricochet 1 in 8 times */
 
 
951
                if ((FastRandom() & 65535) < 8192)
 
 
952
                    MakeImpactSparks(&beta, &LOS_ObjectNormal, &LOS_Point);
 
 
953
            }
 
 
954
            else if(LOS_ObjectHitPtr->ObStrategyBlock)
 
 
955
            {
 
 
956
                STRATEGYBLOCK* hit_sbptr = LOS_ObjectHitPtr->ObStrategyBlock;
 
 
957
                VECTORCH incoming, *invec = NULL;
 
 
958
 
 
 
959
                switch(hit_sbptr->type)
 
 
960
                {
 
 
961
                    case I_BehaviourInanimateObject:
 
 
962
                    {
 
 
963
                        INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)hit_sbptr->dataptr;
 
 
964
 
 
 
965
                        if(objectstatusptr->event_target)
 
 
966
                            continue; /*This object has best be left*/
 
 
967
                    }
 
 
968
                    break;
 
 
969
                    case I_BehaviourQueenAlien:
 
 
970
                    {
 
 
971
                        if ((FastRandom() & 65535) < 8192)
 
 
972
                            MakeImpactSparks(&beta, &LOS_ObjectNormal, &LOS_Point);
 
 
973
                    }
 
 
974
                    default:
 
 
975
                    break;
 
 
976
                }
 
 
977
 
 
 
978
                if (hit_sbptr->DynPtr)
 
 
979
                {
 
 
980
                    MATRIXCH WtoLMat = hit_sbptr->DynPtr->OrientMat;
 
 
981
                    /* Consider incoming hit direction. */
 
 
982
                    TransposeMatrixCH(&WtoLMat);
 
 
983
                    RotateAndCopyVector(&beta, &incoming, &WtoLMat);
 
 
984
                    invec = &incoming;
 
 
985
                }
 
 
986
 
 
 
987
                if (LOS_HModel_Section && hit_sbptr->DisplayBlock && hit_sbptr->DisplayBlock->HModelControlBlock)
 
 
988
                {
 
 
989
                    AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point, LOS_HModel_Section);
 
 
990
                    CauseDamageToHModel(hit_sbptr->DisplayBlock->HModelControlBlock, hit_sbptr, &TemplateAmmo[AMMO_AUTOGUN].MaxDamage, ONE_FIXED,
LOS_HModel_Section, invec, &LOS_Point, 0);
 
 
991
                }
 
 
992
                else
 
 
993
                {
 
 
994
                    CauseDamageToObject(hit_sbptr, &TemplateAmmo[AMMO_AUTOGUN].MaxDamage, ONE_FIXED, invec);
 
 
995
                }
 
 
996
 
 
 
997
                if (hit_sbptr->DynPtr)
 
 
998
                {
 
 
999
                    DYNAMICSBLOCK *dynPtr = hit_sbptr->DynPtr;
 
 
1000
                    EULER rotation;
 
 
1001
                    int magnitudeOfForce = (5000 * TotalKineticDamage(&TemplateAmmo[AMMO_AUTOGUN].MaxDamage)) / dynPtr->Mass;
 
 
1002
                    /* okay, not too sure yet what this should do */
 
 
1003
                    dynPtr->LinImpulse.vx += MUL_FIXED(beta.vx, magnitudeOfForce);
 
 
1004
                    dynPtr->LinImpulse.vy += MUL_FIXED(beta.vy, magnitudeOfForce);
 
 
1005
                    dynPtr->LinImpulse.vz += MUL_FIXED(beta.vz, magnitudeOfForce);
 
 
1006
                }
 
 
1007
            }
 
 
1008
        }
 
 
1009
    }
 
 
1010
 
 
 
1011
    if (agunStatusPointer->GunFlash == NULL)
 
 
1012
    {
 
 
1013
        DISPLAYBLOCK *dPtr = CreateSFXObject(SFX_MUZZLE_FLASH_SMARTGUN);
 
 
1014
 
 
 
1015
        if(dPtr)
 
 
1016
        {
 
 
1017
            dPtr->ObWorld = dum->World_Offset;
 
 
1018
            dPtr->ObMat = dum->SecMat;
 
 
1019
            AddLightingEffectToObject(dPtr, LFX_MUZZLEFLASH);
 
 
1020
            dPtr->SfxPtr->EffectDrawnLastFrame = 0;
 
 
1021
            agunStatusPointer->GunFlash = dPtr;
 
 
1022
        }
 
 
1023
    }
 
 
1024
    else
 
 
1025
    {
 
 
1026
 
 
 
1027
        agunStatusPointer->GunFlash->ObWorld = dum->World_Offset;
 
 
1028
        agunStatusPointer->GunFlash->ObMat = dum->SecMat;
 
 
1029
        AddLightingEffectToObject(agunStatusPointer->GunFlash, LFX_MUZZLEFLASH);
 
 
1030
    }
 
 
1031
 
 
 
1032
    if (agunStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
1033
    {
 
 
1034
        SentryFire_SoundData.position = sbPtr->DynPtr->Position;
 
 
1035
        //Sound_Play(SID_SENTRY_GUN, "nel", &SentryFire_SoundData, &agunStatusPointer->soundHandle);
 
 
1036
        Sound_Play(SID_SENTRY_GUN, "ed", &agunStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
1037
    }
 
 
1038
    else
 
 
1039
    {
 
 
1040
        if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex != SID_SENTRY_GUN)
 
 
1041
            Sound_Stop(agunStatusPointer->soundHandle);
 
 
1042
    }
 
 
1043
}
 
 
1044
 
 
 
1045
void Execute_AGun_Dying(STRATEGYBLOCK *sbPtr)
 
 
1046
{
 
 
1047
    assert(sbPtr);
 
 
1048
    AUTOGUN_STATUS_BLOCK *agunStatusPointer    = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
1049
    assert(agunStatusPointer);
 
 
1050
 
 
 
1051
    /* Droop the gun. */
 
 
1052
    if (agunStatusPointer->Gun_Tilt < 8192)
 
 
1053
    {
 
 
1054
        agunStatusPointer->Gun_Tilt += NormalFrameTime >> 3;
 
 
1055
 
 
 
1056
        if (agunStatusPointer->Gun_Tilt > (SGUN_PITCH_GIMBALL << 3))
 
 
1057
        {
 
 
1058
            agunStatusPointer->Gun_Tilt = SGUN_PITCH_GIMBALL << 3;
 
 
1059
        }
 
 
1060
        else if (agunStatusPointer->Gun_Tilt > 8192)
 
 
1061
        {
 
 
1062
            agunStatusPointer->Gun_Tilt = 8192;
 
 
1063
        }
 
 
1064
    }
 
 
1065
 
 
 
1066
    {
 
 
1067
        /* do we have a displayblock? */
 
 
1068
        DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock;
 
 
1069
 
 
 
1070
        if (dispPtr)
 
 
1071
        {
 
 
1072
            dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
 
 
1073
            dispPtr->ObFlags2 = agunStatusPointer->stateTimer/2;
 
 
1074
 
 
 
1075
            if (dispPtr->ObFlags2 < ONE_FIXED)
 
 
1076
                agunStatusPointer->HModelController.DisableBleeding = 1;
 
 
1077
        }
 
 
1078
    }
 
 
1079
 
 
 
1080
    agunStatusPointer->stateTimer -= NormalFrameTime;
 
 
1081
}
 
 
1082
 
 
 
1083
void AutoGunBehaveFun(STRATEGYBLOCK* sbPtr)
 
 
1084
{
 
 
1085
    assert(sbPtr);
 
 
1086
    AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1087
    assert(agunStatusPointer);
 
 
1088
 
 
 
1089
    /* test if we've got a containing module: if we haven't, do nothing.
 
 
1090
    This is important as the object could have been marked for deletion by the visibility 
 
 
1091
    management system...*/
 
 
1092
 
 
 
1093
    if(!sbPtr->containingModule)
 
 
1094
    {
 
 
1095
        sbPtr->please_destroy_me = 1; /* just to make sure */
 
 
1096
    return;
 
 
1097
    }
 
 
1098
 
 
 
1099
    #if DEBUG
 
 
1100
    if(sbPtr->DisplayBlock)
 
 
1101
    {
 
 
1102
        assert(ModuleCurrVisArray[sbPtr->containingModule->m_index]);                        
 
 
1103
    }
 
 
1104
    #endif
 
 
1105
 
 
 
1106
    Autogun_VerifyDeltaControllers(sbPtr);
 
 
1107
 
 
 
1108
    if (agunStatusPointer->Target)
 
 
1109
    {
 
 
1110
        if (NULL == agunStatusPointer->Target->DisplayBlock)
 
 
1111
        {
 
 
1112
            agunStatusPointer->Target = Autogun_GetNewTarget(sbPtr);
 
 
1113
 
 
 
1114
            if (agunStatusPointer->Target)
 
 
1115
            {
 
 
1116
                COPY_NAME(agunStatusPointer->Target_SBname, agunStatusPointer->Target->SBname);
 
 
1117
                GetTargetingPointOfObject_Far(agunStatusPointer->Target, &agunStatusPointer->targetTrackPos);
 
 
1118
            }
 
 
1119
            else
 
 
1120
            {
 
 
1121
                agunStatusPointer->targetTrackPos.vx = agunStatusPointer->targetTrackPos.vy = agunStatusPointer->targetTrackPos.vz = 0;
 
 
1122
            }
 
 
1123
        }
 
 
1124
        else
 
 
1125
        {
 
 
1126
            /* We have a valid target that we can't see? */
 
 
1127
            if (NAME_ISEQUAL(agunStatusPointer->Target->SBname, agunStatusPointer->Target_SBname)
 
 
1128
            && !NPC_IsDead(agunStatusPointer->Target) && NPCCanSeeTarget(sbPtr, agunStatusPointer->Target))
 
 
1129
            {
 
 
1130
                GetTargetingPointOfObject_Far(agunStatusPointer->Target, &agunStatusPointer->targetTrackPos);
 
 
1131
            }
 
 
1132
            else
 
 
1133
            {
 
 
1134
                agunStatusPointer->Target = NULL;
 
 
1135
                agunStatusPointer->targetTrackPos.vx = agunStatusPointer->targetTrackPos.vy = agunStatusPointer->targetTrackPos.vz = 0;
 
 
1136
            }
 
 
1137
        }
 
 
1138
    }
 
 
1139
    else
 
 
1140
    {
 
 
1141
        if (sbPtr->DisplayBlock)
 
 
1142
        {
 
 
1143
            agunStatusPointer->Target = Autogun_GetNewTarget(sbPtr);
 
 
1144
 
 
 
1145
            if (agunStatusPointer->Target)
 
 
1146
            {
 
 
1147
                COPY_NAME(agunStatusPointer->Target_SBname, agunStatusPointer->Target->SBname);
 
 
1148
                GetTargetingPointOfObject_Far(agunStatusPointer->Target, &agunStatusPointer->targetTrackPos);
 
 
1149
            }
 
 
1150
            else
 
 
1151
            {
 
 
1152
                agunStatusPointer->targetTrackPos.vx = agunStatusPointer->targetTrackPos.vy = agunStatusPointer->targetTrackPos.vz = 0;
 
 
1153
            }
 
 
1154
        }
 
 
1155
    }
 
 
1156
 
 
 
1157
    if (agunStatusPointer->Firing)
 
 
1158
    {
 
 
1159
        agunStatusPointer->Firing -= NormalFrameTime;
 
 
1160
 
 
 
1161
        if (agunStatusPointer->Firing < 0)
 
 
1162
            agunStatusPointer->Firing = 0;
 
 
1163
    }
 
 
1164
 
 
 
1165
    /* Unset incident flag. */
 
 
1166
    agunStatusPointer->incidentFlag = 0;
 
 
1167
    agunStatusPointer->incidentTimer -= NormalFrameTime;
 
 
1168
 
 
 
1169
    if (agunStatusPointer->incidentTimer < 0)
 
 
1170
    {
 
 
1171
        agunStatusPointer->incidentFlag = 1;
 
 
1172
        agunStatusPointer->incidentTimer = 32767+(FastRandom()&65535);
 
 
1173
    }
 
 
1174
 
 
 
1175
    /* Now, switch by state. */
 
 
1176
    switch (agunStatusPointer->behaviourState)
 
 
1177
    {
 
 
1178
        case I_inactive:
 
 
1179
            AGunMovement_Centre(sbPtr,2);
 
 
1180
            agunStatusPointer->Target = NULL;
 
 
1181
        break;
 
 
1182
        case I_tracking:
 
 
1183
            if (agunStatusPointer->Target == NULL)
 
 
1184
                AGunMovement_ScanLeftRight(sbPtr,2);
 
 
1185
            else
 
 
1186
                Execute_AGun_Target(sbPtr);
 
 
1187
        break;
 
 
1188
        case I_disabled:
 
 
1189
            /* Dying function. */
 
 
1190
            Execute_AGun_Dying(sbPtr);
 
 
1191
        break;
 
 
1192
        default:
 
 
1193
            /* No action? */
 
 
1194
            break;
 
 
1195
    }
 
 
1196
 
 
 
1197
    /* if we have actually died, we need to remove the strategyblock... so do this here */
 
 
1198
 
 
 
1199
    if((agunStatusPointer->behaviourState == I_disabled) && (agunStatusPointer->stateTimer <= 0))
 
 
1200
        sbPtr->please_destroy_me = 1;
 
 
1201
 
 
 
1202
    agunStatusPointer->WhirrSoundOn = 0;
 
 
1203
    AGun_ComputeDeltaValues(sbPtr);
 
 
1204
 
 
 
1205
    if (agunStatusPointer->WhirrSoundOn && (agunStatusPointer->behaviourState != I_disabled))
 
 
1206
    {
 
 
1207
        int dist = VectorDistance(&PlayerStatus.DisplayBlock->ObWorld, &sbPtr->DynPtr->Position);
 
 
1208
 
 
 
1209
        if (dist < SentryWhirr_SoundData.outer_range)
 
 
1210
        {
 
 
1211
            /* Play whirr sound.  Start and End sounds removed for artistic reasons. */
 
 
1212
 
 
 
1213
            if (agunStatusPointer->soundHandle2 == SOUND_NOACTIVEINDEX)
 
 
1214
            {
 
 
1215
                SentryWhirr_SoundData.position = sbPtr->DynPtr->Position;
 
 
1216
                //Sound_Play(SID_SENTRYTURN, "nel", &SentryWhirr_SoundData, &agunStatusPointer->soundHandle2);
 
 
1217
                Sound_Play(SID_SENTRYTURN, "edl", &agunStatusPointer->soundHandle2, &sbPtr->DynPtr->Position);
 
 
1218
            }
 
 
1219
            #if DEBUG
 
 
1220
            else
 
 
1221
            {
 
 
1222
                assert(ActiveSounds[agunStatusPointer->soundHandle2].soundIndex == SID_SENTRYTURN);
 
 
1223
            }
 
 
1224
            #endif
 
 
1225
        }
 
 
1226
        else
 
 
1227
        {
 
 
1228
            /* Stop whirr sound. */
 
 
1229
            if (agunStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX)
 
 
1230
                Sound_Stop(agunStatusPointer->soundHandle2);
 
 
1231
        }
 
 
1232
    }
 
 
1233
    else
 
 
1234
    {
 
 
1235
        /* Stop whirr sound. */
 
 
1236
        if (agunStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX)
 
 
1237
            Sound_Stop(agunStatusPointer->soundHandle2);
 
 
1238
    }
 
 
1239
 
 
 
1240
    /* Verify firing. */
 
 
1241
    if (agunStatusPointer->behaviourState == I_disabled)
 
 
1242
        agunStatusPointer->Firing = 0;
 
 
1243
 
 
 
1244
    ProveHModel_Far(&agunStatusPointer->HModelController, sbPtr);
 
 
1245
 
 
 
1246
    /* Now, are we firing? */
 
 
1247
 
 
 
1248
    if(!sbPtr->DisplayBlock)
 
 
1249
        agunStatusPointer->Firing = 0; // Just to be sure, for now.
 
 
1250
 
 
 
1251
    AGun_MaintainGun(sbPtr);
 
 
1252
 
 
 
1253
    /* Think sounds. */
 
 
1254
    if (!agunStatusPointer->Firing)
 
 
1255
    {
 
 
1256
        if (agunStatusPointer->soundHandle != SOUND_NOACTIVEINDEX)
 
 
1257
        {
 
 
1258
            if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex == SID_SENTRY_GUN)
 
 
1259
                Sound_Play(SID_SENTRY_END, "d", &sbPtr->DynPtr->Position);
 
 
1260
 
 
 
1261
            Sound_Stop(agunStatusPointer->soundHandle);
 
 
1262
        }
 
 
1263
 
 
 
1264
        /* Sequences! */
 
 
1265
        if (agunStatusPointer->HModelController.Sub_Sequence != XBSS_Powered_Up_Standard)
 
 
1266
            InitHModelTweening(&agunStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Xenoborg, XBSS_Powered_Up_Standard, (ONE_FIXED),
1);
 
 
1267
    }
 
 
1268
    else
 
 
1269
    {
 
 
1270
        if (agunStatusPointer->HModelController.Sub_Sequence != XBSS_Fire_Bolter)
 
 
1271
            InitHModelTweening(&agunStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Xenoborg, XBSS_Fire_Bolter, (ONE_FIXED>>2),
1);
 
 
1272
    }
 
 
1273
 
 
 
1274
    if (agunStatusPointer->soundHandle != SOUND_NOACTIVEINDEX)
 
 
1275
        Sound_Update3d(agunStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
1276
}
 
 
1277
 
 
 
1278
void SentryGunIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming)
 
 
1279
{
 
 
1280
    if (sbPtr->DamageBlock.Health <= 0)
 
 
1281
    {
 
 
1282
        AUTOGUN_STATUS_BLOCK *agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1283
 
 
 
1284
        /* Oh yes, kill them, too. */
 
 
1285
 
 
 
1286
        if (agunStatusPointer->behaviourState != I_disabled)
 
 
1287
        {      
 
 
1288
            /* make an explosion sound */    
 
 
1289
            Sound_Play(SID_SENTRYGUNDEST, "d", &sbPtr->DynPtr->Position);  
 
 
1290
 
 
 
1291
            agunStatusPointer->stateTimer = AGUN_DYINGTIME;
 
 
1292
            agunStatusPointer->HModelController.Looped = 0;
 
 
1293
            agunStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
1294
            /* switch state */
 
 
1295
            agunStatusPointer->behaviourState = I_disabled;
 
 
1296
 
 
 
1297
            if(agunStatusPointer->death_target_sbptr)
 
 
1298
                RequestState(agunStatusPointer->death_target_sbptr,agunStatusPointer->death_target_request, 0);
 
 
1299
 
 
 
1300
            if (agunStatusPointer->soundHandle != SOUND_NOACTIVEINDEX)
 
 
1301
                Sound_Stop(agunStatusPointer->soundHandle); // Well, it shouldn't be!
 
 
1302
        }
 
 
1303
    }
 
 
1304
}
 
 
1305
 
 
 
1306
/*--------------------**
 
 
1307
** Loading and Saving **
 
 
1308
**--------------------*/
 
 
1309
#include "savegame.h"
 
 
1310
 
 
 
1311
typedef struct agun_save_block
 
 
1312
{
 
 
1313
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
1314
 
 
 
1315
//behaviour block stuff
 
 
1316
    AG_STATE behaviourState;
 
 
1317
    int stateTimer;
 
 
1318
 
 
 
1319
    VECTORCH targetTrackPos;
 
 
1320
 
 
 
1321
    int Gun_Pan;
 
 
1322
    int Gun_Tilt;
 
 
1323
    int incidentFlag;
 
 
1324
    int incidentTimer;
 
 
1325
    int ammo;
 
 
1326
    int roundsFired;
 
 
1327
    int volleyFired;
 
 
1328
    int Firing;
 
 
1329
    int WhirrSoundOn;
 
 
1330
    int Drama;
 
 
1331
 
 
 
1332
      unsigned int createdByPlayer:1;
 
 
1333
    unsigned int gunpandir    :1;
 
 
1334
    unsigned int guntiltdir    :1;
 
 
1335
    unsigned int OnTarget    :1;
 
 
1336
    unsigned int OnTarget_LastFrame    :1;
 
 
1337
//annoying pointer related things
 
 
1338
 
 
 
1339
    char Target_SBname[SB_NAME_LENGTH];
 
 
1340
 
 
 
1341
//strategy block stuff
 
 
1342
    DAMAGEBLOCK DamageBlock;
 
 
1343
    DYNAMICSBLOCK dynamics;
 
 
1344
 
 
 
1345
} AGUN_SAVE_BLOCK;
 
 
1346
 
 
 
1347
//defines for load/save macros
 
 
1348
#define SAVELOAD_BLOCK block
 
 
1349
#define SAVELOAD_BEHAV agunStatusPointer
 
 
1350
 
 
 
1351
void LoadStrategy_Autogun(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
1352
{
 
 
1353
    AGUN_SAVE_BLOCK* block = (AGUN_SAVE_BLOCK*) header; 
 
 
1354
 
 
 
1355
    //check the size of the save block
 
 
1356
    if(header->size != sizeof(*block))
 
 
1357
        return;
 
 
1358
 
 
 
1359
    //find the existing strategy block
 
 
1360
    STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname);
 
 
1361
 
 
 
1362
    if(!sbPtr)
 
 
1363
        return;
 
 
1364
 
 
 
1365
    //make sure the strategy found is of the right type
 
 
1366
    if(sbPtr->type != I_BehaviourAutoGun)
 
 
1367
        return;
 
 
1368
 
 
 
1369
    AUTOGUN_STATUS_BLOCK* agunStatusPointer = (AUTOGUN_STATUS_BLOCK*) sbPtr->dataptr;
 
 
1370
 
 
 
1371
    //start copying stuff
 
 
1372
    COPYELEMENT_LOAD(behaviourState)
 
 
1373
    COPYELEMENT_LOAD(stateTimer)
 
 
1374
    COPYELEMENT_LOAD(targetTrackPos)
 
 
1375
    COPYELEMENT_LOAD(Gun_Pan)
 
 
1376
    COPYELEMENT_LOAD(Gun_Tilt)
 
 
1377
    COPYELEMENT_LOAD(incidentFlag)
 
 
1378
    COPYELEMENT_LOAD(incidentTimer)
 
 
1379
    COPYELEMENT_LOAD(ammo)
 
 
1380
    COPYELEMENT_LOAD(roundsFired)
 
 
1381
    COPYELEMENT_LOAD(volleyFired)
 
 
1382
    COPYELEMENT_LOAD(Firing)
 
 
1383
    COPYELEMENT_LOAD(WhirrSoundOn)
 
 
1384
    COPYELEMENT_LOAD(Drama)
 
 
1385
    COPYELEMENT_LOAD(createdByPlayer)
 
 
1386
    COPYELEMENT_LOAD(gunpandir)
 
 
1387
    COPYELEMENT_LOAD(guntiltdir)
 
 
1388
    COPYELEMENT_LOAD(OnTarget)
 
 
1389
    COPYELEMENT_LOAD(OnTarget_LastFrame)
 
 
1390
 
 
 
1391
    //load target
 
 
1392
    COPY_NAME(agunStatusPointer->Target_SBname,block->Target_SBname);
 
 
1393
    agunStatusPointer->Target = FindSBWithName(agunStatusPointer->Target_SBname);
 
 
1394
 
 
 
1395
    //copy strategy block stuff
 
 
1396
    *sbPtr->DynPtr = block->dynamics;
 
 
1397
    sbPtr->DamageBlock = block->DamageBlock;
 
 
1398
 
 
 
1399
    //load hierarchy
 
 
1400
    {
 
 
1401
        SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
1402
 
 
 
1403
        if(hier_header)
 
 
1404
            LoadHierarchy(hier_header,&agunStatusPointer->HModelController);
 
 
1405
    }
 
 
1406
 
 
 
1407
    //get delta controller pointers
 
 
1408
    Autogun_VerifyDeltaControllers(sbPtr);
 
 
1409
 
 
 
1410
    Load_SoundState(&agunStatusPointer->soundHandle);
 
 
1411
    Load_SoundState(&agunStatusPointer->soundHandle2);
 
 
1412
}
 
 
1413
 
 
 
1414
void SaveStrategy_Autogun(STRATEGYBLOCK* sbPtr)
 
 
1415
{
 
 
1416
    AUTOGUN_STATUS_BLOCK* agunStatusPointer;
 
 
1417
    AGUN_SAVE_BLOCK* block;
 
 
1418
 
 
 
1419
    GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
 
 
1420
    agunStatusPointer =(AUTOGUN_STATUS_BLOCK*) sbPtr->dataptr;
 
 
1421
 
 
 
1422
    //start copying stuff
 
 
1423
    COPYELEMENT_SAVE(behaviourState)
 
 
1424
    COPYELEMENT_SAVE(stateTimer)
 
 
1425
    COPYELEMENT_SAVE(targetTrackPos)
 
 
1426
    COPYELEMENT_SAVE(Gun_Pan)
 
 
1427
    COPYELEMENT_SAVE(Gun_Tilt)
 
 
1428
    COPYELEMENT_SAVE(incidentFlag)
 
 
1429
    COPYELEMENT_SAVE(incidentTimer)
 
 
1430
    COPYELEMENT_SAVE(ammo)
 
 
1431
    COPYELEMENT_SAVE(roundsFired)
 
 
1432
    COPYELEMENT_SAVE(volleyFired)
 
 
1433
    COPYELEMENT_SAVE(Firing)
 
 
1434
    COPYELEMENT_SAVE(WhirrSoundOn)
 
 
1435
    COPYELEMENT_SAVE(Drama)
 
 
1436
    COPYELEMENT_SAVE(createdByPlayer)
 
 
1437
    COPYELEMENT_SAVE(gunpandir)
 
 
1438
    COPYELEMENT_SAVE(guntiltdir)
 
 
1439
    COPYELEMENT_SAVE(OnTarget)
 
 
1440
    COPYELEMENT_SAVE(OnTarget_LastFrame)
 
 
1441
 
 
 
1442
    //save target
 
 
1443
    COPY_NAME(block->Target_SBname,agunStatusPointer->Target_SBname);
 
 
1444
 
 
 
1445
    //save strategy block stuff
 
 
1446
    block->dynamics = *sbPtr->DynPtr;
 
 
1447
    block->dynamics.CollisionReportPtr = NULL;
 
 
1448
    block->DamageBlock = sbPtr->DamageBlock;
 
 
1449
 
 
 
1450
    //save the hierarchy
 
 
1451
    SaveHierarchy(&agunStatusPointer->HModelController);
 
 
1452
 
 
 
1453
    Save_SoundState(&agunStatusPointer->soundHandle);
 
 
1454
    Save_SoundState(&agunStatusPointer->soundHandle2);
 
 
1455
}