4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
#include "npc_common.h"
 
 
2
#include "game_statistics.h"
 
 
3
#include "npc_facehugger.h"
 
 
4
#include "psndplat.h"
 
 
5
#include "hud.h"
 
 
6
#include <stdlib.h>
 
 
7
 
 
 
8
extern int deathFadeLevel;
 
 
9
extern int RealFrameTime;
 
 
10
extern void FadeDownScreen(int brightness, int colour);
 
 
11
 
 
 
12
enum HuggerSubSequences
 
 
13
{
 
 
14
    HSS_Stand = 0,
 
 
15
    HSS_Run,
 
 
16
    HSS_Dies,
 
 
17
    HSS_Jump,
 
 
18
    HSS_Attack,
 
 
19
    HSS_DieOnFire,
 
 
20
    HSS_Floats
 
 
21
};
 
 
22
 
 
 
23
#define HUGGER_STATE_PRINT    0
 
 
24
 
 
 
25
extern void AssignNewSBName(STRATEGYBLOCK *sbPtr);
 
 
26
 
 
 
27
static int make_new_facehugger(STRATEGYBLOCK* sbPtr, FACEHUGGER_NEAR_BHSTATE starting_state)
 
 
28
{
 
 
29
    sbPtr->dataptr = malloc(sizeof(FACEHUGGER_STATUS_BLOCK));
 
 
30
 
 
 
31
    if(NULL == sbPtr->dataptr)
 
 
32
    {                       
 
 
33
        RemoveBehaviourStrategy(sbPtr);
 
 
34
        return 0;
 
 
35
    }
 
 
36
 
 
 
37
    sbPtr->maintainVisibility = 1;
 
 
38
    sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
39
 
 
 
40
    FACEHUGGER_STATUS_BLOCK *new_facehugger = (FACEHUGGER_STATUS_BLOCK *)sbPtr->dataptr;
 
 
41
 
 
 
42
    new_facehugger->HModelController.Deltas = NULL;
 
 
43
    new_facehugger->HModelController.Root_Section = NULL;
 
 
44
    new_facehugger->HModelController.section_data = NULL;
 
 
45
    new_facehugger->nearBehaviourState = starting_state;
 
 
46
    new_facehugger->stateTimer = 0;
 
 
47
    new_facehugger->CurveRadius = 0;
 
 
48
    new_facehugger->CurveLength = 0;
 
 
49
    new_facehugger->CurveTimeOut = 0;
 
 
50
    new_facehugger->soundHandle_fire = SOUND_NOACTIVEINDEX;
 
 
51
 
 
 
52
    {
 
 
53
    int i = 0;
 
 
54
    for(; i < SB_NAME_LENGTH; i++)
 
 
55
        new_facehugger->death_target_ID[i] = 0;
 
 
56
    }
 
 
57
 
 
 
58
    COPY_NAME(new_facehugger->Target_SBname, Null_Name);
 
 
59
    new_facehugger->death_target_sbptr = NULL;
 
 
60
    new_facehugger->death_target_request = 0;
 
 
61
    new_facehugger->Target = NULL;
 
 
62
 
 
 
63
    NPC_InitMovementData(&new_facehugger->moveData);
 
 
64
 
 
 
65
    {
 
 
66
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_FaceHugger];
 
 
67
        sbPtr->DamageBlock = NpcData->StartingStats;
 
 
68
        sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
69
        sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
70
    }
 
 
71
 
 
 
72
    SECTION *root_section = GetNamedHierarchyFromLibrary("hnpchugger", "Template");
 
 
73
 
 
 
74
    if ((NULL == root_section) || (NULL == sbPtr->containingModule))
 
 
75
    {
 
 
76
        RemoveBehaviourStrategy(sbPtr);
 
 
77
        return 0;
 
 
78
    }
 
 
79
 
 
 
80
    Create_HModel(&new_facehugger->HModelController, root_section);
 
 
81
    InitHModelSequence(&new_facehugger->HModelController, 0, 0, ONE_FIXED);
 
 
82
    ProveHModel_Far(&new_facehugger->HModelController, sbPtr);
 
 
83
 
 
 
84
    return 1;
 
 
85
}
 
 
86
 
 
 
87
static void PlotFaceHugger(STRATEGYBLOCK *sbPtr) 
 
 
88
{
 
 
89
    extern void DisplayFacehuggerOnHud(DISPLAYBLOCK *dbPtr);
 
 
90
 
 
 
91
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
92
    assert(sbPtr->DisplayBlock);    
 
 
93
 
 
 
94
    {
 
 
95
        VECTORCH x,y,z;
 
 
96
 
 
 
97
        x.vx = -Global_VDB.VDB_Mat.mat11;
 
 
98
        x.vy = -Global_VDB.VDB_Mat.mat21;
 
 
99
        x.vz = -Global_VDB.VDB_Mat.mat31;
 
 
100
        y.vx = -Global_VDB.VDB_Mat.mat13;
 
 
101
        y.vy = -Global_VDB.VDB_Mat.mat23;
 
 
102
        y.vz = -Global_VDB.VDB_Mat.mat33;
 
 
103
        z.vx = -Global_VDB.VDB_Mat.mat12;
 
 
104
        z.vy = -Global_VDB.VDB_Mat.mat22;
 
 
105
        z.vz = -Global_VDB.VDB_Mat.mat32;
 
 
106
 
 
 
107
        Normalise(&x);
 
 
108
        Normalise(&y);
 
 
109
        Normalise(&z);
 
 
110
 
 
 
111
        dynPtr->OrientMat.mat11 = x.vx;
 
 
112
        dynPtr->OrientMat.mat12 = x.vy;
 
 
113
        dynPtr->OrientMat.mat13 = x.vz;
 
 
114
        dynPtr->OrientMat.mat21 = y.vx;
 
 
115
        dynPtr->OrientMat.mat22 = y.vy;
 
 
116
        dynPtr->OrientMat.mat23 = y.vz;
 
 
117
        dynPtr->OrientMat.mat31 = z.vx;
 
 
118
        dynPtr->OrientMat.mat32 = z.vy;
 
 
119
        dynPtr->OrientMat.mat33 = z.vz;
 
 
120
    }
 
 
121
 
 
 
122
    /* set position */
 
 
123
    dynPtr->Position.vx = 0;
 
 
124
    dynPtr->Position.vz = FACEHUGGER_ATTACKZOFFSET / 4;
 
 
125
    dynPtr->Position.vy = FACEHUGGER_ATTACKYOFFSET;
 
 
126
 
 
 
127
    {
 
 
128
        MATRIXCH myMat = Global_VDB.VDB_Mat;
 
 
129
        TransposeMatrixCH(&myMat);
 
 
130
        RotateVector(&dynPtr->Position, &myMat);    
 
 
131
    }
 
 
132
 
 
 
133
    dynPtr->Position.vx += Global_VDB.VDB_World.vx;
 
 
134
    dynPtr->Position.vy += Global_VDB.VDB_World.vy;
 
 
135
    dynPtr->Position.vz += Global_VDB.VDB_World.vz;
 
 
136
 
 
 
137
    sbPtr->DisplayBlock->ObFlags &= ~ObFlag_NotVis;
 
 
138
    sbPtr->DisplayBlock->ObWorld = dynPtr->Position;
 
 
139
    sbPtr->DisplayBlock->ObMat = dynPtr->OrientMat;
 
 
140
 
 
 
141
    ProveHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr->DisplayBlock);
 
 
142
    DoHModel(sbPtr->DisplayBlock);
 
 
143
    sbPtr->DisplayBlock->ObFlags |= ObFlag_NotVis;
 
 
144
 
 
 
145
    if(deathFadeLevel > ONE_FIXED/2)
 
 
146
    {
 
 
147
        deathFadeLevel -= RealFrameTime / 8;
 
 
148
        //FadeDownScreen(deathFadeLevel, 0);
 
 
149
    }
 
 
150
}
 
 
151
 
 
 
152
void InitFacehuggerBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
 
 
153
{
 
 
154
    TOOLS_DATA_FACEHUGGER *toolsData = (TOOLS_DATA_FACEHUGGER *)bhdata; 
 
 
155
    int i;
 
 
156
 
 
 
157
    for(i=0; i < SB_NAME_LENGTH; i++)
 
 
158
        sbPtr->SBname[i] = toolsData->nameID[i];
 
 
159
 
 
 
160
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
161
 
 
 
162
    if(sbPtr->DynPtr)
 
 
163
    {
 
 
164
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
165
        dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
 
 
166
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
167
        TransposeMatrixCH(&dynPtr->OrientMat);              
 
 
168
        dynPtr->Mass = 3;
 
 
169
        dynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
 
 
170
 
 
 
171
        if(make_new_facehugger(sbPtr, (toolsData->startInactive ? FHNS_Floating : FHNS_Approach)))
 
 
172
        {
 
 
173
            FACEHUGGER_STATUS_BLOCK *facehuggerStatus = (FACEHUGGER_STATUS_BLOCK *)sbPtr->dataptr;
 
 
174
 
 
 
175
            if (toolsData->startInactive)
 
 
176
            {
 
 
177
                InitHModelTweening(&facehuggerStatus->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Floats, (ONE_FIXED << 1),
1);
 
 
178
                sbPtr->DynPtr->GravityOn = 0;
 
 
179
            }
 
 
180
            else
 
 
181
            {
 
 
182
                InitHModelTweening(&facehuggerStatus->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Stand, ONE_FIXED, 0);
 
 
183
                facehuggerStatus->HModelController.Playing = 0; // don't show up on motion tracker
 
 
184
            }
 
 
185
 
 
 
186
            for(i=0; i < SB_NAME_LENGTH; i++)
 
 
187
                facehuggerStatus->death_target_ID[i] = toolsData->death_target_ID[i];
 
 
188
 
 
 
189
            facehuggerStatus->death_target_request = toolsData->death_target_request;
 
 
190
        }
 
 
191
    }
 
 
192
    else
 
 
193
    {
 
 
194
        RemoveBehaviourStrategy(sbPtr);
 
 
195
    }
 
 
196
}
 
 
197
 
 
 
198
static void Execute_FHNS_Approach(STRATEGYBLOCK *sbPtr)
 
 
199
{
 
 
200
    FACEHUGGER_STATUS_BLOCK *fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
201
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
202
 
 
 
203
    /* do climb on walls, etc */
 
 
204
    dynPtr->UseStandardGravity = 1;
 
 
205
    /* If you think I'm going to let facehuggers climb on walls for *
 
 
206
     * ONE SECOND, you are INSANE, Jack!!! */
 
 
207
 
 
 
208
    VECTORCH targetPos = fhugStatusPointer->Target->DynPtr->Position;
 
 
209
 
 
 
210
    /* translate target into hugger local space */
 
 
211
    {
 
 
212
        MATRIXCH toLocalSpaceMatrix = dynPtr->OrientMat;
 
 
213
        TransposeMatrixCH(&toLocalSpaceMatrix);
 
 
214
 
 
 
215
        targetPos.vx -= dynPtr->Position.vx;
 
 
216
        targetPos.vy -= dynPtr->Position.vy;
 
 
217
        targetPos.vz -= dynPtr->Position.vz;
 
 
218
        RotateVector(&targetPos, &toLocalSpaceMatrix);
 
 
219
    }
 
 
220
 
 
 
221
    /* Fix vy. */
 
 
222
    targetPos.vy = 0;
 
 
223
 
 
 
224
    /* tracking movement */
 
 
225
    if (dynPtr->IsInContactWithFloor)
 
 
226
    {
 
 
227
        int distanceToTarget = Magnitude(&targetPos);
 
 
228
 
 
 
229
        if (fhugStatusPointer->CurveTimeOut <= 0)
 
 
230
        {
 
 
231
            fhugStatusPointer->CurveLength = distanceToTarget;
 
 
232
            fhugStatusPointer->CurveRadius = ((FastRandom()&16383)-8192)*2;
 
 
233
            fhugStatusPointer->CurveTimeOut= ONE_FIXED * 3;
 
 
234
        }
 
 
235
        else
 
 
236
        {
 
 
237
            fhugStatusPointer->CurveTimeOut -= NormalFrameTime;
 
 
238
        }
 
 
239
 
 
 
240
        int offset = MUL_FIXED(fhugStatusPointer->CurveRadius, GetCos((1024 * distanceToTarget / fhugStatusPointer->CurveLength) & 4095));
 
 
241
 
 
 
242
        dynPtr->LinVelocity.vx = 
 
 
243
            WideMulNarrowDiv(FACEHUGGER_NEAR_SPEED, targetPos.vx, distanceToTarget)
 
 
244
            -WideMulNarrowDiv(offset, targetPos.vz, distanceToTarget);
 
 
245
 
 
 
246
        dynPtr->LinVelocity.vz = 
 
 
247
            WideMulNarrowDiv(FACEHUGGER_NEAR_SPEED, targetPos.vz, distanceToTarget)
 
 
248
            +
 
 
249
            WideMulNarrowDiv(offset, targetPos.vx, distanceToTarget);
 
 
250
 
 
 
251
        RotateVector(&dynPtr->LinVelocity, &dynPtr->OrientMat);
 
 
252
        /* align to velocity */
 
 
253
 
 
 
254
        NPCOrientateToVector(sbPtr, &dynPtr->LinVelocity, NPC_TURNRATE);
 
 
255
 
 
 
256
        //if(!DynamicObjectIsMoving(&fhugStatusPointer->Target->DynPtr))
 
 
257
        {
 
 
258
            /* should we jump at the player? */
 
 
259
            int distanceToTarget = VectorDistance(&dynPtr->Position, &fhugStatusPointer->Target->DynPtr->Position);
 
 
260
 
 
 
261
            if(distanceToTarget <= FACEHUGGER_JUMPDISTANCE)
 
 
262
            {
 
 
263
                fhugStatusPointer->nearBehaviourState = FHNS_AboutToJump;
 
 
264
                fhugStatusPointer->stateTimer = 0;
 
 
265
                return;
 
 
266
            }
 
 
267
        }
 
 
268
    }
 
 
269
 
 
 
270
    {
 
 
271
        STRATEGYBLOCK *destructableObject;
 
 
272
        NPC_OBSTRUCTIONREPORT obstruction;
 
 
273
        NPC_IsObstructed(sbPtr, &fhugStatusPointer->moveData, &obstruction, &destructableObject);
 
 
274
 
 
 
275
        if(obstruction.environment)
 
 
276
        {
 
 
277
            /* go to avoidance */
 
 
278
            NPC_InitMovementData(&fhugStatusPointer->moveData);
 
 
279
            NPCGetAvoidanceDirection(sbPtr, &fhugStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
280
            fhugStatusPointer->nearBehaviourState = FHNS_Avoidance;
 
 
281
            fhugStatusPointer->stateTimer = NPC_AVOIDTIME;
 
 
282
            /* no sequence change required */
 
 
283
            return;
 
 
284
        }
 
 
285
        else if(obstruction.destructableObject)
 
 
286
        {
 
 
287
            assert(destructableObject);
 
 
288
            CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL);
 
 
289
        }
 
 
290
    }
 
 
291
 
 
 
292
    {
 
 
293
        VECTORCH velocityDirection = dynPtr->LinVelocity;
 
 
294
        Normalise(&velocityDirection);
 
 
295
 
 
 
296
        if(NPC_CannotReachTarget(&fhugStatusPointer->moveData, &targetPos, &velocityDirection))
 
 
297
        {
 
 
298
            /* go to avoidance */
 
 
299
            NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
300
            NPC_InitMovementData(&fhugStatusPointer->moveData);
 
 
301
            NPCGetAvoidanceDirection(sbPtr, &fhugStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
302
            fhugStatusPointer->nearBehaviourState = FHNS_Avoidance;
 
 
303
            fhugStatusPointer->stateTimer = NPC_AVOIDTIME;
 
 
304
            /* no sequence change required */
 
 
305
        }
 
 
306
    }
 
 
307
}
 
 
308
 
 
 
309
static void FHugApplyPounceImpulse(STRATEGYBLOCK *sbPtr)
 
 
310
{
 
 
311
    VECTORCH pounceVector, targetPoint;
 
 
312
 
 
 
313
    FACEHUGGER_STATUS_BLOCK *fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
314
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
315
 
 
 
316
    if (fhugStatusPointer->Target)
 
 
317
        GetTargetingPointOfObject(fhugStatusPointer->Target->DisplayBlock, &targetPoint);
 
 
318
 
 
 
319
    int dist = VectorDistance(&dynPtr->Position, &targetPoint);
 
 
320
 
 
 
321
    /* Apply a correction based on range. */
 
 
322
    targetPoint.vy -= (dist >> 3);
 
 
323
 
 
 
324
    pounceVector.vx = targetPoint.vx - dynPtr->Position.vx;
 
 
325
    pounceVector.vy = targetPoint.vy - dynPtr->Position.vy;
 
 
326
    pounceVector.vz = targetPoint.vz - dynPtr->Position.vz;
 
 
327
 
 
 
328
    Normalise(&pounceVector);
 
 
329
    /* Must jump at least a little bit upwards. */
 
 
330
 
 
 
331
    if (pounceVector.vy > -10000)
 
 
332
        pounceVector.vy = -10000;
 
 
333
 
 
 
334
    pounceVector.vx = MUL_FIXED(FACEHUGGER_JUMP_SPEED, pounceVector.vx);
 
 
335
    pounceVector.vy = MUL_FIXED(FACEHUGGER_JUMP_SPEED, pounceVector.vy);
 
 
336
    pounceVector.vz = MUL_FIXED(FACEHUGGER_JUMP_SPEED, pounceVector.vz);
 
 
337
 
 
 
338
    sbPtr->DynPtr->LinImpulse = pounceVector;
 
 
339
}
 
 
340
 
 
 
341
static void Execute_FHNS_Jumping(STRATEGYBLOCK *sbPtr)
 
 
342
{
 
 
343
    FACEHUGGER_STATUS_BLOCK *fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
344
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
345
 
 
 
346
    /* don't climb on walls, etc */
 
 
347
    dynPtr->UseStandardGravity = 1;
 
 
348
 
 
 
349
    /* Firstly, are we actually pouncing yet? */
 
 
350
    /* NearStateTimer is a status flag. */
 
 
351
 
 
 
352
    if (fhugStatusPointer->stateTimer != 2)
 
 
353
    {
 
 
354
        /* Still tweening? */
 
 
355
 
 
 
356
        if (fhugStatusPointer->HModelController.keyframe_flags)
 
 
357
        {
 
 
358
            /* We have the flag. */
 
 
359
            fhugStatusPointer->HModelController.Playing = 0;
 
 
360
            fhugStatusPointer->stateTimer = 1;
 
 
361
        }
 
 
362
 
 
 
363
        if (fhugStatusPointer->stateTimer == 1)
 
 
364
        {
 
 
365
            /* We've finished!  Are we facing right? */
 
 
366
            VECTORCH orientationDirn = { 0,0,0 };
 
 
367
 
 
 
368
            if (fhugStatusPointer->Target)
 
 
369
            {
 
 
370
                orientationDirn.vx = fhugStatusPointer->Target->DynPtr->Position.vx - dynPtr->Position.vx;
 
 
371
                orientationDirn.vz = fhugStatusPointer->Target->DynPtr->Position.vz - dynPtr->Position.vz;
 
 
372
            }
 
 
373
 
 
 
374
            if (!NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE << 2))
 
 
375
            {
 
 
376
                /* Still not right!  Wait for proper facing. */
 
 
377
                fhugStatusPointer->HModelController.Playing = 0;
 
 
378
                return;
 
 
379
            }
 
 
380
            else
 
 
381
            {
 
 
382
                /* Okay, pounce! */
 
 
383
                FHugApplyPounceImpulse(sbPtr);
 
 
384
                fhugStatusPointer->HModelController.Playing = 1;
 
 
385
                fhugStatusPointer->stateTimer = 2;
 
 
386
            }
 
 
387
        }
 
 
388
    }
 
 
389
    else if(dynPtr->CollisionReportPtr)
 
 
390
    {
 
 
391
        /* We must be in the jump.  Can't break out of this until we hit something. */
 
 
392
        COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
 
 
393
 
 
 
394
        fhugStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
395
        fhugStatusPointer->stateTimer = fhugStatusPointer->CurveTimeOut = 0;
 
 
396
 
 
 
397
        do
 
 
398
        {
 
 
399
            STRATEGYBLOCK *hitSbPtr = reportPtr->ObstacleSBPtr;
 
 
400
            /* You know what?  Just did! What? */
 
 
401
 
 
 
402
            if (hitSbPtr && hitSbPtr->DisplayBlock && (hitSbPtr->DisplayBlock == fhugStatusPointer->Target->DisplayBlock))
 
 
403
            {
 
 
404
                /* Got him, My Precious, we've Got Him! */
 
 
405
                /* Test for attach, or merely bite? */
 
 
406
                fhugStatusPointer->nearBehaviourState = FHNS_Attached;
 
 
407
                fhugStatusPointer->stateTimer = FACEHUGGER_NEARATTACKTIME;
 
 
408
                InitHModelTweening(&fhugStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Attack, ONE_FIXED, 1);
 
 
409
                dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS;     /* turn off collisons */    
 
 
410
                dynPtr->GravityOn = sbPtr->maintainVisibility = 0; /* turn off visibility support- be carefull! */
 
 
411
                sbPtr->DisplayBlock->ObFlags |= ObFlag_NotVis; /* Make not vis */
 
 
412
 
 
 
413
                if (hitSbPtr->DisplayBlock == PlayerStatus.DisplayBlock) 
 
 
414
                {
 
 
415
                    deathFadeLevel = ONE_FIXED;
 
 
416
                    Sound_Play(SID_FACEHUGGERSLAP, "h");
 
 
417
                }
 
 
418
                break;
 
 
419
            }
 
 
420
 
 
 
421
            reportPtr = reportPtr->NextCollisionReportPtr;
 
 
422
 
 
 
423
        } while (reportPtr);
 
 
424
    }
 
 
425
}
 
 
426
 
 
 
427
static int TargetFilter(STRATEGYBLOCK *candidate)
 
 
428
{
 
 
429
    switch (candidate->type)
 
 
430
    {
 
 
431
        case I_BehaviourMarinePlayer:
 
 
432
        case I_BehaviourPredatorPlayer:
 
 
433
        case I_BehaviourPredator:
 
 
434
        case I_BehaviourMarine:
 
 
435
            return 1;
 
 
436
        case I_BehaviourNetGhost:
 
 
437
        {
 
 
438
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
439
 
 
 
440
            switch (dataptr->type)
 
 
441
            {
 
 
442
                case I_BehaviourMarinePlayer:
 
 
443
                case I_BehaviourPredatorPlayer:
 
 
444
                    return 1;
 
 
445
                default:
 
 
446
                    return 0;
 
 
447
            }
 
 
448
        }
 
 
449
        default:
 
 
450
            return 0;
 
 
451
    }
 
 
452
}
 
 
453
 
 
 
454
static STRATEGYBLOCK *GetNewTarget(VECTORCH *facehuggerpos)
 
 
455
{
 
 
456
    int i,neardist = ONE_FIXED;
 
 
457
    STRATEGYBLOCK *nearest = NULL;
 
 
458
    MODULE *dmod = ModuleFromPosition(facehuggerpos, PlayerStatus.sbptr->containingModule);
 
 
459
    //MODULE *dmod = ModuleFromPosition(facehuggerpos, NULL);
 
 
460
 
 
 
461
    assert(dmod);
 
 
462
 
 
 
463
    for (i=0; i < NumActiveStBlocks; i++) 
 
 
464
    {
 
 
465
        STRATEGYBLOCK *candidate = ActiveStBlockList[i];
 
 
466
 
 
 
467
        if (TargetFilter(candidate)) 
 
 
468
        {
 
 
469
            VECTORCH offset;
 
 
470
 
 
 
471
            offset.vx = facehuggerpos->vx - candidate->DynPtr->Position.vx;
 
 
472
            offset.vy = facehuggerpos->vy - candidate->DynPtr->Position.vy;
 
 
473
            offset.vz = facehuggerpos->vz - candidate->DynPtr->Position.vz;
 
 
474
 
 
 
475
            int dist = Approximate3dMagnitude(&offset);
 
 
476
            /* Preferentially ignore predators? */
 
 
477
 
 
 
478
            if (candidate->type == I_BehaviourPredator) 
 
 
479
                dist <<= 2;
 
 
480
 
 
 
481
            if ((dist < neardist) && !NPC_IsDead(candidate) && IsModuleVisibleFromModule(dmod, candidate->containingModule)) 
 
 
482
            {
 
 
483
                nearest = candidate;
 
 
484
                neardist = dist;
 
 
485
            }
 
 
486
        }
 
 
487
    }
 
 
488
 
 
 
489
return nearest;
 
 
490
}
 
 
491
 
 
 
492
void FacehuggerBehaviour(STRATEGYBLOCK *sbPtr)
 
 
493
{
 
 
494
    FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
495
 
 
 
496
    /* set velocity to zero */
 
 
497
    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
498
 
 
 
499
    if(FHNS_Dying == facehuggerStatusPointer->nearBehaviourState)
 
 
500
    {
 
 
501
        #if HUGGER_STATE_PRINT
 
 
502
            printf("Hugger Dying...\n");
 
 
503
        #endif
 
 
504
 
 
 
505
        facehuggerStatusPointer->stateTimer -= NormalFrameTime;
 
 
506
 
 
 
507
        if(sbPtr->DisplayBlock)
 
 
508
        {
 
 
509
            sbPtr->DisplayBlock->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
 
 
510
            sbPtr->DisplayBlock->ObFlags2 = facehuggerStatusPointer->stateTimer / 2;
 
 
511
        }
 
 
512
 
 
 
513
        sbPtr->please_destroy_me = (facehuggerStatusPointer->stateTimer <= 0);
 
 
514
        return;
 
 
515
    }
 
 
516
    else if(NULL == sbPtr->DisplayBlock)
 
 
517
    {
 
 
518
        return; // No far behaviour for facehuggers
 
 
519
    }
 
 
520
 
 
 
521
    if (sbPtr->DamageBlock.IsOnFire)
 
 
522
    {
 
 
523
        facehuggerStatusPointer->Target = NULL;
 
 
524
        facehuggerStatusPointer->nearBehaviourState = FHNS_Avoidance;
 
 
525
 
 
 
526
        CauseDamageToObject(sbPtr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL);
 
 
527
 
 
 
528
        if (facehuggerStatusPointer->soundHandle_fire != SOUND_NOACTIVEINDEX)
 
 
529
            Sound_Update3d(facehuggerStatusPointer->soundHandle_fire, &sbPtr->DynPtr->Position);
 
 
530
        else
 
 
531
             Sound_Play(SID_FIRE, "dle", &sbPtr->DynPtr->Position, &facehuggerStatusPointer->soundHandle_fire);
 
 
532
    }
 
 
533
    else
 
 
534
    {
 
 
535
        if (facehuggerStatusPointer->soundHandle_fire != SOUND_NOACTIVEINDEX)
 
 
536
            Sound_Stop(facehuggerStatusPointer->soundHandle_fire);
 
 
537
 
 
 
538
        if(NULL != facehuggerStatusPointer->Target)
 
 
539
        {
 
 
540
            if (NPC_IsDead(facehuggerStatusPointer->Target) || !NAME_ISEQUAL(facehuggerStatusPointer->Target->SBname,
facehuggerStatusPointer->Target_SBname))
 
 
541
            {
 
 
542
                if(FHNS_Attached == facehuggerStatusPointer->nearBehaviourState)
 
 
543
                {
 
 
544
                    InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Dies,
FACEHUGGER_DYINGTIME >> 3, 1);
 
 
545
                    sbPtr->DynPtr->GravityOn = 1;
 
 
546
 
 
 
547
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Dying;
 
 
548
                    facehuggerStatusPointer->HModelController.Looped = 0;
 
 
549
                    facehuggerStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
550
                    facehuggerStatusPointer->stateTimer = FACEHUGGER_DYINGTIME;
 
 
551
                    //facehuggerStatusPointer->Target = NULL;
 
 
552
                }
 
 
553
                else
 
 
554
                {
 
 
555
                    facehuggerStatusPointer->Target = NULL;
 
 
556
                    facehuggerStatusPointer->stateTimer = 0;
 
 
557
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Wait;
 
 
558
                }
 
 
559
            }
 
 
560
        }
 
 
561
        else
 
 
562
        {
 
 
563
            facehuggerStatusPointer->Target = GetNewTarget(&sbPtr->DynPtr->Position);
 
 
564
 
 
 
565
            if (NULL != facehuggerStatusPointer->Target)
 
 
566
            {
 
 
567
                COPY_NAME(facehuggerStatusPointer->Target_SBname, facehuggerStatusPointer->Target->SBname);
 
 
568
                facehuggerStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
569
            }
 
 
570
            else
 
 
571
            {
 
 
572
                facehuggerStatusPointer->stateTimer = 0;
 
 
573
                facehuggerStatusPointer->nearBehaviourState = FHNS_Wait;
 
 
574
            }
 
 
575
        }
 
 
576
    }
 
 
577
 
 
 
578
    #if DEBUG
 
 
579
    if(sbPtr->maintainVisibility)
 
 
580
        assert(ModuleCurrVisArray[sbPtr->containingModule->m_index]);
 
 
581
    #endif
 
 
582
 
 
 
583
    switch(facehuggerStatusPointer->nearBehaviourState)
 
 
584
    {
 
 
585
        case FHNS_Approach:
 
 
586
        {
 
 
587
            #if HUGGER_STATE_PRINT
 
 
588
                printf("Hugger Approaching...\n");
 
 
589
            #endif
 
 
590
 
 
 
591
            if(HSS_Run != facehuggerStatusPointer->HModelController.Sub_Sequence)
 
 
592
                InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Run, (ONE_FIXED*2)/3,
1);
 
 
593
 
 
 
594
            Execute_FHNS_Approach(sbPtr);
 
 
595
        }
 
 
596
        break;
 
 
597
        case FHNS_Attached:
 
 
598
        {
 
 
599
            #if HUGGER_STATE_PRINT
 
 
600
                printf("Hugger Attacking...\n");
 
 
601
            #endif
 
 
602
 
 
 
603
            if (facehuggerStatusPointer->Target == PlayerStatus.sbptr)
 
 
604
            {
 
 
605
                PlayerStatus.sbptr->DamageBlock.Indestructable = 0; // there's no escape
 
 
606
                PlayerStatus.FirstPersonView = 1;
 
 
607
                PlotFaceHugger(sbPtr);
 
 
608
            }
 
 
609
 
 
 
610
            facehuggerStatusPointer->stateTimer -= NormalFrameTime;
 
 
611
 
 
 
612
            if(facehuggerStatusPointer->stateTimer <= 0)
 
 
613
            {
 
 
614
                facehuggerStatusPointer->stateTimer = FACEHUGGER_NEARATTACKTIME;
 
 
615
                CauseDamageToObject(facehuggerStatusPointer->Target, &TemplateAmmo[AMMO_FACEHUGGER].MaxDamage, ONE_FIXED, NULL);
 
 
616
            }
 
 
617
        }
 
 
618
        break;
 
 
619
        case FHNS_Jumping:
 
 
620
        {
 
 
621
            #if HUGGER_STATE_PRINT
 
 
622
                printf("Hugger Jumping...\n");
 
 
623
            #endif
 
 
624
 
 
 
625
            Execute_FHNS_Jumping(sbPtr);
 
 
626
        }
 
 
627
        break;
 
 
628
        case FHNS_AboutToJump:
 
 
629
        {
 
 
630
            #if HUGGER_STATE_PRINT
 
 
631
                printf("Hugger AboutToJump...\n");
 
 
632
            #endif
 
 
633
 
 
 
634
            /* Should still be playing Walk. */
 
 
635
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
636
 
 
 
637
            /* don't climb on walls, etc */
 
 
638
            dynPtr->UseStandardGravity = 1;
 
 
639
            /* Orientate to target. */
 
 
640
            VECTORCH orientationDirn;
 
 
641
            orientationDirn.vx = facehuggerStatusPointer->Target->DynPtr->Position.vx - dynPtr->Position.vx;
 
 
642
            orientationDirn.vy = 0;
 
 
643
            orientationDirn.vz = facehuggerStatusPointer->Target->DynPtr->Position.vz - dynPtr->Position.vz;
 
 
644
 
 
 
645
            if (NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE))
 
 
646
            {
 
 
647
                /* Okay, pounce! */
 
 
648
                int distanceToTarget = VectorDistance(&dynPtr->Position, &facehuggerStatusPointer->Target->DynPtr->Position);
 
 
649
 
 
 
650
                if((distanceToTarget <= FACEHUGGER_JUMPDISTANCE) && dynPtr->IsInContactWithFloor)
 
 
651
                {
 
 
652
                    InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Jump, ONE_FIXED, 1);
 
 
653
                    facehuggerStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
654
                    facehuggerStatusPointer->CurveTimeOut = 0;
 
 
655
                    facehuggerStatusPointer->HModelController.Looped = 0;
 
 
656
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Jumping;
 
 
657
                }
 
 
658
                else
 
 
659
                {
 
 
660
                    /* Return to approach. */
 
 
661
                    NPC_InitMovementData(&facehuggerStatusPointer->moveData);
 
 
662
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
663
                    /* no sequence change required */
 
 
664
                }
 
 
665
 
 
 
666
                facehuggerStatusPointer->stateTimer = 0;
 
 
667
            }
 
 
668
        }
 
 
669
        break;
 
 
670
        case FHNS_Wait:
 
 
671
        {
 
 
672
            #if HUGGER_STATE_PRINT
 
 
673
                printf("Hugger Waiting...\n");
 
 
674
            #endif
 
 
675
 
 
 
676
            if (facehuggerStatusPointer->Target)
 
 
677
            {
 
 
678
                NPC_InitMovementData(&facehuggerStatusPointer->moveData);
 
 
679
                facehuggerStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
680
                facehuggerStatusPointer->stateTimer = 0;
 
 
681
                facehuggerStatusPointer->CurveTimeOut = 0;
 
 
682
            }
 
 
683
            else if(HSS_Stand != facehuggerStatusPointer->HModelController.Sub_Sequence)
 
 
684
            {
 
 
685
                InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Stand, ONE_FIXED, 0);
 
 
686
                facehuggerStatusPointer->HModelController.Playing = 0; // don't show up on motion tracker
 
 
687
            }
 
 
688
        }
 
 
689
        break;
 
 
690
        case FHNS_Avoidance:
 
 
691
        {
 
 
692
            #if HUGGER_STATE_PRINT
 
 
693
                printf("Hugger Avoiding...\n");
 
 
694
            #endif
 
 
695
 
 
 
696
            int terminateState = 0;
 
 
697
 
 
 
698
            assert((facehuggerStatusPointer->moveData.avoidanceDirn.vx !=0)
 
 
699
            ||
 
 
700
            (facehuggerStatusPointer->moveData.avoidanceDirn.vy != 0)
 
 
701
            ||
 
 
702
            (facehuggerStatusPointer->moveData.avoidanceDirn.vz != 0));
 
 
703
 
 
 
704
            NPCSetVelocity(sbPtr, &facehuggerStatusPointer->moveData.avoidanceDirn, FACEHUGGER_NEAR_SPEED);
 
 
705
 
 
 
706
            /* next, decrement state timer */
 
 
707
            facehuggerStatusPointer->stateTimer -= NormalFrameTime;
 
 
708
 
 
 
709
            if(facehuggerStatusPointer->stateTimer <= 0)
 
 
710
                terminateState = 1;
 
 
711
 
 
 
712
            /* and check for an impeding collision */
 
 
713
            {
 
 
714
                STRATEGYBLOCK *destructableObject = NULL;
 
 
715
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
716
                NPC_IsObstructed(sbPtr, &facehuggerStatusPointer->moveData, &obstruction, &destructableObject);
 
 
717
 
 
 
718
                if(obstruction.anySingleObstruction)
 
 
719
                    terminateState = 1;
 
 
720
            }
 
 
721
 
 
 
722
            if(terminateState)
 
 
723
            {
 
 
724
                if(facehuggerStatusPointer->Target)
 
 
725
                {
 
 
726
                    /* switch to approach */
 
 
727
                    NPC_InitMovementData(&facehuggerStatusPointer->moveData);
 
 
728
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
729
                    facehuggerStatusPointer->stateTimer = 0;
 
 
730
                    /* no sequence change required */
 
 
731
                }
 
 
732
                else if (!sbPtr->DamageBlock.IsOnFire)
 
 
733
                {
 
 
734
                    /* switch to wait */
 
 
735
                    NPC_InitMovementData(&facehuggerStatusPointer->moveData);
 
 
736
                    facehuggerStatusPointer->nearBehaviourState = FHNS_Wait;          
 
 
737
                    facehuggerStatusPointer->stateTimer = 0;
 
 
738
                    /* no sequence change required */
 
 
739
                }
 
 
740
            }
 
 
741
        }
 
 
742
        break;
 
 
743
        case FHNS_Floating:
 
 
744
        {
 
 
745
            #if HUGGER_STATE_PRINT
 
 
746
                printf("Hugger Floating...\n");
 
 
747
            #endif
 
 
748
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
749
 
 
 
750
            dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0;    
 
 
751
            dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0;    
 
 
752
            dynPtr->GravityOn = 0;
 
 
753
 
 
 
754
            /* Just float there... */
 
 
755
        }
 
 
756
        default:
 
 
757
        break;
 
 
758
    }
 
 
759
}
 
 
760
 
 
 
761
void CreateFacehuggerBot(VECTORCH *Position)
 
 
762
{
 
 
763
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFaceHugger);
 
 
764
 
 
 
765
    if(!sbPtr)
 
 
766
    {
 
 
767
        GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
 
 
768
        return;
 
 
769
    }
 
 
770
 
 
 
771
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
772
 
 
 
773
    if(sbPtr->DynPtr)
 
 
774
    {
 
 
775
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
776
        AssignNewSBName(sbPtr);
 
 
777
        dynPtr->PrevPosition = dynPtr->Position = *Position;
 
 
778
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
779
        TransposeMatrixCH(&dynPtr->OrientMat);
 
 
780
        dynPtr->Mass = 3;
 
 
781
        dynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
 
 
782
        make_new_facehugger(sbPtr, FHNS_Wait);
 
 
783
    }
 
 
784
    else
 
 
785
    {
 
 
786
        RemoveBehaviourStrategy(sbPtr);
 
 
787
        GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
 
 
788
    }
 
 
789
}
 
 
790
 
 
 
791
void CastFacehuggerBot()
 
 
792
{
 
 
793
    #define BOTRANGE 3000
 
 
794
 
 
 
795
    VECTORCH position;
 
 
796
    position = PlayerStatus.sbptr->DynPtr->Position;
 
 
797
    position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE);
 
 
798
    position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE);
 
 
799
    position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE);
 
 
800
 
 
 
801
    CreateFacehuggerBot(&position);
 
 
802
}
 
 
803
 
 
 
804
void MakeFacehuggerNear(STRATEGYBLOCK *sbPtr)
 
 
805
{
 
 
806
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
807
    FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
808
    DISPLAYBLOCK *dPtr = CreateActiveObject();
 
 
809
 
 
 
810
    if(dPtr == NULL)
 
 
811
        return; /* cannot create displayblock, so leave far */
 
 
812
 
 
 
813
    sbPtr->DisplayBlock = dPtr;
 
 
814
    dPtr->ObStrategyBlock = sbPtr;
 
 
815
 
 
 
816
    /* need to initialise positional information in the new display block */ 
 
 
817
    dPtr->ObWorld = dynPtr->Position;
 
 
818
    dPtr->ObEuler = dynPtr->OrientEuler;
 
 
819
    dPtr->ObMat = dynPtr->OrientMat;
 
 
820
 
 
 
821
    facehuggerStatusPointer->stateTimer = 0;
 
 
822
    facehuggerStatusPointer->CurveRadius = 0;
 
 
823
    facehuggerStatusPointer->CurveLength = 0;
 
 
824
    facehuggerStatusPointer->CurveTimeOut = 0;
 
 
825
    facehuggerStatusPointer->Target = NULL;
 
 
826
 
 
 
827
       /* state and sequence init */
 
 
828
    dPtr->HModelControlBlock = &facehuggerStatusPointer->HModelController;
 
 
829
 
 
 
830
       switch(facehuggerStatusPointer->nearBehaviourState)
 
 
831
    {
 
 
832
        case FHNS_Floating:
 
 
833
        case FHNS_Dying:
 
 
834
        break;
 
 
835
        default:
 
 
836
        {
 
 
837
            NPC_InitMovementData(&facehuggerStatusPointer->moveData);
 
 
838
            facehuggerStatusPointer->nearBehaviourState = facehuggerStatusPointer->Target ? FHNS_Approach : FHNS_Wait;
 
 
839
        }
 
 
840
    }
 
 
841
 
 
 
842
    ProveHModel(dPtr->HModelControlBlock, dPtr);
 
 
843
}
 
 
844
 
 
 
845
void MakeFacehuggerFar(STRATEGYBLOCK *sbPtr)
 
 
846
{
 
 
847
    FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
848
 
 
 
849
    if (facehuggerStatusPointer->soundHandle_fire != SOUND_NOACTIVEINDEX)
 
 
850
        Sound_Stop(facehuggerStatusPointer->soundHandle_fire);
 
 
851
 
 
 
852
    DestroyActiveObject(&sbPtr->DisplayBlock);
 
 
853
    facehuggerStatusPointer->Target = NULL;
 
 
854
    facehuggerStatusPointer->stateTimer = 0;
 
 
855
    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;    
 
 
856
 
 
 
857
    if(sbPtr->DamageBlock.IsOnFire)
 
 
858
    {
 
 
859
        facehuggerStatusPointer->nearBehaviourState = FHNS_Dying;
 
 
860
    }
 
 
861
    else
 
 
862
    {
 
 
863
        facehuggerStatusPointer->nearBehaviourState = FHNS_Wait;
 
 
864
        InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)HSS_Stand, ONE_FIXED, 0);
 
 
865
        facehuggerStatusPointer->HModelController.Playing = 0; // don't show up on motion tracker
 
 
866
    }
 
 
867
}
 
 
868
 
 
 
869
void FacehuggerIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, VECTORCH *incoming)
 
 
870
{
 
 
871
    FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
872
 
 
 
873
    switch(facehuggerStatusPointer->nearBehaviourState)
 
 
874
    {
 
 
875
        case FHNS_Dying:
 
 
876
        return;
 
 
877
        case FHNS_Floating:
 
 
878
        {
 
 
879
            facehuggerStatusPointer->nearBehaviourState = FHNS_Approach;
 
 
880
            sbPtr->DynPtr->GravityOn = 1;
 
 
881
        } // no break;
 
 
882
        default:
 
 
883
        if (sbPtr->DamageBlock.Health <= 0)
 
 
884
        {
 
 
885
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
886
 
 
 
887
            switch(damage->Id)
 
 
888
            {
 
 
889
                case EXPLOSIONFIRE_BLAST:
 
 
890
                case AMMO_FRAGMENTATION_GRENADE:
 
 
891
                    Extreme_Gibbing(sbPtr, facehuggerStatusPointer->HModelController.section_data, ONE_FIXED, incoming);
 
 
892
                    sbPtr->please_destroy_me = 1;
 
 
893
                break;
 
 
894
                case AMMO_FLECHETTE: 
 
 
895
                    Extreme_Gibbing(sbPtr, facehuggerStatusPointer->HModelController.section_data, ONE_FIXED >> 4, incoming);
 
 
896
                    sbPtr->please_destroy_me = 1;
 
 
897
                break;
 
 
898
                default:
 
 
899
                {
 
 
900
                    /* Stop any hugger sound if playing */
 
 
901
                    /*If face hugger has a death target, send a request*/
 
 
902
                    if(facehuggerStatusPointer->death_target_sbptr)
 
 
903
                        RequestState(facehuggerStatusPointer->death_target_sbptr, facehuggerStatusPointer->death_target_request, 0);
 
 
904
 
 
 
905
                    /* More restrained death. */
 
 
906
                    /* switch sequence */
 
 
907
    InitHModelTweening(&facehuggerStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_Hugger, (int)(sbPtr->DamageBlock.IsOnFire ?
HSS_DieOnFire : HSS_Dies), FACEHUGGER_DYINGTIME >> 3, 1);
 
 
908
 
 
 
909
                    facehuggerStatusPointer->HModelController.Looped = 0;
 
 
910
                    facehuggerStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
911
                    facehuggerStatusPointer->stateTimer = FACEHUGGER_DYINGTIME;
 
 
912
 
 
 
913
                    /* stop motion */
 
 
914
                    dynPtr->LinImpulse.vx = sbPtr->DynPtr->LinVelocity.vx;
 
 
915
                    dynPtr->LinImpulse.vy = sbPtr->DynPtr->LinVelocity.vy;
 
 
916
                    dynPtr->LinImpulse.vz = sbPtr->DynPtr->LinVelocity.vz;
 
 
917
                    dynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
918
                    /* Okay... */
 
 
919
                }
 
 
920
            }
 
 
921
 
 
 
922
                CurrentGameStats_CreatureKilled(sbPtr, NULL);
 
 
923
                facehuggerStatusPointer->nearBehaviourState = FHNS_Dying;
 
 
924
        }
 
 
925
    }
 
 
926
}
 
 
927
 
 
 
928
/*--------------------**
 
 
929
** Loading and Saving **
 
 
930
**--------------------*/
 
 
931
#include "savegame.h"
 
 
932
 
 
 
933
typedef struct face_hugger_save_block
 
 
934
{
 
 
935
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
936
 
 
 
937
    FACEHUGGER_NEAR_BHSTATE nearBehaviourState;    
 
 
938
    int stateTimer;
 
 
939
    int CurveRadius;
 
 
940
    int CurveLength;
 
 
941
    int CurveTimeOut;
 
 
942
    STRATEGYBLOCK *Target;
 
 
943
    char Target_SBname[SB_NAME_LENGTH];
 
 
944
 
 
 
945
    //strategyblock stuff
 
 
946
    DAMAGEBLOCK DamageBlock;
 
 
947
    DYNAMICSBLOCK dynamics;
 
 
948
 
 
 
949
} FACE_HUGGER_SAVE_BLOCK;
 
 
950
 
 
 
951
//defines for load/save macros
 
 
952
#define SAVELOAD_BLOCK block
 
 
953
#define SAVELOAD_BEHAV huggerStatusPointer
 
 
954
 
 
 
955
void LoadStrategy_FaceHugger(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
956
{
 
 
957
    FACE_HUGGER_SAVE_BLOCK* block = (FACE_HUGGER_SAVE_BLOCK*) header; 
 
 
958
 
 
 
959
    //check the size of the save block
 
 
960
    if(header->size != sizeof(*block))
 
 
961
        return;
 
 
962
 
 
 
963
    //find the existing strategy block
 
 
964
    STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname);
 
 
965
 
 
 
966
    if(!sbPtr)
 
 
967
        return;
 
 
968
 
 
 
969
    //make sure the strategy found is of the right type
 
 
970
    if(sbPtr->type != I_BehaviourFaceHugger)
 
 
971
        return;
 
 
972
 
 
 
973
    FACEHUGGER_STATUS_BLOCK* huggerStatusPointer = (FACEHUGGER_STATUS_BLOCK*)sbPtr->dataptr;
 
 
974
 
 
 
975
    //start copying stuff
 
 
976
    COPYELEMENT_LOAD(nearBehaviourState)
 
 
977
    COPYELEMENT_LOAD(stateTimer)
 
 
978
    COPYELEMENT_LOAD(CurveRadius)
 
 
979
    COPYELEMENT_LOAD(CurveLength)
 
 
980
    COPYELEMENT_LOAD(CurveTimeOut)
 
 
981
    COPY_NAME(huggerStatusPointer->Target_SBname, block->Target_SBname);
 
 
982
    huggerStatusPointer->Target = FindSBWithName(huggerStatusPointer->Target_SBname);
 
 
983
 
 
 
984
    //copy strategy block stuff
 
 
985
    *sbPtr->DynPtr = block->dynamics;
 
 
986
    sbPtr->DamageBlock = block->DamageBlock;
 
 
987
 
 
 
988
    //load the hierarchy
 
 
989
    {
 
 
990
        SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
991
        if(hier_header)
 
 
992
            LoadHierarchy(hier_header,&huggerStatusPointer->HModelController);
 
 
993
    }
 
 
994
 
 
 
995
    Load_SoundState(&huggerStatusPointer->soundHandle_fire);
 
 
996
}
 
 
997
 
 
 
998
void SaveStrategy_FaceHugger(STRATEGYBLOCK* sbPtr)
 
 
999
{
 
 
1000
    FACE_HUGGER_SAVE_BLOCK* block;
 
 
1001
    FACEHUGGER_STATUS_BLOCK* huggerStatusPointer = (FACEHUGGER_STATUS_BLOCK*)sbPtr->dataptr;
 
 
1002
 
 
 
1003
    GET_STRATEGY_SAVE_BLOCK(block, sbPtr);
 
 
1004
 
 
 
1005
    //start copying stuff
 
 
1006
    COPYELEMENT_SAVE(nearBehaviourState)
 
 
1007
    COPYELEMENT_SAVE(stateTimer)
 
 
1008
    COPYELEMENT_SAVE(CurveRadius)
 
 
1009
    COPYELEMENT_SAVE(CurveLength)
 
 
1010
    COPYELEMENT_SAVE(CurveTimeOut)
 
 
1011
    COPY_NAME(block->Target_SBname, huggerStatusPointer->Target_SBname);
 
 
1012
 
 
 
1013
    //save strategy block stuff
 
 
1014
    block->dynamics = *sbPtr->DynPtr;
 
 
1015
    block->dynamics.CollisionReportPtr = 0;
 
 
1016
    block->DamageBlock = sbPtr->DamageBlock;
 
 
1017
 
 
 
1018
    SaveHierarchy(&huggerStatusPointer->HModelController);
 
 
1019
    Save_SoundState(&huggerStatusPointer->soundHandle_fire);
 
 
1020
}