4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
/*------------------------Patrick 6/11/96-----------------------------
 
 
2
  Source file for alien AI behaviour functions....
 
 
3
  --------------------------------------------------------------------*/
 
 
4
#include "npc_common.h"
 
 
5
#include "bh_light.h"
 
 
6
 
 
 
7
#define ALIEN_CURVETOPLAYERDIST 8000
 
 
8
 
 
 
9
extern int NearAliens;
 
 
10
extern int FarAliens;
 
 
11
extern int ShowHiveState;
 
 
12
 
 
 
13
extern ATTACK_DATA Alien_Special_Gripping_Attack;
 
 
14
 
 
 
15
static int GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES sequence_type, int subsequence)
 
 
16
{
 
 
17
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
18
 
 
 
19
    int factortype = -1;
 
 
20
 
 
 
21
    switch (sequence_type)
 
 
22
    {
 
 
23
        case HMSQT_AlienRun:
 
 
24
            switch ((ALIENRUN_SUBSEQUENCES)subsequence)
 
 
25
            {
 
 
26
                case ARSS_Standard:
 
 
27
                case ARSS_Attack_Swipe:
 
 
28
                    factortype = 2;
 
 
29
                break;
 
 
30
                case ARSS_Jump:
 
 
31
                    factortype = 1;
 
 
32
                break;
 
 
33
                case ARSS_Dies:
 
 
34
                    factortype = 0;
 
 
35
                break;
 
 
36
                default:
 
 
37
                    assert(0);
 
 
38
            }
 
 
39
        break;
 
 
40
        case HMSQT_AlienCrawl:
 
 
41
            switch ((ALIENCRAWL_SUBSEQUENCES)subsequence)
 
 
42
            {
 
 
43
                case ACSS_Standard:
 
 
44
                case ACSS_Crawl_Hurt:
 
 
45
                case ACSS_Scamper:
 
 
46
                    factortype = 2;
 
 
47
                break;
 
 
48
                case ACSS_Attack_Bite:
 
 
49
                case ACSS_Attack_Tail:
 
 
50
                    factortype = 1;
 
 
51
                break;
 
 
52
                case ACSS_Dies:
 
 
53
                case ACSS_Pain_Fall_Fwd:
 
 
54
                case ACSS_Pain_Fall_Back:
 
 
55
                case ACSS_Pain_Fall_Left:
 
 
56
                case ACSS_Pain_Fall_Right:
 
 
57
                case ACSS_Boom_Fall_Fwd:
 
 
58
                case ACSS_Boom_Fall_Back:
 
 
59
                case ACSS_Boom_Fall_Left:
 
 
60
                case ACSS_Boom_Fall_Right:
 
 
61
                    factortype = 0;
 
 
62
                break;
 
 
63
                default:
 
 
64
                    assert(0);
 
 
65
            }
 
 
66
        break;
 
 
67
        case HMSQT_AlienStand:
 
 
68
            switch ((ALIENSTAND_SUBSEQUENCES)subsequence)
 
 
69
            {
 
 
70
                case ASSS_Taunt:
 
 
71
                case ASSS_Taunt2:
 
 
72
                case ASSS_Taunt3:
 
 
73
                case ASSS_Fear:
 
 
74
                case ASSS_Standard:
 
 
75
                case ASSS_FidgetA:
 
 
76
                case ASSS_FidgetB:
 
 
77
                case ASSS_Attack_Right_Swipe_In:
 
 
78
                case ASSS_Attack_Left_Swipe_In:
 
 
79
                case ASSS_Attack_Both_In:
 
 
80
                case ASSS_Attack_Both_Down:
 
 
81
                case ASSS_Attack_Bite:
 
 
82
                case ASSS_Attack_Tail:
 
 
83
                case ASSS_Attack_Low_Left_Swipe:
 
 
84
                case ASSS_Attack_Low_Right_Swipe:
 
 
85
                case ASSS_Feed:
 
 
86
                case ASSS_Unfurl:
 
 
87
                case ASSS_Dormant:
 
 
88
                    factortype = 1;
 
 
89
                break;
 
 
90
                case ASSS_Dies:
 
 
91
                case ASSS_Pain_Fall_Fwd:
 
 
92
                case ASSS_Pain_Fall_Back:
 
 
93
                case ASSS_Pain_Fall_Left:
 
 
94
                case ASSS_Pain_Fall_Right:
 
 
95
                case ASSS_Boom_Fall_Fwd:
 
 
96
                case ASSS_Boom_Fall_Back:
 
 
97
                case ASSS_Boom_Fall_Left:
 
 
98
                case ASSS_Boom_Fall_Right:
 
 
99
                case ASSS_Spin_Clockwise:
 
 
100
                case ASSS_Spin_Anticlockwise:
 
 
101
                case ASSS_BurningDeath:
 
 
102
                    factortype = 0;
 
 
103
                break;
 
 
104
                default:
 
 
105
                    assert(0);
 
 
106
            }
 
 
107
        break;
 
 
108
        case HMSQT_AlienCrouch:
 
 
109
            switch ((ALIENCROUCH_SUBSEQUENCES)subsequence)
 
 
110
            {
 
 
111
                case ACrSS_Standard:
 
 
112
                    factortype = 2;
 
 
113
                break;
 
 
114
                case ACrSS_Attack_Bite:
 
 
115
                case ACrSS_Attack_Tail:
 
 
116
                case ACrSS_Attack_Swipe:
 
 
117
                case ACrSS_Pounce:
 
 
118
                case ACrSS_Taunt:
 
 
119
                    factortype = 1;
 
 
120
                break;
 
 
121
                case ACrSS_Dies:
 
 
122
                case ACrSS_Dies_Thrash:
 
 
123
                    factortype = 0;
 
 
124
                break;
 
 
125
                default:
 
 
126
                    assert(0);
 
 
127
            }
 
 
128
        break;
 
 
129
        default:
 
 
130
            /* Nooooo! */
 
 
131
            assert(0);
 
 
132
            break;
 
 
133
    }
 
 
134
 
 
 
135
    assert(factortype != -1);
 
 
136
 
 
 
137
    switch(factortype)
 
 
138
    {
 
 
139
        case 0:
 
 
140
            return ONE_FIXED;
 
 
141
        break;
 
 
142
        case 1:
 
 
143
        {
 
 
144
            /* Affected by alien type. */
 
 
145
 
 
 
146
            switch (alienStatusPointer->Type)
 
 
147
            {
 
 
148
                case Standard:
 
 
149
                    return ONE_FIXED;
 
 
150
                case Predalien:
 
 
151
                    return PREDALIEN_SPEED_FACTOR;
 
 
152
                case Praetorian:
 
 
153
                    return PRAETORIAN_SPEED_FACTOR;
 
 
154
            }
 
 
155
        }
 
 
156
        break;
 
 
157
        case 2:
 
 
158
        {
 
 
159
            /* More complex.  Affected by alien type and health. */
 
 
160
            const NPC_DATA *NpcData;
 
 
161
            int prefactor;
 
 
162
 
 
 
163
            switch (alienStatusPointer->Type)
 
 
164
            {
 
 
165
                case Standard:
 
 
166
                default: // silence compiler warning
 
 
167
                    NpcData = &NpcDataList[I_NPC_Alien];
 
 
168
                    prefactor = ONE_FIXED;
 
 
169
                break;
 
 
170
                case Predalien:
 
 
171
                    NpcData = &NpcDataList[I_NPC_PredatorAlien];
 
 
172
                    prefactor = PREDALIEN_SPEED_FACTOR;
 
 
173
                break;
 
 
174
                case Praetorian:    
 
 
175
                    NpcData = &NpcDataList[I_NPC_PraetorianGuard];
 
 
176
                    prefactor = PRAETORIAN_SPEED_FACTOR;
 
 
177
            }
 
 
178
 
 
 
179
            int factor = sbPtr->DamageBlock.Health / NpcData->StartingStats.Health;
 
 
180
            /* ONE_FIXED shift already included. */
 
 
181
            assert(factor <= ONE_FIXED);
 
 
182
 
 
 
183
            factor += ONE_FIXED;
 
 
184
            factor >>= 1;
 
 
185
 
 
 
186
            /* Wounding effects. */
 
 
187
            if (alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg))
 
 
188
            {
 
 
189
                /* Missing a leg. */
 
 
190
                factor -= (ONE_FIXED/3);
 
 
191
            }
 
 
192
            else if ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot))
 
 
193
            {
 
 
194
                /* Missing both feet. */
 
 
195
                factor -= (ONE_FIXED>>2);
 
 
196
            }
 
 
197
            else if ((alienStatusPointer->Wounds & section_flag_left_foot) || (alienStatusPointer->Wounds & section_flag_right_foot))
 
 
198
            {
 
 
199
                /* Missing one foot. */
 
 
200
                factor -= (ONE_FIXED>>3);
 
 
201
            }
 
 
202
 
 
 
203
            if (factor < (ONE_FIXED >> 3))
 
 
204
                factor = (ONE_FIXED >> 3);
 
 
205
 
 
 
206
            if (prefactor != ONE_FIXED)
 
 
207
                factor = MUL_FIXED(prefactor,factor);
 
 
208
 
 
 
209
            return factor;
 
 
210
        }
 
 
211
        break;
 
 
212
        default:
 
 
213
            assert(0);
 
 
214
    }
 
 
215
 
 
 
216
return 0;
 
 
217
}
 
 
218
 
 
 
219
static void RecomputeAlienSpeed(STRATEGYBLOCK *sbPtr)
 
 
220
{
 
 
221
    int basespeed;
 
 
222
 
 
 
223
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
224
 
 
 
225
    /* Change max speed. */
 
 
226
    int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard);
 
 
227
 
 
 
228
    switch (alienStatusPointer->Type)
 
 
229
    {
 
 
230
        case Standard:
 
 
231
        default:
 
 
232
            basespeed = ALIEN_FORWARDVELOCITY;
 
 
233
        break;
 
 
234
        case Predalien:
 
 
235
            basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, PREDALIEN_SPEED_FACTOR);
 
 
236
        break;
 
 
237
        case Praetorian:
 
 
238
            if (alienStatusPointer->IAmCrouched)
 
 
239
                basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_CRAWLSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR));
 
 
240
            else
 
 
241
                basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR));
 
 
242
    }
 
 
243
 
 
 
244
    alienStatusPointer->MaxSpeed = MUL_FIXED(factor, basespeed);
 
 
245
}
 
 
246
 
 
 
247
/* Patrick 27/6/97 *********************************
 
 
248
Some support functions for the alien:
 
 
249
Hopefully, these are fairly obvious...
 
 
250
****************************************************/
 
 
251
static void SetAlienShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr, int type, int subtype, int length, int tweeningtime)
 
 
252
{
 
 
253
    ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
254
    assert(length != 0);
 
 
255
 
 
 
256
    if ((alienStatus->HModelController.Sequence_Type == type) && (subtype == alienStatus->HModelController.Sub_Sequence))
 
 
257
            return;
 
 
258
 
 
 
259
    alienStatus->last_anim_length = length;
 
 
260
 
 
 
261
    if (alienStatus->last_anim_length == -1)
 
 
262
        alienStatus->last_anim_length = ONE_FIXED; /* Stops divisions by zero. */
 
 
263
 
 
 
264
    /* Consider wounding. */
 
 
265
    {
 
 
266
        int factor = GetAlienSpeedFactor_ForSequence(sbPtr, type, subtype);
 
 
267
 
 
 
268
        if (factor != ONE_FIXED)
 
 
269
            length = DIV_FIXED(length, factor);
 
 
270
    }
 
 
271
 
 
 
272
    if (tweeningtime <= 0)
 
 
273
        InitHModelSequence(&alienStatus->HModelController, (int)type, subtype, length);
 
 
274
    else
 
 
275
        InitHModelTweening(&alienStatus->HModelController, tweeningtime, (int)type, subtype, length, 1);
 
 
276
 
 
 
277
    if(NetworkPeer == AvP.PlayMode)
 
 
278
        AddNetMsg_AlienAISeqChange(sbPtr, type, subtype, length, tweeningtime);
 
 
279
 
 
 
280
    alienStatus->HModelController.Playing = 1;
 
 
281
    RecomputeAlienSpeed(sbPtr);
 
 
282
}
 
 
283
 
 
 
284
static int AlienShouldBeCrawling(STRATEGYBLOCK *sbPtr)
 
 
285
{
 
 
286
    ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
287
 
 
 
288
    if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT)
 
 
289
        return 1;
 
 
290
 
 
 
291
    /* Stand if you've lost both arm sections. */
 
 
292
    if ((alienStatus->Wounds & section_flag_left_arm) && (alienStatus->Wounds & section_flag_right_arm))
 
 
293
        return 0; /* This just looks silly. */
 
 
294
 
 
 
295
    if(sbPtr->DynPtr->OrientMat.mat22 < 63000)
 
 
296
        return 1;
 
 
297
 
 
 
298
    if (AlienIsEncouragedToCrawl() && alienStatus->EnableWaypoints)
 
 
299
        return 1;
 
 
300
 
 
 
301
    if(ABS_Attack != alienStatus->BehaviourState)
 
 
302
    {
 
 
303
        if(alienStatus->incidentFlag)
 
 
304
        {
 
 
305
            switch(alienStatus->Type)
 
 
306
            {
 
 
307
                case Standard:
 
 
308
                    return ((FastRandom() % 65535) < 16384);
 
 
309
                break;
 
 
310
                case Predalien:
 
 
311
                case Praetorian:
 
 
312
                    return ((FastRandom() % 65535) > 16384);
 
 
313
            }
 
 
314
        }
 
 
315
    }
 
 
316
 
 
 
317
return alienStatus->IAmCrouched;
 
 
318
}
 
 
319
 
 
 
320
static void AlienHandleMovingAnimation(STRATEGYBLOCK *sbPtr) 
 
 
321
{
 
 
322
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
323
 
 
 
324
    if(alienStatusPointer->CanStand)
 
 
325
    {
 
 
326
        /* Make sure we're playing a 'moving' sequence, if we're actually moving. */
 
 
327
 
 
 
328
        VECTORCH offset;
 
 
329
        offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx;
 
 
330
        offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy;
 
 
331
        offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz;
 
 
332
 
 
 
333
        alienStatusPointer->IAmCrouched = AlienShouldBeCrawling(sbPtr);
 
 
334
 
 
 
335
        /* ...compute speed factor... */
 
 
336
        int speed = Magnitude(&offset);
 
 
337
/*
 
 
338
        if (speed < (MUL_FIXED(NormalFrameTime, 100)))
 
 
339
        {
 
 
340
            // Not moving much, are we?
 
 
341
            // Make sure we're playing a 'standing still' sequence.
 
 
342
 
 
 
343
            if (alienStatusPointer->IAmCrouched)
 
 
344
                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrouch, ACrSS_Standard, -1, (ONE_FIXED >> 3));
 
 
345
            else 
 
 
346
                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienStand, ASSS_Standard, -1, (ONE_FIXED >> 3));
 
 
347
        }
 
 
348
        else
 
 
349
    */
 
 
350
        if(alienStatusPointer->IAmCrouched)
 
 
351
        {
 
 
352
            if( ((Standard == alienStatusPointer->Type) && (sbPtr->DynPtr->OrientMat.mat22 < 63000)) || (Predalien ==
alienStatusPointer->Type))
 
 
353
            {
 
 
354
                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Standard, ONE_FIXED >> 2, (ONE_FIXED >> 2));
 
 
355
            }
 
 
356
            else
 
 
357
            {
 
 
358
                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Scamper, ONE_FIXED >> 2, (ONE_FIXED >> 2));
 
 
359
            }
 
 
360
        }
 
 
361
        else
 
 
362
        {
 
 
363
            SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Standard, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
364
        }
 
 
365
    }
 
 
366
    else
 
 
367
    {
 
 
368
        alienStatusPointer->IAmCrouched = 1;
 
 
369
        SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Crawl_Hurt, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
370
    }
 
 
371
}
 
 
372
 
 
 
373
static int Alien_Special_Pounce_Condition(STRATEGYBLOCK *sbPtr) 
 
 
374
{
 
 
375
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
376
 
 
 
377
    if (sbPtr->containingModule->m_aimodule->m_waypoints == NULL)
 
 
378
    {
 
 
379
        /* If in an unwaypointed module... */
 
 
380
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
381
 
 
 
382
        if ((alienStatusPointer->Target->DynPtr->Position.vy - dynPtr->Position.vy) < -2000)
 
 
383
            return 1; // And the target is directly above us...
 
 
384
    }
 
 
385
 
 
 
386
return 0;
 
 
387
}
 
 
388
 
 
 
389
static void StartAlienAttackSequence(STRATEGYBLOCK *sbPtr) 
 
 
390
{
 
 
391
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
392
 
 
 
393
/*
 
 
394
    DYNAMICSBLOCK *objectDynPtr = sbPtr->DynPtr;
 
 
395
    ATTACK_DATA *thisAttack = NULL;
 
 
396
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Swipe, -1, 1);
 
 
397
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Pounce, -1, 1);
 
 
398
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Bite, -1, 1);
 
 
399
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Left_Swipe_In, -1, 1);
 
 
400
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Right_Swipe_In, -1, 1);
 
 
401
 
 
 
402
 
 
 
403
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Tail, -1, 1); // not
predalien
 
 
404
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Both_Down, -1, 1); // not
pratorian
 
 
405
 
 
 
406
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Bite, -1, 1); // only
standard alien and pratorian bad
 
 
407
    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Tail, -1, 1); // only
predalien and standard bad
 
 
408
 
 
 
409
    int left_arm_disabled = ((alienStatusPointer->Wounds & section_flag_left_arm) || (alienStatusPointer->Wounds & section_flag_left_hand));
 
 
410
    int right_arm_disabled = ((alienStatusPointer->Wounds & section_flag_right_arm) || (alienStatusPointer->Wounds & section_flag_right_hand));
 
 
411
    int have_both_arms = !left_arm_disabled && !right_arm_disabled;
 
 
412
 
 
 
413
    //if(alienStatusPointer->IAmCrouched) { }
 
 
414
 
 
 
415
    switch(alienStatusPointer->Type)
 
 
416
    {
 
 
417
        case Standard:
 
 
418
        {
 
 
419
        if(0)
 
 
420
            if(DynamicObjectIsMoving(alienStatusPointer->Target->DynPtr))
 
 
421
            {
 
 
422
                if(alienStatusPointer->IAmCrouched)
 
 
423
                {
 
 
424
                    alienStatusPointer->IAmCrouched = 0;
 
 
425
                }
 
 
426
                else
 
 
427
                {
 
 
428
                    InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienRun, (int)ARSS_Attack_Swipe, -1, 1);
 
 
429
                }
 
 
430
            }
 
 
431
            else
 
 
432
            {
 
 
433
        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrawl, (int)ACSS_Attack_Swipe, -1, 1);
 
 
434
        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Low_Left_Swipe, -1, 1);
 
 
435
        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Low_Right_Swipe, -1,
1);
 
 
436
        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Both_In, -1, 1);
 
 
437
        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Feed, -1, 1); // only standard
eat dead corsp on ground
 
 
438
            }
 
 
439
        }
 
 
440
        break;
 
 
441
        case Predalien:
 
 
442
        {
 
 
443
        }
 
 
444
        break;
 
 
445
        case Praetorian:
 
 
446
        {
 
 
447
 
 
 
448
        }
 
 
449
    }
 
 
450
 
 
 
451
    //}
 
 
452
    //return;
 
 
453
    if (!alienStatusPointer->Type && 0)
 
 
454
    {
 
 
455
        int collidingWithTarget = 0;
 
 
456
 
 
 
457
        // Test for gripping attack!
 
 
458
        {
 
 
459
            struct collisionreport *nextReport = sbPtr->DynPtr->CollisionReportPtr;
 
 
460
 
 
 
461
            while(nextReport)
 
 
462
            {        
 
 
463
                if(nextReport->ObstacleSBPtr)
 
 
464
                {    
 
 
465
                    if (nextReport->ObstacleSBPtr == alienStatusPointer->Target)
 
 
466
                        collidingWithTarget = 1;
 
 
467
                }
 
 
468
 
 
 
469
                nextReport = nextReport->NextCollisionReportPtr;
 
 
470
            }
 
 
471
        }
 
 
472
 
 
 
473
        if(collidingWithTarget && HModelSequence_Exists(&alienStatusPointer->HModelController, Alien_Special_Gripping_Attack.Sequence_Type,
Alien_Special_Gripping_Attack.Sub_Sequence))
 
 
474
        {
 
 
475
            VECTORCH offset,mypos;
 
 
476
            GetTargetingPointOfObject_Far(alienStatusPointer->Target, &offset);
 
 
477
            GetTargetingPointOfObject_Far(sbPtr, &mypos);
 
 
478
            offset.vx -= mypos.vx;
 
 
479
            offset.vy -= mypos.vy;
 
 
480
            offset.vz -= mypos.vz;
 
 
481
            Normalise(&offset);
 
 
482
 
 
 
483
            if (sbPtr->DynPtr->UseStandardGravity)
 
 
484
            {
 
 
485
                sbPtr->DynPtr->GravityDirection.vx = 0;
 
 
486
                sbPtr->DynPtr->GravityDirection.vy = 65536;
 
 
487
                sbPtr->DynPtr->GravityDirection.vz = 0;
 
 
488
            }
 
 
489
 
 
 
490
            if ((DotProduct(&offset,&sbPtr->DynPtr->GravityDirection) > 16962) && collidingWithTarget)
 
 
491
                thisAttack = &Alien_Special_Gripping_Attack; // 75 degs...
 
 
492
        }
 
 
493
        else if(DynamicObjectIsMoving(objectDynPtr))
 
 
494
        {
 
 
495
            //InitHModelSequence(&alienStatusPointer->HModelController,(int)HMSQT_AlienRun, (int)ARSS_Attack_Swipe, ONE_FIXED/2);
 
 
496
        }
 
 
497
    }
 
 
498
 
 
 
499
    if(NULL == thisAttack)
 
 
500
        thisAttack = GetAttackSequence(&alienStatusPointer->HModelController, alienStatusPointer->Wounds, alienStatusPointer->IAmCrouched, 1);
 
 
501
*/
 
 
502
    ATTACK_DATA *thisAttack = GetAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, alienStatusPointer->IAmCrouched,
1);
 
 
503
    SetAlienShapeAnimSequence_Core(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime);
 
 
504
 
 
 
505
    alienStatusPointer->current_attack = thisAttack;
 
 
506
}
 
 
507
 
 
 
508
static void AlienRandomHiss(STRATEGYBLOCK *sbPtr)
 
 
509
{
 
 
510
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
511
 
 
 
512
    if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX)
 
 
513
    {
 
 
514
        SpeciesSound((int)alienStatusPointer->Type, ASC_Scream_General, 0, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position,
ALIEN_SOUND);
 
 
515
 
 
 
516
        if(NetworkPeer == AvP.PlayMode)
 
 
517
            AddNetMsg_SpotAlienSound((int)ASC_Scream_General, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position);
 
 
518
    }
 
 
519
}
 
 
520
 
 
 
521
static int GoToJump(STRATEGYBLOCK *sbPtr)
 
 
522
{
 
 
523
    int speed;
 
 
524
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
525
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
526
 
 
 
527
    /* Must be upright. */
 
 
528
    if((dynPtr->OrientMat.mat22 < 63000) || !alienStatusPointer->CanStand)
 
 
529
    {
 
 
530
        return 0;
 
 
531
    }
 
 
532
 
 
 
533
    /* Should be able to jump now! */
 
 
534
 
 
 
535
    dynPtr->LinImpulse.vx = 0;
 
 
536
    dynPtr->LinImpulse.vy = -10000;
 
 
537
    dynPtr->LinImpulse.vz = 20000;
 
 
538
 
 
 
539
    RotateVector(&dynPtr->LinImpulse, &dynPtr->OrientMat);
 
 
540
    Normalise(&dynPtr->LinImpulse);
 
 
541
 
 
 
542
    switch (alienStatusPointer->Type)
 
 
543
    {
 
 
544
        case Standard:
 
 
545
        default:
 
 
546
            speed = ALIEN_JUMP_SPEED;
 
 
547
        break;
 
 
548
        case Predalien:
 
 
549
            speed = PREDALIEN_JUMP_SPEED;
 
 
550
        break;
 
 
551
        case Praetorian:
 
 
552
            speed = PRAETORIAN_JUMP_SPEED;
 
 
553
    }
 
 
554
 
 
 
555
    int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard);
 
 
556
    speed = MUL_FIXED(speed, factor);
 
 
557
 
 
 
558
    dynPtr->LinImpulse.vx = MUL_FIXED(speed, dynPtr->LinImpulse.vx);
 
 
559
    dynPtr->LinImpulse.vy = MUL_FIXED(speed, dynPtr->LinImpulse.vy);
 
 
560
    dynPtr->LinImpulse.vz = MUL_FIXED(speed, dynPtr->LinImpulse.vz);
 
 
561
 
 
 
562
    alienStatusPointer->BehaviourState = ABS_Jump;
 
 
563
    alienStatusPointer->StateTimer = 0;
 
 
564
    SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Jump, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
565
 
 
 
566
return 1;
 
 
567
}
 
 
568
 
 
 
569
static int AlienIsAbleToClimb(STRATEGYBLOCK *sbPtr) 
 
 
570
{
 
 
571
    ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
572
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
573
 
 
 
574
    return (alienStatus->CanClimb && alienStatus->IAmCrouched);
 
 
575
 
 
 
576
    if (!alienStatus->CanClimb || !alienStatus->IAmCrouched)
 
 
577
        return 0;
 
 
578
 
 
 
579
{
 
 
580
    struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr;
 
 
581
 
 
 
582
    while(CollisionReportPtr)
 
 
583
    {
 
 
584
        if(CollisionReportPtr->ObstacleSBPtr)
 
 
585
        {
 
 
586
            STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr;
 
 
587
 
 
 
588
            switch(hit_sbptr->type)
 
 
589
            {
 
 
590
                case I_BehaviourInanimateObject:
 
 
591
                case I_BehaviourPlatform:
 
 
592
                case I_BehaviourVideoScreen:
 
 
593
                case I_BehaviourGrapplingHook:
 
 
594
                //case I_BehaviourPlacedLight:
 
 
595
                return 1;
 
 
596
                case I_BehaviourMarine:
 
 
597
                case I_BehaviourMarinePlayer:
 
 
598
                case I_BehaviourPredatorPlayer:
 
 
599
                case I_BehaviourPredator:
 
 
600
                case I_BehaviourPlacedLight:
 
 
601
                    CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL);
 
 
602
                case I_BehaviourAlien:
 
 
603
                case I_BehaviourAlienPlayer:
 
 
604
                case I_BehaviourFaceHugger:
 
 
605
                case I_BehaviourXenoborg:
 
 
606
                case I_BehaviourQueenAlien:
 
 
607
                    return 0;
 
 
608
                default:
 
 
609
                break;
 
 
610
            }
 
 
611
            return 0;
 
 
612
        }
 
 
613
        else
 
 
614
        return 1;
 
 
615
 
 
 
616
        CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr;
 
 
617
    }
 
 
618
}
 
 
619
 
 
 
620
return 0;
 
 
621
}
 
 
622
 
 
 
623
static int StartAlienTaunt(STRATEGYBLOCK *sbPtr) 
 
 
624
{
 
 
625
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
626
 
 
 
627
    if(alienStatusPointer->IAmCrouched)
 
 
628
    {
 
 
629
        if(Standard != alienStatusPointer->Type)
 
 
630
            return 0; /* No sequence - can't do it. */
 
 
631
 
 
 
632
        SetAlienShapeAnimSequence_Core(sbPtr, (int)HMSQT_AlienCrouch, ACrSS_Taunt, -1, (ONE_FIXED >> 3));
 
 
633
    }
 
 
634
    else
 
 
635
    {
 
 
636
        int sub_sequence = ASSS_Taunt;
 
 
637
 
 
 
638
        if(Standard == alienStatusPointer->Type)
 
 
639
        {
 
 
640
            switch(FastRandom() % 3)
 
 
641
            {
 
 
642
                case 0:
 
 
643
                default:
 
 
644
                break;
 
 
645
                case 1:
 
 
646
                    sub_sequence = ASSS_Taunt2;
 
 
647
                break;
 
 
648
                case 2:
 
 
649
                    sub_sequence = ASSS_Taunt3;
 
 
650
            }
 
 
651
        }
 
 
652
 
 
 
653
        /* The things I do for transparent code... */
 
 
654
 
 
 
655
        SetAlienShapeAnimSequence_Core(sbPtr, (int)HMSQT_AlienStand, sub_sequence, -1, (ONE_FIXED >> 3));
 
 
656
    }
 
 
657
 
 
 
658
    alienStatusPointer->HModelController.Looped = 0;
 
 
659
    alienStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
660
    alienStatusPointer->BehaviourState = ABS_Taunting;
 
 
661
    alienStatusPointer->StateTimer = 0;
 
 
662
 
 
 
663
    AlienRandomHiss(sbPtr);
 
 
664
/*
 
 
665
    if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX)
 
 
666
    {
 
 
667
        SpeciesSound((int)alienStatusPointer->Type, ASC_Taunt, 0, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position, ALIEN_SOUND);
 
 
668
 
 
 
669
        if(NetworkPeer == AvP.PlayMode)
 
 
670
            AddNetMsg_SpotAlienSound((int)ASC_Taunt, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position);
 
 
671
    }
 
 
672
*/
 
 
673
 
 
 
674
return 1;
 
 
675
}
 
 
676
 
 
 
677
static int TargetIsFiringFlamethrowerAtAlien(STRATEGYBLOCK *sbPtr, int distance_to_target)
 
 
678
{
 
 
679
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
680
 
 
 
681
    /* First, let's see what the target is. */
 
 
682
    switch(alienStatusPointer->Target->type)
 
 
683
    {
 
 
684
        case I_BehaviourMarinePlayer:
 
 
685
        {
 
 
686
            /* Is the player firing a flamethrower? */
 
 
687
 
 
 
688
            if ((PlayerStatus.SelectedWeapon->WeaponIDNumber == WEAPON_FLAMETHROWER) && (PlayerStatus.WeaponState == WEAPONSTATE_FIRING_PRIMARY))
 
 
689
            //if ((PlayerStatus.SelectedWeapon->WeaponIDNumber == WEAPON_FLAMETHROWER) && (PlayerStatus.weapon.HModelControlBlock->Sub_Sequence ==
MHSS_Standard_Fire))
 
 
690
                break;
 
 
691
        }
 
 
692
        return 0;
 
 
693
        case I_BehaviourMarine:
 
 
694
        {
 
 
695
            MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(alienStatusPointer->Target->dataptr);
 
 
696
 
 
 
697
            switch(marineStatusPointer->My_Weapon->id)
 
 
698
            {
 
 
699
                case MNPCW_Flamethrower:
 
 
700
                case MNPCW_CivilianFlamer:
 
 
701
                    if (!marineStatusPointer->IAmFiring)
 
 
702
                        return 0;
 
 
703
                break;
 
 
704
                default:
 
 
705
                return 0;
 
 
706
            }
 
 
707
        }
 
 
708
        default:
 
 
709
        {
 
 
710
            /* Gotta insert a case for netghosts. */
 
 
711
            return 0;
 
 
712
        }
 
 
713
    }
 
 
714
 
 
 
715
    /* Next, let's see if the alien and the target are both in the other's front arc. */
 
 
716
 
 
 
717
    {
 
 
718
        VECTORCH sourcepos,targetpos,offset;
 
 
719
        MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
720
        GetTargetingPointOfObject_Far(sbPtr, &sourcepos);
 
 
721
        GetTargetingPointOfObject_Far(alienStatusPointer->Target, &targetpos);
 
 
722
 
 
 
723
        offset.vx = sourcepos.vx - targetpos.vx;
 
 
724
        offset.vy = sourcepos.vy - targetpos.vy;
 
 
725
        offset.vz = sourcepos.vz - targetpos.vz;
 
 
726
 
 
 
727
        TransposeMatrixCH(&WtoL);
 
 
728
        RotateVector(&offset,&WtoL);
 
 
729
 
 
 
730
        if ( (offset.vz <0) 
 
 
731
            && (offset.vz <  offset.vx) 
 
 
732
            && (offset.vz < -offset.vx) 
 
 
733
            && (offset.vz <  offset.vy) 
 
 
734
            && (offset.vz < -offset.vy) )
 
 
735
        {
 
 
736
            /* 90 horizontal, 90 vertical... continue. */
 
 
737
        }
 
 
738
        else
 
 
739
        {
 
 
740
            return 0;
 
 
741
        }
 
 
742
 
 
 
743
        /* Now test it for the other way round. */
 
 
744
 
 
 
745
        WtoL = alienStatusPointer->Target->DynPtr->OrientMat;
 
 
746
        GetTargetingPointOfObject_Far(alienStatusPointer->Target,&sourcepos);
 
 
747
        GetTargetingPointOfObject_Far(sbPtr,&targetpos);
 
 
748
 
 
 
749
        offset.vx = sourcepos.vx - targetpos.vx;
 
 
750
        offset.vy = sourcepos.vy - targetpos.vy;
 
 
751
        offset.vz = sourcepos.vz - targetpos.vz;
 
 
752
 
 
 
753
        TransposeMatrixCH(&WtoL);
 
 
754
        RotateVector(&offset, &WtoL);
 
 
755
 
 
 
756
        if ( (offset.vz < 0) 
 
 
757
            && (offset.vz <  offset.vx) 
 
 
758
            && (offset.vz < -offset.vx) 
 
 
759
            && (offset.vz <  offset.vy) 
 
 
760
            && (offset.vz < -offset.vy) )
 
 
761
        {
 
 
762
 
 
 
763
            /* 90 horizontal, 90 vertical... continue. */
 
 
764
        }
 
 
765
        else
 
 
766
        {
 
 
767
            return 0;
 
 
768
        }
 
 
769
    }
 
 
770
 
 
 
771
    //int range = VectorDistance(&alienStatusPointer->Target->DynPtr->Position, &sbPtr->DynPtr->Position);
 
 
772
    //printf("range %d\n", range);
 
 
773
 
 
 
774
    if (distance_to_target > 18000)
 
 
775
    {
 
 
776
        return StartAlienTaunt(sbPtr);
 
 
777
    }
 
 
778
    else
 
 
779
    {
 
 
780
        NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
781
        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
782
        NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
783
        alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
784
        alienStatusPointer->StateTimer = NPC_AVOIDTIME/2;
 
 
785
    }
 
 
786
 
 
 
787
/* If here, then it must be true! */
 
 
788
return 1;
 
 
789
}
 
 
790
 
 
 
791
static ATTACK_DATA *AlienIsAbleToPounce(STRATEGYBLOCK *sbPtr) 
 
 
792
{
 
 
793
    VECTORCH targetPoint;
 
 
794
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
795
 
 
 
796
    /* Also not if you're badly hurt. */
 
 
797
    {
 
 
798
        int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard);
 
 
799
 
 
 
800
        if (factor < ((ONE_FIXED*3)/4))
 
 
801
            return NULL;
 
 
802
    }
 
 
803
 
 
 
804
    if (NULL != alienStatusPointer->Target->DisplayBlock)
 
 
805
    {
 
 
806
        GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock, &targetPoint);
 
 
807
 
 
 
808
        /* Do we have a clear line of sight? */
 
 
809
 
 
 
810
        if (IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->DisplayBlock, alienStatusPointer->Target->DisplayBlock, &targetPoint))
 
 
811
        {
 
 
812
            /* Finally, test the sequence. */
 
 
813
            ATTACK_DATA *thisAttack = GetAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds,
alienStatusPointer->IAmCrouched, 0);
 
 
814
 
 
 
815
            if ((thisAttack == NULL) && !alienStatusPointer->IAmCrouched)
 
 
816
            {
 
 
817
                /* Try again crouched. Pook. */
 
 
818
                thisAttack = GetAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, 1, 0);
 
 
819
            }
 
 
820
            return thisAttack;
 
 
821
        }
 
 
822
    }
 
 
823
 
 
 
824
return NULL;
 
 
825
}
 
 
826
 
 
 
827
static int StartAlienPounce(STRATEGYBLOCK *sbPtr) 
 
 
828
{
 
 
829
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
830
 
 
 
831
    if((sbPtr->DynPtr->OrientMat.mat22 < 63000) || (sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT))
 
 
832
    {
 
 
833
        // First rule.  Must be on a flat floor,  And not in an airduct.
 
 
834
    }
 
 
835
    else if(alienStatusPointer->CanStand && sbPtr->DynPtr->IsInContactWithFloor)
 
 
836
    {
 
 
837
        ATTACK_DATA *thisAttack = AlienIsAbleToPounce(sbPtr);
 
 
838
 
 
 
839
        if (NULL != thisAttack)
 
 
840
        {
 
 
841
            SetAlienShapeAnimSequence_Core(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime);
 
 
842
 
 
 
843
            alienStatusPointer->HModelController.Looped = 0;
 
 
844
            alienStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
845
            alienStatusPointer->current_attack = thisAttack;
 
 
846
            alienStatusPointer->BehaviourState = ABS_Pounce;
 
 
847
            alienStatusPointer->StateTimer = 0;
 
 
848
            return 1;
 
 
849
        }
 
 
850
    }
 
 
851
 
 
 
852
return 0;
 
 
853
}
 
 
854
 
 
 
855
static enum AMMO_ID GetAttackDamageType(STRATEGYBLOCK *sbPtr, int flagnum) 
 
 
856
{
 
 
857
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
858
 
 
 
859
    if (alienStatusPointer->current_attack == NULL)
 
 
860
        return AMMO_NONE;
 
 
861
 
 
 
862
    /* Fix praetorian damage here! */
 
 
863
 
 
 
864
    switch (alienStatusPointer->Type)
 
 
865
    {
 
 
866
        case Standard:
 
 
867
        default:
 
 
868
            /* No change. */
 
 
869
            return (alienStatusPointer->current_attack->flag_damage[flagnum]);
 
 
870
        case Predalien:
 
 
871
        {
 
 
872
            switch (alienStatusPointer->current_attack->flag_damage[flagnum])
 
 
873
            {
 
 
874
                case AMMO_ALIEN_CLAW:
 
 
875
                default:
 
 
876
                    return AMMO_NPC_PREDALIEN_CLAW;
 
 
877
                case AMMO_ALIEN_TAIL:
 
 
878
                    return AMMO_NPC_PREDALIEN_TAIL;
 
 
879
                case AMMO_NPC_ALIEN_BITE:
 
 
880
                    return AMMO_NPC_PREDALIEN_BITE;
 
 
881
            }
 
 
882
        }
 
 
883
        case Praetorian:
 
 
884
        {
 
 
885
            switch (alienStatusPointer->current_attack->flag_damage[flagnum])
 
 
886
            {
 
 
887
                case AMMO_ALIEN_CLAW:
 
 
888
                default:
 
 
889
                    return AMMO_NPC_PRAETORIAN_CLAW;
 
 
890
                case AMMO_ALIEN_TAIL:
 
 
891
                    return AMMO_NPC_PRAETORIAN_TAIL;
 
 
892
                case AMMO_NPC_ALIEN_BITE:
 
 
893
                    return AMMO_NPC_PRAETORIAN_BITE;
 
 
894
            }
 
 
895
        }
 
 
896
    }
 
 
897
}
 
 
898
 
 
 
899
static void AlienNearDamageShell(STRATEGYBLOCK *sbPtr)
 
 
900
{
 
 
901
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
902
 
 
 
903
    /* Damage shell! */
 
 
904
    int workingflags = alienStatusPointer->HModelController.keyframe_flags >> 1;
 
 
905
 
 
 
906
    int a=0;
 
 
907
    for (; a < NUM_ATTACKFLAGS; a++)
 
 
908
    {
 
 
909
        if (workingflags & 1)
 
 
910
        {
 
 
911
            /* Oops, check range first. */
 
 
912
            VECTORCH rel_pos, attack_dir;
 
 
913
            rel_pos.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
914
            rel_pos.vy = alienStatusPointer->Target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy;
 
 
915
            rel_pos.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
916
            GetDirectionOfAttack(alienStatusPointer->Target, &rel_pos, &attack_dir);
 
 
917
 
 
 
918
            if (alienStatusPointer->Target->DisplayBlock && alienStatusPointer->Target->DisplayBlock->HModelControlBlock)
 
 
919
                HtoHDamageToHModel(alienStatusPointer->Target, &TemplateAmmo[GetAttackDamageType(sbPtr, a)].MaxDamage, ONE_FIXED, sbPtr,
&attack_dir);
 
 
920
            else
 
 
921
                CauseDamageToObject(alienStatusPointer->Target, &TemplateAmmo[GetAttackDamageType(sbPtr, a)].MaxDamage, ONE_FIXED, &attack_dir);
 
 
922
        }
 
 
923
 
 
 
924
        /* Prepare next flag. */
 
 
925
        workingflags >>= 1;
 
 
926
    }
 
 
927
}
 
 
928
 
 
 
929
static AIMODULE *FarNPC_GetTargetAIModuleForGlobalHunt(STRATEGYBLOCK *sbPtr)
 
 
930
{
 
 
931
    unsigned int highestSmell = 0;
 
 
932
    AIMODULE* targetModule = NULL;
 
 
933
 
 
 
934
    AIMODULE **AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs;
 
 
935
 
 
 
936
    /* check that there is a list of adjacent modules, and that it is not
 
 
937
    empty (ie points to zero) */
 
 
938
 
 
 
939
    if(AdjModuleRefPtr)
 
 
940
    {
 
 
941
        while(*AdjModuleRefPtr != 0)
 
 
942
        {
 
 
943
            /* get the index */
 
 
944
            int AdjModuleIndex = (*AdjModuleRefPtr)->m_index;
 
 
945
 
 
 
946
            /* if this adjacent module's smell value is higher than
 
 
947
            the current 'highest smell' record the new module as the
 
 
948
            target. */
 
 
949
 
 
 
950
            if(PherAls_ReadBuf[AdjModuleIndex] > highestSmell)
 
 
951
            {                        
 
 
952
                highestSmell = PherAls_ReadBuf[AdjModuleIndex];
 
 
953
                targetModule = *AdjModuleRefPtr;                            
 
 
954
            }
 
 
955
            /* next adjacent module reference pointer */
 
 
956
            AdjModuleRefPtr++;
 
 
957
        }
 
 
958
    }
 
 
959
 
 
 
960
    if (highestSmell < PherAls_ReadBuf[sbPtr->containingModule->m_aimodule->m_index])
 
 
961
        return (sbPtr->containingModule->m_aimodule);
 
 
962
    else
 
 
963
        return (targetModule);
 
 
964
}
 
 
965
 
 
 
966
static void CheckPounceIntegrity(STRATEGYBLOCK *sbPtr) 
 
 
967
{
 
 
968
    VECTORCH targetPoint;
 
 
969
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
970
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
971
 
 
 
972
    if (alienStatusPointer->Target == NULL)
 
 
973
    {
 
 
974
        /* Attack what? */
 
 
975
        alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
976
        alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
977
        return;
 
 
978
    }
 
 
979
 
 
 
980
    if ((alienStatusPointer->Target->DisplayBlock == NULL) || ((alienStatusPointer->Target->DynPtr->Position.vy -
sbPtr->DynPtr->Position.vy) > 1000))
 
 
981
    {
 
 
982
        /* Yuck.  Target is far, or too far below you. */
 
 
983
        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
984
        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
985
 
 
 
986
        alienStatusPointer->StateTimer = 0;
 
 
987
        alienStatusPointer->CurveTimeOut = 0;
 
 
988
        return;
 
 
989
    }
 
 
990
 
 
 
991
    GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock, &targetPoint);
 
 
992
 
 
 
993
    /* Do we have a clear line of sight? */
 
 
994
 
 
 
995
    if (!IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->DisplayBlock, alienStatusPointer->Target->DisplayBlock, &targetPoint))
 
 
996
    {
 
 
997
        /* Can't see! */
 
 
998
        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
999
        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
1000
 
 
 
1001
        alienStatusPointer->StateTimer = 0;
 
 
1002
        alienStatusPointer->CurveTimeOut = 0;
 
 
1003
        return;
 
 
1004
    }
 
 
1005
 
 
 
1006
    /* Orientate towards player, just to make sure we're facing */
 
 
1007
    {
 
 
1008
        VECTORCH orientationDirn;
 
 
1009
        orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
1010
        orientationDirn.vy = 0;
 
 
1011
        orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
1012
 
 
 
1013
        if (!NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE))
 
 
1014
        {
 
 
1015
            /* Still not right.  Be careful. */
 
 
1016
            alienStatusPointer->HModelController.StopAfterTweening = 1;
 
 
1017
        }
 
 
1018
        else
 
 
1019
        {
 
 
1020
            /* Okay for the moment. */
 
 
1021
            alienStatusPointer->HModelController.StopAfterTweening = 0;
 
 
1022
        }
 
 
1023
    }
 
 
1024
 
 
 
1025
    /* change back to approach?: don't need to directly test if we should go to wander, as 
 
 
1026
    approach state will do this... */
 
 
1027
    {
 
 
1028
        int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position);
 
 
1029
 
 
 
1030
        if(distance_to_target > ALIEN_POUNCE_MAXRANGE)
 
 
1031
        {
 
 
1032
            NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
1033
            alienStatusPointer->BehaviourState = ABS_Approach;
 
 
1034
 
 
 
1035
            alienStatusPointer->StateTimer = 0;
 
 
1036
            alienStatusPointer->CurveTimeOut = 0;
 
 
1037
            return;
 
 
1038
        }
 
 
1039
    }
 
 
1040
 
 
 
1041
    /* Are we still able to pounce? */
 
 
1042
 
 
 
1043
    /* Not if you've lost any leg sections. */    
 
 
1044
    if ( (alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg)) 
 
 
1045
        /* Also not if you've lost both feet. */
 
 
1046
        || ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot)) )
 
 
1047
    {
 
 
1048
        /* Can't stand either.  Fall over. */
 
 
1049
        /* That implies going back to approach, btw. */
 
 
1050
        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
1051
        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
1052
 
 
 
1053
        alienStatusPointer->StateTimer = 0;
 
 
1054
        alienStatusPointer->CurveTimeOut = 0;
 
 
1055
    }
 
 
1056
}
 
 
1057
 
 
 
1058
static void ApplyPounceImpulse(STRATEGYBLOCK *sbPtr) 
 
 
1059
{
 
 
1060
    VECTORCH pounceVector,targetPoint;
 
 
1061
    int speed;
 
 
1062
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1063
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1064
 
 
 
1065
    GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock,&targetPoint);
 
 
1066
 
 
 
1067
    int dist = VectorDistance(&dynPtr->Position, &targetPoint);
 
 
1068
 
 
 
1069
    /* Apply a correction based on range. */
 
 
1070
    targetPoint.vy -= dist >> 3;
 
 
1071
 
 
 
1072
    pounceVector.vx = targetPoint.vx - dynPtr->Position.vx;
 
 
1073
    pounceVector.vy = targetPoint.vy - dynPtr->Position.vy;
 
 
1074
    pounceVector.vz = targetPoint.vz - dynPtr->Position.vz;
 
 
1075
 
 
 
1076
    Normalise(&pounceVector);
 
 
1077
    /* Must jump at least a little bit upwards. */
 
 
1078
    if (pounceVector.vy > -10000)
 
 
1079
        pounceVector.vy = -10000;
 
 
1080
 
 
 
1081
    switch (alienStatusPointer->Type)
 
 
1082
    {
 
 
1083
        case Standard:
 
 
1084
        default:
 
 
1085
            speed = ALIEN_JUMP_SPEED;
 
 
1086
        break;
 
 
1087
        case Predalien:
 
 
1088
            speed = PREDALIEN_JUMP_SPEED;
 
 
1089
        break;
 
 
1090
        case Praetorian:
 
 
1091
            speed = PRAETORIAN_JUMP_SPEED;
 
 
1092
    }
 
 
1093
 
 
 
1094
    int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard);
 
 
1095
    speed = MUL_FIXED(speed, factor);
 
 
1096
 
 
 
1097
    pounceVector.vx = MUL_FIXED(speed,pounceVector.vx);
 
 
1098
    pounceVector.vy = MUL_FIXED(speed,pounceVector.vy);
 
 
1099
    pounceVector.vz = MUL_FIXED(speed,pounceVector.vz);
 
 
1100
 
 
 
1101
    sbPtr->DynPtr->LinImpulse = pounceVector;
 
 
1102
}
 
 
1103
 
 
 
1104
static int make_new_alien(STRATEGYBLOCK *sbPtr, ALIEN_TYPE type_of_alien, ALIEN_BHSTATE starting_state, STRATEGYBLOCK *Generator)
 
 
1105
{
 
 
1106
    sbPtr->dataptr = malloc(sizeof(ALIEN_STATUS_BLOCK));
 
 
1107
    sbPtr->maintainVisibility = 1;
 
 
1108
    sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
1109
 
 
 
1110
    if(NULL == sbPtr->dataptr)
 
 
1111
    {
 
 
1112
        RemoveBehaviourStrategy(sbPtr);
 
 
1113
        return 0;
 
 
1114
    }
 
 
1115
 
 
 
1116
    ALIEN_STATUS_BLOCK *new_alien = (ALIEN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
1117
 
 
 
1118
    new_alien->HModelController.Deltas = NULL;
 
 
1119
    new_alien->HModelController.Root_Section = NULL;
 
 
1120
    new_alien->HModelController.section_data = NULL;
 
 
1121
    new_alien->Type = type_of_alien;
 
 
1122
    new_alien->BehaviourState = starting_state;
 
 
1123
    new_alien->MaxSpeed = 0;
 
 
1124
    new_alien->Wounds = 0;
 
 
1125
    new_alien->last_anim_length = ONE_FIXED;
 
 
1126
    new_alien->incidentFlag = 0;
 
 
1127
    new_alien->incidentTimer = 0;
 
 
1128
    new_alien->CurveRadius = 0;
 
 
1129
    new_alien->CurveLength = 0;
 
 
1130
    new_alien->CurveTimeOut = 0;
 
 
1131
    new_alien->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
1132
    new_alien->IAmCrouched = 0;
 
 
1133
    new_alien->CurrentLightAtAlien = 0;
 
 
1134
    new_alien->EnableWaypoints = 0;
 
 
1135
    new_alien->aliensIgniterId = 0; //Which player in a multiplayer game toasted this poor beast?
 
 
1136
    new_alien->soundOnFire = SOUND_NOACTIVEINDEX;
 
 
1137
    new_alien->sound_mouth = SOUND_NOACTIVEINDEX;
 
 
1138
    new_alien->unconscious = 0;
 
 
1139
    new_alien->CanStand = 1;
 
 
1140
    new_alien->CanClimb = 1;
 
 
1141
    new_alien->current_attack = NULL;
 
 
1142
    new_alien->huntingModule = NULL;
 
 
1143
    new_alien->Target = NULL;
 
 
1144
 
 
 
1145
    COPY_NAME(new_alien->Target_SBname, Null_Name);
 
 
1146
 
 
 
1147
{
 
 
1148
    int i = 0;
 
 
1149
    for(; i < SB_NAME_LENGTH; i++)
 
 
1150
        new_alien->death_target_ID[i] = 0;
 
 
1151
}
 
 
1152
    new_alien->death_target_sbptr = NULL;
 
 
1153
    new_alien->generator_sbptr = Generator;
 
 
1154
 
 
 
1155
    {
 
 
1156
        const NPC_DATA *NpcData;
 
 
1157
        const SECTION *root_section;
 
 
1158
 
 
 
1159
        switch (new_alien->Type)
 
 
1160
        {
 
 
1161
            case 0:
 
 
1162
            default:
 
 
1163
                NpcData = &NpcDataList[I_NPC_Alien];
 
 
1164
                new_alien->MaxSpeed = ALIEN_FORWARDVELOCITY;
 
 
1165
                new_alien->EnableWaypoints = !(FastRandom() & 7);
 
 
1166
                sbPtr->DynPtr->Mass = ALIEN_MASS;
 
 
1167
                root_section = GetNamedHierarchyFromLibrary("hnpcalien", "alien");
 
 
1168
            break;
 
 
1169
            case 1:
 
 
1170
                NpcData = &NpcDataList[I_NPC_PredatorAlien];
 
 
1171
                new_alien->MaxSpeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, PREDALIEN_SPEED_FACTOR);
 
 
1172
                new_alien->EnableWaypoints = 1;
 
 
1173
                sbPtr->DynPtr->Mass = PREDALIEN_MASS;
 
 
1174
                root_section = GetNamedHierarchyFromLibrary("hnpcpred_alien", "TEMPLATE");
 
 
1175
            break;
 
 
1176
            case 2:
 
 
1177
                NpcData = &NpcDataList[I_NPC_PraetorianGuard];
 
 
1178
                new_alien->MaxSpeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR));
 
 
1179
                sbPtr->DynPtr->Mass = PRAETORIAN_MASS;
 
 
1180
                new_alien->EnableWaypoints = 0;
 
 
1181
                root_section = GetNamedHierarchyFromLibrary("hnpcpretorian", "Template");
 
 
1182
                new_alien->CanClimb = 0; // Praetorian Guard can't climb.  Sorry.
 
 
1183
        }
 
 
1184
 
 
 
1185
        sbPtr->DamageBlock = NpcData->StartingStats;
 
 
1186
        sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
1187
        sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
1188
 
 
 
1189
        if (!root_section || !sbPtr->containingModule)
 
 
1190
        {
 
 
1191
            RemoveBehaviourStrategy(sbPtr);
 
 
1192
            return 0;
 
 
1193
        }
 
 
1194
 
 
 
1195
        Create_HModel(&new_alien->HModelController, root_section);
 
 
1196
    }
 
 
1197
 
 
 
1198
    NPC_InitMovementData(&new_alien->moveData);
 
 
1199
    NPC_InitWanderData(&new_alien->wanderData);
 
 
1200
    Initialise_AvoidanceManager(&new_alien->avoidanceManager);
 
 
1201
    InitWaypointManager(&new_alien->waypointManager);
 
 
1202
 
 
 
1203
    if(ABS_Dormant == new_alien->BehaviourState)
 
 
1204
        InitHModelSequence(&new_alien->HModelController, HMSQT_AlienStand, ASSS_Dormant, -1);
 
 
1205
    else
 
 
1206
        InitHModelSequence(&new_alien->HModelController, 0, 0, ONE_FIXED);
 
 
1207
 
 
 
1208
    new_alien->HModelController.Playing = 0;
 
 
1209
 
 
 
1210
    if (CHEATMODE_SLUGTRAIL == UserProfile.active_bonus) 
 
 
1211
    {
 
 
1212
        /* Blow off a leg? */
 
 
1213
        SECTION_DATA *leg = GetThisSectionData(new_alien->HModelController.section_data, "left thigh");
 
 
1214
 
 
 
1215
        if (leg) 
 
 
1216
        {
 
 
1217
            Prune_HModel_Virtual(leg);
 
 
1218
            new_alien->Wounds = section_flag_left_leg | section_flag_left_foot;
 
 
1219
            new_alien->CanStand = 0;
 
 
1220
            sbPtr->DamageBlock.Health -= (20 << ONE_FIXED_SHIFT);
 
 
1221
        }
 
 
1222
    }
 
 
1223
 
 
 
1224
    if (HModelSequence_Exists(&new_alien->HModelController, (int)HMSQT_AlienStand, (int)ASSS_Hit_Right))
 
 
1225
    {
 
 
1226
        Add_Delta_Sequence(&new_alien->HModelController, "HitDelta", (int)HMSQT_AlienStand, (int)ASSS_Hit_Right, -1);
 
 
1227
    }
 
 
1228
 
 
 
1229
    ProveHModel_Far(&new_alien->HModelController, sbPtr);
 
 
1230
 
 
 
1231
return 1;
 
 
1232
}
 
 
1233
 
 
 
1234
void CreateAlienBot(VECTORCH *Position, int type)
 
 
1235
{
 
 
1236
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien);
 
 
1237
 
 
 
1238
    if(!sbPtr)
 
 
1239
        return;
 
 
1240
 
 
 
1241
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
1242
 
 
 
1243
    if(sbPtr->DynPtr)
 
 
1244
    {
 
 
1245
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1246
        AssignNewSBName(sbPtr);
 
 
1247
        dynPtr->PrevPosition = dynPtr->Position = *Position;
 
 
1248
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
1249
        TransposeMatrixCH(&dynPtr->OrientMat);      
 
 
1250
        sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
 
 
1251
        make_new_alien(sbPtr, type, ABS_Hunt, NULL);
 
 
1252
    }
 
 
1253
    else
 
 
1254
    {
 
 
1255
        RemoveBehaviourStrategy(sbPtr);
 
 
1256
    }
 
 
1257
}
 
 
1258
 
 
 
1259
void CastAlienBot(int type)
 
 
1260
{
 
 
1261
    //#define BOTRANGE 2000
 
 
1262
    #define BOTRANGE 50000
 
 
1263
 
 
 
1264
    VECTORCH position;
 
 
1265
    position = PlayerStatus.sbptr->DynPtr->Position;
 
 
1266
    position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE);
 
 
1267
    position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE);
 
 
1268
    position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE);
 
 
1269
 
 
 
1270
    CreateAlienBot(&position, type);
 
 
1271
}
 
 
1272
 
 
 
1273
/*----------------------Patrick 15/11/96-----------------------------
 
 
1274
This function is called by the alien generators, to dynamically
 
 
1275
create a new alien, during the game.  The alien is initialised
 
 
1276
as invisible.
 
 
1277
 
 
 
1278
1. create a new strategy block (no diplay block)
 
 
1279
2. attach a dynamics block
 
 
1280
3. attach an alien data block
 
 
1281
4. initialise for far behaviour
 
 
1282
 
 
 
1283
NB the strategyblock passed here is a reference to the generator sb
 
 
1284
--------------------------------------------------------------------*/
 
 
1285
void CreateAlienDynamic(STRATEGYBLOCK *Generator, ALIEN_TYPE type_of_alien)
 
 
1286
{
 
 
1287
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien);
 
 
1288
 
 
 
1289
    if(NULL != sbPtr)
 
 
1290
    {
 
 
1291
        DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
1292
 
 
 
1293
        if(NULL != dynPtr)
 
 
1294
        {
 
 
1295
            sbPtr->DynPtr = dynPtr;
 
 
1296
            AssignNewSBName(sbPtr);
 
 
1297
            dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->dataptr)->Position;
 
 
1298
            CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
1299
            TransposeMatrixCH(&dynPtr->OrientMat);      
 
 
1300
            sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
 
 
1301
            make_new_alien(sbPtr, type_of_alien, ABS_Hunt, Generator);
 
 
1302
 
 
 
1303
            /* assert alien is starting as invisible */
 
 
1304
            assert(!ModuleCurrVisArray[sbPtr->containingModule->m_index]);
 
 
1305
        }
 
 
1306
        else
 
 
1307
        {
 
 
1308
            RemoveBehaviourStrategy(sbPtr);
 
 
1309
        }
 
 
1310
    }
 
 
1311
}
 
 
1312
 
 
 
1313
void MakeAlienFar(STRATEGYBLOCK *sbPtr)
 
 
1314
{
 
 
1315
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1316
    DestroyActiveObject(&sbPtr->DisplayBlock);
 
 
1317
 
 
 
1318
    if(alienStatusPointer->soundOnFire != SOUND_NOACTIVEINDEX)
 
 
1319
        Sound_Stop(alienStatusPointer->soundOnFire);                
 
 
1320
 
 
 
1321
    if(alienStatusPointer->sound_mouth != SOUND_NOACTIVEINDEX)
 
 
1322
        Sound_Stop(alienStatusPointer->sound_mouth);
 
 
1323
 
 
 
1324
    switch(alienStatusPointer->BehaviourState)
 
 
1325
    {
 
 
1326
        case ABS_Dormant:
 
 
1327
        case ABS_Awakening:
 
 
1328
        break;
 
 
1329
        default:
 
 
1330
            alienStatusPointer->BehaviourState = alienStatusPointer->Target ? ABS_Hunt : ABS_Wander;
 
 
1331
    }
 
 
1332
 
 
 
1333
    NPC_InitWanderData(&alienStatusPointer->wanderData);
 
 
1334
    alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;    
 
 
1335
    alienStatusPointer->current_attack = NULL;
 
 
1336
}
 
 
1337
 
 
 
1338
/*----------------------Patrick 7/11/96-----------------------------
 
 
1339
This function is used to initialise a riff-loaded in alien.
 
 
1340
-------------------------------------------------------------------*/
 
 
1341
void InitAlienBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
 
 
1342
{
 
 
1343
    TOOLS_DATA_ALIEN *toolsData = (TOOLS_DATA_ALIEN *)bhdata;
 
 
1344
    int i;
 
 
1345
 
 
 
1346
    /*
 
 
1347
    NB it is necessary that placed aliens are initialised without a
 
 
1348
    displayblock, otherwise far aliens will be re-initialised by
 
 
1349
    MakeAlienFar() to a hunting state instead of a wait state....*/            
 
 
1350
 
 
 
1351
    assert(!sbPtr->DisplayBlock);
 
 
1352
 
 
 
1353
    if(SinglePlayer == AvP.PlayMode)
 
 
1354
    {
 
 
1355
        for(i=0; i < SB_NAME_LENGTH; i++)
 
 
1356
            sbPtr->SBname[i] = toolsData->nameID[i];
 
 
1357
    }
 
 
1358
    else
 
 
1359
    {
 
 
1360
        //in a network game , generate a new sb name (so that it gets a reasonably low value)
 
 
1361
        AssignNewSBName(sbPtr);
 
 
1362
    }
 
 
1363
 
 
 
1364
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
1365
 
 
 
1366
    if(sbPtr->DynPtr)
 
 
1367
    {
 
 
1368
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1369
        dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
 
 
1370
        dynPtr->OrientEuler = toolsData->starteuler;
 
 
1371
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
1372
        TransposeMatrixCH(&dynPtr->OrientMat);      
 
 
1373
        sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN;
 
 
1374
 
 
 
1375
        if(make_new_alien(sbPtr, toolsData->type, ((toolsData->start_inactive) ? ABS_Dormant : ABS_Wait), NULL))
 
 
1376
        {
 
 
1377
            ALIEN_STATUS_BLOCK * alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
1378
 
 
 
1379
            for(i=0; i < SB_NAME_LENGTH; i++)
 
 
1380
                alienStatus->death_target_ID[i] = toolsData->death_target_ID[i];
 
 
1381
        }
 
 
1382
    }
 
 
1383
    else
 
 
1384
    {
 
 
1385
        RemoveBehaviourStrategy(sbPtr);
 
 
1386
    }
 
 
1387
}
 
 
1388
 
 
 
1389
static int PlayerIsDeadAndNoLivingNetghosts()
 
 
1390
{
 
 
1391
    if(SinglePlayer == AvP.PlayMode)
 
 
1392
    {
 
 
1393
        //just need to check for the only player we have
 
 
1394
        return !PlayerStatus.Alive || Observer;
 
 
1395
    }
 
 
1396
    else
 
 
1397
    {
 
 
1398
        int sbIndex = 0;
 
 
1399
        //first check the host player
 
 
1400
 
 
 
1401
        if(PlayerStatus.Alive || Observer)
 
 
1402
            return 0;
 
 
1403
 
 
 
1404
        /* go through the strategy blocks looking for players*/
 
 
1405
        for(; sbIndex < NumActiveStBlocks; sbIndex++)
 
 
1406
        {
 
 
1407
            STRATEGYBLOCK *playerSbPtr = ActiveStBlockList[sbIndex];
 
 
1408
 
 
 
1409
            if(playerSbPtr->type == I_BehaviourNetGhost)
 
 
1410
            {
 
 
1411
                NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->dataptr;
 
 
1412
 
 
 
1413
                switch(ghostData->type)
 
 
1414
                {
 
 
1415
                    case I_BehaviourMarinePlayer:
 
 
1416
                    case I_BehaviourPredatorPlayer:
 
 
1417
                        //found a netghost of a player
 
 
1418
                        return 0;
 
 
1419
                    default:
 
 
1420
                    break;
 
 
1421
                }
 
 
1422
            }
 
 
1423
        }
 
 
1424
    }
 
 
1425
 
 
 
1426
//Dead, all dead.
 
 
1427
return 1;
 
 
1428
}
 
 
1429
 
 
 
1430
static int Alien_TargetFilter(STRATEGYBLOCK *candidate, const ALIEN_STATUS_BLOCK *alienStatusPointer)
 
 
1431
{
 
 
1432
    switch (candidate->type)
 
 
1433
    {
 
 
1434
        case I_BehaviourFlare:
 
 
1435
            return (!alienStatusPointer->Wounds && !(FastRandom() & 3)); // this could be a trap from marine bot or marine player
 
 
1436
        case I_BehaviourMarine:
 
 
1437
        case I_BehaviourMarinePlayer:
 
 
1438
        case I_BehaviourPredatorPlayer:
 
 
1439
        case I_BehaviourPredator:
 
 
1440
        case I_BehaviourAutoGun:
 
 
1441
        //case I_BehaviourAlien:
 
 
1442
        case I_BehaviourCorpse:
 
 
1443
            return 1;
 
 
1444
        case I_BehaviourPlacedLight:
 
 
1445
        {
 
 
1446
            if((Standard == alienStatusPointer->Type) && alienStatusPointer->EnableWaypoints)
 
 
1447
            {
 
 
1448
                if(candidate->maintainVisibility || !candidate->DamageBlock.Indestructable)
 
 
1449
                {
 
 
1450
                    PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = (PLACED_LIGHT_BEHAV_BLOCK*)candidate->dataptr;
 
 
1451
 
 
 
1452
                    if(FastRandom() & 5)
 
 
1453
                        return ((Light_State_Broken != pl_bhv->state) && (Light_OnOff_Off != pl_bhv->on_off_state));
 
 
1454
                }
 
 
1455
            }
 
 
1456
        }
 
 
1457
        break;
 
 
1458
        case I_BehaviourNetGhost:
 
 
1459
        {
 
 
1460
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
1461
 
 
 
1462
            switch (dataptr->type) 
 
 
1463
            {
 
 
1464
                case I_BehaviourMarinePlayer:
 
 
1465
                case I_BehaviourPredatorPlayer:
 
 
1466
                    return 1;
 
 
1467
                default:
 
 
1468
                    return 0;
 
 
1469
            }
 
 
1470
        }
 
 
1471
        default:
 
 
1472
        return 0;
 
 
1473
    }
 
 
1474
return 0;
 
 
1475
}
 
 
1476
 
 
 
1477
struct alien_targets
 
 
1478
{
 
 
1479
    int distance;
 
 
1480
    STRATEGYBLOCK * target;
 
 
1481
};
 
 
1482
 
 
 
1483
static int AlienHasPathToTarget(STRATEGYBLOCK *sbPtr) 
 
 
1484
{
 
 
1485
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
1486
 
 
 
1487
    return (alienStatusPointer->Target != NULL) ? ( NULL != GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule,
alienStatusPointer->Target->containingModule->m_aimodule, 4, 1, 1)) : 0;
 
 
1488
    //return (alienStatusPointer->Target != NULL) ? ( NULL != GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule,
alienStatusPointer->Target->containingModule->m_aimodule, 7, 0, 1)) : 0;
 
 
1489
}
 
 
1490
 
 
 
1491
static int sort_targets(const void *void_a, const void *void_b)
 
 
1492
{
 
 
1493
    const struct alien_targets * a = void_a;
 
 
1494
    const struct alien_targets * b = void_b;
 
 
1495
 
 
 
1496
    return (a->distance < b->distance) ? -1 : (a->distance > b->distance);
 
 
1497
}
 
 
1498
 
 
 
1499
static STRATEGYBLOCK *Alien_GetNewTarget(const STRATEGYBLOCK *sbptr)
 
 
1500
{
 
 
1501
    struct alien_targets Targets[5] = { {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL} };
 
 
1502
    int neardist = ONE_FIXED;
 
 
1503
    STRATEGYBLOCK *nearest = NULL;
 
 
1504
    //MODULE *dmod = ModuleFromPosition(&sbptr->DynPtr->Position, PlayerStatus.sbptr->containingModule);
 
 
1505
    //MODULE *dmod = ModuleFromPosition(&sbptr->DynPtr->Position, NULL);
 
 
1506
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbptr->dataptr);    
 
 
1507
    int a;
 
 
1508
    int i = 0;
 
 
1509
    int wraps = 0;
 
 
1510
    const VECTORCH *alienpos = &sbptr->DynPtr->Position;
 
 
1511
 
 
 
1512
    for (a = 0; a < NumActiveStBlocks; a++)
 
 
1513
    {
 
 
1514
        STRATEGYBLOCK *candidate = ActiveStBlockList[a];
 
 
1515
 
 
 
1516
        if (Alien_TargetFilter(candidate, alienStatusPointer))
 
 
1517
        {
 
 
1518
            VECTORCH offset;
 
 
1519
 
 
 
1520
            offset.vx = alienpos->vx - candidate->DynPtr->Position.vx;
 
 
1521
            offset.vy = alienpos->vy - candidate->DynPtr->Position.vy;
 
 
1522
            offset.vz = alienpos->vz - candidate->DynPtr->Position.vz;
 
 
1523
 
 
 
1524
            int dist = Approximate3dMagnitude(&offset);
 
 
1525
 
 
 
1526
            if (dist < neardist)
 
 
1527
            {
 
 
1528
                //if (!NPC_IsDead(candidate) && AlienHasPathToTarget(sbptr) && IsModuleVisibleFromModule(dmod, candidate->containingModule))
 
 
1529
                if (!NPC_IsDead(candidate))// && IsModuleVisibleFromModule(dmod, candidate->containingModule))
 
 
1530
                {
 
 
1531
                    nearest = candidate;
 
 
1532
                    neardist = dist;
 
 
1533
 
 
 
1534
                    if(4 == i)
 
 
1535
                    {
 
 
1536
                        i = 0;
 
 
1537
                        wraps = 1;
 
 
1538
                    }
 
 
1539
 
 
 
1540
                    Targets[i].target = candidate;
 
 
1541
                    Targets[i].distance = dist;
 
 
1542
                    i++;
 
 
1543
                }
 
 
1544
            }
 
 
1545
        }
 
 
1546
    }
 
 
1547
 
 
 
1548
 
 
 
1549
return nearest;
 
 
1550
    if(nearest)
 
 
1551
    {
 
 
1552
        int numberofnear_marines = 0;
 
 
1553
        int numberofnear_aliens = 0;
 
 
1554
        int numberofnear_predators = 0;
 
 
1555
        int hiding_in_waiting = 0;
 
 
1556
 
 
 
1557
        if (!alienStatusPointer->CurrentLightAtAlien)
 
 
1558
            hiding_in_waiting = !DynamicObjectIsMoving(sbptr->DynPtr);
 
 
1559
 
 
 
1560
        switch (nearest->type)
 
 
1561
        {
 
 
1562
            case I_BehaviourMarine:
 
 
1563
            case I_BehaviourMarinePlayer:
 
 
1564
            case I_BehaviourPredator:
 
 
1565
            case I_BehaviourPredatorPlayer:
 
 
1566
            {
 
 
1567
                if(neardist < ALIEN_POUNCE_MAXRANGE)
 
 
1568
                {
 
 
1569
                    if (alienStatusPointer->Wounds && (alienStatusPointer->Type == Standard))
 
 
1570
                    {
 
 
1571
                        alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
1572
                        return NULL;
 
 
1573
                    }
 
 
1574
 
 
 
1575
                    return nearest;
 
 
1576
                }
 
 
1577
            }
 
 
1578
            default:
 
 
1579
            break;
 
 
1580
        }
 
 
1581
 
 
 
1582
        if (wraps)
 
 
1583
            i = 5;
 
 
1584
 
 
 
1585
        qsort(Targets, 5, sizeof(struct alien_targets), sort_targets);
 
 
1586
 
 
 
1587
        for (a = 0; a < i; a++)
 
 
1588
        {
 
 
1589
            if(NULL == Targets[a].target || (Targets[a].target == nearest))
 
 
1590
                continue;
 
 
1591
 
 
 
1592
            //printf("TARGETS type %d distance %d\n", Targets[a].target->type, Targets[a].distance);
 
 
1593
 
 
 
1594
            //if (alienStatusPointer->Wounds)
 
 
1595
            STRATEGYBLOCK *target = Targets[a].target;
 
 
1596
 
 
 
1597
            switch(target->type)
 
 
1598
            {
 
 
1599
                case I_BehaviourMarine:
 
 
1600
                case I_BehaviourMarinePlayer:
 
 
1601
                    numberofnear_marines++;
 
 
1602
 
 
 
1603
                    if (Targets[a].distance < ALIEN_POUNCE_MAXRANGE)
 
 
1604
                    {
 
 
1605
                        //if(hiding_in_waiting)
 
 
1606
                            return Targets[a].target;
 
 
1607
                    }
 
 
1608
                break;
 
 
1609
                case I_BehaviourPredatorPlayer:
 
 
1610
                case I_BehaviourPredator:
 
 
1611
                    numberofnear_predators++;
 
 
1612
 
 
 
1613
                    if (Targets[a].distance < ALIEN_POUNCE_MAXRANGE)
 
 
1614
                    {
 
 
1615
                        //if(hiding_in_waiting)
 
 
1616
                            return Targets[a].target;
 
 
1617
                    }
 
 
1618
                break;
 
 
1619
                case I_BehaviourPlacedLight:
 
 
1620
                    if(alienStatusPointer->CurrentLightAtAlien || alienStatusPointer->Wounds)
 
 
1621
                        return Targets[a].target;
 
 
1622
                break;
 
 
1623
                case I_BehaviourFlare:
 
 
1624
                {
 
 
1625
                    if (!alienStatusPointer->Wounds && !(FastRandom() & 3)) // this could be a trap from marine bot or marine player
 
 
1626
                    {
 
 
1627
                        alienStatusPointer->IAmCrouched = 0;
 
 
1628
                        return Targets[a].target;
 
 
1629
                    }
 
 
1630
                }
 
 
1631
                break;
 
 
1632
                case I_BehaviourAlien:
 
 
1633
                {
 
 
1634
                    ALIEN_STATUS_BLOCK *alien_friend = (ALIEN_STATUS_BLOCK *)(target->dataptr);    
 
 
1635
                    numberofnear_aliens++;
 
 
1636
 
 
 
1637
                    if(numberofnear_aliens > 3) // we have a cluster of aliens let's give alien cluster a target
 
 
1638
                    {
 
 
1639
                        STRATEGYBLOCK *chossen_target = NULL;
 
 
1640
                        neardist = ONE_FIXED;
 
 
1641
                        int x = 0;
 
 
1642
                        for (; x < NumActiveStBlocks; x++)
 
 
1643
                        {
 
 
1644
                            STRATEGYBLOCK *candidate = ActiveStBlockList[x];
 
 
1645
 
 
 
1646
                            if ((candidate != sbptr) && candidate->DynPtr)
 
 
1647
                            {
 
 
1648
                                switch (candidate->type)
 
 
1649
                                {
 
 
1650
                                    case I_BehaviourMarinePlayer:
 
 
1651
                                    case I_BehaviourPredatorPlayer:
 
 
1652
                                    case I_BehaviourMarine:
 
 
1653
                                    case I_BehaviourPredator:
 
 
1654
                                    {
 
 
1655
                                        VECTORCH offset;
 
 
1656
 
 
 
1657
                                        offset.vx = alienpos->vx - candidate->DynPtr->Position.vx;
 
 
1658
                                        offset.vy = alienpos->vy - candidate->DynPtr->Position.vy;
 
 
1659
                                        offset.vz = alienpos->vz - candidate->DynPtr->Position.vz;
 
 
1660
 
 
 
1661
                                        int dist = Approximate3dMagnitude(&offset);
 
 
1662
 
 
 
1663
                                        if (dist < neardist) 
 
 
1664
                                        {
 
 
1665
                                            if (!NPC_IsDead(candidate))// && IsModuleVisibleFromModule(dmod, candidate->containingModule)) 
 
 
1666
                                            {
 
 
1667
                                                chossen_target = candidate;
 
 
1668
                                                neardist = dist;
 
 
1669
                                            }
 
 
1670
                                        }
 
 
1671
                                    }
 
 
1672
                                    default:
 
 
1673
                                    break;
 
 
1674
                                }
 
 
1675
                            }
 
 
1676
                        }
 
 
1677
 
 
 
1678
                        if(chossen_target)
 
 
1679
                        {
 
 
1680
                            x=0;
 
 
1681
                            for (; x < i; x++)
 
 
1682
                            {
 
 
1683
                                ALIEN_STATUS_BLOCK *alien_friend = (ALIEN_STATUS_BLOCK *)(Targets[x].target->dataptr);    
 
 
1684
                                alien_friend->Target = chossen_target;
 
 
1685
                                //Targets[i].target
 
 
1686
                            }
 
 
1687
                            puts("realsing cluster");
 
 
1688
                        }
 
 
1689
 
 
 
1690
                        return nearest;
 
 
1691
                    }
 
 
1692
 
 
 
1693
                    //if(Targets[a].target->DynPtr->OrientMat.mat22 < 63000)
 
 
1694
                    if (!alien_friend->CurrentLightAtAlien && (NULL == alien_friend->Target))
 
 
1695
                    //if (NULL == alien_friend->Target)
 
 
1696
                    {
 
 
1697
                        // let's join up
 
 
1698
                        puts("let's join up");
 
 
1699
                        return Targets[a].target;
 
 
1700
                    }
 
 
1701
 
 
 
1702
                    if (alien_friend->Target)
 
 
1703
                    {
 
 
1704
                        switch (alien_friend->Target->type)
 
 
1705
                        {
 
 
1706
                            case I_BehaviourMarinePlayer:
 
 
1707
                            case I_BehaviourPredatorPlayer:
 
 
1708
                            case I_BehaviourPredator:
 
 
1709
                            case I_BehaviourAutoGun:
 
 
1710
                                return Targets[a].target;
 
 
1711
                            default:
 
 
1712
                            break;
 
 
1713
                        }
 
 
1714
                    }
 
 
1715
                }
 
 
1716
                default:
 
 
1717
                break;
 
 
1718
            }
 
 
1719
        }
 
 
1720
 
 
 
1721
        if(1 == numberofnear_aliens)
 
 
1722
        {
 
 
1723
            if((numberofnear_marines > 2) || numberofnear_predators)
 
 
1724
            {
 
 
1725
                alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
1726
                return NULL;
 
 
1727
            }
 
 
1728
        }
 
 
1729
        else if (numberofnear_aliens > 2)
 
 
1730
        {
 
 
1731
            //if(I_BehaviourPlacedLight == nearest->type)
 
 
1732
            a = 0;
 
 
1733
            for (; a < i; a++)
 
 
1734
            {
 
 
1735
                switch(Targets[a].target->type)
 
 
1736
                {
 
 
1737
                    case I_BehaviourPlacedLight:
 
 
1738
                        return Targets[a].target;
 
 
1739
                    default:
 
 
1740
                    break;
 
 
1741
                }
 
 
1742
            }
 
 
1743
        }
 
 
1744
        else if (numberofnear_predators && (numberofnear_aliens < 2))
 
 
1745
        {
 
 
1746
        }
 
 
1747
    }
 
 
1748
 
 
 
1749
return nearest;
 
 
1750
}
 
 
1751
 
 
 
1752
/*--------------------Patrick 27/1/97----------------------
 
 
1753
  This function is used by the various far alien behaviour 
 
 
1754
  functions to move an alien NPC: it decides whether and how 
 
 
1755
  to move an alien into a given target.
 
 
1756
 
 
 
1757
  2/7/97 extra bit:
 
 
1758
  If a location fails, we flip the y-orientation of the npc,
 
 
1759
  so that wandering behaviour can find a new path;
 
 
1760
  ----------------------------------------------------------*/
 
 
1761
 
 
 
1762
static int ProcessFarAlienTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
 
 
1763
{
 
 
1764
    VECTORCH oldPos = sbPtr->DynPtr->Position;
 
 
1765
 
 
 
1766
    /* get the target module's status, and decide what to do */
 
 
1767
    switch(GetTargetAIModuleStatus(sbPtr, targetModule, 1))
 
 
1768
    {
 
 
1769
        case NPCTM_NoEntryPoint:
 
 
1770
        {
 
 
1771
            /* do nothing: can't get in. */
 
 
1772
            FarNpc_FlipAround(sbPtr);
 
 
1773
            //entryPointFailures++;
 
 
1774
        }
 
 
1775
        break;
 
 
1776
        case NPCTM_NormalRoom:
 
 
1777
        case NPCTM_LiftDoorOpen:
 
 
1778
        case NPCTM_ProxDoorOpen:
 
 
1779
        case NPCTM_AirDuct:
 
 
1780
        case NPCTM_SecurityDoorOpen:
 
 
1781
            /* locate to target    */
 
 
1782
            LocateFarNPCInAIModule(sbPtr, targetModule);
 
 
1783
        break;
 
 
1784
        case NPCTM_ProxDoorNotOpen:
 
 
1785
        {
 
 
1786
            MODULE *renderModule = *(targetModule->m_module_ptrs);
 
 
1787
            /* trigger the door, and set timer to quick so we can catch the door when it's open */
 
 
1788
            ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->dataptr)->alienTrigger = 1;
 
 
1789
        break;
 
 
1790
        }
 
 
1791
        case NPCTM_LiftTeleport: /* do nothing: aliens can't use lifts */
 
 
1792
        case NPCTM_LiftDoorNotOpen:
 
 
1793
        case NPCTM_SecurityDoorNotOpen:
 
 
1794
            /*  do nothing - well, there's nothing we can do, really*/
 
 
1795
            FarNpc_FlipAround(sbPtr);
 
 
1796
           break;
 
 
1797
        default:
 
 
1798
        {
 
 
1799
            assert(1==0);
 
 
1800
        }
 
 
1801
    }
 
 
1802
 
 
 
1803
    /* Now, deduce how far it's moved... */
 
 
1804
    oldPos.vx -= sbPtr->DynPtr->Position.vx;
 
 
1805
    oldPos.vy -= sbPtr->DynPtr->Position.vy;
 
 
1806
    oldPos.vz -= sbPtr->DynPtr->Position.vz;
 
 
1807
 
 
 
1808
    {
 
 
1809
        int distance = Approximate3dMagnitude(&oldPos);
 
 
1810
        /* How long? */
 
 
1811
 
 
 
1812
        return !distance ? ALIEN_FAR_MOVE_TIME : DIV_FIXED(distance, (ALIEN_FORWARDVELOCITY >> 1));
 
 
1813
    }
 
 
1814
}
 
 
1815
 
 
 
1816
void Alien_Awaken(STRATEGYBLOCK *sbPtr) 
 
 
1817
{
 
 
1818
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);        
 
 
1819
 
 
 
1820
    alienStatusPointer->BehaviourState = ABS_Awakening;
 
 
1821
    SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienStand, ASSS_Unfurl, -1, (ONE_FIXED>>2));
 
 
1822
    alienStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
1823
}
 
 
1824
 
 
 
1825
/*----------------------Patrick 7/11/96-----------------------------
 
 
1826
AI alien behaviour execution shell:
 
 
1827
 
 
 
1828
1. patch to trap aliens who's current module is not set (and set it).
 
 
1829
2. call the visibility checking function.
 
 
1830
3. select either near or far behaviour functions.
 
 
1831
 
 
 
1832
NB the visibility checking function initialises near/far behaviour and
 
 
1833
allocates/deallocates displayblock based on changes in visibility
 
 
1834
for the alien's module.  This will, in due course, be invoked by a
 
 
1835
call back function from the module handler.
 
 
1836
--------------------------------------------------------------------*/
 
 
1837
 
 
 
1838
int AlienIsAwareOfTarget(STRATEGYBLOCK *sbPtr)
 
 
1839
{
 
 
1840
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
1841
 
 
 
1842
    if (alienStatusPointer->Target != NULL)
 
 
1843
    {
 
 
1844
        assert(alienStatusPointer->Target->containingModule);
 
 
1845
 
 
 
1846
        switch(alienStatusPointer->Target->type)
 
 
1847
        {
 
 
1848
            case I_BehaviourMarinePlayer:
 
 
1849
            case I_BehaviourPredatorPlayer:
 
 
1850
                //return PlayerStatus.Alive;
 
 
1851
            default:
 
 
1852
                return IsModuleVisibleFromModule(sbPtr->containingModule, alienStatusPointer->Target->containingModule);
 
 
1853
        }
 
 
1854
    }
 
 
1855
 
 
 
1856
return 0;
 
 
1857
}
 
 
1858
 
 
 
1859
/*
 
 
1860
        if(alienStatusPointer->Type == Standard)
 
 
1861
        {
 
 
1862
            alienStatusPointer->CurrentLightAtAlien = LightIntensityAtPoint(&sbPtr->DynPtr->Position);
 
 
1863
 
 
 
1864
            printf("alienStatusPointer->BehaviourState %d\n", alienStatusPointer->BehaviourState);
 
 
1865
 
 
 
1866
            switch(alienStatusPointer->BehaviourState)
 
 
1867
            {
 
 
1868
                case ABS_Approach:
 
 
1869
                {
 
 
1870
                    if (!alienStatusPointer->CurrentLightAtAlien && alienStatusPointer->IAmCrouched &&
(sbPtr->DynPtr->OrientMat.mat22 < 63000))
 
 
1871
                    {
 
 
1872
                        switch(alienStatusPointer->Target->type)
 
 
1873
                        {
 
 
1874
                            case I_BehaviourAlien:
 
 
1875
                            {
 
 
1876
                                int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position);
 
 
1877
 
 
 
1878
                                if(distance_to_target < ALIEN_POUNCE_MAXRANGE)
 
 
1879
                                {
 
 
1880
                                    alienStatusPointer->BehaviourState = ABS_Wait;
 
 
1881
                                }
 
 
1882
                            }
 
 
1883
                            break;
 
 
1884
                            case I_BehaviourPlacedLight:
 
 
1885
                            {
 
 
1886
                                alienStatusPointer->BehaviourState = ABS_Wait;
 
 
1887
                                //alienStatusPointer->Target = NULL;
 
 
1888
                            }
 
 
1889
                            break;
 
 
1890
                            default:
 
 
1891
                            {
 
 
1892
                                int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position);
 
 
1893
                                int target_previous_distance = VectorDistance(&alienStatusPointer->Target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position);
 
 
1894
                                printf("hunt Distance to Target %d\n", distance_to_target);
 
 
1895
 
 
 
1896
                                if(target_previous_distance > distance_to_target)
 
 
1897
                                {
 
 
1898
                                    alienStatusPointer->BehaviourState = ABS_Wait;
 
 
1899
                                }
 
 
1900
                                else
 
 
1901
                                {
 
 
1902
                                    if((distance_to_target - target_previous_distance) > ALIEN_POUNCE_MAXRANGE*2)
 
 
1903
                                        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
1904
                                    else
 
 
1905
                                        alienStatusPointer->BehaviourState = ((FastRandom() & 65535) > 20000) ? ABS_Approach : ABS_Wait;
 
 
1906
                                }
 
 
1907
                            }
 
 
1908
                        }
 
 
1909
                    }
 
 
1910
                }
 
 
1911
                break;
 
 
1912
                case ABS_Wait:
 
 
1913
                {
 
 
1914
                    if(alienStatusPointer->CurrentLightAtAlien)
 
 
1915
                    {
 
 
1916
                        if(alienStatusPointer->Target)
 
 
1917
                        {
 
 
1918
                            int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position);
 
 
1919
                            printf("wait Distance to Target %d\n", distance_to_target);
 
 
1920
 
 
 
1921
                            if(distance_to_target < ALIEN_ATTACKDISTANCE_MAX)
 
 
1922
                            {
 
 
1923
                                alienStatusPointer->BehaviourState = ABS_Attack;
 
 
1924
                            }
 
 
1925
                            else
 
 
1926
                            {
 
 
1927
                                if ((FastRandom() & 65535) < 24000)
 
 
1928
                                {
 
 
1929
                                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
1930
                                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
1931
                                }
 
 
1932
                                else
 
 
1933
                                {
 
 
1934
                                    alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
1935
                                }
 
 
1936
                            }
 
 
1937
                        }
 
 
1938
                        else
 
 
1939
                        {
 
 
1940
                            alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
1941
                            alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
1942
                        }
 
 
1943
                    }
 
 
1944
                    else
 
 
1945
                    {
 
 
1946
                        int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position, &alienStatusPointer->Target->DynPtr->Position);
 
 
1947
                        printf("Distance to Target %d\n", distance_to_target);
 
 
1948
 
 
 
1949
                        if (distance_to_target < ALIEN_POUNCE_MAXRANGE)
 
 
1950
                        {
 
 
1951
                            if(distance_to_target < ALIEN_ATTACKDISTANCE_MAX)
 
 
1952
                            {
 
 
1953
                                alienStatusPointer->BehaviourState = ABS_Attack;
 
 
1954
                            }
 
 
1955
                            else
 
 
1956
                            {
 
 
1957
                                //if ((FastRandom() & 127) < 80) AlienRandomHiss(sbPtr);
 
 
1958
                            }
 
 
1959
                        }
 
 
1960
                        else
 
 
1961
                        {
 
 
1962
                            int target_previous_distance = VectorDistance(&alienStatusPointer->Target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position);
 
 
1963
 
 
 
1964
                            if(target_previous_distance < distance_to_target)
 
 
1965
                            {
 
 
1966
                                alienStatusPointer->BehaviourState = ABS_Wait;
 
 
1967
                            }
 
 
1968
                            else
 
 
1969
                            {
 
 
1970
                                alienStatusPointer->BehaviourState = ((FastRandom() & 65535) < 25000) ? ABS_Approach : ABS_Wait;
 
 
1971
                            }
 
 
1972
                        }
 
 
1973
                    }
 
 
1974
                }
 
 
1975
                break;
 
 
1976
                case ABS_Wander:
 
 
1977
                    if (!alienStatusPointer->CurrentLightAtAlien && alienStatusPointer->IAmCrouched &&
(sbPtr->DynPtr->OrientMat.mat22 < 63000))
 
 
1978
                            alienStatusPointer->BehaviourState = ABS_Wait;
 
 
1979
                default:
 
 
1980
                break;
 
 
1981
            }
 
 
1982
        }
 
 
1983
        */
 
 
1984
 
 
 
1985
static void NearAlienBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1986
{
 
 
1987
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1988
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
1989
 
 
 
1990
    InitWaypointSystem(alienStatusPointer->EnableWaypoints);
 
 
1991
 
 
 
1992
    switch(alienStatusPointer->BehaviourState)
 
 
1993
    {
 
 
1994
        case ABS_Approach:
 
 
1995
        {
 
 
1996
            VECTORCH targetPos;
 
 
1997
 
 
 
1998
            if (NULL == alienStatusPointer->Target)
 
 
1999
            {
 
 
2000
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2001
                alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
2002
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2003
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2004
                return;
 
 
2005
            }
 
 
2006
 
 
 
2007
            int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position);
 
 
2008
 
 
 
2009
            if(NPCCanSeeTarget(sbPtr, alienStatusPointer->Target))
 
 
2010
            {
 
 
2011
                if(distance_to_target < ALIEN_POUNCE_STARTMAXRANGE)
 
 
2012
                {
 
 
2013
                    if (distance_to_target > ALIEN_POUNCE_MINRANGE)
 
 
2014
                    {
 
 
2015
                        int EnablePounce = 0;
 
 
2016
 
 
 
2017
                        if(alienStatusPointer->incidentFlag)
 
 
2018
                        {
 
 
2019
                            switch(alienStatusPointer->Type)
 
 
2020
                            {
 
 
2021
                                case Standard:
 
 
2022
                                default:
 
 
2023
                                    EnablePounce = ((FastRandom() % 65535) < 16384);
 
 
2024
                                break;
 
 
2025
                                case Predalien:
 
 
2026
                                case Praetorian:
 
 
2027
                                    EnablePounce = ((FastRandom() % 65535) > 16384);
 
 
2028
                            }
 
 
2029
                        }
 
 
2030
 
 
 
2031
                        if ((EnablePounce || Alien_Special_Pounce_Condition(sbPtr)) && StartAlienPounce(sbPtr))
 
 
2032
                            return; // Success.
 
 
2033
                    }
 
 
2034
                    else if (distance_to_target < ALIEN_ATTACKDISTANCE_MIN)
 
 
2035
                    {
 
 
2036
                        alienStatusPointer->BehaviourState = ABS_Attack;
 
 
2037
                        return;
 
 
2038
                    }
 
 
2039
                }
 
 
2040
                else if ((distance_to_target < 30000) && !sbPtr->DamageBlock.IsOnFire)
 
 
2041
                {
 
 
2042
                    /* Hang on, should we be doing this? */
 
 
2043
                    if ((dynPtr->OrientMat.mat22 >= 63000) && dynPtr->IsInContactWithFloor)
 
 
2044
                    {
 
 
2045
                        /* 150% flamethrower 'range'. */
 
 
2046
                        if(TargetIsFiringFlamethrowerAtAlien(sbPtr, distance_to_target))
 
 
2047
                            return;
 
 
2048
                    }
 
 
2049
                }
 
 
2050
 
 
 
2051
            }
 
 
2052
            else if (alienStatusPointer->incidentFlag)
 
 
2053
            {
 
 
2054
                STRATEGYBLOCK *new_target = Alien_GetNewTarget(sbPtr);
 
 
2055
 
 
 
2056
                if((NULL != new_target) && (new_target != alienStatusPointer->Target))
 
 
2057
                {
 
 
2058
                    switch (new_target->type)
 
 
2059
                    {
 
 
2060
                        case I_BehaviourFlare:
 
 
2061
                            alienStatusPointer->IAmCrouched = 1;
 
 
2062
                        case I_BehaviourPlacedLight:
 
 
2063
                        case I_BehaviourMarine:
 
 
2064
                        case I_BehaviourMarinePlayer:
 
 
2065
                            alienStatusPointer->Target = new_target;
 
 
2066
                        default:
 
 
2067
                        break;
 
 
2068
                    }
 
 
2069
 
 
 
2070
                    if (alienStatusPointer->Target != NULL) 
 
 
2071
                    {
 
 
2072
                        COPY_NAME(alienStatusPointer->Target_SBname, alienStatusPointer->Target->SBname);
 
 
2073
                        alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
2074
                    }
 
 
2075
                }
 
 
2076
            }
 
 
2077
 
 
 
2078
            if(alienStatusPointer->incidentFlag)
 
 
2079
            {
 
 
2080
                if (dynPtr->IsInContactWithFloor || dynPtr->IsInContactWithNearlyFlatFloor)
 
 
2081
                if(alienStatusPointer->CanStand && alienStatusPointer->CanClimb && (Standard == alienStatusPointer->Type) &&
((FastRandom() & 65535) < 10000))
 
 
2082
                {
 
 
2083
                    VECTORCH normal = sbPtr->DynPtr->GravityDirection;;
 
 
2084
                    normal.vx *= -1;
 
 
2085
                    normal.vy *= -1;
 
 
2086
                    normal.vz *= -1;
 
 
2087
 
 
 
2088
                    //MakeParticle(&sbPtr->DynPtr->Position, &normal, PARTICLE_PLASMATRAIL);
 
 
2089
 
 
 
2090
                    if(FindPolygonInLineOfSight(&normal, &sbPtr->DynPtr->Position, sbPtr->DisplayBlock))
 
 
2091
                    {
 
 
2092
                        if((NULL == LOS_ObjectHitPtr->ObStrategyBlock)
 
 
2093
                        || (LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock && LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->Module))
 
 
2094
                        {
 
 
2095
                            if ((LOS_Lambda > 2500) && (LOS_Lambda < 10000))
 
 
2096
                            {
 
 
2097
                                dynPtr->TimeNotInContactWithFloor = 0;
 
 
2098
                                dynPtr->UseStandardGravity = 1;
 
 
2099
                                alienStatusPointer->IAmCrouched = 1;
 
 
2100
                                dynPtr->LinImpulse.vx += MUL_FIXED(normal.vx, ALIEN_JUMPVELOCITY*3);
 
 
2101
                                dynPtr->LinImpulse.vy += MUL_FIXED(normal.vy, ALIEN_JUMPVELOCITY*3);
 
 
2102
                                dynPtr->LinImpulse.vz += MUL_FIXED(normal.vz, ALIEN_JUMPVELOCITY*3);
 
 
2103
                                alienStatusPointer->BehaviourState = ABS_Jump;
 
 
2104
                                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Jump, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
2105
                                return;
 
 
2106
                            }
 
 
2107
                        }
 
 
2108
                    }
 
 
2109
                }
 
 
2110
 
 
 
2111
                switch (alienStatusPointer->Type)
 
 
2112
                {
 
 
2113
                    case Standard:
 
 
2114
                        if (((FastRandom() & 65535) < ALIEN_JUMPINESS) && GoToJump(sbPtr))
 
 
2115
                            return; // Boop!
 
 
2116
                    break;
 
 
2117
                    case Predalien:
 
 
2118
                        if (((FastRandom() & 65535) < PREDALIEN_JUMPINESS) && GoToJump(sbPtr))
 
 
2119
                            return; // Boop!
 
 
2120
                    break;
 
 
2121
                    case Praetorian:
 
 
2122
                        if (((FastRandom() & 65535) < PRAETORIAN_JUMPINESS) && GoToJump(sbPtr))
 
 
2123
                            return; // Boop!
 
 
2124
                }
 
 
2125
            }
 
 
2126
 
 
 
2127
            AlienHandleMovingAnimation(sbPtr);
 
 
2128
 
 
 
2129
            /* target acquisition ? */
 
 
2130
            /* Never curve in a waypoint module, you might hurt yourself. */
 
 
2131
            if((distance_to_target < ALIEN_CURVETOPLAYERDIST) && (NULL == sbPtr->containingModule->m_aimodule->m_waypoints))
 
 
2132
            {
 
 
2133
                GetTargetingPointOfObject_Far(alienStatusPointer->Target, &targetPos);
 
 
2134
 
 
 
2135
                //printf("curving alien \n");
 
 
2136
                /* translate target into alien's local space */
 
 
2137
 
 
 
2138
                {
 
 
2139
                    MATRIXCH toLocalSpaceMatrix = dynPtr->OrientMat;
 
 
2140
                    TransposeMatrixCH(&toLocalSpaceMatrix);
 
 
2141
 
 
 
2142
                    targetPos.vx -= dynPtr->Position.vx;
 
 
2143
                    targetPos.vy -= dynPtr->Position.vy;
 
 
2144
                    targetPos.vz -= dynPtr->Position.vz;
 
 
2145
                    RotateVector(&targetPos, &toLocalSpaceMatrix);
 
 
2146
                }
 
 
2147
 
 
 
2148
                /* tracking movement */
 
 
2149
 
 
 
2150
                if (dynPtr->IsInContactWithFloor)
 
 
2151
                {
 
 
2152
                    int distanceToTarget = Magnitude(&targetPos);
 
 
2153
 
 
 
2154
                    if (alienStatusPointer->CurveTimeOut <= 0)
 
 
2155
                    {
 
 
2156
                        alienStatusPointer->CurveLength = distanceToTarget;
 
 
2157
                        alienStatusPointer->CurveRadius = ((FastRandom() & 16383) - 8192) * 2;
 
 
2158
                        alienStatusPointer->CurveTimeOut= ONE_FIXED * 3;
 
 
2159
                    }
 
 
2160
                    else
 
 
2161
                    {
 
 
2162
                        alienStatusPointer->CurveTimeOut -= NormalFrameTime;
 
 
2163
                    }
 
 
2164
 
 
 
2165
                    int offset = MUL_FIXED(alienStatusPointer->CurveRadius, GetCos((1024*(distanceToTarget)/alienStatusPointer->CurveLength)&4095));
 
 
2166
 
 
 
2167
                    dynPtr->LinVelocity.vx = 
 
 
2168
                        WideMulNarrowDiv(alienStatusPointer->MaxSpeed, targetPos.vx, distanceToTarget)
 
 
2169
                        -
 
 
2170
                        WideMulNarrowDiv(offset, targetPos.vz, distanceToTarget);
 
 
2171
 
 
 
2172
                    dynPtr->LinVelocity.vz =
 
 
2173
                        WideMulNarrowDiv ( alienStatusPointer->MaxSpeed, targetPos.vz, distanceToTarget)
 
 
2174
                        +
 
 
2175
                        WideMulNarrowDiv ( offset, targetPos.vx, distanceToTarget);
 
 
2176
 
 
 
2177
                    if (!dynPtr->UseStandardGravity && (sbPtr->containingModule == PlayerStatus.sbptr->containingModule))
 
 
2178
                    {
 
 
2179
                        //VECTORCH velocityDirection=dynPtr->LinVelocity;
 
 
2180
                        VECTORCH velocityDirection;
 
 
2181
                        GetTargetingPointOfObject_Far(alienStatusPointer->Target, &velocityDirection);
 
 
2182
                        velocityDirection.vx -= dynPtr->Position.vx;
 
 
2183
                        velocityDirection.vy -= dynPtr->Position.vy;
 
 
2184
                        velocityDirection.vz -= dynPtr->Position.vz;
 
 
2185
 
 
 
2186
                        Normalise(&velocityDirection);
 
 
2187
 
 
 
2188
                        if(DotProduct(&dynPtr->GravityDirection, &velocityDirection) < -60000)
 
 
2189
                        {
 
 
2190
                            /* patrick 29/7/97: I have added the extra condition of not being in the same module as
 
 
2191
                            the player, so that alien does not jump at entry-points */
 
 
2192
                            dynPtr->TimeNotInContactWithFloor = 0;
 
 
2193
                            dynPtr->UseStandardGravity = 1;
 
 
2194
                            dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx, ALIEN_JUMPVELOCITY);
 
 
2195
                            dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy, ALIEN_JUMPVELOCITY);
 
 
2196
                            dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz, ALIEN_JUMPVELOCITY);
 
 
2197
                        }
 
 
2198
                    }
 
 
2199
 
 
 
2200
                    RotateVector(&dynPtr->LinVelocity, &dynPtr->OrientMat);
 
 
2201
 
 
 
2202
                    /* align to velocity */
 
 
2203
                    NPCOrientateToVector(sbPtr, &dynPtr->LinVelocity, NPC_TURNRATE);
 
 
2204
                }
 
 
2205
            }
 
 
2206
            else
 
 
2207
            {
 
 
2208
                int approachingAirDuct = 0;
 
 
2209
                NPCGetMovementTarget(sbPtr, alienStatusPointer->Target, &targetPos, &approachingAirDuct, 1);
 
 
2210
 
 
 
2211
                /* use standard NPC direction finding... */
 
 
2212
                VECTORCH velocityDirection = {0,0,0};
 
 
2213
 
 
 
2214
                NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPos, (alienStatusPointer->EnableWaypoints ?
&alienStatusPointer->waypointManager : NULL));
 
 
2215
 
 
 
2216
                NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed);
 
 
2217
                alienStatusPointer->CurveTimeOut = 0; /* forces curve init next time curving is used */
 
 
2218
 
 
 
2219
                /* Consider ripping off the wall. */
 
 
2220
                if (!dynPtr->UseStandardGravity && (distance_to_target < ALIEN_POUNCE_MAXRANGE))
 
 
2221
                {
 
 
2222
                    if (DotProduct(&dynPtr->GravityDirection, &velocityDirection) < -60000)
 
 
2223
                    {
 
 
2224
                        dynPtr->TimeNotInContactWithFloor = 0;
 
 
2225
                        dynPtr->UseStandardGravity = 1;
 
 
2226
                        dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx, ALIEN_JUMPVELOCITY);
 
 
2227
                        dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy, ALIEN_JUMPVELOCITY);
 
 
2228
                        dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz, ALIEN_JUMPVELOCITY);
 
 
2229
                        return;
 
 
2230
                    }
 
 
2231
                }
 
 
2232
            }
 
 
2233
 
 
 
2234
            if ((dynPtr->IsInContactWithFloor || dynPtr->IsInContactWithNearlyFlatFloor) && (dynPtr->OrientMat.mat22 < 63000))
 
 
2235
            if(alienStatusPointer->CanStand && alienStatusPointer->CanClimb && (Standard == alienStatusPointer->Type) &&
((FastRandom() & 65535) > 40000))
 
 
2236
            {
 
 
2237
                VECTORCH offset;
 
 
2238
                offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx;
 
 
2239
                offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy;
 
 
2240
                offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz;
 
 
2241
 
 
 
2242
                int speed = Magnitude(&offset);
 
 
2243
 
 
 
2244
                if (speed < (MUL_FIXED(NormalFrameTime, 100)))
 
 
2245
                {
 
 
2246
                    VECTORCH sight_vec;
 
 
2247
                    sight_vec.vx = sbPtr->DynPtr->OrientMat.mat31;
 
 
2248
                    sight_vec.vy = sbPtr->DynPtr->OrientMat.mat32;
 
 
2249
                    sight_vec.vz = sbPtr->DynPtr->OrientMat.mat33;
 
 
2250
                    SECTION_DATA *head_sec = GetThisSectionData(alienStatusPointer->HModelController.section_data, "head");
 
 
2251
                    assert(head_sec);
 
 
2252
 
 
 
2253
                    if(FindPolygonInLineOfSight(&sight_vec, &head_sec->World_Offset, sbPtr->DisplayBlock))
 
 
2254
                    {
 
 
2255
                        if((NULL == LOS_ObjectHitPtr->ObStrategyBlock) || (LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock &&
LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->Module))
 
 
2256
                        {
 
 
2257
                            if ((LOS_Lambda > 2500) && (LOS_Lambda < 10000))
 
 
2258
                            {
 
 
2259
                                dynPtr->TimeNotInContactWithFloor = 0;
 
 
2260
                                dynPtr->UseStandardGravity = 1;
 
 
2261
                                dynPtr->LinImpulse.vx += MUL_FIXED(sight_vec.vx, ALIEN_JUMPVELOCITY*3);
 
 
2262
                                dynPtr->LinImpulse.vy += MUL_FIXED(sight_vec.vy, ALIEN_JUMPVELOCITY*3);
 
 
2263
                                dynPtr->LinImpulse.vz += MUL_FIXED(sight_vec.vz, ALIEN_JUMPVELOCITY*3);
 
 
2264
                                alienStatusPointer->BehaviourState = ABS_Jump;
 
 
2265
                                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Jump, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
2266
                                return;
 
 
2267
                            }
 
 
2268
 
 
 
2269
                        }
 
 
2270
                    }
 
 
2271
                }
 
 
2272
            }
 
 
2273
 
 
 
2274
            /* test here for impeding collisions, and not being able to reach target... */
 
 
2275
            {
 
 
2276
                STRATEGYBLOCK *destructableObject = NULL;
 
 
2277
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
2278
 
 
 
2279
                NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction, &destructableObject);
 
 
2280
 
 
 
2281
                if(obstruction.environment)
 
 
2282
                {
 
 
2283
                    if(!alienStatusPointer->IAmCrouched && (Praetorian != alienStatusPointer->Type))
 
 
2284
                    {
 
 
2285
                        alienStatusPointer->IAmCrouched = 1;
 
 
2286
                    }
 
 
2287
                    else
 
 
2288
                    {
 
 
2289
                        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2290
                        NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
2291
                        alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2292
                        alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2293
                    }
 
 
2294
                return;
 
 
2295
                }
 
 
2296
                else if(obstruction.destructableObject)
 
 
2297
                {
 
 
2298
                    assert(destructableObject);
 
 
2299
                    CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL);
 
 
2300
 
 
 
2301
                }
 
 
2302
                else if (obstruction.anySingleObstruction && !obstruction.otherCharacter)
 
 
2303
                {
 
 
2304
                    /* Try for a nearer target? */
 
 
2305
                    //alienStatusPointer->Target = NULL;
 
 
2306
                }
 
 
2307
            }
 
 
2308
 
 
 
2309
            {
 
 
2310
                VECTORCH velocityDirection = dynPtr->LinVelocity;
 
 
2311
                Normalise(&velocityDirection);
 
 
2312
 
 
 
2313
                if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &targetPos, &velocityDirection))
 
 
2314
                {
 
 
2315
                    NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
2316
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2317
                    NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);                        
 
 
2318
                    alienStatusPointer->BehaviourState = ABS_Avoidance;          
 
 
2319
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME * 2;
 
 
2320
                }
 
 
2321
            }
 
 
2322
        }
 
 
2323
        break;
 
 
2324
        case ABS_Attack:
 
 
2325
        {
 
 
2326
            //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr);
 
 
2327
 
 
 
2328
            /* patrick 13/6/97: a little addition: Orientate towards player, just to make sure we're facing */
 
 
2329
            if (dynPtr->UseStandardGravity)
 
 
2330
            {
 
 
2331
                if(alienStatusPointer->CanStand)
 
 
2332
                    alienStatusPointer->IAmCrouched = 0;
 
 
2333
 
 
 
2334
                VECTORCH orientationDirn;
 
 
2335
                orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
2336
                orientationDirn.vy = 0;
 
 
2337
                orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
2338
                int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
2339
            }
 
 
2340
            else
 
 
2341
            {
 
 
2342
                /* Replace this! */
 
 
2343
                VECTORCH orientationDirn;
 
 
2344
                orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
2345
                orientationDirn.vy = alienStatusPointer->Target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy;
 
 
2346
                orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
2347
 
 
 
2348
                int dot = -DotProduct(&dynPtr->GravityDirection, &orientationDirn);
 
 
2349
                /* Hold that thought. */
 
 
2350
                orientationDirn.vx -= MUL_FIXED(dot, dynPtr->GravityDirection.vx);
 
 
2351
                orientationDirn.vy -= MUL_FIXED(dot, dynPtr->GravityDirection.vy);
 
 
2352
                orientationDirn.vz -= MUL_FIXED(dot, dynPtr->GravityDirection.vz);
 
 
2353
 
 
 
2354
                int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
2355
            }
 
 
2356
 
 
 
2357
            int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position);
 
 
2358
 
 
 
2359
            if(distance_to_target > ALIEN_ATTACKDISTANCE_MAX)
 
 
2360
            {
 
 
2361
                alienStatusPointer->current_attack = NULL;
 
 
2362
                if(alienStatusPointer->Wounds && ((FastRandom() & 127) < 10))
 
 
2363
                {
 
 
2364
                    StartAlienTaunt(sbPtr);
 
 
2365
                }
 
 
2366
                else if(0)//if((Standard == alienStatusPointer->Type) && dynPtr->UseStandardGravity && alienStatusPointer->CanStand)
 
 
2367
                {
 
 
2368
                    //if(DynamicObjectIsMoving(alienStatusPointer->Target->DynPtr))
 
 
2369
                    {
 
 
2370
                        //if ((HMSQT_AlienRun != alienStatusPointer->HModelController.Sequence_Type) && (ARSS_Attack_Swipe !=
alienStatusPointer->HModelController.Sub_Sequence))
 
 
2371
                        extern ATTACK_DATA Alien_Attacks[];
 
 
2372
                        SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Attack_Swipe, ONE_FIXED >> 1, (ONE_FIXED >> 3));
 
 
2373
                        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2374
                        InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2375
                        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2376
                        alienStatusPointer->StateTimer = 0;
 
 
2377
                        alienStatusPointer->CurveTimeOut = 0;
 
 
2378
                        alienStatusPointer->current_attack = &Alien_Attacks[12]; // does not matter unless it's NULL
 
 
2379
                    }
 
 
2380
                }
 
 
2381
                else
 
 
2382
                {
 
 
2383
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2384
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2385
                    alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2386
                    alienStatusPointer->StateTimer = 0;
 
 
2387
                    alienStatusPointer->CurveTimeOut = 0;
 
 
2388
                    alienStatusPointer->current_attack = NULL;
 
 
2389
                }
 
 
2390
            }
 
 
2391
            else if (NULL == alienStatusPointer->current_attack)
 
 
2392
            {
 
 
2393
                StartAlienAttackSequence(sbPtr);
 
 
2394
            }
 
 
2395
            else
 
 
2396
            {
 
 
2397
                /* alien can inflict nastiness on the target */
 
 
2398
                alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
2399
                AlienNearDamageShell(sbPtr);
 
 
2400
 
 
 
2401
                if (alienStatusPointer->HModelController.keyframe_flags & 1)
 
 
2402
                    alienStatusPointer->current_attack = NULL;
 
 
2403
 
 
 
2404
                if ((FastRandom() & 127) < 20)
 
 
2405
                    AlienRandomHiss(sbPtr);
 
 
2406
            }
 
 
2407
        }
 
 
2408
        break;
 
 
2409
        case ABS_Pounce:
 
 
2410
        {
 
 
2411
            /* Firstly, are we actually pouncing yet? */
 
 
2412
            /* StateTimer is a status flag. */
 
 
2413
 
 
 
2414
            if (!alienStatusPointer->StateTimer)
 
 
2415
            {
 
 
2416
                /* Still tweening? */
 
 
2417
                if (!alienStatusPointer->HModelController.Tweening)
 
 
2418
                {
 
 
2419
                    /* We've finished!  Are we facing right? */
 
 
2420
                    VECTORCH orientationDirn;
 
 
2421
 
 
 
2422
                    orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
2423
                    orientationDirn.vy = 0;
 
 
2424
                    orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
2425
 
 
 
2426
                    if (NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE))
 
 
2427
                    {
 
 
2428
                        /* Okay, pounce! */
 
 
2429
 
 
 
2430
                        ApplyPounceImpulse(sbPtr);
 
 
2431
 
 
 
2432
                        alienStatusPointer->HModelController.Playing = 1;
 
 
2433
                        alienStatusPointer->StateTimer = 1;
 
 
2434
                    }
 
 
2435
                    else
 
 
2436
                    {
 
 
2437
                        /* Still not right!  Wait for proper facing. */
 
 
2438
                        alienStatusPointer->HModelController.Playing = 0;
 
 
2439
                        CheckPounceIntegrity(sbPtr);
 
 
2440
                    }
 
 
2441
                }
 
 
2442
                else
 
 
2443
                {
 
 
2444
                    /* Yup, still tweening.  Check state validity. */
 
 
2445
                    CheckPounceIntegrity(sbPtr);
 
 
2446
                }
 
 
2447
            }
 
 
2448
            else
 
 
2449
            {
 
 
2450
                struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr;
 
 
2451
 
 
 
2452
                if(CollisionReportPtr)
 
 
2453
                {
 
 
2454
                    do
 
 
2455
                    {
 
 
2456
                        if(CollisionReportPtr->ObstacleSBPtr)
 
 
2457
                        {
 
 
2458
                            STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr;
 
 
2459
 
 
 
2460
                            switch(hit_sbptr->type)
 
 
2461
                            {
 
 
2462
                                case I_BehaviourMarine:
 
 
2463
                                case I_BehaviourMarinePlayer:
 
 
2464
                                case I_BehaviourPredatorPlayer:
 
 
2465
                                case I_BehaviourPredator:
 
 
2466
                                case I_BehaviourPlacedLight:
 
 
2467
                                    CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL);
 
 
2468
                                default:
 
 
2469
                                break;
 
 
2470
                            }
 
 
2471
                        }
 
 
2472
 
 
 
2473
                        CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr;
 
 
2474
 
 
 
2475
                    } while(CollisionReportPtr);
 
 
2476
 
 
 
2477
                    dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr);
 
 
2478
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2479
                    alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2480
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2481
                    alienStatusPointer->StateTimer = 0;
 
 
2482
                    alienStatusPointer->CurveTimeOut = 0;
 
 
2483
                    alienStatusPointer->current_attack = NULL;
 
 
2484
                }
 
 
2485
            }
 
 
2486
        }
 
 
2487
        break;
 
 
2488
        case ABS_Jump:
 
 
2489
        {
 
 
2490
            int terminateState = 0;
 
 
2491
            struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr;
 
 
2492
 
 
 
2493
            /* Pretty simple one, this.  Just fly through the air, until you hit something. */
 
 
2494
 
 
 
2495
            if (dynPtr->IsInContactWithFloor || dynPtr->IsInContactWithNearlyFlatFloor)
 
 
2496
                terminateState = 1;
 
 
2497
 
 
 
2498
            if(CollisionReportPtr)
 
 
2499
            {
 
 
2500
                do
 
 
2501
                {
 
 
2502
                    if(CollisionReportPtr->ObstacleSBPtr)
 
 
2503
                    {
 
 
2504
                        STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr;
 
 
2505
 
 
 
2506
                        switch(hit_sbptr->type)
 
 
2507
                        {
 
 
2508
                            case I_BehaviourMarine:
 
 
2509
                            case I_BehaviourMarinePlayer:
 
 
2510
                            case I_BehaviourPredatorPlayer:
 
 
2511
                            case I_BehaviourPredator:
 
 
2512
                            case I_BehaviourPlacedLight:
 
 
2513
                                CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL);
 
 
2514
                            default:
 
 
2515
                            break;
 
 
2516
                        }
 
 
2517
                    }
 
 
2518
 
 
 
2519
                    CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr;
 
 
2520
 
 
 
2521
                } while(CollisionReportPtr);
 
 
2522
 
 
 
2523
                terminateState = 1;
 
 
2524
            }
 
 
2525
 
 
 
2526
            if (terminateState)
 
 
2527
            {
 
 
2528
                /* should be crawling. */
 
 
2529
                alienStatusPointer->IAmCrouched = 1;
 
 
2530
                dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr);
 
 
2531
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2532
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2533
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2534
                alienStatusPointer->StateTimer = 0;
 
 
2535
                alienStatusPointer->CurveTimeOut = 0;
 
 
2536
                alienStatusPointer->current_attack = NULL;
 
 
2537
            }
 
 
2538
        }
 
 
2539
        break;
 
 
2540
        case ABS_Avoidance:
 
 
2541
        {
 
 
2542
            alienStatusPointer->IAmCrouched;
 
 
2543
            AlienHandleMovingAnimation(sbPtr);
 
 
2544
            int terminateState = 0;
 
 
2545
            //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr);
 
 
2546
 
 
 
2547
        #if ALL_NEW_AVOIDANCE_ALIEN
 
 
2548
 
 
 
2549
            NPCSetVelocity(sbPtr, &alienStatusPointer->avoidanceManager.avoidanceDirection, alienStatusPointer->MaxSpeed);
 
 
2550
            /* Velocity CANNOT be zero, unless deliberately so! */    
 
 
2551
            {
 
 
2552
                if (AllNewAvoidanceKernel(sbPtr,&alienStatusPointer->avoidanceManager) != AvRC_Avoidance)
 
 
2553
                    terminateState = 1;
 
 
2554
            }
 
 
2555
        #else
 
 
2556
            /* set velocity */
 
 
2557
            assert((alienStatusPointer->moveData.avoidanceDirn.vx!=0)||
 
 
2558
                        (alienStatusPointer->moveData.avoidanceDirn.vy!=0)||
 
 
2559
                        (alienStatusPointer->moveData.avoidanceDirn.vz!=0));
 
 
2560
 
 
 
2561
            NPCSetVelocity(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, alienStatusPointer->MaxSpeed);
 
 
2562
 
 
 
2563
            /* next, decrement state timer */
 
 
2564
            alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
2565
 
 
 
2566
            if(alienStatusPointer->StateTimer <= 0)
 
 
2567
                terminateState = 1;
 
 
2568
 
 
 
2569
            /* and check for an impeding collision */
 
 
2570
            {
 
 
2571
                STRATEGYBLOCK *destructableObject;
 
 
2572
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
2573
                NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction, &destructableObject);
 
 
2574
 
 
 
2575
                if(obstruction.anySingleObstruction)
 
 
2576
                    terminateState = 1; // return to approach
 
 
2577
            }
 
 
2578
        #endif
 
 
2579
 
 
 
2580
            if(terminateState)
 
 
2581
            {
 
 
2582
                //if(Standard == alienStatusPointer->Type) alienStatusPointer->EnableWaypoints = 1;
 
 
2583
                if(AlienHasPathToTarget(sbPtr))
 
 
2584
                {
 
 
2585
                    /* switch to approach */
 
 
2586
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2587
                    alienStatusPointer->BehaviourState = ABS_Approach;          
 
 
2588
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2589
                    alienStatusPointer->StateTimer = 0;
 
 
2590
 
 
 
2591
                    /* no sequence change required */
 
 
2592
                }
 
 
2593
                else if (AlienIsAwareOfTarget(sbPtr))
 
 
2594
                {
 
 
2595
                    alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2596
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2597
                    alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
2598
                }
 
 
2599
                else
 
 
2600
                {
 
 
2601
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2602
                    NPC_InitWanderData(&alienStatusPointer->wanderData);
 
 
2603
                    alienStatusPointer->BehaviourState = ABS_Wander;          
 
 
2604
                    alienStatusPointer->StateTimer = 0;
 
 
2605
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2606
                    /* no sequence change required */
 
 
2607
                }
 
 
2608
            }
 
 
2609
        }
 
 
2610
        break;
 
 
2611
        case ABS_Hunt:
 
 
2612
        {
 
 
2613
            AlienHandleMovingAnimation(sbPtr);
 
 
2614
            VECTORCH velocityDirection = {0,0,0};
 
 
2615
            alienStatusPointer->IAmCrouched = 1;
 
 
2616
            //dynPtr->UseStandardGravity = !alienStatusPointer->CanClimb;
 
 
2617
 
 
 
2618
            /* should we change to approach state? */
 
 
2619
 
 
 
2620
            if(AlienHasPathToTarget(sbPtr))
 
 
2621
            {
 
 
2622
                /* doesn't require a sequence change */
 
 
2623
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2624
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2625
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2626
                alienStatusPointer->CurveTimeOut = 0;
 
 
2627
 
 
 
2628
                /* Bloodthirsty, these aliens... */
 
 
2629
                break;
 
 
2630
            }
 
 
2631
 
 
 
2632
            /* Hunting target aquisition. */
 
 
2633
            //if (sbPtr->containingModule != alienStatusPointer->my_containing_module) alienStatusPointer->huntingModule = NULL;
 
 
2634
 
 
 
2635
            /* Check again. */
 
 
2636
            if (alienStatusPointer->huntingModule != NULL)
 
 
2637
            {
 
 
2638
                FARENTRYPOINT *thisEp = GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule);
 
 
2639
 
 
 
2640
                if (!thisEp)
 
 
2641
                    alienStatusPointer->huntingModule = NULL;
 
 
2642
            }
 
 
2643
 
 
 
2644
            if (alienStatusPointer->huntingModule == NULL)
 
 
2645
            {
 
 
2646
                AIMODULE *targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr);
 
 
2647
 
 
 
2648
                if (targetModule == NULL)
 
 
2649
                {
 
 
2650
                    /* Better have a handler for this. */
 
 
2651
                    alienStatusPointer->BehaviourState = ABS_Wander;
 
 
2652
                    alienStatusPointer->CurveTimeOut = 0;
 
 
2653
                    //printf("Target module is NULL!\n");
 
 
2654
                    break;
 
 
2655
                }
 
 
2656
 
 
 
2657
                //printf("Target module is %s\n", targetModule->name);
 
 
2658
                //printf("Target AI module for hunt found, %x.\n", (int)targetModule);
 
 
2659
 
 
 
2660
                if (targetModule == sbPtr->containingModule->m_aimodule)
 
 
2661
                {
 
 
2662
                    /* We should have arrived - get a new target? */
 
 
2663
                    if (alienStatusPointer->Target == NULL)
 
 
2664
                    {
 
 
2665
                        /* Oops - nobody about. */
 
 
2666
                        NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2667
                        NPC_InitWanderData(&alienStatusPointer->wanderData);
 
 
2668
                        alienStatusPointer->BehaviourState = ABS_Wander;
 
 
2669
                        alienStatusPointer->CurveTimeOut = 0;
 
 
2670
                        InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2671
                    }
 
 
2672
                    else
 
 
2673
                    {
 
 
2674
                        alienStatusPointer->Target = NULL;
 
 
2675
                        alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2676
                        InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2677
                        alienStatusPointer->CurveTimeOut = 0;
 
 
2678
                    }
 
 
2679
                return;
 
 
2680
                }
 
 
2681
 
 
 
2682
                alienStatusPointer->huntingModule = targetModule;
 
 
2683
            }
 
 
2684
 
 
 
2685
            {
 
 
2686
                FARENTRYPOINT *thisEp = GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule);
 
 
2687
 
 
 
2688
                if (!thisEp)
 
 
2689
                {
 
 
2690
        printf("This assert is a busted adjacency!\nNo EP between %s and
%s.",(*(alienStatusPointer->huntingModule->m_module_ptrs))->name,sbPtr->containingModule->name);
 
 
2691
                    //printf("This assert is a busted adjacency!");
 
 
2692
                    assert(thisEp);
 
 
2693
                }
 
 
2694
                /* If that fired, there's a farped adjacency. */
 
 
2695
 
 
 
2696
                alienStatusPointer->wanderData.worldPosition = thisEp->position;
 
 
2697
                alienStatusPointer->wanderData.worldPosition.vx += alienStatusPointer->huntingModule->m_world.vx;
 
 
2698
                alienStatusPointer->wanderData.worldPosition.vy += alienStatusPointer->huntingModule->m_world.vy;
 
 
2699
                alienStatusPointer->wanderData.worldPosition.vz += alienStatusPointer->huntingModule->m_world.vz;
 
 
2700
            }
 
 
2701
 
 
 
2702
            /* ok: should have a current target at this stage... */
 
 
2703
            NPCGetMovementDirection(sbPtr, &velocityDirection,
&alienStatusPointer->wanderData.worldPosition,&alienStatusPointer->waypointManager);
 
 
2704
            NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed);
 
 
2705
 
 
 
2706
            /* test here for impeding collisions, and not being able to reach target... */
 
 
2707
            #if ALL_NEW_AVOIDANCE_ALIEN
 
 
2708
            {
 
 
2709
                if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager))
 
 
2710
                {
 
 
2711
                    /* Go to all new avoidance. */
 
 
2712
                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2713
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2714
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2715
                    break;
 
 
2716
                }
 
 
2717
            }
 
 
2718
            #else
 
 
2719
            {
 
 
2720
                STRATEGYBLOCK *destructableObject = NULL;
 
 
2721
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
2722
                NPC_IsObstructed(sbPtr,&alienStatusPointer->moveData,&obstruction,&destructableObject);
 
 
2723
 
 
 
2724
                if(obstruction.environment || obstruction.otherCharacter)
 
 
2725
                {
 
 
2726
                    /* go to avoidance */
 
 
2727
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2728
                    NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);                        
 
 
2729
                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2730
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2731
                    /* no sequence change required */
 
 
2732
                    break;
 
 
2733
                }
 
 
2734
 
 
 
2735
                if(obstruction.destructableObject)
 
 
2736
                {
 
 
2737
                    assert(destructableObject);
 
 
2738
                    CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL);
 
 
2739
                }
 
 
2740
            }
 
 
2741
 
 
 
2742
            if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection))
 
 
2743
            {
 
 
2744
                /* go to avoidance */
 
 
2745
                NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
2746
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2747
                NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);                        
 
 
2748
                alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2749
                alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2750
                /* no sequence change required */
 
 
2751
            }
 
 
2752
            #endif
 
 
2753
        }
 
 
2754
        break;
 
 
2755
        case ABS_Wait:
 
 
2756
        {
 
 
2757
            if (!alienStatusPointer->IAmCrouched)
 
 
2758
            {
 
 
2759
                alienStatusPointer->IAmCrouched = 1;
 
 
2760
                alienStatusPointer->StateTimer = ONE_FIXED * 2;
 
 
2761
            }
 
 
2762
            else if(!alienStatusPointer->Wounds)
 
 
2763
            {
 
 
2764
                if(alienStatusPointer->HModelController.Playing)
 
 
2765
                {
 
 
2766
                    if(!alienStatusPointer->HModelController.Tweening)
 
 
2767
                        sbPtr->DisplayBlock->HModelControlBlock->Playing = 0;
 
 
2768
 
 
 
2769
                //if(alienStatusPointer->StateTimer < 0)
 
 
2770
                    sbPtr->DisplayBlock->HModelControlBlock->Playing = 0;
 
 
2771
                {
 
 
2772
                    alienStatusPointer->HModelController.Playing = 0;;
 
 
2773
                    puts("not player ANIM");
 
 
2774
                    //alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME * 40;
 
 
2775
                }
 
 
2776
                }
 
 
2777
            }
 
 
2778
        /*
 
 
2779
            if(AlienHasPathToTarget(sbPtr))
 
 
2780
            {
 
 
2781
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2782
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2783
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2784
 
 
 
2785
                alienStatusPointer->CurveTimeOut = 0;
 
 
2786
                alienStatusPointer->StateTimer = 0;    
 
 
2787
 
 
 
2788
            return;
 
 
2789
            }
 
 
2790
            else if (AlienIsAwareOfTarget(sbPtr))
 
 
2791
            {
 
 
2792
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2793
                alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
2794
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2795
            }
 
 
2796
        */
 
 
2797
            /* still waiting: decrement timer */
 
 
2798
            alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
2799
 
 
 
2800
            if(alienStatusPointer->StateTimer <= 0)
 
 
2801
            {
 
 
2802
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2803
                NPC_InitWanderData(&alienStatusPointer->wanderData);
 
 
2804
                alienStatusPointer->BehaviourState = ABS_Wander;
 
 
2805
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2806
                alienStatusPointer->StateTimer = 0;        
 
 
2807
            }
 
 
2808
        }
 
 
2809
        break;
 
 
2810
        case ABS_Wander:
 
 
2811
        {
 
 
2812
            AlienHandleMovingAnimation(sbPtr);
 
 
2813
            VECTORCH velocityDirection = {0,0,0};
 
 
2814
 
 
 
2815
            /* Do something else? */
 
 
2816
 
 
 
2817
            /* should we change to approach state? */
 
 
2818
            if(AlienHasPathToTarget(sbPtr))
 
 
2819
            {
 
 
2820
                /* doesn't require a sequence change */
 
 
2821
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2822
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2823
                alienStatusPointer->CurveTimeOut = 0;
 
 
2824
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2825
            break;
 
 
2826
            }
 
 
2827
            else if (AlienIsAwareOfTarget(sbPtr))
 
 
2828
            {
 
 
2829
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2830
                alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
2831
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2832
            }
 
 
2833
 
 
 
2834
            /* Try to reaquire target? */
 
 
2835
            alienStatusPointer->Target = NULL;
 
 
2836
 
 
 
2837
            if(alienStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2838
            {
 
 
2839
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2840
                NPC_FindAIWanderTarget(sbPtr,&alienStatusPointer->wanderData, &alienStatusPointer->moveData, 1);
 
 
2841
            }
 
 
2842
            else if(alienStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index)
 
 
2843
            {
 
 
2844
                NPC_FindAIWanderTarget(sbPtr, &alienStatusPointer->wanderData, &alienStatusPointer->moveData, 1);
 
 
2845
            }
 
 
2846
 
 
 
2847
            /* if we still haven't got one, go to wait */
 
 
2848
            if(alienStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2849
            {
 
 
2850
                alienStatusPointer->BehaviourState = ABS_Wait;
 
 
2851
                alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
2852
            }
 
 
2853
 
 
 
2854
            /* ok: should have a current target at this stage... */
 
 
2855
            NPCGetMovementDirection(sbPtr, &velocityDirection, &alienStatusPointer->wanderData.worldPosition,
&alienStatusPointer->waypointManager);
 
 
2856
            NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed);
 
 
2857
 
 
 
2858
            /* test here for impeding collisions, and not being able to reach target... */
 
 
2859
 
 
 
2860
        #if ALL_NEW_AVOIDANCE_ALIEN
 
 
2861
            {
 
 
2862
                if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager))
 
 
2863
                {
 
 
2864
                    /* Go to all new avoidance. */
 
 
2865
                    alienStatusPointer->BehaviourState = ABS_Avoidance;          
 
 
2866
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2867
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2868
                    break;
 
 
2869
                }
 
 
2870
            }
 
 
2871
        #else
 
 
2872
            {
 
 
2873
                STRATEGYBLOCK *destructableObject = NULL;
 
 
2874
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
2875
                NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction,&destructableObject);
 
 
2876
 
 
 
2877
                if(obstruction.environment || obstruction.otherCharacter)
 
 
2878
                {
 
 
2879
                    /* go to avoidance */
 
 
2880
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2881
                    NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);                        
 
 
2882
                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2883
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2884
                    /* no sequence change required */
 
 
2885
                    break;
 
 
2886
                }
 
 
2887
 
 
 
2888
                if(obstruction.destructableObject)
 
 
2889
                {
 
 
2890
                    assert(destructableObject);
 
 
2891
                    CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL);
 
 
2892
                }
 
 
2893
            }
 
 
2894
 
 
 
2895
            if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection))
 
 
2896
            {
 
 
2897
                /* go to avoidance */
 
 
2898
                NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
2899
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2900
                NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
2901
                alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2902
                alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2903
                /* no sequence change required */
 
 
2904
            }
 
 
2905
        #endif
 
 
2906
        }
 
 
2907
        break;
 
 
2908
        case ABS_Retreat:
 
 
2909
        {
 
 
2910
            AlienHandleMovingAnimation(sbPtr);
 
 
2911
            VECTORCH velocityDirection = {0,0,0};
 
 
2912
 
 
 
2913
            /* should we change to approach state? */
 
 
2914
            if(AlienIsAwareOfTarget(sbPtr))
 
 
2915
            {
 
 
2916
                // doesn't require a sequence change
 
 
2917
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2918
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
2919
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2920
                alienStatusPointer->CurveTimeOut = 0;
 
 
2921
 
 
 
2922
                // Bloodthirsty, these aliens...
 
 
2923
                return;
 
 
2924
            }
 
 
2925
 
 
 
2926
            /* Retreat target aquisition. */
 
 
2927
            {
 
 
2928
                AIMODULE *targetModule = NearNPC_GetTargetAIModuleForRetreat(sbPtr, &(alienStatusPointer->moveData));
 
 
2929
 
 
 
2930
        /*        if (targetModule)
 
 
2931
                {
 
 
2932
                    //printf("Target module is %s\n",targetModule->name);
 
 
2933
                    //printf("Target AI module found, %x.\n",(int)targetModule);
 
 
2934
                }
 
 
2935
                else
 
 
2936
                {
 
 
2937
                    printf("Target module is NULL!\n");
 
 
2938
                }
 
 
2939
        */
 
 
2940
                if ((targetModule == sbPtr->containingModule->m_aimodule) || (targetModule == NULL))
 
 
2941
                {
 
 
2942
                    /* Hey, it'll drop through. */
 
 
2943
                    alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
2944
                    alienStatusPointer->CurveTimeOut = 0;
 
 
2945
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2946
                return;
 
 
2947
                }
 
 
2948
 
 
 
2949
                assert(targetModule);
 
 
2950
 
 
 
2951
                FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
 
 
2952
 
 
 
2953
                if (!thisEp)
 
 
2954
                {
 
 
2955
                    //printf("This assert is a busted adjacency!\nNo EP between %s and
%s.",targetModule->name,sbPtr->containingModule->name);
 
 
2956
                    printf("This assert is a busted adjacency!");
 
 
2957
                    assert(thisEp);
 
 
2958
                }
 
 
2959
                /* If that fired, there's a farped adjacency. */
 
 
2960
 
 
 
2961
                alienStatusPointer->wanderData.worldPosition = thisEp->position;
 
 
2962
                alienStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx;
 
 
2963
                alienStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy;
 
 
2964
                alienStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz;
 
 
2965
            }
 
 
2966
 
 
 
2967
            /* ok: should have a current target at this stage... */
 
 
2968
            NPCGetMovementDirection(sbPtr, &velocityDirection,
&(alienStatusPointer->wanderData.worldPosition),&alienStatusPointer->waypointManager);
 
 
2969
            NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed);    
 
 
2970
 
 
 
2971
            /* test here for impeding collisions, and not being able to reach target... */
 
 
2972
        #if ALL_NEW_AVOIDANCE_ALIEN
 
 
2973
            {
 
 
2974
                if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager))
 
 
2975
                {
 
 
2976
                    /* Go to all new avoidance. */
 
 
2977
                    alienStatusPointer->BehaviourState = ABS_Avoidance;          
 
 
2978
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2979
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
2980
                    return;
 
 
2981
                }
 
 
2982
            }
 
 
2983
        #else
 
 
2984
            {
 
 
2985
                STRATEGYBLOCK *destructableObject = NULL;
 
 
2986
                NPC_OBSTRUCTIONREPORT obstruction;
 
 
2987
                NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction,&destructableObject);
 
 
2988
 
 
 
2989
                if(obstruction.environment || obstruction.otherCharacter)
 
 
2990
                {
 
 
2991
                    /* go to avoidance */
 
 
2992
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
2993
                    NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);                        
 
 
2994
                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
2995
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
2996
                    /* no sequence change required */
 
 
2997
                    return;
 
 
2998
                }
 
 
2999
 
 
 
3000
                if(obstruction.destructableObject)
 
 
3001
                {
 
 
3002
                    assert(destructableObject);
 
 
3003
                    CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL);
 
 
3004
                }
 
 
3005
            }
 
 
3006
 
 
 
3007
            if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection))
 
 
3008
            {
 
 
3009
                /* go to avoidance */
 
 
3010
                NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0};
 
 
3011
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3012
                NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
3013
                alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
3014
                alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
3015
                /* no sequence change required */
 
 
3016
            }
 
 
3017
        #endif
 
 
3018
        }
 
 
3019
        default:
 
 
3020
        break;
 
 
3021
      }
 
 
3022
}
 
 
3023
 
 
 
3024
static void FarAlienBehaviour(STRATEGYBLOCK *sbPtr)
 
 
3025
{
 
 
3026
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3027
 
 
 
3028
    switch(alienStatusPointer->BehaviourState)
 
 
3029
    {
 
 
3030
        case ABS_Hunt:
 
 
3031
        {
 
 
3032
            alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
3033
 
 
 
3034
            if (alienStatusPointer->Target && (alienStatusPointer->Target->containingModule->m_aimodule ==
sbPtr->containingModule->m_aimodule))
 
 
3035
            {
 
 
3036
                alienStatusPointer->BehaviourState = ABS_Wait;
 
 
3037
                alienStatusPointer->StateTimer = 0;
 
 
3038
            }
 
 
3039
            else
 
 
3040
            {
 
 
3041
                /* check if far state timer has timed-out. If so, it is time 
 
 
3042
                to do something. Otherwise just return. */
 
 
3043
                if(alienStatusPointer->StateTimer > 0)
 
 
3044
                    return;
 
 
3045
 
 
 
3046
                /* check the alien hive, to see itf we've switched to regroup:
 
 
3047
                if so, reset the alien far behaviour state to retreat, with the alien far 
 
 
3048
                state timer set to 0, forcing a retreating movement next frame... */
 
 
3049
 
 
 
3050
                if(NPCHive.currentState == HS_Regroup)
 
 
3051
                {
 
 
3052
                    alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
3053
                    alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3054
                    return;
 
 
3055
                }
 
 
3056
 
 
 
3057
                if (!AlienIsAwareOfTarget(sbPtr) && (alienStatusPointer->Target == PlayerStatus.sbptr) && NPC_IsDead(PlayerStatus.sbptr))
 
 
3058
                {
 
 
3059
                    alienStatusPointer->BehaviourState = ABS_Wander;
 
 
3060
                    alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3061
                }
 
 
3062
                else
 
 
3063
                {
 
 
3064
                    AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 1);
 
 
3065
 
 
 
3066
                    /* if there is no target module, it means that the alien is trapped in an
 
 
3067
                    unlinked module. In this case, reset the timer and return. */            
 
 
3068
 
 
 
3069
                    if(NULL == targetModule)
 
 
3070
                    {
 
 
3071
                        alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
3072
                        alienStatusPointer->BehaviourState = ABS_Wander;
 
 
3073
                        alienStatusPointer->CurveTimeOut = 0;
 
 
3074
                    }
 
 
3075
                    else
 
 
3076
                    {
 
 
3077
                        alienStatusPointer->StateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule);
 
 
3078
                        alienStatusPointer->StateTimer += ONE_FIXED * 3 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
3079
                    }
 
 
3080
                }
 
 
3081
            }
 
 
3082
        }
 
 
3083
          break;
 
 
3084
           case ABS_Retreat:
 
 
3085
        {
 
 
3086
            alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
3087
 
 
 
3088
            /* check if far state timer has timed-out. If so, it is time 
 
 
3089
            to do something. Otherwise just return. */
 
 
3090
 
 
 
3091
            if(alienStatusPointer->StateTimer > 0)
 
 
3092
                return;
 
 
3093
 
 
 
3094
            /* check the alien hive, to see if we've switched to attack:
 
 
3095
            if so, reset the alien far behaviour state to attack, with the alien far 
 
 
3096
            state timer set to 0, forcing a movement next frame... 
 
 
3097
            NB if we can't attack the player, hunting function will automatically
 
 
3098
            switch to wander */
 
 
3099
 
 
 
3100
            if(NPCHive.currentState == HS_Attack)
 
 
3101
            {
 
 
3102
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3103
                alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3104
                return;
 
 
3105
            }
 
 
3106
 
 
 
3107
            /* get the target module... */
 
 
3108
            AIMODULE *targetModule = FarNPC_GetTargetAIModuleForRetreat(sbPtr);
 
 
3109
 
 
 
3110
            /* if there is no target module, reset the timer and return. */            
 
 
3111
            if(!targetModule)
 
 
3112
            {
 
 
3113
                alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
3114
                return;        
 
 
3115
            }
 
 
3116
 
 
 
3117
            /* Examine target, and decide what to do */
 
 
3118
            assert(AIModuleIsPhysical(targetModule));
 
 
3119
 
 
 
3120
            alienStatusPointer->StateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule);
 
 
3121
        }
 
 
3122
          break;
 
 
3123
           case ABS_Wander:
 
 
3124
        {
 
 
3125
            /* Decrement the Far state timer */
 
 
3126
            alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
3127
 
 
 
3128
            /* check if far state timer has timed-out. If so, it is time to do something. Otherwise just return. */
 
 
3129
            if(alienStatusPointer->StateTimer > 0)
 
 
3130
                return;
 
 
3131
 
 
 
3132
            /* check for state changes:
 
 
3133
            if hive says retreat, then retreat, regardless of whether or not we can see the player 
 
 
3134
            otherwise, if we can see the player, go to hunt */
 
 
3135
 
 
 
3136
            if(NPCHive.currentState == HS_Regroup)
 
 
3137
            {
 
 
3138
                alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
3139
                alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3140
                return;
 
 
3141
            }
 
 
3142
 
 
 
3143
            /* see if we want to switch to attack */
 
 
3144
            if(AlienIsAwareOfTarget(sbPtr))
 
 
3145
            {
 
 
3146
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3147
                alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3148
                return;
 
 
3149
            }
 
 
3150
 
 
 
3151
            /* get the target module... */
 
 
3152
 
 
 
3153
            AIMODULE *targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 1);
 
 
3154
 
 
 
3155
            /* if there is no target module, reset the timer and return. */
 
 
3156
            alienStatusPointer->StateTimer = (NULL != targetModule) ? ProcessFarAlienTargetModule(sbPtr, targetModule) : ALIEN_FAR_MOVE_TIME;
 
 
3157
        }
 
 
3158
        break;
 
 
3159
        case ABS_Wait:
 
 
3160
        {
 
 
3161
            if (alienStatusPointer->Target && alienStatusPointer->Target->containingModule->m_aimodule !=
sbPtr->containingModule->m_aimodule)
 
 
3162
            {
 
 
3163
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3164
                alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3165
            }
 
 
3166
            else
 
 
3167
            {
 
 
3168
                /* Decrement the Far state timer */
 
 
3169
                alienStatusPointer->StateTimer -= NormalFrameTime;
 
 
3170
 
 
 
3171
                /* check if far state timer has timed-out. If so, it is time to do something. Otherwise just return. */
 
 
3172
                if(alienStatusPointer->StateTimer > 0)
 
 
3173
                    return;
 
 
3174
            }
 
 
3175
        }
 
 
3176
        case ABS_Dormant:
 
 
3177
        case ABS_Awakening:
 
 
3178
        break;
 
 
3179
        case ABS_Avoidance:
 
 
3180
        {
 
 
3181
            /* No obstacles in far behaviour. */
 
 
3182
            Initialise_AvoidanceManager(&alienStatusPointer->avoidanceManager);
 
 
3183
        }
 
 
3184
        // no break
 
 
3185
        default:
 
 
3186
        {
 
 
3187
            alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3188
            alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/
 
 
3189
        }
 
 
3190
    }
 
 
3191
 
 
 
3192
    /* check here to see if the alien is in a doorway....
 
 
3193
    If so, and it is a proximity door, make sure it is open. */
 
 
3194
    {
 
 
3195
        MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
 
 
3196
 
 
 
3197
        if(doorType == MDT_ProxDoor)
 
 
3198
            ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->dataptr)->alienTrigger = 1;
 
 
3199
    }
 
 
3200
 
 
 
3201
    if (ShowHiveState)
 
 
3202
    {
 
 
3203
        MODULE *thisModule = sbPtr->containingModule;
 
 
3204
        printf("This FAR ALIEN is in module %d, %s\n", thisModule->m_index, thisModule->name);
 
 
3205
    }
 
 
3206
 
 
 
3207
    /* make sure that we are inside a module:
 
 
3208
    if this fires it means that a far alien is not inside
 
 
3209
    the module it is supposed to be in */
 
 
3210
 
 
 
3211
    #if UseLocalAssert   
 
 
3212
    {
 
 
3213
        VECTORCH localCoords;
 
 
3214
        MODULE *thisModule = sbPtr->containingModule;
 
 
3215
 
 
 
3216
        assert(thisModule);
 
 
3217
 
 
 
3218
        localCoords = sbPtr->DynPtr->Position;
 
 
3219
        localCoords.vx -= thisModule->m_world.vx;
 
 
3220
        localCoords.vy -= thisModule->m_world.vy;
 
 
3221
        localCoords.vz -= thisModule->m_world.vz;
 
 
3222
 
 
 
3223
        if(!PointIsInModule(thisModule, &localCoords))
 
 
3224
        {
 
 
3225
            //printf("FAR ALIEN MODULE CONTAINMENT FAILURE \n");
 
 
3226
 
 
 
3227
            printf("Alien containment failure: alien is in %s, position is %d,%d,%d:\nModule extents are: %d:%d, %d:%d, %d:%d",
 
 
3228
                thisModule->name,localCoords.vx,localCoords.vy,localCoords.vz,
 
 
3229
                thisModule->m_maxx,thisModule->m_minx,thisModule->m_maxy,thisModule->m_miny,
 
 
3230
                thisModule->m_maxz,thisModule->m_minz);
 
 
3231
 
 
 
3232
            assert(1==0);
 
 
3233
        }  
 
 
3234
    }
 
 
3235
    #endif
 
 
3236
 
 
 
3237
    // printf("NO ENTRY POINT COUNT %d \n", entryPointFailures);
 
 
3238
}
 
 
3239
 
 
 
3240
void AlienBehaviour(STRATEGYBLOCK *sbPtr)
 
 
3241
{
 
 
3242
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3243
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
3244
 
 
 
3245
    dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0;
 
 
3246
    dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr);
 
 
3247
 
 
 
3248
    if(alienStatusPointer->unconscious)
 
 
3249
    {
 
 
3250
        alienStatusPointer->Target = NULL;
 
 
3251
        alienStatusPointer->current_attack = NULL;
 
 
3252
        alienStatusPointer->unconscious -= NormalFrameTime;
 
 
3253
 
 
 
3254
        if(alienStatusPointer->unconscious < 0)
 
 
3255
        {
 
 
3256
            alienStatusPointer->IAmCrouched = 1;
 
 
3257
 
 
 
3258
            if(alienStatusPointer->unconscious < -(ONE_FIXED * 2))
 
 
3259
            {
 
 
3260
                alienStatusPointer->unconscious = 0;
 
 
3261
                alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3262
            }
 
 
3263
            else
 
 
3264
            {
 
 
3265
                SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrouch, ACrSS_Standard, -1, (ONE_FIXED>>3));
 
 
3266
            }
 
 
3267
        }
 
 
3268
 
 
 
3269
        if(alienStatusPointer->unconscious)
 
 
3270
            return;
 
 
3271
    }
 
 
3272
 
 
 
3273
    /* Unset incident flag. */
 
 
3274
    alienStatusPointer->incidentFlag = (alienStatusPointer->incidentTimer < 0);
 
 
3275
    alienStatusPointer->incidentTimer -= NormalFrameTime;
 
 
3276
 
 
 
3277
    if(alienStatusPointer->incidentFlag)
 
 
3278
        alienStatusPointer->incidentTimer = 32767 + (FastRandom() & 65535);
 
 
3279
 
 
 
3280
    if (sbPtr->DamageBlock.IsOnFire)
 
 
3281
    {
 
 
3282
        if(alienStatusPointer->soundOnFire != SOUND_NOACTIVEINDEX)
 
 
3283
            Sound_Update3d(alienStatusPointer->soundOnFire, &sbPtr->DynPtr->Position);
 
 
3284
        else
 
 
3285
              Sound_Play(SID_FIRE, "dle", &sbPtr->DynPtr->Position, &alienStatusPointer->soundOnFire);
 
 
3286
 
 
 
3287
/*
 
 
3288
        //for multiplayer games it is necessary to say who is doing this damage
 
 
3289
        //(that would be the person who set the alien on fire in the first place)
 
 
3290
        {
 
 
3291
            extern int myNetworkKillerId;
 
 
3292
            extern int AVPDPNetID;
 
 
3293
            myNetworkKillerId = alienStatusPointer->aliensIgniterId;
 
 
3294
            myNetworkKillerId = AVPDPNetID;
 
 
3295
        }
 
 
3296
*/
 
 
3297
 
 
 
3298
        if (alienStatusPointer->incidentFlag && ((FastRandom() & 65535) < 32767))
 
 
3299
        {
 
 
3300
            sbPtr->DamageBlock.IsOnFire = 0;
 
 
3301
            Sound_Stop(alienStatusPointer->soundOnFire);
 
 
3302
        }
 
 
3303
        else
 
 
3304
        {
 
 
3305
            int speed = Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity);
 
 
3306
            /* Go out? */
 
 
3307
 
 
 
3308
            if (speed > 22000)
 
 
3309
            {
 
 
3310
                /* Jumping alien. */
 
 
3311
                sbPtr->DamageBlock.IsOnFire -= NormalFrameTime * 6;
 
 
3312
            }
 
 
3313
            else if (speed > 15000) 
 
 
3314
            {
 
 
3315
                /* Running alien. */
 
 
3316
                sbPtr->DamageBlock.IsOnFire -= NormalFrameTime << 2;
 
 
3317
            }
 
 
3318
            else 
 
 
3319
            {
 
 
3320
                /* Normal bloke. */
 
 
3321
                sbPtr->DamageBlock.IsOnFire -= NormalFrameTime;
 
 
3322
            }
 
 
3323
 
 
 
3324
            if (sbPtr->DamageBlock.IsOnFire <= 0) 
 
 
3325
            {
 
 
3326
                sbPtr->DamageBlock.IsOnFire = 0;
 
 
3327
                Sound_Stop(alienStatusPointer->soundOnFire);
 
 
3328
            }
 
 
3329
        }
 
 
3330
    }
 
 
3331
 
 
 
3332
    switch(alienStatusPointer->BehaviourState)
 
 
3333
    {
 
 
3334
        case ABS_Awakening:
 
 
3335
        {
 
 
3336
            /* wait until near state timer runs out, then wander:
 
 
3337
            alternatively, if we can attack the player, go straight to approach */
 
 
3338
 
 
 
3339
            if (!sbPtr->DisplayBlock)
 
 
3340
                ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr);
 
 
3341
 
 
 
3342
            if (!alienStatusPointer->HModelController.Tweening && (alienStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
3343
            {
 
 
3344
                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3345
                alienStatusPointer->BehaviourState = ABS_Approach;
 
 
3346
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
3347
                alienStatusPointer->CurveTimeOut = 0;
 
 
3348
                alienStatusPointer->StateTimer = 0;    
 
 
3349
            }
 
 
3350
        }
 
 
3351
        return;
 
 
3352
        case ABS_Dormant:
 
 
3353
        {
 
 
3354
            /* wait until near state timer runs out, then wander:
 
 
3355
            alternatively, if we can attack the player, go straight to approach */
 
 
3356
 
 
 
3357
            /* Also used for FAR! */
 
 
3358
 
 
 
3359
            if (!sbPtr->DisplayBlock)
 
 
3360
            {
 
 
3361
                if (alienStatusPointer->HModelController.Playing)
 
 
3362
                {
 
 
3363
                    /* Try to call this as little as possible. */
 
 
3364
                    ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr);
 
 
3365
 
 
 
3366
                    if (!alienStatusPointer->HModelController.Tweening)
 
 
3367
                        alienStatusPointer->HModelController.Playing = 0;
 
 
3368
                }
 
 
3369
            }
 
 
3370
            else
 
 
3371
            {
 
 
3372
                //alienStatusPointer->HModelController.Playing = 1;
 
 
3373
            }
 
 
3374
 
 
 
3375
            /* Brushing Test. */
 
 
3376
            {
 
 
3377
                struct collisionreport *nextReport = sbPtr->DynPtr->CollisionReportPtr;
 
 
3378
 
 
 
3379
                while(nextReport)
 
 
3380
                {
 
 
3381
                    if(nextReport->ObstacleSBPtr)
 
 
3382
                    {    
 
 
3383
                        switch(nextReport->ObstacleSBPtr->type)
 
 
3384
                        {
 
 
3385
                            case I_BehaviourAlienPlayer:
 
 
3386
                            case I_BehaviourMarinePlayer:
 
 
3387
                            case I_BehaviourMarine:
 
 
3388
                            case I_BehaviourPredatorPlayer:
 
 
3389
                            case I_BehaviourNetGhost:
 
 
3390
                            case I_BehaviourXenoborg:
 
 
3391
                            case I_BehaviourQueenAlien:
 
 
3392
                            case I_BehaviourFaceHugger:
 
 
3393
                                Alien_Awaken(sbPtr);
 
 
3394
                            default:
 
 
3395
                            break;
 
 
3396
                        }
 
 
3397
                    }
 
 
3398
 
 
 
3399
                    nextReport = nextReport->NextCollisionReportPtr;
 
 
3400
                }
 
 
3401
            }
 
 
3402
        }
 
 
3403
        return;
 
 
3404
        case ABS_Taunting:
 
 
3405
        {
 
 
3406
            if (!sbPtr->DisplayBlock)
 
 
3407
            {
 
 
3408
                ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr);
 
 
3409
            }
 
 
3410
            else if (alienStatusPointer->Target)
 
 
3411
            {
 
 
3412
                /* Orientate towards target, to avoid looking stupid */
 
 
3413
                VECTORCH orientationDirn;
 
 
3414
                orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
3415
                orientationDirn.vy = 0;
 
 
3416
                orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
3417
                NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
3418
            }
 
 
3419
 
 
 
3420
            if (HModelAnimation_IsFinished(&alienStatusPointer->HModelController))
 
 
3421
            {
 
 
3422
                /* Exit state somehow. */
 
 
3423
                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
3424
 
 
 
3425
                if (NULL != alienStatusPointer->Target)
 
 
3426
                    alienStatusPointer->BehaviourState = ABS_Wander;
 
 
3427
                else
 
 
3428
                    alienStatusPointer->BehaviourState = sbPtr->DisplayBlock ? ABS_Approach : ABS_Hunt;
 
 
3429
            }
 
 
3430
        }
 
 
3431
        return;
 
 
3432
        default:
 
 
3433
        {
 
 
3434
            if (NULL != alienStatusPointer->Target)
 
 
3435
            {
 
 
3436
                //if(NPC_IsDead(alienStatusPointer->Target) || !NAME_ISEQUAL(alienStatusPointer->Target->SBname, alienStatusPointer->Target_SBname)
|| !AlienHasPathToTarget(sbPtr))
 
 
3437
                if(NPC_IsDead(alienStatusPointer->Target) || !NAME_ISEQUAL(alienStatusPointer->Target->SBname, alienStatusPointer->Target_SBname))
 
 
3438
                {
 
 
3439
                    alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3440
                    alienStatusPointer->Target = NULL;
 
 
3441
                    alienStatusPointer->current_attack = NULL;
 
 
3442
                    alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
3443
                    InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
3444
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3445
                }
 
 
3446
            }
 
 
3447
 
 
 
3448
            if (sbPtr->DisplayBlock || alienStatusPointer->incidentFlag) 
 
 
3449
            {
 
 
3450
                if (alienStatusPointer->Target == NULL) 
 
 
3451
                {
 
 
3452
                    alienStatusPointer->current_attack = NULL;
 
 
3453
                    alienStatusPointer->Target = Alien_GetNewTarget(sbPtr);
 
 
3454
 
 
 
3455
                    if (alienStatusPointer->Target != NULL) 
 
 
3456
                    {
 
 
3457
                        COPY_NAME(alienStatusPointer->Target_SBname, alienStatusPointer->Target->SBname);
 
 
3458
 
 
 
3459
                        alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
3460
                        alienStatusPointer->StateTimer = 0;
 
 
3461
                        alienStatusPointer->BehaviourState = ABS_Approach;
 
 
3462
                    }
 
 
3463
                    else
 
 
3464
                    {
 
 
3465
                        //printf("Alien found no target!\n");
 
 
3466
                        AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 1);
 
 
3467
 
 
 
3468
                        if (!targetModule || PlayerIsDeadAndNoLivingNetghosts()) 
 
 
3469
                        {
 
 
3470
                            if (alienStatusPointer->BehaviourState != ABS_Wander) 
 
 
3471
                            {
 
 
3472
                                NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3473
                                alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
3474
                                alienStatusPointer->StateTimer = 0;
 
 
3475
                                alienStatusPointer->BehaviourState = ABS_Wander;
 
 
3476
                            }
 
 
3477
                        }
 
 
3478
                        else if (alienStatusPointer->BehaviourState != ABS_Hunt) 
 
 
3479
                        {
 
 
3480
                            alienStatusPointer->BehaviourState = ABS_Hunt;
 
 
3481
 
 
 
3482
                            if (sbPtr->DisplayBlock)
 
 
3483
                            {
 
 
3484
                                InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
3485
                                alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME;
 
 
3486
                            }
 
 
3487
                            else
 
 
3488
                            {
 
 
3489
                                alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;
 
 
3490
                            }
 
 
3491
                        }
 
 
3492
                    }
 
 
3493
                }
 
 
3494
            }
 
 
3495
        }
 
 
3496
    }
 
 
3497
 
 
 
3498
    if(sbPtr->DisplayBlock) 
 
 
3499
    {
 
 
3500
        NearAliens++;
 
 
3501
        //printf("Near alien behaviour %d is in module %d, %s\n", alienStatusPointer->BehaviourState, sbPtr->containingModule->m_index,
sbPtr->containingModule->name);
 
 
3502
        NearAlienBehaviour(sbPtr);
 
 
3503
    }
 
 
3504
    else
 
 
3505
    {
 
 
3506
        //printf("Far Alien in module %s \n", sbPtr->containingModule->name);
 
 
3507
        FarAliens++;
 
 
3508
        FarAlienBehaviour(sbPtr);
 
 
3509
    }
 
 
3510
 
 
 
3511
    /* Update delta playing flag. */
 
 
3512
    {
 
 
3513
        DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&alienStatusPointer->HModelController, "HitDelta");
 
 
3514
 
 
 
3515
        if (hitdelta && DeltaAnimation_IsFinished(hitdelta))
 
 
3516
            hitdelta->Playing = 0;
 
 
3517
    }
 
 
3518
 
 
 
3519
    HModel_Regen(&alienStatusPointer->HModelController, 4 * ONE_FIXED );
 
 
3520
}
 
 
3521
 
 
 
3522
/*----------------------Patrick 7/11/96-----------------------------
 
 
3523
This pair of functions handle the alien visibility switching....
 
 
3524
Note that the ai-pheromone system is maintained by these functions.
 
 
3525
--------------------------------------------------------------------*/
 
 
3526
void MakeAlienNear(STRATEGYBLOCK *sbPtr)
 
 
3527
{
 
 
3528
    /* first of all, see how many aliens are currently near: if there are too many,
 
 
3529
    destroy this alien, and try to force a generator to make a replacement */
 
 
3530
 
 
 
3531
    if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS)
 
 
3532
    {
 
 
3533
        sbPtr->please_destroy_me = 1;
 
 
3534
        ForceAGenerator();
 
 
3535
    }
 
 
3536
 
 
 
3537
    DISPLAYBLOCK *dPtr = CreateActiveObject();
 
 
3538
 
 
 
3539
    if(NULL != dPtr)
 
 
3540
    {
 
 
3541
        ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3542
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
3543
        sbPtr->DisplayBlock = dPtr;
 
 
3544
        dPtr->ObStrategyBlock = sbPtr;
 
 
3545
 
 
 
3546
        /* also need to initialise positional information in the new display block, 
 
 
3547
        from the existing dynamics block.
 
 
3548
        NB this necessary because this function is (usually) called between the 
 
 
3549
        dynamics and rendering systems so it is not initialised by the dynamics 
 
 
3550
        system the first frame it is drawn. */
 
 
3551
        dPtr->ObWorld = dynPtr->Position;
 
 
3552
        dPtr->ObEuler = dynPtr->OrientEuler;
 
 
3553
        dPtr->ObMat = dynPtr->OrientMat;
 
 
3554
 
 
 
3555
        dPtr->HModelControlBlock = &alienStatusPointer->HModelController;
 
 
3556
        ProveHModel(dPtr->HModelControlBlock, dPtr);
 
 
3557
 
 
 
3558
        /* init state timers */
 
 
3559
        alienStatusPointer->StateTimer = 0;
 
 
3560
        alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME;    
 
 
3561
        alienStatusPointer->CurveRadius = alienStatusPointer->CurveLength = alienStatusPointer->CurveTimeOut = 0;
 
 
3562
        InitWaypointManager(&alienStatusPointer->waypointManager);
 
 
3563
        dPtr->HModelControlBlock->Playing = 1;
 
 
3564
    }
 
 
3565
}
 
 
3566
 
 
 
3567
extern DEATH_DATA Alien_Deaths[];
 
 
3568
 
 
 
3569
/* patrick 29/7/97 -----------------------------------
 
 
3570
This function to be called only from behaviour
 
 
3571
-- ChrisF 1/4/98 What a stupid idea. This function ---
 
 
3572
-- to be called only from AlienIsDamaged. ------------
 
 
3573
------------------------------------------------------*/
 
 
3574
static void KillAlien(STRATEGYBLOCK *sbPtr, int wounds, const DAMAGE_PROFILE *damage, VECTORCH *incoming)
 
 
3575
{
 
 
3576
    DEATH_DATA *this_death = NULL;
 
 
3577
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3578
    HIT_FACING facing = { 0,0,0,0 };
 
 
3579
 
 
 
3580
    if (incoming) 
 
 
3581
    {
 
 
3582
        if (incoming->vz > 0) 
 
 
3583
            facing.Back = 1;
 
 
3584
        else
 
 
3585
            facing.Front = 1;
 
 
3586
 
 
 
3587
        if (incoming->vx > 0) 
 
 
3588
            facing.Right = 1;
 
 
3589
        else
 
 
3590
            facing.Left = 1;
 
 
3591
    }
 
 
3592
 
 
 
3593
    /*If alien has a death target ,send a request*/
 
 
3594
    if(alienStatusPointer->death_target_sbptr)
 
 
3595
        RequestState(alienStatusPointer->death_target_sbptr, 1, 0);
 
 
3596
 
 
 
3597
    int deathtype = 0, GibbFactor = 0;
 
 
3598
    int electrical = damage->Electrical;
 
 
3599
 
 
 
3600
    switch(damage->Id)
 
 
3601
    {
 
 
3602
        case EXPLOSIONFIRE_BLAST:
 
 
3603
        case AMMO_FRAGMENTATION_GRENADE:
 
 
3604
        {
 
 
3605
            GibbFactor = (alienStatusPointer->Type == Standard) ? ONE_FIXED >> 1 : ONE_FIXED >> 3;
 
 
3606
            Extreme_Gibbing(sbPtr, alienStatusPointer->HModelController.section_data, GibbFactor, incoming);
 
 
3607
        }
 
 
3608
        break;
 
 
3609
        case AMMO_FLECHETTE: 
 
 
3610
        {
 
 
3611
            GibbFactor = ONE_FIXED >> 4;
 
 
3612
            Extreme_Gibbing(sbPtr, alienStatusPointer->HModelController.section_data, GibbFactor, incoming);
 
 
3613
        }
 
 
3614
        default:
 
 
3615
        break;
 
 
3616
    }
 
 
3617
 
 
 
3618
    if(alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX)
 
 
3619
    {
 
 
3620
        /* make a sound... if you have a head. */
 
 
3621
        SECTION_DATA *chest = GetThisSectionData(alienStatusPointer->HModelController.section_data, "chest");
 
 
3622
 
 
 
3623
        if(NULL != chest)
 
 
3624
        {
 
 
3625
            SECTION_DATA *head = GetThisSectionData(alienStatusPointer->HModelController.section_data, "head");
 
 
3626
 
 
 
3627
            /* Is it still attached? */
 
 
3628
            if (head && !(head->flags & section_data_notreal))
 
 
3629
            {
 
 
3630
                SpeciesSound((int)alienStatusPointer->Type, ASC_Scream_Dying, 0, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position,
ALIEN_SOUND);
 
 
3631
                //SpeciesSound((int)alienStatusPointer->Type, ASC_Death, 0, NULL, &sbPtr->DynPtr->Position, ALIEN_SOUND);
 
 
3632
 
 
 
3633
                if(NetworkPeer == AvP.PlayMode)
 
 
3634
                    AddNetMsg_SpotAlienSound((int)ASC_Scream_Dying, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position);
 
 
3635
            }
 
 
3636
        }
 
 
3637
    }
 
 
3638
 
 
 
3639
    if(sbPtr->DynPtr->OrientMat.mat22 < 63000) // should be crouched
 
 
3640
    {
 
 
3641
    }
 
 
3642
    else if(alienStatusPointer->IAmCrouched) // crouched on flat
 
 
3643
    {
 
 
3644
        if (Standard == alienStatusPointer->Type)
 
 
3645
        {
 
 
3646
            if (damage->Electrical)
 
 
3647
            {
 
 
3648
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrawl, (int)ACSS_Pain_Fall_Right, -1,
0);
 
 
3649
                this_death = &Alien_Deaths[1];
 
 
3650
            }
 
 
3651
            else if(facing.Front && damage->ExplosivePower)
 
 
3652
            {
 
 
3653
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl, (int)ACSS_Boom_Fall_Back,
ONE_FIXED, 0);
 
 
3654
                this_death = &Alien_Deaths[2];
 
 
3655
            }
 
 
3656
            else
 
 
3657
            {
 
 
3658
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies, -1, 0);
 
 
3659
                this_death = &Alien_Deaths[0];
 
 
3660
            }
 
 
3661
        }
 
 
3662
        else if(Predalien == alienStatusPointer->Type && ((FastRandom() & 65535) < 25000))
 
 
3663
        {
 
 
3664
            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies_Thrash, -1, 0);
 
 
3665
            this_death = &Alien_Deaths[9];
 
 
3666
        }
 
 
3667
        else
 
 
3668
        {
 
 
3669
            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies, -1, 0);
 
 
3670
            this_death = &Alien_Deaths[0];
 
 
3671
        }
 
 
3672
    }
 
 
3673
    else // standing on flat
 
 
3674
    {
 
 
3675
        if (Standard == alienStatusPointer->Type)
 
 
3676
        {
 
 
3677
            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Back, -1, 0); //
not now
 
 
3678
            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Spin_Clockwise, -1, 0); //
now now
 
 
3679
 
 
 
3680
            if(damage->ExplosivePower)
 
 
3681
            {
 
 
3682
                if((FastRandom() & 65535) < 30000)
 
 
3683
                {
 
 
3684
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back,
-1, 0);
 
 
3685
                    this_death = &Alien_Deaths[3];
 
 
3686
                }
 
 
3687
                else if(facing.Front)
 
 
3688
                {
 
 
3689
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0);
 
 
3690
                    this_death = &Alien_Deaths[4];
 
 
3691
                }
 
 
3692
                else if(facing.Back)
 
 
3693
                {
 
 
3694
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0);
 
 
3695
                    this_death = &Alien_Deaths[6];
 
 
3696
                }
 
 
3697
            }
 
 
3698
            else if(damage->Electrical && ((FastRandom() & 65535) > 20000))
 
 
3699
            {
 
 
3700
                if((FastRandom() & 65535) < 30000)
 
 
3701
                {
 
 
3702
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0);
 
 
3703
                    this_death = &Alien_Deaths[5];
 
 
3704
                }
 
 
3705
                else
 
 
3706
                {
 
 
3707
                }
 
 
3708
            }
 
 
3709
            else
 
 
3710
            {
 
 
3711
                if(facing.Front && ((FastRandom() & 65535) < 30000))
 
 
3712
                {
 
 
3713
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0);
 
 
3714
                    this_death = &Alien_Deaths[4];
 
 
3715
                }
 
 
3716
                else
 
 
3717
                {
 
 
3718
                    switch(FastRandom() % 3)
 
 
3719
                    {
 
 
3720
                    case 0:
 
 
3721
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd,
-1, 0);
 
 
3722
                        this_death = &Alien_Deaths[6];
 
 
3723
                    break;
 
 
3724
                    case 1:
 
 
3725
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0);
 
 
3726
                        this_death = &Alien_Deaths[3];
 
 
3727
                    break;
 
 
3728
                    case 2:
 
 
3729
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0);
 
 
3730
                        this_death = &Alien_Deaths[5];
 
 
3731
                    }
 
 
3732
                }
 
 
3733
            }
 
 
3734
        }
 
 
3735
        else if (Predalien == alienStatusPointer->Type)
 
 
3736
        {
 
 
3737
            switch(FastRandom() % 4)
 
 
3738
            {
 
 
3739
            case 0:
 
 
3740
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back, -1,
0);
 
 
3741
                this_death = &Alien_Deaths[3];
 
 
3742
            break;
 
 
3743
            case 1:
 
 
3744
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0);
 
 
3745
                this_death = &Alien_Deaths[4];
 
 
3746
            break;
 
 
3747
            case 2:
 
 
3748
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd, -1,
0);
 
 
3749
                this_death = &Alien_Deaths[5];
 
 
3750
            break;
 
 
3751
            case 3:
 
 
3752
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0);
 
 
3753
                this_death = &Alien_Deaths[6];
 
 
3754
            }
 
 
3755
    /*
 
 
3756
            if(facing.Front)
 
 
3757
            {
 
 
3758
                if(fall_back)
 
 
3759
                {
 
 
3760
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0);
 
 
3761
                    this_death = &Alien_Deaths[4];
 
 
3762
                }
 
 
3763
                else
 
 
3764
                {
 
 
3765
                    if((FastRandom() & 65535) > 20000)
 
 
3766
                    {
 
 
3767
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Fwd, -1, 0);
 
 
3768
                        this_death = &Alien_Deaths[5];
 
 
3769
                    }
 
 
3770
                    else
 
 
3771
                    {
 
 
3772
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1,
0);
 
 
3773
                        this_death = &Alien_Deaths[4];
 
 
3774
                    }
 
 
3775
                }
 
 
3776
            }
 
 
3777
            else
 
 
3778
            {
 
 
3779
                if(fall_back)
 
 
3780
                {
 
 
3781
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0);
 
 
3782
                    this_death = &Alien_Deaths[5];
 
 
3783
                }
 
 
3784
                else
 
 
3785
                {
 
 
3786
                    if((FastRandom() & 65535) > 20000)
 
 
3787
                    {
 
 
3788
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0);
 
 
3789
                        this_death = &Alien_Deaths[3];
 
 
3790
                    }
 
 
3791
                    else
 
 
3792
                    {
 
 
3793
                        //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienStand,
(int)ASSS_Boom_Fall_Fwd, -1, 0);
 
 
3794
                        this_death = &Alien_Deaths[6];
 
 
3795
                    }
 
 
3796
                }
 
 
3797
            }
 
 
3798
    */
 
 
3799
        }
 
 
3800
        else
 
 
3801
        {
 
 
3802
            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Back, -1, 0);
// not now
 
 
3803
 
 
 
3804
            if(damage->Electrical)
 
 
3805
            {
 
 
3806
                //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back, -1,
0);
 
 
3807
                this_death = &Alien_Deaths[3];
 
 
3808
            }
 
 
3809
            else if(facing.Front)
 
 
3810
            {
 
 
3811
                if(damage->ExplosivePower)
 
 
3812
                {
 
 
3813
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Spin_Clockwise,
-1, 0);
 
 
3814
                    this_death = &Alien_Deaths[8];
 
 
3815
                }
 
 
3816
                else
 
 
3817
                {
 
 
3818
                    switch(FastRandom() % 3)
 
 
3819
                    {
 
 
3820
                        case 0:
 
 
3821
                            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies,
-1, 0);
 
 
3822
                            this_death = &Alien_Deaths[4];
 
 
3823
                        break;
 
 
3824
                        case 1:
 
 
3825
                            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0);
 
 
3826
                            this_death = &Alien_Deaths[3];
 
 
3827
                        break;
 
 
3828
                        case 2:
 
 
3829
                            //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Boom_Fall_Fwd, -1, 0);
 
 
3830
                            this_death = &Alien_Deaths[6];
 
 
3831
                    }
 
 
3832
                }
 
 
3833
            }
 
 
3834
            else
 
 
3835
            {
 
 
3836
                if((FastRandom() & 65535) < 20000)
 
 
3837
                {
 
 
3838
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back,
-1, 0);
 
 
3839
                    this_death = &Alien_Deaths[3];
 
 
3840
                }
 
 
3841
                else
 
 
3842
                {
 
 
3843
                    //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0);
 
 
3844
                    this_death = &Alien_Deaths[6];
 
 
3845
                }
 
 
3846
            }
 
 
3847
        }
 
 
3848
    }
 
 
3849
 
 
 
3850
if(this_death == NULL)
 
 
3851
this_death = GetDeathSequence(&alienStatusPointer->HModelController, NULL, alienStatusPointer->Wounds, alienStatusPointer->Wounds, deathtype,
&facing, 0, alienStatusPointer->IAmCrouched, electrical,2);
 
 
3852
 
 
 
3853
    Convert_Alien_To_Corpse(sbPtr, this_death, damage);
 
 
3854
 
 
 
3855
    if(SinglePlayer != AvP.PlayMode)
 
 
3856
        AddNetMsg_AlienAIKilled(sbPtr, this_death->Multiplayer_Code, ALIEN_DYINGTIME, GibbFactor, damage);
 
 
3857
}
 
 
3858
 
 
 
3859
/*----------------------Patrick 7/11/96-----------------------------
 
 
3860
Handle weapon impact on an alien
 
 
3861
--------------------------------------------------------------------*/
 
 
3862
/* KJL 11:46:43 12/17/96 - rewritten */
 
 
3863
 
 
 
3864
// JB 16/6/97 rewritten
 
 
3865
// Patrick 29/7/97 rewritten again. again.
 
 
3866
// ChrisF 16/9/97 rewritten again again, again.
 
 
3867
// ChrisF 26/11/97 rewritten again, again, again, again.
 
 
3868
// ChrisF 1/4/98 rewritten again again again again again.  Okay, 'modified' then. Added directional parameter.
 
 
3869
// ChrisF 20/11/98 rewritten again again again again again again, added hit delta support.
 
 
3870
// ChrisF 15/2/99 rewritten again again again again again again again, added fragging noise.
 
 
3871
 
 
 
3872
void AlienIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, int wounds, SECTION_DATA *Section, VECTORCH *incoming)
 
 
3873
{
 
 
3874
    ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3875
 
 
 
3876
    alienStatusPointer->Wounds |= wounds;
 
 
3877
 
 
 
3878
    alienStatusPointer->CanStand = !((alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg))
 
 
3879
    || ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot)));
 
 
3880
 
 
 
3881
    /* Can only climb if alien has both hands... */
 
 
3882
    alienStatusPointer->CanClimb = !((alienStatusPointer->Wounds & section_flag_left_hand) || (alienStatusPointer->Wounds &
section_flag_right_hand));
 
 
3883
 
 
 
3884
    //if(!(alienStatusPointer->CanStand && alienStatusPointer->CanClimb))
 
 
3885
 
 
 
3886
    if(!alienStatusPointer->CanStand)
 
 
3887
        alienStatusPointer->IAmCrouched = 1;
 
 
3888
 
 
 
3889
    //if (incoming) printf("Alien hit from %d %d %d\n", incoming->vx, incoming->vy, incoming->vz);
 
 
3890
 
 
 
3891
    if (sbPtr->DamageBlock.Health <= 0)
 
 
3892
    {
 
 
3893
        if (AvP.PlayerType != I_Alien)
 
 
3894
            CurrentGameStats_CreatureKilled(sbPtr, Section);
 
 
3895
 
 
 
3896
        sbPtr->DynPtr->UseStandardGravity = 1;
 
 
3897
        KillAlien(sbPtr, wounds, damage, incoming);
 
 
3898
    }
 
 
3899
    else //if(!alienStatusPointer->unconscious)
 
 
3900
    {
 
 
3901
        if(incoming && damage->ExplosivePower)
 
 
3902
            sbPtr->DynPtr->UseStandardGravity = 1;
 
 
3903
 
 
 
3904
        switch(alienStatusPointer->BehaviourState)
 
 
3905
        {
 
 
3906
            ABS_Avoidance:
 
 
3907
            break;
 
 
3908
            case ABS_Dormant:
 
 
3909
                Alien_Awaken(sbPtr);
 
 
3910
            break;
 
 
3911
            default:
 
 
3912
                if(NULL == alienStatusPointer->Target)
 
 
3913
                {
 
 
3914
                    NPC_OBSTRUCTIONREPORT obstruction = {0, 0, 1, 0};
 
 
3915
                    NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3916
                    NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
3917
                    alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
3918
                    alienStatusPointer->StateTimer = NPC_AVOIDTIME;
 
 
3919
                    //alienStatusPointer->BehaviourState = ABS_Retreat;
 
 
3920
                }
 
 
3921
                else if(alienStatusPointer->Wounds && ((FastRandom() & 32) < 11))
 
 
3922
                {
 
 
3923
                    if(!alienStatusPointer->IAmCrouched || alienStatusPointer->incidentFlag)
 
 
3924
                    {
 
 
3925
                        if((Praetorian != alienStatusPointer->Type))
 
 
3926
                        {
 
 
3927
                            NPC_OBSTRUCTIONREPORT obstruction = {0, 0, 1, 0};
 
 
3928
                            NPC_InitMovementData(&alienStatusPointer->moveData);
 
 
3929
                            NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction);
 
 
3930
                            alienStatusPointer->BehaviourState = ABS_Avoidance;
 
 
3931
                            alienStatusPointer->StateTimer = NPC_AVOIDTIME/8;
 
 
3932
                        }
 
 
3933
                    }
 
 
3934
                    else
 
 
3935
                    {
 
 
3936
                        sbPtr->DynPtr->UseStandardGravity = 1;
 
 
3937
                    }
 
 
3938
                }
 
 
3939
        }
 
 
3940
 
 
 
3941
        if(!alienStatusPointer->CanStand)
 
 
3942
            SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Crawl_Hurt, ONE_FIXED >> 1, (ONE_FIXED >> 2));
 
 
3943
 
 
 
3944
        if(((alienStatusPointer->Wounds & section_flag_left_arm) && (alienStatusPointer->Wounds & section_flag_right_arm))
 
 
3945
        ||
 
 
3946
        ((alienStatusPointer->Wounds & section_flag_left_hand) && (alienStatusPointer->Wounds & section_flag_right_hand)))
 
 
3947
        {
 
 
3948
            alienStatusPointer->MaxSpeed = 800;
 
 
3949
        }
 
 
3950
        else
 
 
3951
        {
 
 
3952
            RecomputeAlienSpeed(sbPtr);
 
 
3953
        }
 
 
3954
 
 
 
3955
        /* Now, get anim speed. */
 
 
3956
 
 
 
3957
        HMODEL_SEQUENCE_TYPES sequence_type = (HMODEL_SEQUENCE_TYPES)alienStatusPointer->HModelController.Sequence_Type;
 
 
3958
 
 
 
3959
        int subsequence = alienStatusPointer->HModelController.Sub_Sequence;
 
 
3960
        /* That is what the controller thinks the shape is playing. */
 
 
3961
 
 
 
3962
        int factor = GetAlienSpeedFactor_ForSequence(sbPtr, sequence_type, subsequence);
 
 
3963
        int changespeed = 0;
 
 
3964
 
 
 
3965
        switch (alienStatusPointer->Type)
 
 
3966
        {
 
 
3967
            case Standard:
 
 
3968
                changespeed = (factor != ONE_FIXED);
 
 
3969
            break;
 
 
3970
            case Predalien:
 
 
3971
                changespeed = (factor != PREDALIEN_SPEED_FACTOR);
 
 
3972
            break;
 
 
3973
            case Praetorian:
 
 
3974
                changespeed = (factor != PRAETORIAN_SPEED_FACTOR);
 
 
3975
        }
 
 
3976
 
 
 
3977
        if (changespeed)
 
 
3978
        {
 
 
3979
            /* ONE_FIXED implies we're playing an invariant length anim. */
 
 
3980
            int newspeed = DIV_FIXED(alienStatusPointer->last_anim_length, factor);
 
 
3981
 
 
 
3982
            HModel_ChangeSpeed(&alienStatusPointer->HModelController, newspeed);
 
 
3983
        }
 
 
3984
 
 
 
3985
        if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX)
 
 
3986
        {
 
 
3987
            int pitch = (FastRandom() & 255) - 128;
 
 
3988
 
 
 
3989
            SpeciesSound((int)alienStatusPointer->Type, ASC_Scream_Hurt, pitch, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position,
ALIEN_SOUND);
 
 
3990
 
 
 
3991
            if(NetworkPeer == AvP.PlayMode)
 
 
3992
                AddNetMsg_SpotAlienSound(ASC_Scream_Hurt, (int)alienStatusPointer->Type, pitch, &sbPtr->DynPtr->Position);
 
 
3993
        }
 
 
3994
 
 
 
3995
        if (TotalKineticDamage(damage) >= 10)
 
 
3996
        {
 
 
3997
            int frontback = 1;
 
 
3998
 
 
 
3999
            if (incoming && (incoming->vz >= 0))
 
 
4000
                frontback = 0;
 
 
4001
 
 
 
4002
            if (frontback)
 
 
4003
            {
 
 
4004
                DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&alienStatusPointer->HModelController, "HitDelta");
 
 
4005
 
 
 
4006
                /* Only do it from the front. */
 
 
4007
                if (hitdelta && !hitdelta->Playing)
 
 
4008
                {
 
 
4009
                    if(damage->ExplosivePower && (sbPtr->DynPtr->OrientMat.mat22 > 63000))
 
 
4010
                    {
 
 
4011
                        if(!alienStatusPointer->IAmCrouched)
 
 
4012
                        {
 
 
4013
                            if ((Praetorian == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000))
 
 
4014
                                InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand,
(int)ASSS_Spin_Clockwise, -1, 0);
 
 
4015
                            else
 
 
4016
                                InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies,
-1, 0);
 
 
4017
 
 
 
4018
                            alienStatusPointer->unconscious = ONE_FIXED * 5 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
4019
                        }
 
 
4020
                        else if ((Standard == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000))
 
 
4021
                        {
 
 
4022
                            InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl,
(int)ACSS_Boom_Fall_Back, ONE_FIXED, 0);
 
 
4023
                            alienStatusPointer->unconscious = ONE_FIXED * 6 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
4024
                        }
 
 
4025
                    }
 
 
4026
                    else
 
 
4027
                    {
 
 
4028
                        /* A hierarchy with hit deltas! */
 
 
4029
                        int CrouchSubSequence;
 
 
4030
                        int StandSubSequence;
 
 
4031
 
 
 
4032
                        if (Section == NULL)
 
 
4033
                        {
 
 
4034
                            if ((FastRandom() & 65535) < 32767)
 
 
4035
                            {
 
 
4036
                                CrouchSubSequence = ACrSS_Hit_Left;
 
 
4037
                                StandSubSequence = ASSS_Hit_Left;
 
 
4038
                            }
 
 
4039
                            else
 
 
4040
                            {
 
 
4041
                                CrouchSubSequence = ACrSS_Hit_Right;
 
 
4042
                                StandSubSequence = ASSS_Hit_Right;
 
 
4043
                            }
 
 
4044
                        }
 
 
4045
                        else if ((Section->sempai->flags & section_flag_left_arm) || (Section->sempai->flags & section_flag_left_hand))
 
 
4046
                        {
 
 
4047
                            CrouchSubSequence = ACrSS_Hit_Left;
 
 
4048
                            StandSubSequence = ASSS_Hit_Left;
 
 
4049
                        }
 
 
4050
                        else if ((Section->sempai->flags & section_flag_right_arm) || (Section->sempai->flags & section_flag_right_hand))
 
 
4051
                        {
 
 
4052
                            CrouchSubSequence = ACrSS_Hit_Right;
 
 
4053
                            StandSubSequence = ASSS_Hit_Right;
 
 
4054
                        }
 
 
4055
                        else
 
 
4056
                        {
 
 
4057
                            /* Chest or misc. hit. */
 
 
4058
                            if ((FastRandom() & 65535) < 32767)
 
 
4059
                            {
 
 
4060
                                CrouchSubSequence = ACrSS_Hit_Left;
 
 
4061
                                StandSubSequence = ASSS_Hit_Left;
 
 
4062
                            }
 
 
4063
                            else
 
 
4064
                            {
 
 
4065
                                CrouchSubSequence = ACrSS_Hit_Right;
 
 
4066
                                StandSubSequence = ASSS_Hit_Right;
 
 
4067
                            }
 
 
4068
                        }
 
 
4069
 
 
 
4070
                        if(alienStatusPointer->IAmCrouched)
 
 
4071
                        {
 
 
4072
                            if (HModelSequence_Exists(&alienStatusPointer->HModelController, (int)HMSQT_AlienCrouch, CrouchSubSequence))
 
 
4073
                                Start_Delta_Sequence(hitdelta, (int)HMSQT_AlienCrouch, CrouchSubSequence, -1);
 
 
4074
                        }
 
 
4075
                        else
 
 
4076
                        {
 
 
4077
                            if (HModelSequence_Exists(&alienStatusPointer->HModelController, (int)HMSQT_AlienStand, StandSubSequence))
 
 
4078
                                Start_Delta_Sequence(hitdelta, (int)HMSQT_AlienStand, StandSubSequence, -1);
 
 
4079
                        }
 
 
4080
                    }
 
 
4081
                }
 
 
4082
                else if(damage->ExplosivePower && (sbPtr->DynPtr->OrientMat.mat22 > 63000))
 
 
4083
                {
 
 
4084
                    if(!alienStatusPointer->IAmCrouched)
 
 
4085
                    {
 
 
4086
                        if ((Praetorian == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000))
 
 
4087
                            InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand,
(int)ASSS_Spin_Clockwise, -1, 0);
 
 
4088
                        else
 
 
4089
                            InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1,
0);
 
 
4090
 
 
 
4091
                        alienStatusPointer->unconscious = ONE_FIXED * 5 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
4092
                    }
 
 
4093
                    else if ((Standard == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000))
 
 
4094
                    {
 
 
4095
                        InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl,
(int)ACSS_Boom_Fall_Back, ONE_FIXED, 0);
 
 
4096
                        alienStatusPointer->unconscious = ONE_FIXED * 6 + ( (FastRandom() & 7) * ONE_FIXED);
 
 
4097
                    }
 
 
4098
                }
 
 
4099
            }
 
 
4100
        }
 
 
4101
    }
 
 
4102
}
 
 
4103
 
 
 
4104
/*--------------------**
 
 
4105
** Loading and Saving **
 
 
4106
**--------------------*/
 
 
4107
#include "savegame.h"
 
 
4108
typedef struct alien_save_block
 
 
4109
{
 
 
4110
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
4111
 
 
 
4112
    ALIEN_TYPE Type;
 
 
4113
    int Wounds;
 
 
4114
    int last_anim_length;
 
 
4115
    ALIEN_BHSTATE BehaviourState;    
 
 
4116
 
 
 
4117
    int incidentFlag;
 
 
4118
    int incidentTimer;
 
 
4119
 
 
 
4120
    int CurveRadius;
 
 
4121
    int CurveLength;
 
 
4122
    int CurveTimeOut;
 
 
4123
    int StateTimer;
 
 
4124
    int IAmCrouched;
 
 
4125
    int CurrentLightAtAlien;
 
 
4126
    int unconscious;
 
 
4127
    int CanStand;
 
 
4128
    int CanClimb;
 
 
4129
    int huntingModuleIndex;
 
 
4130
    int currentAttackCode;
 
 
4131
//    NPC_MOVEMENTDATA moveData;
 
 
4132
    NPC_WANDERDATA wanderData;
 
 
4133
 
 
 
4134
//    HMODELCONTROLLER HModelController;
 
 
4135
 
 
 
4136
//    STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator
 
 
4137
 
 
 
4138
    char Target_SBname[SB_NAME_LENGTH];
 
 
4139
    char Generator_SBname[SB_NAME_LENGTH];
 
 
4140
 
 
 
4141
    //strategyblock stuff
 
 
4142
    DAMAGEBLOCK DamageBlock;
 
 
4143
    DYNAMICSBLOCK dynamics;
 
 
4144
 
 
 
4145
} ALIEN_SAVE_BLOCK;
 
 
4146
 
 
 
4147
//defines for load/save macros
 
 
4148
#define SAVELOAD_BLOCK block
 
 
4149
#define SAVELOAD_BEHAV alienStatusPointer
 
 
4150
 
 
 
4151
void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
4152
{
 
 
4153
    ALIEN_STATUS_BLOCK* alienStatusPointer;
 
 
4154
    ALIEN_SAVE_BLOCK* block = (ALIEN_SAVE_BLOCK*) header; 
 
 
4155
 
 
 
4156
    //check the size of the save block
 
 
4157
    if(header->size != sizeof(*block))
 
 
4158
        return;
 
 
4159
 
 
 
4160
    //find the existing strategy block
 
 
4161
    STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname);
 
 
4162
 
 
 
4163
    if(sbPtr)
 
 
4164
    {
 
 
4165
        //make sure the strategy found is of the right type
 
 
4166
        if(sbPtr->type != I_BehaviourAlien)
 
 
4167
            return;
 
 
4168
    }
 
 
4169
    else
 
 
4170
    {
 
 
4171
        //we will have to generate an alien then
 
 
4172
        TOOLS_DATA_ALIEN tda;
 
 
4173
 
 
 
4174
        //make sure the alien is in a module 
 
 
4175
        if(!ModuleFromPosition(&block->dynamics.Position, NULL))
 
 
4176
            return;
 
 
4177
 
 
 
4178
        sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien);
 
 
4179
 
 
 
4180
        if(!sbPtr)
 
 
4181
            return;
 
 
4182
 
 
 
4183
        sbPtr->maintainVisibility = 1;
 
 
4184
        COPY_NAME(sbPtr->SBname,block->header.SBname);
 
 
4185
 
 
 
4186
        //create using a fake tools data
 
 
4187
        tda.position = block->dynamics.Position;
 
 
4188
        COPY_NAME(tda.nameID, block->header.SBname);
 
 
4189
        COPY_NAME(tda.death_target_ID, Null_Name);
 
 
4190
        tda.type = block->Type;
 
 
4191
        tda.start_inactive = 0;
 
 
4192
 
 
 
4193
        tda.starteuler.EulerX = tda.starteuler.EulerY = tda.starteuler.EulerZ = 0;
 
 
4194
 
 
 
4195
         EnableBehaviourType(sbPtr, &tda);
 
 
4196
     }
 
 
4197
 
 
 
4198
    alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->dataptr;
 
 
4199
 
 
 
4200
    //start copying stuff
 
 
4201
 
 
 
4202
    COPYELEMENT_LOAD(Type)
 
 
4203
    COPYELEMENT_LOAD(Wounds)
 
 
4204
    COPYELEMENT_LOAD(last_anim_length)
 
 
4205
    COPYELEMENT_LOAD(BehaviourState)
 
 
4206
    COPYELEMENT_LOAD(incidentFlag)
 
 
4207
    COPYELEMENT_LOAD(incidentTimer)
 
 
4208
    COPYELEMENT_LOAD(CurveRadius)
 
 
4209
    COPYELEMENT_LOAD(CurveLength)
 
 
4210
    COPYELEMENT_LOAD(CurveTimeOut)
 
 
4211
    COPYELEMENT_LOAD(StateTimer)
 
 
4212
    COPYELEMENT_LOAD(IAmCrouched)
 
 
4213
    COPYELEMENT_LOAD(CurrentLightAtAlien)
 
 
4214
    COPYELEMENT_LOAD(unconscious)
 
 
4215
    COPYELEMENT_LOAD(CanStand)
 
 
4216
    COPYELEMENT_LOAD(CanClimb)
 
 
4217
    COPYELEMENT_LOAD(wanderData)
 
 
4218
 
 
 
4219
    //load target
 
 
4220
    COPY_NAME(alienStatusPointer->Target_SBname,block->Target_SBname);
 
 
4221
    alienStatusPointer->Target = FindSBWithName(alienStatusPointer->Target_SBname);
 
 
4222
 
 
 
4223
    //load hunting module
 
 
4224
    if(block->huntingModuleIndex >= 0 && block->huntingModuleIndex < AIModuleArraySize)
 
 
4225
        alienStatusPointer->huntingModule = &AIModuleArray[block->huntingModuleIndex];
 
 
4226
    else
 
 
4227
        alienStatusPointer->huntingModule = NULL;
 
 
4228
 
 
 
4229
    //get the alien's attack from the attack code
 
 
4230
    alienStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode);
 
 
4231
 
 
 
4232
    *sbPtr->DynPtr = block->dynamics;
 
 
4233
    sbPtr->DamageBlock = block->DamageBlock;
 
 
4234
 
 
 
4235
    //find the alien's generator
 
 
4236
    alienStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname);
 
 
4237
 
 
 
4238
    //load the aliens hierarchy
 
 
4239
    {
 
 
4240
        SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
4241
 
 
 
4242
        if(hier_header)
 
 
4243
            LoadHierarchy(hier_header,&alienStatusPointer->HModelController);
 
 
4244
    }
 
 
4245
 
 
 
4246
    Load_SoundState(&alienStatusPointer->soundOnFire);
 
 
4247
    Load_SoundState(&alienStatusPointer->sound_mouth);
 
 
4248
}
 
 
4249
 
 
 
4250
void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr)
 
 
4251
{
 
 
4252
    ALIEN_SAVE_BLOCK *block;
 
 
4253
    ALIEN_STATUS_BLOCK* alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->dataptr;
 
 
4254
 
 
 
4255
    GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
 
 
4256
 
 
 
4257
    //start copying stuff
 
 
4258
 
 
 
4259
    COPYELEMENT_SAVE(Type)
 
 
4260
    COPYELEMENT_SAVE(Wounds)
 
 
4261
    COPYELEMENT_SAVE(last_anim_length)
 
 
4262
    COPYELEMENT_SAVE(BehaviourState)
 
 
4263
    COPYELEMENT_SAVE(incidentFlag)
 
 
4264
    COPYELEMENT_SAVE(incidentTimer)
 
 
4265
    COPYELEMENT_SAVE(CurveRadius)
 
 
4266
    COPYELEMENT_SAVE(CurveLength)
 
 
4267
    COPYELEMENT_SAVE(CurveTimeOut)
 
 
4268
    COPYELEMENT_SAVE(StateTimer)
 
 
4269
    COPYELEMENT_SAVE(IAmCrouched)
 
 
4270
    COPYELEMENT_SAVE(CurrentLightAtAlien)
 
 
4271
    COPYELEMENT_LOAD(unconscious)
 
 
4272
    COPYELEMENT_LOAD(CanStand)
 
 
4273
    COPYELEMENT_LOAD(CanClimb)
 
 
4274
    COPYELEMENT_SAVE(wanderData)
 
 
4275
 
 
 
4276
    //save target
 
 
4277
    COPY_NAME(block->Target_SBname,alienStatusPointer->Target_SBname);
 
 
4278
 
 
 
4279
    //save hunting module
 
 
4280
    if(alienStatusPointer->huntingModule)
 
 
4281
        block->huntingModuleIndex = alienStatusPointer->huntingModule->m_index;
 
 
4282
    else
 
 
4283
        block->huntingModuleIndex = -1;
 
 
4284
 
 
 
4285
    //save attack code
 
 
4286
    if(alienStatusPointer->current_attack)
 
 
4287
        block->currentAttackCode = alienStatusPointer->current_attack->Unique_Code;
 
 
4288
    else
 
 
4289
        block->currentAttackCode = -1;
 
 
4290
 
 
 
4291
    //save the alien's generator name
 
 
4292
    if(alienStatusPointer->generator_sbptr)
 
 
4293
    {
 
 
4294
        COPY_NAME(block->Generator_SBname, alienStatusPointer->generator_sbptr->SBname);
 
 
4295
    }
 
 
4296
    else
 
 
4297
    {
 
 
4298
        COPY_NAME(block->Generator_SBname, Null_Name);
 
 
4299
    }
 
 
4300
 
 
 
4301
    block->dynamics = *sbPtr->DynPtr;
 
 
4302
    block->dynamics.CollisionReportPtr = 0;
 
 
4303
    block->DamageBlock = sbPtr->DamageBlock;
 
 
4304
 
 
 
4305
    //save the aliens hierarchy
 
 
4306
    SaveHierarchy(&alienStatusPointer->HModelController);
 
 
4307
 
 
 
4308
    Save_SoundState(&alienStatusPointer->soundOnFire);
 
 
4309
    Save_SoundState(&alienStatusPointer->sound_mouth);
 
 
4310
}