4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
#include "npc_queen.h"
 
 
2
#include "npc_common.h"
 
 
3
#include "dynamics.h"
 
 
4
#include "sequnces.h"
 
 
5
#include "bh_track.h"
 
 
6
#include "sfx.h"
 
 
7
#include <math.h>
 
 
8
#include <stdlib.h>
 
 
9
#include <string.h>
 
 
10
 
 
 
11
    enum QueenLeftStanceTemplateSubSequences
 
 
12
    {
 
 
13
        QLSTSS_Standard,
 
 
14
        QLSTSS_Forward_L2R,
 
 
15
        QLSTSS_Backward_L2R,
 
 
16
        QLSTSS_Right_L2L,
 
 
17
        QLSTSS_Left_L2L,
 
 
18
        QLSTSS_LeftSwipe,
 
 
19
        QLSTSS_RightSwipe,
 
 
20
        QLSTSS_RightHit,
 
 
21
        QLSTSS_LeftHit,
 
 
22
        QLSTSS_end
 
 
23
    };
 
 
24
 
 
 
25
    enum QueenLeftStanceFull_SubSequences
 
 
26
    {
 
 
27
        QLSFSS_Standard_Hiss,
 
 
28
        QLSFSS_Taunt,
 
 
29
        QLSFSS_Forward_L2R,
 
 
30
        QLSFSS_Backward_L2R,
 
 
31
        QLSFSS_Right_L2L,
 
 
32
        QLSFSS_Left_L2L,
 
 
33
        QLSFSS_end
 
 
34
    };
 
 
35
 
 
 
36
    enum QueenRightStanceTemplateSubSequences
 
 
37
    {
 
 
38
        QRSTSS_Standard,
 
 
39
        QRSTSS_Forward_R2L,
 
 
40
        QRSTSS_Backward_R2L,
 
 
41
        QRSTSS_Right_R2R,
 
 
42
        QRSTSS_Left_R2R,
 
 
43
        QRSTSS_LeftSwipe,
 
 
44
        QRSTSS_RightSwipe,
 
 
45
        QRSTSS_RightHit,
 
 
46
        QRSTSS_LeftHit,
 
 
47
        QRSTSS_LeftSwipe_Low,
 
 
48
        QRSTSS_RightSwipe_Low,
 
 
49
        QRSTSS_end
 
 
50
    };
 
 
51
 
 
 
52
    enum QueenRightStanceFull_SubSequences
 
 
53
    {
 
 
54
        QRSFSS_Standard_Hiss,
 
 
55
        QRSFSS_Taunt,
 
 
56
        QRSFSS_Forward_R2L,
 
 
57
        QRSFSS_Backward_R2L,
 
 
58
        QRSFSS_Right_R2R,
 
 
59
        QRSFSS_Left_R2R,
 
 
60
        QRSFSS_end
 
 
61
    };
 
 
62
 
 
 
63
    enum QueenGeneral_SubSequences
 
 
64
    {
 
 
65
        QGSS_SquashDeath,
 
 
66
        QGSS_FaceDeath,
 
 
67
        QGSS_FallDeath,
 
 
68
        QGSS_ButtConnect,
 
 
69
        QGSS_RunButtAttack,
 
 
70
        QGSS_Walk,
 
 
71
        QGSS_Explode_Death,
 
 
72
        QGSS_Sprint,
 
 
73
        QGSS_Stop_To_Left,
 
 
74
        QGSS_Stop_To_Right,
 
 
75
        QGSS_Walk_II,
 
 
76
        QGSS_Sprint_II,
 
 
77
        QGSS_Spine_Elevation,
 
 
78
        QGSS_Search_Floor,
 
 
79
        QGSS_Fire_Flinch,
 
 
80
        QGSS_Fire_Steps,
 
 
81
        QGSS_Sprint_Full,
 
 
82
        QGSS_Explosion_Stun,
 
 
83
        QGSS_ClimbOut,
 
 
84
        QGSS_end
 
 
85
    };
 
 
86
 
 
 
87
extern void AssignNewSBName(STRATEGYBLOCK *sbPtr);
 
 
88
extern const MATRIXCH IdentityMatrix;
 
 
89
 
 
 
90
#define QueenAttackRange 3500
 
 
91
 
 
 
92
/*minimum time for flamethrower before queen takes notice*/
 
 
93
#define QueenMinimumFireTime ONE_FIXED/8
 
 
94
 
 
 
95
static int PlayerInTrench = 0;
 
 
96
static int PlayerInLocker = 0;
 
 
97
static int AirlockTimeOpen = 0;
 
 
98
 
 
 
99
/*special hangar airlock state stuff*/
 
 
100
static int UpperAirlockDoorOpen = 0;
 
 
101
static int LowerAirlockDoorOpen = 0;
 
 
102
static STRATEGYBLOCK* UpperAirlockDoorSbptr = 0;
 
 
103
static VECTORCH UpperAirlockDoorStart;
 
 
104
static STRATEGYBLOCK* LowerAirlockDoorSbptr = 0;
 
 
105
static VECTORCH LowerAirlockDoorStart;
 
 
106
static STRATEGYBLOCK* LockerDoorSbptr = 0;
 
 
107
 
 
 
108
#define QUEEN_MAX_OBJECT 10
 
 
109
int NumQueenObjects;
 
 
110
STRATEGYBLOCK* QueenObjectList[QUEEN_MAX_OBJECT];
 
 
111
 
 
 
112
QUEEN_MANOEUVRE Queen_Next_Command;
 
 
113
 
 
 
114
int Queen_Next_Waypoint = 0;
 
 
115
int Queen_Walk_Rate = 100000;
 
 
116
int Queen_Walk_Step_Speed = ONE_FIXED/4.5;
 
 
117
int Queen_ButtCharge_Rate = 30000;
 
 
118
int Queen_Step_Time = 50000;
 
 
119
int Queen_Charge_Step_Speed = 7500;
 
 
120
int Queen_Turn_Rate = (NPC_TURNRATE>>2);
 
 
121
 
 
 
122
#define QUEEN_BUTTCHARGE_SPEED 16000
 
 
123
#define QUEEN_CHARGE_SPEED 12000
 
 
124
#define QUEEN_CLOSE_SPEED 3000
 
 
125
#define QUEEN_WALK_SPEED 7000
 
 
126
#define QUEEN_THROWN_OBJECT_SPEED 60000
 
 
127
 
 
 
128
const VECTORCH Queen_Waypoints[] =
 
 
129
{
 
 
130
    {37361,2900,-51942},
 
 
131
    {32937,2900,-19959},
 
 
132
    {62809,2900,-28509},
 
 
133
    {64658,2900,-13328},
 
 
134
    {64658,0,-13328},
 
 
135
    {64991,2900,-50362},
 
 
136
    {32239,2900,-53578},
 
 
137
    {-1,-1,-1}
 
 
138
};
 
 
139
 
 
 
140
static void MakeNonFragable_Recursion(SECTION_DATA *this_section_data)
 
 
141
{
 
 
142
    /* flag this section. */
 
 
143
    this_section_data->sempai->flags |= section_flag_never_frag;
 
 
144
 
 
 
145
    /* Now call recursion... */
 
 
146
 
 
 
147
    if (this_section_data->First_Child != NULL)
 
 
148
    {
 
 
149
        SECTION_DATA *child_list_ptr = this_section_data->First_Child;
 
 
150
 
 
 
151
        while (child_list_ptr != NULL)
 
 
152
        {
 
 
153
            MakeNonFragable_Recursion(child_list_ptr);
 
 
154
            child_list_ptr = child_list_ptr->Next_Sibling;
 
 
155
        }
 
 
156
    }
 
 
157
}
 
 
158
 
 
 
159
static void MakeNonFragable(HMODELCONTROLLER *controller)
 
 
160
{
 
 
161
    MakeNonFragable_Recursion(controller->section_data);
 
 
162
}
 
 
163
 
 
 
164
static int make_new_queen(STRATEGYBLOCK *sbPtr)
 
 
165
{
 
 
166
    sbPtr->dataptr = malloc(sizeof(QUEEN_STATUS_BLOCK));
 
 
167
    sbPtr->maintainVisibility = 1;
 
 
168
    sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
169
 
 
 
170
    if(NULL == sbPtr->dataptr)
 
 
171
    {
 
 
172
        RemoveBehaviourStrategy(sbPtr);
 
 
173
        return 0;
 
 
174
    }
 
 
175
 
 
 
176
    {
 
 
177
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_AlienQueen];
 
 
178
        sbPtr->DamageBlock = NpcData->StartingStats;
 
 
179
        sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
180
        sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
181
    }
 
 
182
 
 
 
183
    QUEEN_STATUS_BLOCK *new_queen = (QUEEN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
184
 
 
 
185
    NPC_InitMovementData(&new_queen->moveData);
 
 
186
    NPC_InitWanderData(&new_queen->wanderData);
 
 
187
 
 
 
188
    new_queen->HModelController.Deltas = NULL;
 
 
189
    new_queen->HModelController.Root_Section = NULL;
 
 
190
    new_queen->HModelController.section_data = NULL;
 
 
191
    new_queen->QueenState = QBS_Reconsider;
 
 
192
    new_queen->current_move = QM_Standby;
 
 
193
    new_queen->next_move = QM_Standby;
 
 
194
    new_queen->fixed_foot = RightFoot;
 
 
195
    new_queen->fixed_foot_section = NULL;
 
 
196
    new_queen->fixed_foot_oldpos.vx = new_queen->fixed_foot_oldpos.vy = new_queen->fixed_foot_oldpos.vz = 0;
 
 
197
    new_queen->TargetPos.vx = new_queen->TargetPos.vy = new_queen->TargetPos.vz = 0;
 
 
198
    new_queen->moveTimer = 0;
 
 
199
 
 
 
200
    new_queen->attack_delta = NULL;
 
 
201
    new_queen->hit_delta = NULL;
 
 
202
    new_queen->TargetPos.vx = 0;
 
 
203
    new_queen->TargetPos.vy = 0;
 
 
204
    new_queen->TargetPos.vz = 0;
 
 
205
 
 
 
206
    {
 
 
207
    int i;
 
 
208
    for(i=0; i < SB_NAME_LENGTH; i++)
 
 
209
        new_queen->death_target_ID[i] = 0;
 
 
210
    }
 
 
211
 
 
 
212
    new_queen->death_target_sbptr = NULL;
 
 
213
    new_queen->death_target_request = 0;
 
 
214
 
 
 
215
    new_queen->TempTarget = 0;
 
 
216
    new_queen->TempTargetTimer = 0;
 
 
217
    new_queen->CurrentQueenObject = 0;
 
 
218
    new_queen->QueenStateTimer = 0;
 
 
219
    new_queen->QueenObjectBias = 1;
 
 
220
    new_queen->QueenPlayerBias = 5;
 
 
221
    new_queen->QueenTauntTimer = 0;
 
 
222
    new_queen->QueenFireTimer = 0;
 
 
223
    new_queen->LastVelocity.vx = 0;
 
 
224
    new_queen->LastVelocity.vy = 0;
 
 
225
    new_queen->LastVelocity.vz = 0;
 
 
226
 
 
 
227
    new_queen->QueenRightHand = NULL;
 
 
228
    new_queen->QueenTargetSB = NULL;
 
 
229
 
 
 
230
    new_queen->BeenInAirlock = 0;
 
 
231
    new_queen->QueenActivated = 0; //queen is inactive until seen
 
 
232
 
 
 
233
    new_queen->TargetInfoValid = 0; //have the next three items been set
 
 
234
    new_queen->TargetDistance = 0; //distance of current target from queen
 
 
235
    new_queen->TargetRelSpeed = 0; //targets speed in queen's direction
 
 
236
    new_queen->TargetDirection.vx = 0;
 
 
237
    new_queen->TargetDirection.vy = 0;
 
 
238
    new_queen->TargetDirection.vz = 0;
 
 
239
    new_queen->VectToTarget.vx = 0;
 
 
240
    new_queen->VectToTarget.vy = 0;
 
 
241
    new_queen->VectToTarget.vz = 0;
 
 
242
 
 
 
243
    new_queen->PlayingHitDelta = 0;
 
 
244
 
 
 
245
    new_queen->SwerveTimer = 0;
 
 
246
    new_queen->SwerveDirection = 0;
 
 
247
 
 
 
248
    new_queen->ClimbStartPosition.vx = 0;
 
 
249
    new_queen->ClimbStartPosition.vy = 0;
 
 
250
    new_queen->ClimbStartPosition.vz = 0;
 
 
251
    new_queen->AttackDoneItsDamage = 0;
 
 
252
 
 
 
253
    new_queen->upper_airlockdoor_sbptr = NULL;
 
 
254
    new_queen->upper_airlockdoor_start.vx = 0;
 
 
255
    new_queen->upper_airlockdoor_start.vy = 0;
 
 
256
    new_queen->upper_airlockdoor_start.vz = 0;
 
 
257
    new_queen->lower_airlockdoor_sbptr = NULL;
 
 
258
    new_queen->lower_airlockdoor_start.vx = 0;
 
 
259
    new_queen->lower_airlockdoor_start.vy = 0;
 
 
260
    new_queen->lower_airlockdoor_start.vz = 0;
 
 
261
 
 
 
262
    new_queen->soundHandle = SOUND_NOACTIVEINDEX;
 
 
263
    new_queen->lastSoundCategory = QSC_Hiss;
 
 
264
 
 
 
265
    SECTION *root_section = GetNamedHierarchyFromLibrary("queen", "Template");
 
 
266
 
 
 
267
    if((NULL == root_section) || !sbPtr->containingModule)
 
 
268
    {
 
 
269
        RemoveBehaviourStrategy(sbPtr);
 
 
270
        printf("Failed to load queen hmodel\n");
 
 
271
        return 0;
 
 
272
    }
 
 
273
 
 
 
274
    Create_HModel(&new_queen->HModelController, root_section);
 
 
275
    InitHModelSequence(&new_queen->HModelController, (int)HMSQT_QueenRightStanceTemplate, (int)QRSTSS_Standard, ONE_FIXED);
 
 
276
 
 
 
277
    new_queen->HModelController.Looped = 1;
 
 
278
    new_queen->attack_delta = Add_Delta_Sequence(&new_queen->HModelController, "attack", (int)HMSQT_QueenRightStanceTemplate,
(int)QRSTSS_LeftSwipe, Queen_Step_Time);
 
 
279
    new_queen->hit_delta = Add_Delta_Sequence(&new_queen->HModelController, "hit", (int)HMSQT_QueenRightStanceTemplate, (int)QRSTSS_LeftHit,
Queen_Step_Time);
 
 
280
 
 
 
281
    if(AvP.PlayerType == I_Marine)
 
 
282
        MakeNonFragable(&new_queen->HModelController);
 
 
283
 
 
 
284
    NumQueenObjects = -1;
 
 
285
 
 
 
286
return 1;
 
 
287
}
 
 
288
 
 
 
289
void SetQueenFoot(STRATEGYBLOCK *sbPtr, QUEEN_FOOT foot)
 
 
290
{
 
 
291
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
292
    DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
293
    assert(dPtr);
 
 
294
 
 
 
295
    ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
296
 
 
 
297
    switch (foot)
 
 
298
    {
 
 
299
        case LeftFoot:
 
 
300
            queenStatusPointer->fixed_foot = LeftFoot;
 
 
301
            queenStatusPointer->fixed_foot_section = GetThisSectionData(queenStatusPointer->HModelController.section_data, "left foot");
 
 
302
            assert(queenStatusPointer->fixed_foot_section);
 
 
303
            queenStatusPointer->fixed_foot_oldpos = queenStatusPointer->fixed_foot_section->World_Offset;
 
 
304
        break;
 
 
305
        case RightFoot:
 
 
306
            queenStatusPointer->fixed_foot = RightFoot;
 
 
307
            queenStatusPointer->fixed_foot_section = GetThisSectionData(queenStatusPointer->HModelController.section_data, "right foot");
 
 
308
            assert(queenStatusPointer->fixed_foot_section);
 
 
309
            queenStatusPointer->fixed_foot_oldpos = queenStatusPointer->fixed_foot_section->World_Offset;
 
 
310
        break;
 
 
311
        default:
 
 
312
            assert(0);
 
 
313
            break;
 
 
314
    }
 
 
315
}
 
 
316
 
 
 
317
void MakeQueenNear(STRATEGYBLOCK *sbPtr)
 
 
318
{
 
 
319
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
320
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
321
 
 
 
322
    assert(queenStatusPointer);
 
 
323
    assert(dynPtr);
 
 
324
 
 
 
325
    DISPLAYBLOCK *dPtr = CreateActiveObject();
 
 
326
 
 
 
327
    if(dPtr == NULL)
 
 
328
        return;
 
 
329
 
 
 
330
    sbPtr->DisplayBlock = dPtr;
 
 
331
    dPtr->ObStrategyBlock = sbPtr;
 
 
332
 
 
 
333
    /* also need to initialise positional information in the new display block, 
 
 
334
    from the existing dynamics block.
 
 
335
    NB this necessary because this function is (usually) called between the 
 
 
336
    dynamics and rendering systems so it is not initialised by the dynamics 
 
 
337
    system the first frame it is drawn. */
 
 
338
    dPtr->ObWorld = dynPtr->Position;
 
 
339
    dPtr->ObEuler = dynPtr->OrientEuler;
 
 
340
    dPtr->ObMat = dynPtr->OrientMat;
 
 
341
 
 
 
342
    /* init state timers */
 
 
343
 
 
 
344
    /* initialise our sequence data */
 
 
345
    dPtr->HModelControlBlock = &queenStatusPointer->HModelController;
 
 
346
 
 
 
347
    SetQueenFoot(sbPtr, RightFoot);
 
 
348
 
 
 
349
    /* Calls ProveHModel. */
 
 
350
}
 
 
351
 
 
 
352
void CreateQueenBot(VECTORCH *Position)
 
 
353
{
 
 
354
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourQueenAlien);
 
 
355
 
 
 
356
    if(!sbPtr)
 
 
357
    {
 
 
358
        GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
 
 
359
        return;
 
 
360
    }
 
 
361
 
 
 
362
    AssignNewSBName(sbPtr);
 
 
363
 
 
 
364
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
365
 
 
 
366
    if(sbPtr->DynPtr)
 
 
367
    {
 
 
368
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
369
 
 
 
370
        dynPtr->PrevPosition = dynPtr->Position = *Position;
 
 
371
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
372
        TransposeMatrixCH(&dynPtr->OrientMat);
 
 
373
        /* zero linear velocity in dynamics block */
 
 
374
        dynPtr->Displacement.vx = dynPtr->Displacement.vy =  dynPtr->Displacement.vz = 0;
 
 
375
        dynPtr->UseDisplacement = 1;
 
 
376
        dynPtr->Mass = 60000; /* No knockback, please. */
 
 
377
        make_new_queen(sbPtr);
 
 
378
    }
 
 
379
    else
 
 
380
    {
 
 
381
        /* dynamics block allocation failed... */
 
 
382
        RemoveBehaviourStrategy(sbPtr);
 
 
383
        GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
 
 
384
    }
 
 
385
}
 
 
386
 
 
 
387
void CastQueenBot()
 
 
388
{ 
 
 
389
    #define BOTRANGE 4000
 
 
390
 
 
 
391
    VECTORCH position;
 
 
392
    position = PlayerStatus.sbptr->DynPtr->Position;
 
 
393
    position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE);
 
 
394
    position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE);
 
 
395
    position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE);
 
 
396
 
 
 
397
    CreateQueenBot(&position);
 
 
398
}
 
 
399
 
 
 
400
static void QueenSoundHiss(STRATEGYBLOCK* sbPtr)
 
 
401
{
 
 
402
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
403
 
 
 
404
    if(queenStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
405
    {
 
 
406
        SpeciesSound(0, QSC_Hiss, 0, &queenStatusPointer->soundHandle, &sbPtr->DynPtr->Position, QUEEN_SOUND);
 
 
407
        queenStatusPointer->lastSoundCategory = QSC_Hiss;        
 
 
408
    }
 
 
409
}
 
 
410
 
 
 
411
static void QueenSoundHurt(STRATEGYBLOCK* sbPtr)
 
 
412
{
 
 
413
    assert(sbPtr);
 
 
414
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
415
 
 
 
416
    /* If the queen is currently playing a non-hurt sound then cancel it.  */
 
 
417
 
 
 
418
    if(queenStatusPointer->soundHandle != SOUND_NOACTIVEINDEX)
 
 
419
    {
 
 
420
        if(queenStatusPointer->lastSoundCategory != QSC_Scream_Hurt)
 
 
421
            Sound_Stop(queenStatusPointer->soundHandle);
 
 
422
    }
 
 
423
 
 
 
424
    if(queenStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
425
    {
 
 
426
        SpeciesSound(0, QSC_Scream_Hurt, 0, &queenStatusPointer->soundHandle, &sbPtr->DynPtr->Position, QUEEN_SOUND);
 
 
427
        queenStatusPointer->lastSoundCategory = QSC_Scream_Hurt;        
 
 
428
    }
 
 
429
}
 
 
430
 
 
 
431
static void ThrownObjectBounceNoise(int object_index, VECTORCH* location)
 
 
432
{
 
 
433
    static int QueenObjectSoundHandles[QUEEN_MAX_OBJECT] = 
 
 
434
{SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX
,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX};
 
 
435
    assert(location);
 
 
436
 
 
 
437
    SpeciesSound(0, QSC_Object_Bounce, 0, &QueenObjectSoundHandles[object_index], location, QUEEN_SOUND);
 
 
438
}
 
 
439
 
 
 
440
void InitQueenBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
 
 
441
{
 
 
442
    TOOLS_DATA_QUEEN *toolsData = (TOOLS_DATA_QUEEN *)bhdata; 
 
 
443
 
 
 
444
    /* Reset command interface. */
 
 
445
 
 
 
446
    Queen_Next_Command = QM_Standby;
 
 
447
 
 
 
448
    {
 
 
449
    int i;
 
 
450
    for(i=0; i < SB_NAME_LENGTH; i++)
 
 
451
        sbPtr->SBname[i] = toolsData->nameID[i];
 
 
452
    }
 
 
453
 
 
 
454
    /* create, initialise and attach a dynamics block */
 
 
455
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
456
 
 
 
457
    if(sbPtr->DynPtr)
 
 
458
    {
 
 
459
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
460
        dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
 
 
461
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
462
        TransposeMatrixCH(&dynPtr->OrientMat);              
 
 
463
        dynPtr->UseDisplacement = 1;
 
 
464
        dynPtr->Mass = 60000; /* No knockback, please. */
 
 
465
 
 
 
466
        if(make_new_queen(sbPtr))
 
 
467
        {
 
 
468
            QUEEN_STATUS_BLOCK *queenStatus = (QUEEN_STATUS_BLOCK *)sbPtr->dataptr;
 
 
469
 
 
 
470
            int i = 0;
 
 
471
            for(; i < SB_NAME_LENGTH; i++)
 
 
472
                queenStatus->death_target_ID[i] = toolsData->death_target_ID[i];
 
 
473
 
 
 
474
            queenStatus->death_target_request = toolsData->death_target_request;
 
 
475
 
 
 
476
            //int he predator version , make it more likely for the queen to go after the player
 
 
477
            queenStatus->QueenPlayerBias = !strcmp(AvP.LevelName, "hangar") ? 1 : 5;
 
 
478
            queenStatus->QueenTargetSB = PlayerStatus.sbptr;
 
 
479
 
 
 
480
            NumQueenObjects = -1;
 
 
481
        }
 
 
482
    }
 
 
483
    else
 
 
484
    {
 
 
485
        RemoveBehaviourStrategy(sbPtr);
 
 
486
    }
 
 
487
}
 
 
488
 
 
 
489
static int QueenPlayingStunAnimation(HMODELCONTROLLER* HModelController)
 
 
490
{
 
 
491
    assert(HModelController);
 
 
492
 
 
 
493
    return(HModelController->Sequence_Type == HMSQT_QueenGeneral && HModelController->Sub_Sequence == QGSS_Explosion_Stun &&
!HModelAnimation_IsFinished(HModelController));
 
 
494
}
 
 
495
 
 
 
496
void MakeQueenFar(STRATEGYBLOCK *sbPtr)
 
 
497
{
 
 
498
    DestroyActiveObject(&sbPtr->DisplayBlock);
 
 
499
 
 
 
500
    /* zero linear velocity in dynamics block */
 
 
501
    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
502
}
 
 
503
 
 
 
504
void SetQueenMovement_FromFoot(STRATEGYBLOCK *sbPtr)
 
 
505
{
 
 
506
    VECTORCH delta_offset;
 
 
507
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
508
    DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
509
    assert(dPtr);
 
 
510
 
 
 
511
    //VECTORCH real_pos = queenStatusPointer->fixed_foot_section->World_Offset;
 
 
512
 
 
 
513
    ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
514
 
 
 
515
    delta_offset.vx = queenStatusPointer->fixed_foot_oldpos.vx-queenStatusPointer->fixed_foot_section->World_Offset.vx;
 
 
516
    delta_offset.vy = 0;//queenStatusPointer->fixed_foot_oldpos.vy-queenStatusPointer->fixed_foot_section->World_Offset.vy;
 
 
517
    delta_offset.vz = queenStatusPointer->fixed_foot_oldpos.vz-queenStatusPointer->fixed_foot_section->World_Offset.vz;
 
 
518
 
 
 
519
    delta_offset.vx = DIV_FIXED(delta_offset.vx,NormalFrameTime);
 
 
520
    delta_offset.vy = 0;//DIV_FIXED(delta_offset.vy,NormalFrameTime);
 
 
521
    delta_offset.vz = DIV_FIXED(delta_offset.vz,NormalFrameTime);
 
 
522
 
 
 
523
    sbPtr->DynPtr->LinVelocity.vx = delta_offset.vx;
 
 
524
    sbPtr->DynPtr->LinVelocity.vy = delta_offset.vy;
 
 
525
    sbPtr->DynPtr->LinVelocity.vz = delta_offset.vz;
 
 
526
 
 
 
527
    {
 
 
528
        int facex = sbPtr->DynPtr->OrientMat.mat31;
 
 
529
        int facez = sbPtr->DynPtr->OrientMat.mat33;
 
 
530
 
 
 
531
        if(MUL_FIXED(facex,sbPtr->DynPtr->LinVelocity.vx)+MUL_FIXED(facez,sbPtr->DynPtr->LinVelocity.vz) < 0)
 
 
532
        {
 
 
533
            //don't want queen to move backwards
 
 
534
            sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
535
 
 
 
536
            switch (queenStatusPointer->fixed_foot) 
 
 
537
            {
 
 
538
                case LeftFoot:
 
 
539
                    SetQueenFoot(sbPtr,LeftFoot);
 
 
540
                break;
 
 
541
                case RightFoot:
 
 
542
                    SetQueenFoot(sbPtr,RightFoot);
 
 
543
                 break;
 
 
544
                default:
 
 
545
                    assert(0);
 
 
546
                    break;
 
 
547
            }
 
 
548
        }
 
 
549
    }
 
 
550
}
 
 
551
 
 
 
552
void SetQueenShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime)
 
 
553
{
 
 
554
    QUEEN_STATUS_BLOCK *queenStatus = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
555
 
 
 
556
    assert(length!=0);
 
 
557
 
 
 
558
    if (tweeningtime <= 0)
 
 
559
        InitHModelSequence(&queenStatus->HModelController,(int)type,subtype,length);
 
 
560
    else
 
 
561
        InitHModelTweening(&queenStatus->HModelController, tweeningtime, (int)type,subtype,length, 0);
 
 
562
 
 
 
563
    queenStatus->HModelController.Looped = 0;
 
 
564
}
 
 
565
 
 
 
566
void QueenMove_Standby(STRATEGYBLOCK *sbPtr)
 
 
567
{
 
 
568
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
569
 
 
 
570
    /* Verify correct sequence. */
 
 
571
 
 
 
572
    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
573
 
 
 
574
    if(queenStatusPointer->PlayingHitDelta)
 
 
575
    {
 
 
576
        if(QueenPlayingStunAnimation(&queenStatusPointer->HModelController))
 
 
577
            return; //queen is in the process of playing stun animation
 
 
578
    }
 
 
579
 
 
 
580
    if(!queenStatusPointer->moveTimer)
 
 
581
    {
 
 
582
        //start tweening to standing position
 
 
583
        switch(queenStatusPointer->fixed_foot)
 
 
584
        {
 
 
585
            case LeftFoot:
 
 
586
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, (int)QLSTSS_Standard,-1,ONE_FIXED>>2);
 
 
587
            break;
 
 
588
            case RightFoot:
 
 
589
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, (int)QRSTSS_Standard,-1,ONE_FIXED>>2);
 
 
590
            break;
 
 
591
            default:
 
 
592
                assert(0);
 
 
593
                break;
 
 
594
        }
 
 
595
 
 
 
596
        queenStatusPointer->moveTimer = 1;
 
 
597
    }
 
 
598
}
 
 
599
 
 
 
600
void QueenMove_StepForward(STRATEGYBLOCK *sbPtr)
 
 
601
{
 
 
602
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
603
 
 
 
604
    /* First movement function. */
 
 
605
 
 
 
606
    assert(queenStatusPointer->current_move == QM_StepForward);    
 
 
607
 
 
 
608
    if (!queenStatusPointer->moveTimer)
 
 
609
    {
 
 
610
        /* Do setup. */
 
 
611
        int tweeiningtime = (ONE_FIXED>>3);
 
 
612
 
 
 
613
        switch (queenStatusPointer->fixed_foot)
 
 
614
        {
 
 
615
            case LeftFoot:
 
 
616
                SetQueenFoot(sbPtr,LeftFoot);
 
 
617
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, (int)QLSTSS_Forward_L2R,Queen_Step_Time,tweeiningtime);
 
 
618
            break;
 
 
619
            case RightFoot:
 
 
620
                SetQueenFoot(sbPtr,RightFoot);
 
 
621
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, (int)QRSTSS_Forward_R2L,Queen_Step_Time,tweeiningtime);
 
 
622
            break;
 
 
623
            default:
 
 
624
                assert(0);
 
 
625
                break;
 
 
626
        }
 
 
627
    }
 
 
628
 
 
 
629
    #if DEBUG
 
 
630
    if (!queenStatusPointer->HModelController.Tweening)
 
 
631
    {
 
 
632
        assert(!queenStatusPointer->HModelController.Looped);
 
 
633
    }
 
 
634
    #endif
 
 
635
 
 
 
636
    /* Now... move forward? */
 
 
637
 
 
 
638
    SetQueenMovement_FromFoot(sbPtr);
 
 
639
 
 
 
640
    if (!queenStatusPointer->HModelController.Tweening &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1)))
 
 
641
    {
 
 
642
        queenStatusPointer->current_move = QM_Standby;
 
 
643
 
 
 
644
        switch (queenStatusPointer->fixed_foot)
 
 
645
        {
 
 
646
            case LeftFoot:
 
 
647
                SetQueenFoot(sbPtr,RightFoot);
 
 
648
            break;
 
 
649
            case RightFoot:
 
 
650
                SetQueenFoot(sbPtr,LeftFoot);
 
 
651
            break;
 
 
652
            default:
 
 
653
                assert(0);
 
 
654
                break;
 
 
655
        }
 
 
656
    }
 
 
657
 
 
 
658
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
659
}
 
 
660
 
 
 
661
void QueenMove_StepBack(STRATEGYBLOCK *sbPtr)
 
 
662
{
 
 
663
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
664
 
 
 
665
    /* First movement function. */
 
 
666
 
 
 
667
    assert(queenStatusPointer->current_move == QM_StepBack);    
 
 
668
 
 
 
669
    if (!queenStatusPointer->moveTimer)
 
 
670
    {
 
 
671
        /* Do setup. */
 
 
672
        int tweeiningtime = (ONE_FIXED>>3);
 
 
673
 
 
 
674
        switch (queenStatusPointer->fixed_foot)
 
 
675
        {
 
 
676
            case LeftFoot:
 
 
677
                SetQueenFoot(sbPtr,RightFoot);
 
 
678
                /* Wrong Foot w.r.t. Forward. */
 
 
679
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Backward_L2R,Queen_Step_Time,tweeiningtime);
 
 
680
            break;
 
 
681
            case RightFoot:
 
 
682
                SetQueenFoot(sbPtr,LeftFoot);
 
 
683
                /* Wrong Foot w.r.t. Forward. */
 
 
684
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Backward_R2L,Queen_Step_Time,tweeiningtime);
 
 
685
            break;
 
 
686
            default:
 
 
687
                assert(0);
 
 
688
                break;
 
 
689
        }
 
 
690
    }
 
 
691
 
 
 
692
    #if DEBUG
 
 
693
    if (!queenStatusPointer->HModelController.Tweening)
 
 
694
    {
 
 
695
        assert(queenStatusPointer->HModelController.Looped == 0);
 
 
696
    }
 
 
697
    #endif
 
 
698
 
 
 
699
    /* Now... move forward? */
 
 
700
 
 
 
701
    SetQueenMovement_FromFoot(sbPtr);
 
 
702
 
 
 
703
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
704
 
 
 
705
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
706
    {
 
 
707
         queenStatusPointer->current_move = QM_Standby;
 
 
708
        /* Already changed foot. */
 
 
709
    }
 
 
710
}
 
 
711
 
 
 
712
void QueenMove_ComeToPoint(STRATEGYBLOCK *sbPtr)
 
 
713
{
 
 
714
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
715
    VECTORCH vectotarget;
 
 
716
 
 
 
717
    /* Complex movement function. */
 
 
718
 
 
 
719
    assert(queenStatusPointer->current_move == QM_ComeToPoint);    
 
 
720
 
 
 
721
    if (!queenStatusPointer->moveTimer)
 
 
722
    {
 
 
723
        /* Do setup. */
 
 
724
        int tweeiningtime = 0;
 
 
725
 
 
 
726
        switch (queenStatusPointer->fixed_foot)
 
 
727
        {
 
 
728
            case LeftFoot:
 
 
729
                SetQueenFoot(sbPtr,LeftFoot);
 
 
730
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Forward_L2R,Queen_Step_Time,tweeiningtime);
 
 
731
            break;
 
 
732
            case RightFoot:
 
 
733
                SetQueenFoot(sbPtr,RightFoot);
 
 
734
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Forward_R2L,Queen_Step_Time,tweeiningtime);
 
 
735
            break;
 
 
736
            default:
 
 
737
                assert(0);
 
 
738
                break;
 
 
739
        }
 
 
740
    }
 
 
741
 
 
 
742
    #if DEBUG
 
 
743
    if (!queenStatusPointer->HModelController.Tweening)
 
 
744
    {
 
 
745
        assert(!queenStatusPointer->HModelController.Looped);
 
 
746
    }
 
 
747
    #endif
 
 
748
 
 
 
749
    vectotarget.vx = queenStatusPointer->TargetPos.vx-sbPtr->DynPtr->Position.vx;
 
 
750
    vectotarget.vy = queenStatusPointer->TargetPos.vy-sbPtr->DynPtr->Position.vy;
 
 
751
    vectotarget.vz = queenStatusPointer->TargetPos.vz-sbPtr->DynPtr->Position.vz;
 
 
752
 
 
 
753
    /* Now... turn to face. */
 
 
754
 
 
 
755
    {
 
 
756
        DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
757
        assert(dPtr);
 
 
758
 
 
 
759
        ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
760
 
 
 
761
        NPCOrientateToVector(sbPtr, &vectotarget, Queen_Turn_Rate);
 
 
762
 
 
 
763
        SetQueenMovement_FromFoot(sbPtr);
 
 
764
    }
 
 
765
 
 
 
766
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
767
 
 
 
768
    if (!queenStatusPointer->HModelController.Tweening &&(queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
769
    {
 
 
770
        /* Comsider next step. */
 
 
771
 
 
 
772
        int range = Approximate3dMagnitude(&vectotarget);
 
 
773
 
 
 
774
        if (range < 5000)
 
 
775
            queenStatusPointer->current_move = QM_Standby;
 
 
776
        else
 
 
777
            queenStatusPointer->moveTimer = 0;
 
 
778
 
 
 
779
        switch (queenStatusPointer->fixed_foot)
 
 
780
        {
 
 
781
            case LeftFoot:
 
 
782
                SetQueenFoot(sbPtr,RightFoot);
 
 
783
            break;
 
 
784
            case RightFoot:
 
 
785
                SetQueenFoot(sbPtr,LeftFoot);
 
 
786
            break;
 
 
787
            default:
 
 
788
                assert(0);
 
 
789
                break;
 
 
790
        }
 
 
791
    }
 
 
792
}
 
 
793
 
 
 
794
static void QueenCalculateTargetInfo(STRATEGYBLOCK *sbPtr)
 
 
795
{
 
 
796
    assert(sbPtr);
 
 
797
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
798
    assert(queenStatusPointer);
 
 
799
 
 
 
800
    if(queenStatusPointer->TargetInfoValid)
 
 
801
        return;
 
 
802
 
 
 
803
    //get vector from queen to target
 
 
804
 
 
 
805
    queenStatusPointer->VectToTarget.vx = queenStatusPointer->TargetPos.vx - sbPtr->DynPtr->Position.vx;
 
 
806
    //queenStatusPointer->VectToTarget.vy = queenStatusPointer->TargetPos.vy - sbPtr->DynPtr->Position.vy;
 
 
807
    queenStatusPointer->VectToTarget.vy = 0;
 
 
808
    queenStatusPointer->VectToTarget.vz = queenStatusPointer->TargetPos.vz - sbPtr->DynPtr->Position.vz;
 
 
809
 
 
 
810
    //get length of vector, and then normalise it
 
 
811
    queenStatusPointer->TargetDistance = Approximate3dMagnitude(&queenStatusPointer->VectToTarget);
 
 
812
    Normalise(&queenStatusPointer->VectToTarget);
 
 
813
 
 
 
814
    //rotate vector to queen's local space to get relative direction
 
 
815
    queenStatusPointer->TargetDirection = queenStatusPointer->VectToTarget;
 
 
816
    MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
817
    TransposeMatrixCH(&WtoL);
 
 
818
    RotateVector(&queenStatusPointer->TargetDirection,&WtoL);
 
 
819
 
 
 
820
    queenStatusPointer->TargetRelSpeed = 0;
 
 
821
 
 
 
822
    if(!queenStatusPointer->TempTarget && queenStatusPointer->QueenTargetSB)
 
 
823
    {
 
 
824
        if(queenStatusPointer->QueenTargetSB->DynPtr)
 
 
825
        {
 
 
826
            VECTORCH facing;
 
 
827
            facing.vx = sbPtr->DynPtr->OrientMat.mat31;
 
 
828
            facing.vy = sbPtr->DynPtr->OrientMat.mat32;
 
 
829
            facing.vz = sbPtr->DynPtr->OrientMat.mat33;
 
 
830
 
 
 
831
            queenStatusPointer->TargetRelSpeed = DotProduct(&facing,&queenStatusPointer->QueenTargetSB->DynPtr->LinVelocity);        
 
 
832
        }
 
 
833
    }
 
 
834
 
 
 
835
    queenStatusPointer->TargetInfoValid = 1;
 
 
836
}
 
 
837
 
 
 
838
void QueenMove_Walk(STRATEGYBLOCK *sbPtr)
 
 
839
{
 
 
840
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
841
    int ChangingFoot = 0;
 
 
842
 
 
 
843
    /* Very complex movement function... */
 
 
844
 
 
 
845
    assert(queenStatusPointer->current_move == QM_ComeToPoint);    
 
 
846
 
 
 
847
    if (!queenStatusPointer->moveTimer)
 
 
848
    {
 
 
849
        /* Do setup. */
 
 
850
        int tweeiningtime = (Queen_Step_Time >> 2);
 
 
851
 
 
 
852
        switch (queenStatusPointer->fixed_foot)
 
 
853
        {
 
 
854
            case LeftFoot:
 
 
855
                SetQueenFoot(sbPtr,LeftFoot);
 
 
856
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, (int)QGSS_Walk,-1,tweeiningtime);
 
 
857
                queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
858
                queenStatusPointer->moveTimer = 1; /* It's something of a state flag here. */
 
 
859
            break;
 
 
860
            case RightFoot:
 
 
861
                /* Argh! Can't start from right foot! */
 
 
862
                queenStatusPointer->current_move = QM_Close;
 
 
863
                queenStatusPointer->moveTimer = 0;
 
 
864
                queenStatusPointer->next_move = QM_ComeToPoint;
 
 
865
                return;
 
 
866
            break;
 
 
867
            default:
 
 
868
                assert(0);
 
 
869
                break;
 
 
870
        }
 
 
871
    }
 
 
872
 
 
 
873
    /* Check for change foot? */
 
 
874
 
 
 
875
    if (!queenStatusPointer->HModelController.Tweening)
 
 
876
    {
 
 
877
        if (queenStatusPointer->HModelController.keyframe_flags) 
 
 
878
        {
 
 
879
            if (queenStatusPointer->HModelController.keyframe_flags & 1) 
 
 
880
            {
 
 
881
                SetQueenFoot(sbPtr,LeftFoot);
 
 
882
                ChangingFoot = 1;
 
 
883
            }
 
 
884
 
 
 
885
            if (queenStatusPointer->HModelController.keyframe_flags & 2) 
 
 
886
            {
 
 
887
                SetQueenFoot(sbPtr,RightFoot);
 
 
888
                ChangingFoot = 1;
 
 
889
            }
 
 
890
 
 
 
891
            if(queenStatusPointer->moveTimer == 1)
 
 
892
                queenStatusPointer->moveTimer = 3;
 
 
893
        }
 
 
894
 
 
 
895
        HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_WALK_SPEED);
 
 
896
    }
 
 
897
 
 
 
898
    /* Now... turn to face. */
 
 
899
 
 
 
900
    {
 
 
901
        //DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
902
        //assert(dPtr);
 
 
903
 
 
 
904
        //ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
905
 
 
 
906
        NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget, Queen_Turn_Rate);
 
 
907
 
 
 
908
        //SetQueenMovement_FromFoot(sbPtr);
 
 
909
 
 
 
910
        if (queenStatusPointer->moveTimer != 2) 
 
 
911
        {
 
 
912
            if(queenStatusPointer->moveTimer == 1)
 
 
913
            {
 
 
914
                SetQueenMovement_FromFoot(sbPtr);
 
 
915
            }
 
 
916
            else
 
 
917
            {
 
 
918
                VECTORCH velocity;
 
 
919
                //int walkSpeed;
 
 
920
 
 
 
921
                velocity.vx = sbPtr->DynPtr->OrientMat.mat31;
 
 
922
                velocity.vy = 0;
 
 
923
                velocity.vz = sbPtr->DynPtr->OrientMat.mat33;
 
 
924
 
 
 
925
                if ( !velocity.vx && !velocity.vy && !velocity.vz)
 
 
926
                {
 
 
927
                    sbPtr->DynPtr->LinVelocity.vx =  sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
928
                return;
 
 
929
                }
 
 
930
 
 
 
931
                Normalise(&velocity);
 
 
932
 
 
 
933
                //walkSpeed=DIV_FIXED(Queen_Walk_Step_Speed,Queen_Walk_Rate);
 
 
934
 
 
 
935
                sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_WALK_SPEED);
 
 
936
                sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_WALK_SPEED);
 
 
937
                sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_WALK_SPEED);
 
 
938
            }
 
 
939
        }
 
 
940
    }
 
 
941
 
 
 
942
    /* Consider exit state. */
 
 
943
 
 
 
944
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->moveTimer == 2))
 
 
945
    {
 
 
946
        /* Finished coming to a stop. */
 
 
947
 
 
 
948
        queenStatusPointer->current_move = QM_Standby;
 
 
949
        queenStatusPointer->next_move = QM_Standby;
 
 
950
        queenStatusPointer->moveTimer = 0;
 
 
951
 
 
 
952
        switch (queenStatusPointer->fixed_foot)
 
 
953
        {
 
 
954
            case RightFoot:
 
 
955
                SetQueenFoot(sbPtr,RightFoot);
 
 
956
            break;
 
 
957
            case LeftFoot:
 
 
958
                SetQueenFoot(sbPtr,LeftFoot);
 
 
959
            break;
 
 
960
            default:
 
 
961
                assert(0);
 
 
962
                break;
 
 
963
        }
 
 
964
 
 
 
965
        /* Would you believe the end's in the middle? :-) */
 
 
966
    }
 
 
967
 
 
 
968
    //only check for exiting charge , when changing foot
 
 
969
    {
 
 
970
        QueenCalculateTargetInfo(sbPtr);
 
 
971
        int range = queenStatusPointer->TargetDistance;
 
 
972
 
 
 
973
        if(range < 3000)
 
 
974
            queenStatusPointer->next_move = QM_Close;
 
 
975
 
 
 
976
        if(ChangingFoot)
 
 
977
        {
 
 
978
            if(queenStatusPointer->PlayingHitDelta)
 
 
979
            {
 
 
980
                queenStatusPointer->HModelController.Playing = 0;
 
 
981
                queenStatusPointer->current_move = QM_Standby;
 
 
982
                queenStatusPointer->moveTimer = 0;
 
 
983
                queenStatusPointer->next_move = QM_Standby;
 
 
984
            return;
 
 
985
            }
 
 
986
 
 
 
987
            if(queenStatusPointer->moveTimer != 2)
 
 
988
            {
 
 
989
                if (queenStatusPointer->next_move != QM_Standby && queenStatusPointer->next_move != QM_ComeToPoint) 
 
 
990
                {
 
 
991
                    //exit without tweening to stopped position
 
 
992
                    queenStatusPointer->HModelController.Playing = 0;
 
 
993
                    queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
994
                    queenStatusPointer->next_move = QM_Standby;
 
 
995
                    queenStatusPointer->moveTimer = 0;
 
 
996
                }
 
 
997
                else if(range > 10000 && queenStatusPointer->fixed_foot == LeftFoot && !PlayerInTrench)
 
 
998
                {
 
 
999
                    //go into a charge
 
 
1000
                    queenStatusPointer->current_move = QM_Charge;
 
 
1001
                    queenStatusPointer->next_move = QM_Standby;
 
 
1002
                    queenStatusPointer->moveTimer = 0;
 
 
1003
                }
 
 
1004
 
 
 
1005
                if(range < 5000)
 
 
1006
                {
 
 
1007
                    /*if the queen is near but facing the wrong way need to go into close mode
 
 
1008
                    (turning circle is too large in walk mode)  */
 
 
1009
 
 
 
1010
                    if (queenStatusPointer->TargetDirection.vz < queenStatusPointer->TargetDirection.vx || 
 
 
1011
                        queenStatusPointer->TargetDirection.vz < -queenStatusPointer->TargetDirection.vx) 
 
 
1012
                    {
 
 
1013
                        //need to switch to close mode
 
 
1014
                        queenStatusPointer->HModelController.Playing = 0;
 
 
1015
                        queenStatusPointer->current_move = QM_Close;
 
 
1016
                        queenStatusPointer->moveTimer = 0;
 
 
1017
                        queenStatusPointer->next_move = QM_Standby;
 
 
1018
                    }
 
 
1019
                }
 
 
1020
            }
 
 
1021
        }
 
 
1022
    }
 
 
1023
}
 
 
1024
 
 
 
1025
void QueenMove_Taunt(STRATEGYBLOCK *sbPtr)
 
 
1026
{
 
 
1027
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1028
 
 
 
1029
    /* First movement function. */
 
 
1030
 
 
 
1031
    assert(queenStatusPointer->current_move==QM_Taunt);    
 
 
1032
 
 
 
1033
    if (!queenStatusPointer->moveTimer)
 
 
1034
    {
 
 
1035
        /* Do setup. */
 
 
1036
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1037
 
 
 
1038
        switch (queenStatusPointer->fixed_foot)
 
 
1039
        {
 
 
1040
            case LeftFoot:
 
 
1041
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1042
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Taunt,-1,tweeiningtime);
 
 
1043
            break;
 
 
1044
            case RightFoot:
 
 
1045
                SetQueenFoot(sbPtr,RightFoot);
 
 
1046
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Taunt,-1,tweeiningtime);
 
 
1047
            break;
 
 
1048
            default:
 
 
1049
                assert(0);
 
 
1050
                break;
 
 
1051
        }
 
 
1052
    }
 
 
1053
 
 
 
1054
    #if DEBUG
 
 
1055
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1056
    {
 
 
1057
        assert(!queenStatusPointer->HModelController.Looped);
 
 
1058
    }
 
 
1059
    #endif
 
 
1060
 
 
 
1061
    /* Now... move forward? */
 
 
1062
 
 
 
1063
    SetQueenMovement_FromFoot(sbPtr);
 
 
1064
 
 
 
1065
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
1066
    {
 
 
1067
        queenStatusPointer->current_move = QM_Standby;
 
 
1068
 
 
 
1069
        /* Same foot. */
 
 
1070
    }
 
 
1071
 
 
 
1072
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1073
}
 
 
1074
 
 
 
1075
void QueenMove_Hiss(STRATEGYBLOCK *sbPtr)
 
 
1076
{
 
 
1077
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1078
 
 
 
1079
    /* First movement function. */
 
 
1080
 
 
 
1081
    assert(queenStatusPointer->current_move == QM_Hiss);    
 
 
1082
 
 
 
1083
    if (!queenStatusPointer->moveTimer)
 
 
1084
    {
 
 
1085
        /* Do setup. */
 
 
1086
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1087
 
 
 
1088
        switch (queenStatusPointer->fixed_foot)
 
 
1089
        {
 
 
1090
            case LeftFoot:
 
 
1091
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1092
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1093
                queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1094
            break;
 
 
1095
            case RightFoot:
 
 
1096
                SetQueenFoot(sbPtr,RightFoot);
 
 
1097
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1098
                queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1099
            break;
 
 
1100
            default:
 
 
1101
                assert(0);
 
 
1102
                break;
 
 
1103
        }
 
 
1104
    }
 
 
1105
 
 
 
1106
    /*
 
 
1107
    if (!queenStatusPointer->HModelController.Tweening) 
 
 
1108
    {
 
 
1109
        assert(queenStatusPointer->HModelController.Looped == 0);
 
 
1110
    }
 
 
1111
    */
 
 
1112
 
 
 
1113
    /* Now... move forward? */
 
 
1114
 
 
 
1115
    SetQueenMovement_FromFoot(sbPtr);
 
 
1116
 
 
 
1117
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1118
}
 
 
1119
 
 
 
1120
void QueenMove_LeftSwipe(STRATEGYBLOCK *sbPtr)
 
 
1121
{
 
 
1122
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1123
 
 
 
1124
    /* First movement function. */
 
 
1125
 
 
 
1126
    assert(queenStatusPointer->current_move==QM_LeftSwipe);    
 
 
1127
 
 
 
1128
    if (!queenStatusPointer->moveTimer)
 
 
1129
    {
 
 
1130
        /* Do setup. */
 
 
1131
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1132
 
 
 
1133
        switch (queenStatusPointer->fixed_foot)
 
 
1134
        {
 
 
1135
            case LeftFoot:
 
 
1136
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1137
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1138
 
 
 
1139
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenLeftStanceTemplate,(int)QLSTSS_LeftSwipe,Queen_Step_Time);
 
 
1140
 
 
 
1141
            break;
 
 
1142
            case RightFoot:
 
 
1143
                SetQueenFoot(sbPtr,RightFoot);
 
 
1144
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1145
 
 
 
1146
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe,Queen_Step_Time);
 
 
1147
            break;
 
 
1148
            default:
 
 
1149
                assert(0);
 
 
1150
                break;
 
 
1151
        }
 
 
1152
    }
 
 
1153
 
 
 
1154
    #if DEBUG
 
 
1155
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1156
    {
 
 
1157
        assert(!queenStatusPointer->HModelController.Looped);
 
 
1158
    }
 
 
1159
    #endif
 
 
1160
 
 
 
1161
    /* Now... move forward? */
 
 
1162
 
 
 
1163
    SetQueenMovement_FromFoot(sbPtr);
 
 
1164
 
 
 
1165
    if (!queenStatusPointer->HModelController.Tweening &&(queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
1166
    {
 
 
1167
        queenStatusPointer->current_move = QM_Standby;
 
 
1168
    }
 
 
1169
 
 
 
1170
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1171
}
 
 
1172
 
 
 
1173
void QueenMove_RightSwipe(STRATEGYBLOCK *sbPtr)
 
 
1174
{
 
 
1175
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1176
 
 
 
1177
    /* First movement function. */
 
 
1178
 
 
 
1179
    assert(queenStatusPointer->current_move==QM_RightSwipe);    
 
 
1180
 
 
 
1181
    if (!queenStatusPointer->moveTimer)
 
 
1182
    {
 
 
1183
        /* Do setup. */
 
 
1184
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1185
 
 
 
1186
        switch (queenStatusPointer->fixed_foot)
 
 
1187
        {
 
 
1188
            case LeftFoot:
 
 
1189
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1190
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1191
 
 
 
1192
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenLeftStanceTemplate,(int)QLSTSS_RightSwipe,Queen_Step_Time);
 
 
1193
            break;
 
 
1194
            case RightFoot:
 
 
1195
                SetQueenFoot(sbPtr,RightFoot);
 
 
1196
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime);
 
 
1197
 
 
 
1198
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe,Queen_Step_Time);
 
 
1199
            break;
 
 
1200
            default:
 
 
1201
                assert(0);
 
 
1202
                break;
 
 
1203
        }
 
 
1204
    }
 
 
1205
 
 
 
1206
    #if DEBUG
 
 
1207
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1208
    {
 
 
1209
        assert(queenStatusPointer->HModelController.Looped==0);
 
 
1210
    }
 
 
1211
    #endif
 
 
1212
 
 
 
1213
    /* Now... move forward? */
 
 
1214
 
 
 
1215
    SetQueenMovement_FromFoot(sbPtr);
 
 
1216
 
 
 
1217
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
1218
    {
 
 
1219
        queenStatusPointer->current_move = QM_Standby;
 
 
1220
    }
 
 
1221
 
 
 
1222
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1223
}
 
 
1224
 
 
 
1225
void QueenMove_Charge(STRATEGYBLOCK *sbPtr)
 
 
1226
{
 
 
1227
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1228
    int ChangingFoot = 0;
 
 
1229
 
 
 
1230
    /* Very different movement function... */
 
 
1231
 
 
 
1232
    assert(queenStatusPointer->current_move == QM_Charge);
 
 
1233
 
 
 
1234
    /* Charge at the player. */
 
 
1235
    if(!queenStatusPointer->TempTarget)
 
 
1236
    {
 
 
1237
    //    queenStatusPointer->TargetPos = PlayerStatus.sbptr->DynPtr->Position;
 
 
1238
        queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;
 
 
1239
    }
 
 
1240
 
 
 
1241
    if (!queenStatusPointer->moveTimer) 
 
 
1242
    {
 
 
1243
        /* Do setup. */
 
 
1244
        int tweeiningtime = (Queen_Step_Time >> 2);
 
 
1245
 
 
 
1246
        sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1247
 
 
 
1248
        switch (queenStatusPointer->fixed_foot)
 
 
1249
        {
 
 
1250
            case LeftFoot:
 
 
1251
                {
 
 
1252
                    SetQueenFoot(sbPtr, LeftFoot);
 
 
1253
 
 
 
1254
                    //which version of sprint should we use
 
 
1255
                    if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta))
 
 
1256
                        SetQueenShapeAnimSequence_Core(sbPtr, HMSQT_QueenGeneral, (int)QGSS_Sprint_Full, -1, tweeiningtime);
 
 
1257
                    else
 
 
1258
                        SetQueenShapeAnimSequence_Core(sbPtr, HMSQT_QueenGeneral, (int)QGSS_Sprint, -1, tweeiningtime);
 
 
1259
 
 
 
1260
                    queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1261
                    queenStatusPointer->moveTimer = 1; /* It's something of a state flag here. */
 
 
1262
                }
 
 
1263
            break;
 
 
1264
            case RightFoot:
 
 
1265
                /* Argh! Can't start from right foot! */
 
 
1266
                queenStatusPointer->current_move = QM_Close;
 
 
1267
                queenStatusPointer->moveTimer = 0;
 
 
1268
                queenStatusPointer->next_move = QM_Charge;
 
 
1269
            return;
 
 
1270
            break;
 
 
1271
            default:
 
 
1272
                assert(0);
 
 
1273
                break;
 
 
1274
        }
 
 
1275
            queenStatusPointer->SwerveTimer = (ONE_FIXED/2)+(FastRandom() & 0xffff)*2;
 
 
1276
    return;
 
 
1277
    }
 
 
1278
 
 
 
1279
    /* Check for change foot? */
 
 
1280
 
 
 
1281
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1282
    {
 
 
1283
        if (queenStatusPointer->HModelController.keyframe_flags) 
 
 
1284
        {
 
 
1285
            if (queenStatusPointer->HModelController.keyframe_flags & 1) 
 
 
1286
            {
 
 
1287
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1288
                ChangingFoot = 1;
 
 
1289
            }
 
 
1290
 
 
 
1291
            if (queenStatusPointer->HModelController.keyframe_flags & 2) 
 
 
1292
            {
 
 
1293
                SetQueenFoot(sbPtr,RightFoot);
 
 
1294
                ChangingFoot = 1;
 
 
1295
            }
 
 
1296
 
 
 
1297
            if(queenStatusPointer->moveTimer == 1)
 
 
1298
                queenStatusPointer->moveTimer = 3;
 
 
1299
        }
 
 
1300
 
 
 
1301
        HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_CHARGE_SPEED);
 
 
1302
    }
 
 
1303
 
 
 
1304
    /* Now... turn to face. */
 
 
1305
 
 
 
1306
    if (queenStatusPointer->moveTimer != 2)
 
 
1307
    {
 
 
1308
        DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
1309
        assert(dPtr);
 
 
1310
 
 
 
1311
        ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
1312
 
 
 
1313
        {
 
 
1314
            VECTORCH v;
 
 
1315
 
 
 
1316
            if(queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr && !queenStatusPointer->TempTarget &&
queenStatusPointer->TargetDistance > 5000)
 
 
1317
            {
 
 
1318
                //if charging at player don't go in a straight line
 
 
1319
                #define QUEEN_COS 63302
 
 
1320
                #define QUEEN_SIN 16961
 
 
1321
 
 
 
1322
                if(queenStatusPointer->SwerveDirection)
 
 
1323
                {
 
 
1324
                    v.vx = MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_COS)+MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_SIN);
 
 
1325
                    v.vy = 0;
 
 
1326
                    v.vz = MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_COS)-MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_SIN);
 
 
1327
                }
 
 
1328
                else
 
 
1329
                {
 
 
1330
                    v.vx = MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_COS)-MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_SIN);
 
 
1331
                    v.vy = 0;
 
 
1332
                    v.vz = MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_COS)+MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_SIN);
 
 
1333
                }
 
 
1334
 
 
 
1335
                queenStatusPointer->SwerveTimer -= NormalFrameTime;
 
 
1336
 
 
 
1337
                if(queenStatusPointer->SwerveTimer <= 0)
 
 
1338
                {
 
 
1339
                    //alter swerve direction , and keep it for the next .5 to 2.5 seconds
 
 
1340
                    queenStatusPointer->SwerveTimer = (ONE_FIXED/2)+(FastRandom() & 0xffff)*2;
 
 
1341
                    queenStatusPointer->SwerveDirection = !queenStatusPointer->SwerveDirection;
 
 
1342
                }
 
 
1343
            }
 
 
1344
            else
 
 
1345
            {
 
 
1346
                v = queenStatusPointer->VectToTarget;
 
 
1347
            }
 
 
1348
 
 
 
1349
            NPCOrientateToVector(sbPtr, &v, Queen_Turn_Rate);
 
 
1350
 
 
 
1351
            //NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget, Queen_Turn_Rate);
 
 
1352
        }
 
 
1353
        /* Now, just a normal lin velocity. */
 
 
1354
 
 
 
1355
        if(queenStatusPointer->moveTimer == 1)
 
 
1356
        {
 
 
1357
            SetQueenMovement_FromFoot(sbPtr);
 
 
1358
        }
 
 
1359
        else
 
 
1360
        {
 
 
1361
            VECTORCH velocity;
 
 
1362
 
 
 
1363
            velocity.vx = sbPtr->DynPtr->OrientMat.mat31;
 
 
1364
            velocity.vy = 0;
 
 
1365
            velocity.vz = sbPtr->DynPtr->OrientMat.mat33;
 
 
1366
 
 
 
1367
            if ( !velocity.vx && !velocity.vy && !velocity.vz)
 
 
1368
            {
 
 
1369
                sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1370
            return;
 
 
1371
            }
 
 
1372
 
 
 
1373
            Normalise(&velocity);
 
 
1374
 
 
 
1375
            sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_CHARGE_SPEED);
 
 
1376
            sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_CHARGE_SPEED);
 
 
1377
            sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_CHARGE_SPEED);
 
 
1378
        }
 
 
1379
    }
 
 
1380
 
 
 
1381
    /* Consider exit state. */
 
 
1382
 
 
 
1383
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->moveTimer == 2))
 
 
1384
    {
 
 
1385
        /* We must have finished. */
 
 
1386
 
 
 
1387
        queenStatusPointer->current_move = QM_Standby;
 
 
1388
 
 
 
1389
        switch (queenStatusPointer->fixed_foot)
 
 
1390
        {
 
 
1391
            case LeftFoot:
 
 
1392
                SetQueenFoot(sbPtr,RightFoot);
 
 
1393
            break;
 
 
1394
            case RightFoot:
 
 
1395
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1396
            break;
 
 
1397
            default:
 
 
1398
                assert(0);
 
 
1399
                break;
 
 
1400
        }
 
 
1401
        /* Would you believe the end's in the middle? :-) */
 
 
1402
    }
 
 
1403
 
 
 
1404
    if(ChangingFoot)
 
 
1405
    {
 
 
1406
        QueenCalculateTargetInfo(sbPtr);
 
 
1407
 
 
 
1408
        if(queenStatusPointer->PlayingHitDelta)
 
 
1409
        {
 
 
1410
            queenStatusPointer->HModelController.Playing = 0;
 
 
1411
            queenStatusPointer->current_move = QM_Standby;
 
 
1412
            queenStatusPointer->moveTimer = 0;
 
 
1413
            queenStatusPointer->next_move = QM_Standby;
 
 
1414
        return;
 
 
1415
        }
 
 
1416
 
 
 
1417
        //only check for exiting charge , when changing foot
 
 
1418
            /* Only charge if we're facing the right way. */
 
 
1419
 
 
 
1420
        if (queenStatusPointer->TargetDirection.vz < queenStatusPointer->TargetDirection.vx || 
 
 
1421
            queenStatusPointer->TargetDirection.vz < -queenStatusPointer->TargetDirection.vx)
 
 
1422
        {
 
 
1423
            /* Spin round a bit more. */
 
 
1424
            queenStatusPointer->HModelController.Playing = 0;
 
 
1425
            queenStatusPointer->current_move = QM_Close;
 
 
1426
            queenStatusPointer->moveTimer = 0;
 
 
1427
            queenStatusPointer->next_move = QM_Charge;
 
 
1428
        return;
 
 
1429
        }
 
 
1430
 
 
 
1431
        if (((queenStatusPointer->TargetDistance < 8000 && queenStatusPointer->fixed_foot == LeftFoot
 
 
1432
        && queenStatusPointer->TargetRelSpeed<QUEEN_CLOSE_SPEED) ||queenStatusPointer->next_move != QM_Standby) &&
(queenStatusPointer->moveTimer != 2)) 
 
 
1433
        {
 
 
1434
            queenStatusPointer->HModelController.Playing = 0;
 
 
1435
            queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
1436
            queenStatusPointer->moveTimer = 0;
 
 
1437
 
 
 
1438
            if(queenStatusPointer->current_move == QM_Standby)
 
 
1439
            {
 
 
1440
                if(queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr && !queenStatusPointer->TempTarget)
 
 
1441
                    queenStatusPointer->current_move = QM_Close;
 
 
1442
                else
 
 
1443
                    queenStatusPointer->current_move = QM_ComeToPoint;
 
 
1444
            }
 
 
1445
 
 
 
1446
            queenStatusPointer->next_move = QM_Standby;
 
 
1447
        return;
 
 
1448
        }
 
 
1449
 
 
 
1450
        //check to see if queen should change between sprints
 
 
1451
        if(queenStatusPointer->fixed_foot == LeftFoot)
 
 
1452
        {
 
 
1453
            if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta))
 
 
1454
            {
 
 
1455
                //switch to full sprint if not already doing it
 
 
1456
                if(queenStatusPointer->HModelController.Sub_Sequence != QGSS_Sprint_Full)
 
 
1457
                {
 
 
1458
                    SetQueenShapeAnimSequence_Core(sbPtr, HMSQT_QueenGeneral, (int)QGSS_Sprint_Full, -1, ONE_FIXED>>3);
 
 
1459
                    queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1460
                }
 
 
1461
            }
 
 
1462
            else
 
 
1463
            {
 
 
1464
                //switch to template sprint if not already doing it
 
 
1465
                if(queenStatusPointer->HModelController.Sub_Sequence != QGSS_Sprint)
 
 
1466
                {
 
 
1467
                    SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, (int)QGSS_Sprint,-1,ONE_FIXED>>3);
 
 
1468
                    queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1469
                }
 
 
1470
            }
 
 
1471
        }
 
 
1472
    }
 
 
1473
}
 
 
1474
 
 
 
1475
void QueenMove_ButtAttack(STRATEGYBLOCK* sbPtr)
 
 
1476
{
 
 
1477
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1478
 
 
 
1479
    /* First movement function. */
 
 
1480
 
 
 
1481
    assert(queenStatusPointer->current_move == QM_ButtAttack);    
 
 
1482
 
 
 
1483
    if (!queenStatusPointer->moveTimer)
 
 
1484
    {
 
 
1485
        /* Do setup. */
 
 
1486
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1487
 
 
 
1488
        SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, (int)QGSS_ButtConnect,-1,tweeiningtime);
 
 
1489
    }
 
 
1490
 
 
 
1491
    #if DEBUG
 
 
1492
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1493
    {
 
 
1494
        assert(!queenStatusPointer->HModelController.Looped);
 
 
1495
    }
 
 
1496
    #endif
 
 
1497
 
 
 
1498
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1))) 
 
 
1499
    {
 
 
1500
        queenStatusPointer->current_move = QM_Standby;
 
 
1501
        //finished attack switch back to reconsider
 
 
1502
        queenStatusPointer->QueenState = QBS_Reconsider;
 
 
1503
 
 
 
1504
        //queen ends this sequence with right foot forward
 
 
1505
        SetQueenFoot(sbPtr,RightFoot);
 
 
1506
    }
 
 
1507
 
 
 
1508
    sbPtr->DynPtr->LinVelocity.vx =    sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1509
 
 
 
1510
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1511
}
 
 
1512
 
 
 
1513
void QueenMove_ButtCharge(STRATEGYBLOCK* sbPtr)
 
 
1514
{
 
 
1515
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1516
    int ChangingFoot = 0;
 
 
1517
 
 
 
1518
    /* Very different movement function... */
 
 
1519
 
 
 
1520
    assert(queenStatusPointer->current_move == QM_ButtCharge);
 
 
1521
 
 
 
1522
    /* Charge at the player. */
 
 
1523
    //queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;
 
 
1524
 
 
 
1525
    if (!queenStatusPointer->moveTimer) 
 
 
1526
    {
 
 
1527
        /* Do setup. */
 
 
1528
        int tweeiningtime = (Queen_Step_Time>>2);
 
 
1529
 
 
 
1530
        sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1531
 
 
 
1532
        switch (queenStatusPointer->fixed_foot)
 
 
1533
        {
 
 
1534
            case LeftFoot:
 
 
1535
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1536
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, (int)QGSS_RunButtAttack,-1,tweeiningtime);
 
 
1537
                queenStatusPointer->HModelController.LoopAfterTweening = 1;
 
 
1538
                queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */
 
 
1539
 
 
 
1540
            break;
 
 
1541
            case RightFoot:
 
 
1542
                /* Argh! Can't start from right foot! */
 
 
1543
                queenStatusPointer->current_move = QM_Close;
 
 
1544
                queenStatusPointer->moveTimer = 0;
 
 
1545
                queenStatusPointer->next_move = QM_Charge;
 
 
1546
                return;
 
 
1547
            break;
 
 
1548
            default:
 
 
1549
                assert(0);
 
 
1550
                break;
 
 
1551
        }
 
 
1552
    return;
 
 
1553
    }
 
 
1554
 
 
 
1555
    /* Check for change foot? */
 
 
1556
 
 
 
1557
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1558
    {
 
 
1559
        if (queenStatusPointer->HModelController.keyframe_flags) 
 
 
1560
        {
 
 
1561
            if (queenStatusPointer->HModelController.keyframe_flags & 1) 
 
 
1562
            {
 
 
1563
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1564
                ChangingFoot = 1;
 
 
1565
            }
 
 
1566
 
 
 
1567
            if (queenStatusPointer->HModelController.keyframe_flags & 2) 
 
 
1568
            {
 
 
1569
                SetQueenFoot(sbPtr,RightFoot);
 
 
1570
                ChangingFoot = 1;
 
 
1571
            }
 
 
1572
 
 
 
1573
            if(queenStatusPointer->moveTimer == 1)
 
 
1574
                queenStatusPointer->moveTimer = 3;
 
 
1575
        }
 
 
1576
 
 
 
1577
        HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_BUTTCHARGE_SPEED);
 
 
1578
    }
 
 
1579
 
 
 
1580
    /* Now... turn to face. */
 
 
1581
 
 
 
1582
    if (queenStatusPointer->moveTimer != 2)
 
 
1583
    {
 
 
1584
        DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock;
 
 
1585
        assert(dPtr);
 
 
1586
 
 
 
1587
        ProveHModel(dPtr->HModelControlBlock,dPtr);
 
 
1588
 
 
 
1589
        NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget,Queen_Turn_Rate);
 
 
1590
 
 
 
1591
        /* Now, just a normal lin velocity. */
 
 
1592
        if(queenStatusPointer->moveTimer == 1)
 
 
1593
        {
 
 
1594
            SetQueenMovement_FromFoot(sbPtr);
 
 
1595
        }
 
 
1596
        else
 
 
1597
        {
 
 
1598
            VECTORCH velocity;
 
 
1599
 
 
 
1600
            velocity.vx = sbPtr->DynPtr->OrientMat.mat31;
 
 
1601
            velocity.vy = 0;
 
 
1602
            velocity.vz = sbPtr->DynPtr->OrientMat.mat33;
 
 
1603
 
 
 
1604
            if ( !velocity.vx && !velocity.vy && !velocity.vz)
 
 
1605
            {
 
 
1606
                sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1607
            return;
 
 
1608
            }
 
 
1609
 
 
 
1610
            Normalise(&velocity);
 
 
1611
 
 
 
1612
            //runSpeed=DIV_FIXED(Queen_Charge_Step_Speed,Queen_ButtCharge_Rate);
 
 
1613
 
 
 
1614
            sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_BUTTCHARGE_SPEED);
 
 
1615
            sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_BUTTCHARGE_SPEED);
 
 
1616
            sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_BUTTCHARGE_SPEED);
 
 
1617
        }
 
 
1618
    }
 
 
1619
 
 
 
1620
    if(ChangingFoot)
 
 
1621
    {
 
 
1622
        QueenCalculateTargetInfo(sbPtr);
 
 
1623
        //int range = queenStatusPointer->TargetDistance;
 
 
1624
        //only check for exiting charge , when changing foot
 
 
1625
 
 
 
1626
        if(queenStatusPointer->PlayingHitDelta)
 
 
1627
        {
 
 
1628
            queenStatusPointer->HModelController.Playing = 0;
 
 
1629
            queenStatusPointer->current_move = QM_Standby;
 
 
1630
            queenStatusPointer->moveTimer = 0;
 
 
1631
            queenStatusPointer->next_move = QM_Standby;
 
 
1632
        return;
 
 
1633
        }
 
 
1634
 
 
 
1635
        if(PlayerInLocker)
 
 
1636
        {
 
 
1637
            //stop using butt charge , since the queen can't actually get to the player
 
 
1638
            queenStatusPointer->moveTimer = 0;
 
 
1639
            queenStatusPointer->current_move = QM_Charge;
 
 
1640
            queenStatusPointer->next_move = QM_Standby;
 
 
1641
        return;
 
 
1642
        }
 
 
1643
 
 
 
1644
        if (queenStatusPointer->TargetDirection.vz < queenStatusPointer->TargetDirection.vx || 
 
 
1645
            queenStatusPointer->TargetDirection.vz < -queenStatusPointer->TargetDirection.vx)
 
 
1646
        {
 
 
1647
            /* Spin round a bit more. */
 
 
1648
            queenStatusPointer->HModelController.Playing = 0;
 
 
1649
            queenStatusPointer->current_move = QM_Close;
 
 
1650
            queenStatusPointer->moveTimer = 0;
 
 
1651
            queenStatusPointer->next_move = QM_Standby;
 
 
1652
        return;
 
 
1653
        }
 
 
1654
 
 
 
1655
        if (queenStatusPointer->moveTimer != 2 && queenStatusPointer->next_move != QM_Standby) 
 
 
1656
        {
 
 
1657
            queenStatusPointer->HModelController.Playing = 0;
 
 
1658
            queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
1659
            queenStatusPointer->next_move = QM_Standby;
 
 
1660
            queenStatusPointer->moveTimer = 0;
 
 
1661
        } 
 
 
1662
    }
 
 
1663
}
 
 
1664
 
 
 
1665
void QueenForceReconsider(STRATEGYBLOCK* sbPtr)
 
 
1666
{
 
 
1667
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1668
 
 
 
1669
    if(queenStatusPointer->QueenState == QBS_Reconsider)
 
 
1670
            return;
 
 
1671
 
 
 
1672
    if(queenStatusPointer->QueenState == QBS_CarryingObject)
 
 
1673
    {
 
 
1674
        //need to drop the object
 
 
1675
        if(queenStatusPointer->CurrentQueenObject != -1)
 
 
1676
        {
 
 
1677
            //if the object has been destroyed anywa, don't need to worry about dropping it
 
 
1678
            if(!QueenObjectList[queenStatusPointer->CurrentQueenObject]->destroyed_but_preserved)
 
 
1679
            {
 
 
1680
                //put gravity back on
 
 
1681
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn = 1;
 
 
1682
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment = 0;    
 
 
1683
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat = IdentityMatrix;
 
 
1684
                //give the object a slight impulse away from the queen
 
 
1685
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse.vx += sbPtr->DynPtr->OrientMat.mat31/10;
 
 
1686
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse.vz += sbPtr->DynPtr->OrientMat.mat33/10;
 
 
1687
            }
 
 
1688
        }
 
 
1689
    }
 
 
1690
 
 
 
1691
    queenStatusPointer->CurrentQueenObject = -1;
 
 
1692
    queenStatusPointer->QueenState = QBS_Reconsider;
 
 
1693
    queenStatusPointer->QueenTargetSB = PlayerStatus.sbptr;
 
 
1694
    queenStatusPointer->TempTarget = 0;
 
 
1695
    queenStatusPointer->TargetInfoValid = 0;
 
 
1696
    queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;                    
 
 
1697
}
 
 
1698
 
 
 
1699
void QueenMove_Climb(STRATEGYBLOCK* sbPtr)
 
 
1700
{
 
 
1701
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1702
 
 
 
1703
    assert(queenStatusPointer->current_move == QM_Climbing);
 
 
1704
 
 
 
1705
    if (!queenStatusPointer->moveTimer) 
 
 
1706
    {
 
 
1707
        //just starting to climb out , so start the animation sequence
 
 
1708
        int tweeiningtime = (Queen_Step_Time >> 2);
 
 
1709
        SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, (int)QGSS_ClimbOut,-1,tweeiningtime);
 
 
1710
 
 
 
1711
        queenStatusPointer->HModelController.Playing = 1;
 
 
1712
 
 
 
1713
        //set the start position of this maneuver
 
 
1714
        queenStatusPointer->ClimbStartPosition = sbPtr->DynPtr->Position;
 
 
1715
 
 
 
1716
        //while climbing out queen needs to ignore gravity and collisions
 
 
1717
        sbPtr->DynPtr->GravityOn = 0;
 
 
1718
        sbPtr->DynPtr->OnlyCollideWithObjects = 1;    
 
 
1719
 
 
 
1720
        /*moveTimer is being used as a state flag again*/
 
 
1721
        queenStatusPointer->moveTimer = 1;
 
 
1722
    }
 
 
1723
 
 
 
1724
    /*Adjust the queen's facing*/
 
 
1725
    {
 
 
1726
        VECTORCH direction = {-ONE_FIXED,0,0};
 
 
1727
        NPCOrientateToVector(sbPtr, &direction,Queen_Turn_Rate);
 
 
1728
    }
 
 
1729
 
 
 
1730
    /*If the queen has stopped tweening , then we need to deal with her movement*/
 
 
1731
    if (!queenStatusPointer->HModelController.Tweening)
 
 
1732
    {
 
 
1733
        #define QueenClimbTime1 7598
 
 
1734
        #define QueenClimbTime2 16146
 
 
1735
        #define QueenClimbTime3 42740
 
 
1736
 
 
 
1737
        ProveHModel(sbPtr->DisplayBlock->HModelControlBlock,sbPtr->DisplayBlock);
 
 
1738
 
 
 
1739
        {
 
 
1740
            VECTORCH StageOneMovement = {0,-6771,0};        
 
 
1741
            VECTORCH StageTwoMovement = {-3266,0,-372};        
 
 
1742
 
 
 
1743
            //work out where the queen should be
 
 
1744
            VECTORCH newPosition = queenStatusPointer->ClimbStartPosition;
 
 
1745
            int timer = queenStatusPointer->HModelController.sequence_timer;
 
 
1746
 
 
 
1747
            if(timer < QueenClimbTime1)
 
 
1748
            {
 
 
1749
                //no movement
 
 
1750
            }
 
 
1751
            else if(timer < QueenClimbTime2)
 
 
1752
            {
 
 
1753
                int scale = DIV_FIXED(timer-QueenClimbTime1,QueenClimbTime2-QueenClimbTime1);
 
 
1754
 
 
 
1755
                newPosition.vx += MUL_FIXED(StageOneMovement.vx,scale);
 
 
1756
                newPosition.vy += MUL_FIXED(StageOneMovement.vy,scale);
 
 
1757
                newPosition.vz += MUL_FIXED(StageOneMovement.vz,scale);
 
 
1758
            }
 
 
1759
            else if(timer < QueenClimbTime3)
 
 
1760
            {
 
 
1761
                int scale = DIV_FIXED(timer-QueenClimbTime2, QueenClimbTime3-QueenClimbTime2);
 
 
1762
 
 
 
1763
                newPosition.vx += StageOneMovement.vx;
 
 
1764
                newPosition.vy += StageOneMovement.vy;
 
 
1765
                newPosition.vz += StageOneMovement.vz;
 
 
1766
 
 
 
1767
                newPosition.vx += MUL_FIXED(StageTwoMovement.vx,scale);
 
 
1768
                newPosition.vy += MUL_FIXED(StageTwoMovement.vy,scale);
 
 
1769
                newPosition.vz += MUL_FIXED(StageTwoMovement.vz,scale);
 
 
1770
            }                             
 
 
1771
            else
 
 
1772
            {
 
 
1773
                newPosition.vx += StageOneMovement.vx;
 
 
1774
                newPosition.vy += StageOneMovement.vy;
 
 
1775
                newPosition.vz += StageOneMovement.vz;
 
 
1776
 
 
 
1777
                newPosition.vx += StageTwoMovement.vx;
 
 
1778
                newPosition.vy += StageTwoMovement.vy;
 
 
1779
                newPosition.vz += StageTwoMovement.vz;
 
 
1780
            }
 
 
1781
 
 
 
1782
            sbPtr->DynPtr->Displacement.vx = newPosition.vx - sbPtr->DynPtr->Position.vx;
 
 
1783
            sbPtr->DynPtr->Displacement.vy = newPosition.vy - sbPtr->DynPtr->Position.vy;
 
 
1784
            sbPtr->DynPtr->Displacement.vz = newPosition.vz - sbPtr->DynPtr->Position.vz;
 
 
1785
        }
 
 
1786
 
 
 
1787
        if(queenStatusPointer->HModelController.sequence_timer > 62000)
 
 
1788
        {
 
 
1789
            //the queen has finished getting out
 
 
1790
            queenStatusPointer->current_move = QM_Standby;
 
 
1791
            queenStatusPointer->next_move = QM_Standby;
 
 
1792
            queenStatusPointer->moveTimer = 0;
 
 
1793
 
 
 
1794
            QueenForceReconsider(sbPtr);
 
 
1795
 
 
 
1796
            sbPtr->DynPtr->GravityOn = 1;
 
 
1797
            sbPtr->DynPtr->OnlyCollideWithObjects = 0;    
 
 
1798
 
 
 
1799
            //the queen ends in right stance
 
 
1800
            queenStatusPointer->fixed_foot = RightFoot;
 
 
1801
        }
 
 
1802
    }
 
 
1803
}
 
 
1804
 
 
 
1805
#define Queen_Swipe_Left 0
 
 
1806
#define Queen_Swipe_Right 1
 
 
1807
#define Queen_Swipe_Left_Low 2
 
 
1808
#define Queen_Swipe_Right_Low 3
 
 
1809
 
 
 
1810
void Queen_Do_Swipe(STRATEGYBLOCK *sbPtr,int side)
 
 
1811
{
 
 
1812
    VECTORCH vectohand,targetpos;
 
 
1813
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1814
 
 
 
1815
    /*Is the queen already doing a swipe?*/
 
 
1816
    if ((queenStatusPointer->attack_delta->timer == (ONE_FIXED-1)) || !queenStatusPointer->attack_delta->timer) 
 
 
1817
    {
 
 
1818
        /* She isn't , so start it */
 
 
1819
        switch (side)
 
 
1820
        {
 
 
1821
            case Queen_Swipe_Left:
 
 
1822
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe,ONE_FIXED);
 
 
1823
            break;
 
 
1824
            case Queen_Swipe_Right:
 
 
1825
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe,ONE_FIXED);
 
 
1826
            break;
 
 
1827
            case Queen_Swipe_Left_Low:
 
 
1828
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe_Low,ONE_FIXED);
 
 
1829
            break;
 
 
1830
            case Queen_Swipe_Right_Low:
 
 
1831
                Start_Delta_Sequence(queenStatusPointer->attack_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe_Low,ONE_FIXED);
 
 
1832
            break;
 
 
1833
            default :
 
 
1834
                assert(1==0);
 
 
1835
            break;
 
 
1836
 
 
 
1837
        }
 
 
1838
 
 
 
1839
        queenStatusPointer->attack_delta->Looped = 0;
 
 
1840
        queenStatusPointer->AttackDoneItsDamage = 0;
 
 
1841
    }
 
 
1842
 
 
 
1843
    if(queenStatusPointer->attack_delta->timer > 37000 && !queenStatusPointer->AttackDoneItsDamage)
 
 
1844
    {
 
 
1845
        SECTION_DATA *hand_section;
 
 
1846
        queenStatusPointer->AttackDoneItsDamage = 1;
 
 
1847
 
 
 
1848
        //get the hand corresponding to the currently playing swipe
 
 
1849
        switch(queenStatusPointer->attack_delta->sub_sequence)
 
 
1850
        {
 
 
1851
            case QRSTSS_RightSwipe:
 
 
1852
            case QRSTSS_RightSwipe_Low:
 
 
1853
                hand_section = GetThisSectionData(queenStatusPointer->HModelController.section_data,"right hand");
 
 
1854
                break;
 
 
1855
 
 
 
1856
            case QRSTSS_LeftSwipe:
 
 
1857
            case QRSTSS_LeftSwipe_Low:
 
 
1858
                hand_section = GetThisSectionData(queenStatusPointer->HModelController.section_data,"left hand");
 
 
1859
                break;
 
 
1860
 
 
 
1861
            default:
 
 
1862
                assert(1==0);
 
 
1863
        }
 
 
1864
 
 
 
1865
        GetTargetingPointOfObject(PlayerStatus.DisplayBlock, &targetpos);
 
 
1866
        vectohand.vx = targetpos.vx-hand_section->World_Offset.vx;
 
 
1867
        vectohand.vy = 0;//targetpos.vy-hand_section->World_Offset.vy;
 
 
1868
        vectohand.vz = targetpos.vz-hand_section->World_Offset.vz;
 
 
1869
 
 
 
1870
        int range_to_player = Approximate3dMagnitude(&vectohand);
 
 
1871
 
 
 
1872
        //see if queen hit an intervening object
 
 
1873
        {
 
 
1874
            VECTORCH direction;
 
 
1875
 
 
 
1876
            direction.vx = targetpos.vx - hand_section->World_Offset.vx;
 
 
1877
            direction.vy = targetpos.vy - hand_section->World_Offset.vy;
 
 
1878
            direction.vz = targetpos.vz - hand_section->World_Offset.vz;
 
 
1879
 
 
 
1880
            Normalise(&direction);
 
 
1881
 
 
 
1882
            if(FindPolygonInLineOfSight(&direction, &hand_section->World_Offset, sbPtr->DisplayBlock))
 
 
1883
            {
 
 
1884
                if(LOS_ObjectHitPtr->ObStrategyBlock)
 
 
1885
                {
 
 
1886
                    switch(LOS_ObjectHitPtr->ObStrategyBlock->type)
 
 
1887
                    {
 
 
1888
                        case I_BehaviourInanimateObject:
 
 
1889
                        case I_BehaviourTrackObject:
 
 
1890
                        {
 
 
1891
                            //damage the object instead of the player
 
 
1892
                            //if(LOS_Lambda < QueenAttackRange)
 
 
1893
                                CauseDamageToObject(LOS_ObjectHitPtr->ObStrategyBlock,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage, ONE_FIXED,NULL);
 
 
1894
                            return;
 
 
1895
                        }
 
 
1896
                        default:
 
 
1897
                        break;
 
 
1898
                    }
 
 
1899
                }
 
 
1900
            }
 
 
1901
        }
 
 
1902
 
 
 
1903
        /* ATM, target is always player. */
 
 
1904
 
 
 
1905
        if (range_to_player < QueenAttackRange) 
 
 
1906
        {
 
 
1907
        //do from .75 to 1.25 times base damage
 
 
1908
        CauseDamageToObject(PlayerStatus.sbptr, &TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage, (ONE_FIXED*.75)+(FastRandom()&0x7fff), NULL);
 
 
1909
            queenStatusPointer->QueenTauntTimer=ONE_FIXED/2;                        
 
 
1910
        }
 
 
1911
    }
 
 
1912
}
 
 
1913
 
 
 
1914
void QueenMove_Close(STRATEGYBLOCK *sbPtr)
 
 
1915
{
 
 
1916
    QUEEN_STATUS_BLOCK *queenStatusPointer= (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1917
 
 
 
1918
    /* First movement function. */
 
 
1919
 
 
 
1920
    assert(queenStatusPointer->current_move == QM_Close);
 
 
1921
 
 
 
1922
    if (!queenStatusPointer->moveTimer) 
 
 
1923
    {
 
 
1924
        /* Do setup. */
 
 
1925
        int tweeiningtime = (ONE_FIXED >> 3);
 
 
1926
 
 
 
1927
        sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1928
 
 
 
1929
        switch (queenStatusPointer->fixed_foot)
 
 
1930
        {
 
 
1931
            case LeftFoot:
 
 
1932
                SetQueenFoot(sbPtr,LeftFoot);
 
 
1933
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, (int)QLSTSS_Forward_L2R,-1,tweeiningtime);
 
 
1934
                queenStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
1935
            break;
 
 
1936
            case RightFoot:
 
 
1937
                SetQueenFoot(sbPtr,RightFoot);
 
 
1938
                SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, (int)QRSTSS_Forward_R2L,-1,tweeiningtime);
 
 
1939
                queenStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
1940
            break;
 
 
1941
            default:
 
 
1942
                assert(0);
 
 
1943
                break;
 
 
1944
        }
 
 
1945
 
 
 
1946
        /* Go! */
 
 
1947
        queenStatusPointer->moveTimer++;
 
 
1948
        assert(queenStatusPointer->HModelController.Looped == 0);
 
 
1949
    return;
 
 
1950
    }
 
 
1951
 
 
 
1952
    if (!queenStatusPointer->HModelController.Tweening) 
 
 
1953
    {
 
 
1954
        int moveHalfSpeed = 0;
 
 
1955
 
 
 
1956
        #if DEBUG
 
 
1957
        if (queenStatusPointer->HModelController.Looped != 0)
 
 
1958
        {
 
 
1959
            /* Quirkafleeg */
 
 
1960
            assert(!queenStatusPointer->HModelController.Looped);
 
 
1961
        }
 
 
1962
        #endif
 
 
1963
 
 
 
1964
        QueenCalculateTargetInfo(sbPtr);
 
 
1965
        //if the queen is close to her target , and the target is not in front of her
 
 
1966
        //then she needs to slow down to reduce her turning circle
 
 
1967
 
 
 
1968
        if(queenStatusPointer->TargetDistance < 3000)
 
 
1969
        {
 
 
1970
            if(queenStatusPointer->TargetDirection.vz < queenStatusPointer->TargetDirection.vx ||
 
 
1971
               queenStatusPointer->TargetDirection.vz < -queenStatusPointer->TargetDirection.vx)
 
 
1972
            {
 
 
1973
                moveHalfSpeed = 1;
 
 
1974
            }
 
 
1975
        }
 
 
1976
 
 
 
1977
        if(moveHalfSpeed)
 
 
1978
            HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/(QUEEN_CLOSE_SPEED/2));
 
 
1979
        else
 
 
1980
            HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_CLOSE_SPEED);
 
 
1981
    }
 
 
1982
 
 
 
1983
    /* Now... turn to face. */
 
 
1984
 
 
 
1985
    {
 
 
1986
        //DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock; assert(dPtr);
 
 
1987
 
 
 
1988
        NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget, Queen_Turn_Rate);
 
 
1989
 
 
 
1990
        SetQueenMovement_FromFoot(sbPtr);
 
 
1991
    }
 
 
1992
 
 
 
1993
    queenStatusPointer->moveTimer += NormalFrameTime;
 
 
1994
 
 
 
1995
    if (!queenStatusPointer->HModelController.Tweening && (queenStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1)))
 
 
1996
    {
 
 
1997
        queenStatusPointer->current_move = QM_Standby;
 
 
1998
 
 
 
1999
        switch (queenStatusPointer->fixed_foot)
 
 
2000
        {
 
 
2001
            case LeftFoot:
 
 
2002
                SetQueenFoot(sbPtr,RightFoot);
 
 
2003
            break;
 
 
2004
            case RightFoot:
 
 
2005
                SetQueenFoot(sbPtr,LeftFoot);
 
 
2006
            break;
 
 
2007
            default:
 
 
2008
                assert(0);
 
 
2009
                break;
 
 
2010
        }
 
 
2011
 
 
 
2012
        queenStatusPointer->moveTimer = 0;
 
 
2013
        queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
2014
        queenStatusPointer->next_move = QM_Standby;
 
 
2015
    }
 
 
2016
}
 
 
2017
 
 
 
2018
void KillQueen(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *Section, VECTORCH *incoming)
 
 
2019
{
 
 
2020
    /* Oh my God!  They've killed Queenie! */
 
 
2021
 
 
 
2022
    assert(sbPtr);
 
 
2023
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2024
    assert(queenStatusPointer);
 
 
2025
 
 
 
2026
    /* make a sound.  Just this once without a check. */
 
 
2027
    Sound_Play(SID_ALIEN_KILL, "d", &sbPtr->DynPtr->Position);
 
 
2028
 
 
 
2029
    /*If queen has a death target ,send a request*/
 
 
2030
    if(queenStatusPointer->death_target_sbptr)
 
 
2031
        RequestState(queenStatusPointer->death_target_sbptr,queenStatusPointer->death_target_request, 0);
 
 
2032
 
 
 
2033
    /* Queens never gibb, they're that hard. */
 
 
2034
 
 
 
2035
    /* Deal with sequence. */
 
 
2036
    RemoveAllDeltas(&queenStatusPointer->HModelController);
 
 
2037
 
 
 
2038
    SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,QGSS_FaceDeath,(ONE_FIXED),(ONE_FIXED>>2));
 
 
2039
 
 
 
2040
    //if the queen is carrying an object , release it and reset gravity on it
 
 
2041
 
 
 
2042
    if(queenStatusPointer->QueenState == QBS_CarryingObject)
 
 
2043
    {
 
 
2044
        if(!QueenObjectList[queenStatusPointer->CurrentQueenObject]->destroyed_but_preserved)
 
 
2045
        {
 
 
2046
            QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn = 1;
 
 
2047
            QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment = 0;    
 
 
2048
            queenStatusPointer->CurrentQueenObject = -1;
 
 
2049
        }
 
 
2050
    }
 
 
2051
 
 
 
2052
    /* More restrained death than before... */
 
 
2053
    {
 
 
2054
        queenStatusPointer->QueenState = QBS_Dead;
 
 
2055
 
 
 
2056
        /* stop motion */
 
 
2057
        sbPtr->DynPtr->LinImpulse.vx += sbPtr->DynPtr->LinVelocity.vx;
 
 
2058
        sbPtr->DynPtr->LinImpulse.vy += sbPtr->DynPtr->LinVelocity.vy;
 
 
2059
        sbPtr->DynPtr->LinImpulse.vz += sbPtr->DynPtr->LinVelocity.vz;
 
 
2060
        sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
2061
 
 
 
2062
        sbPtr->DynPtr->IgnoreSameObjectsAsYou = 1;
 
 
2063
        /* Experiment... */
 
 
2064
        sbPtr->DynPtr->UseStandardGravity = 1;
 
 
2065
    }
 
 
2066
}
 
 
2067
 
 
 
2068
void QueenIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming, VECTORCH *point)
 
 
2069
{
 
 
2070
    assert(sbPtr);
 
 
2071
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2072
    assert(queenStatusPointer);
 
 
2073
 
 
 
2074
    /* Ouch. */
 
 
2075
    if (sbPtr->DamageBlock.Health <= 0)
 
 
2076
    {
 
 
2077
        if (queenStatusPointer->QueenState!=QBS_Dead)
 
 
2078
            KillQueen(sbPtr,damage,multiple,Section,incoming);
 
 
2079
    return;
 
 
2080
    }
 
 
2081
 
 
 
2082
    QueenSoundHurt(sbPtr);
 
 
2083
 
 
 
2084
    if(damage->ExplosivePower && incoming)
 
 
2085
    {
 
 
2086
        /*
 
 
2087
        Don't allow the queen to be stunned if she is climbing out of the airlock.
 
 
2088
        This would screw up the sequence to much.
 
 
2089
        */
 
 
2090
        if(queenStatusPointer->current_move != QM_Climbing)
 
 
2091
        {
 
 
2092
            if(!QueenPlayingStunAnimation(&queenStatusPointer->HModelController))
 
 
2093
            {
 
 
2094
                if(EXPLOSIONFIRE_BLAST == damage->Id)
 
 
2095
                {
 
 
2096
                    //big explosion, play fall over anim
 
 
2097
                    SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,(int)QGSS_Explosion_Stun,-1,ONE_FIXED>>3);
 
 
2098
                    queenStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
2099
                    queenStatusPointer->current_move = QM_Stun;
 
 
2100
                    queenStatusPointer->PlayingHitDelta = 1;
 
 
2101
                    QueenForceReconsider(sbPtr);
 
 
2102
 
 
 
2103
                    //the queen ends in right stance
 
 
2104
                    queenStatusPointer->fixed_foot = RightFoot;
 
 
2105
                }
 
 
2106
                else
 
 
2107
                {
 
 
2108
                    //play a hit delta if not already doing so
 
 
2109
                    if ((queenStatusPointer->hit_delta->timer == (ONE_FIXED-1)) ||!queenStatusPointer->hit_delta->timer) 
 
 
2110
                    {
 
 
2111
                        VECTORCH dir = *incoming;
 
 
2112
                        MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
2113
 
 
 
2114
                        TransposeMatrixCH(&WtoL);
 
 
2115
                        RotateVector(&dir,&WtoL);
 
 
2116
 
 
 
2117
                        if(dir.vx > 0)
 
 
2118
                            Start_Delta_Sequence(queenStatusPointer->hit_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightHit,-1);
 
 
2119
                        else
 
 
2120
                            Start_Delta_Sequence(queenStatusPointer->hit_delta, (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftHit,-1);
 
 
2121
 
 
 
2122
                        queenStatusPointer->PlayingHitDelta = 1;
 
 
2123
                        QueenForceReconsider(sbPtr);
 
 
2124
                    }
 
 
2125
                }
 
 
2126
            }
 
 
2127
        }
 
 
2128
    }
 
 
2129
 
 
 
2130
    if(AvP.PlayerType == I_Marine && Section)
 
 
2131
    {
 
 
2132
        //don't allow the marine to completely destroy a section
 
 
2133
        if(Section->current_damage.Health <= 0)
 
 
2134
            Section->current_damage.Health = 1;
 
 
2135
    }
 
 
2136
}
 
 
2137
 
 
 
2138
static void Execute_Queen_Dying(STRATEGYBLOCK *sbPtr)
 
 
2139
{
 
 
2140
    /* Here for completeness.  Queens never melt away. */
 
 
2141
/*
 
 
2142
    assert(sbPtr);
 
 
2143
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2144
    assert(queenStatusPointer); 
 
 
2145
 
 
 
2146
    if(!strcmp(AvP.LevelName, "hangar")
 
 
2147
    {
 
 
2148
        DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock;
 
 
2149
 
 
 
2150
        if (dispPtr)
 
 
2151
        {
 
 
2152
            //dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
 
 
2153
            //dispPtr->ObFlags2 = queenStatusPointer->NearStateTimer / 2;
 
 
2154
        }
 
 
2155
    }
 
 
2156
*/
 
 
2157
}
 
 
2158
 
 
 
2159
void FindQueenObjects()
 
 
2160
{
 
 
2161
    int sbIndex = 0;
 
 
2162
    NumQueenObjects = 0;
 
 
2163
 
 
 
2164
    //search through all the strategies for the throwable objects
 
 
2165
    //also look for the special airlock doors
 
 
2166
    UpperAirlockDoorSbptr = 0;
 
 
2167
    LowerAirlockDoorSbptr = 0;
 
 
2168
    LockerDoorSbptr = 0;
 
 
2169
    UpperAirlockDoorOpen = 0;
 
 
2170
    LowerAirlockDoorOpen = 0;
 
 
2171
 
 
 
2172
    while(sbIndex < NumActiveStBlocks)
 
 
2173
    {    
 
 
2174
        STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++];
 
 
2175
 
 
 
2176
        if(sbPtr->name)
 
 
2177
        {    
 
 
2178
            if(strstr(sbPtr->name, "QueenAmmo"))
 
 
2179
            {
 
 
2180
                if(NumQueenObjects < QUEEN_MAX_OBJECT)
 
 
2181
                {
 
 
2182
                    QueenObjectList[NumQueenObjects++] = sbPtr;    
 
 
2183
                    assert(sbPtr->DynPtr);
 
 
2184
                    sbPtr->preserve_until_end_of_level = 1;
 
 
2185
                }
 
 
2186
            }
 
 
2187
            else if(!strcmp(sbPtr->name, "a1door"))
 
 
2188
            {
 
 
2189
                UpperAirlockDoorSbptr = sbPtr;    
 
 
2190
                UpperAirlockDoorStart = sbPtr->DynPtr->Position;
 
 
2191
            }
 
 
2192
            else if(!strcmp(sbPtr->name, "a3door"))
 
 
2193
            {
 
 
2194
                LowerAirlockDoorSbptr = sbPtr;    
 
 
2195
                LowerAirlockDoorStart = sbPtr->DynPtr->Position;
 
 
2196
            }
 
 
2197
            else if(!strcmp(sbPtr->name, "locker door"))
 
 
2198
            {
 
 
2199
                LockerDoorSbptr = sbPtr;    
 
 
2200
                sbPtr->preserve_until_end_of_level = 1;
 
 
2201
            }
 
 
2202
        }
 
 
2203
    }
 
 
2204
}
 
 
2205
 
 
 
2206
int CalculateTrajectory(VECTORCH* start,VECTORCH* dest,VECTORCH* velocity,int obj_speed,VECTORCH* result)
 
 
2207
{
 
 
2208
    VECTORCH rotated_vel;
 
 
2209
    VECTORCH rotated_result;
 
 
2210
    VECTORCH normal;
 
 
2211
 
 
 
2212
    //get a normalised vector from start to destination
 
 
2213
 
 
 
2214
    normal.vx = dest->vx - start->vx;
 
 
2215
    //normal.vy = dest->vy - start->vy;
 
 
2216
    normal.vy = 0;
 
 
2217
    normal.vz = dest->vz - start->vz;
 
 
2218
 
 
 
2219
    int vertical_distance = normal.vy-1000;
 
 
2220
 
 
 
2221
    if(!normal.vx && !normal.vz)
 
 
2222
        return 0;
 
 
2223
 
 
 
2224
    int distance = Magnitude(&normal);
 
 
2225
 
 
 
2226
    Normalise(&normal);
 
 
2227
 
 
 
2228
    //apply rotation to velocity that would rotate the normal to (ONE_FIXED,0,0)
 
 
2229
    rotated_vel.vx = MUL_FIXED(velocity->vx,normal.vx)+MUL_FIXED(velocity->vz,normal.vz);
 
 
2230
    rotated_vel.vy = 0;
 
 
2231
    rotated_vel.vz = MUL_FIXED(velocity->vx,-normal.vz)+MUL_FIXED(velocity->vz,normal.vx);
 
 
2232
 
 
 
2233
    if(rotated_vel.vz >= obj_speed || -rotated_vel.vz >= obj_speed)
 
 
2234
        return 0; //no hope of hitting
 
 
2235
 
 
 
2236
    rotated_result.vz = rotated_vel.vz;
 
 
2237
 
 
 
2238
    //calculate x component using floats
 
 
2239
    {
 
 
2240
        float z =(float)rotated_result.vz;
 
 
2241
        float speed = (float)obj_speed;
 
 
2242
 
 
 
2243
        float x = sqrt(speed*speed-z*z);
 
 
2244
 
 
 
2245
        rotated_result.vx = x;
 
 
2246
    }
 
 
2247
 
 
 
2248
    int closing_speed = rotated_result.vx-rotated_vel.vx;
 
 
2249
 
 
 
2250
    if(closing_speed <= 0)
 
 
2251
        return 0; //can't hit
 
 
2252
 
 
 
2253
    int time_to_target = DIV_FIXED(distance, closing_speed);
 
 
2254
 
 
 
2255
    if(time_to_target > (3*ONE_FIXED))
 
 
2256
    {
 
 
2257
        //take to long to hit target
 
 
2258
        return 0;
 
 
2259
    }
 
 
2260
 
 
 
2261
    //rotate result back
 
 
2262
    result->vx = MUL_FIXED(rotated_result.vx,normal.vx)+MUL_FIXED(rotated_result.vz,-normal.vz);
 
 
2263
    result->vy = 0;
 
 
2264
    result->vz = MUL_FIXED(rotated_result.vx,normal.vz)+MUL_FIXED(rotated_result.vz,normal.vx);
 
 
2265
 
 
 
2266
    //calculate required up component
 
 
2267
    //u=s/t - a*t/2
 
 
2268
    result->vy = DIV_FIXED(vertical_distance,time_to_target)-MUL_FIXED(time_to_target,GRAVITY_STRENGTH/2);
 
 
2269
 
 
 
2270
//we have a targeting solution.
 
 
2271
return 1;
 
 
2272
}
 
 
2273
 
 
 
2274
#define AirlockMinX 33882
 
 
2275
#define AirlockMaxX 45542
 
 
2276
#define AirlockMinZ -13936
 
 
2277
#define AirlockMaxZ -6266
 
 
2278
#define AirlockCentreX ((AirlockMinX+AirlockMaxX)/2)
 
 
2279
#define AirlockCentreZ ((AirlockMinZ+AirlockMaxZ)/2)
 
 
2280
#define AirlockY   12000
 
 
2281
#define HangarFloorLevel 3950
 
 
2282
#define AirlockOpeningDistance 2500
 
 
2283
#define AirlockOffset 1000
 
 
2284
 
 
 
2285
void QueenCheckForAvoidAirlock(STRATEGYBLOCK *sbPtr)
 
 
2286
{
 
 
2287
    //only need to look out for the airlock in hangar
 
 
2288
    if(!strcmp(AvP.LevelName, "hangar"))
 
 
2289
    {
 
 
2290
        QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
2291
        VECTORCH* qpos = &sbPtr->DynPtr->Position;
 
 
2292
        VECTORCH* tpos = &queenStatusPointer->TargetPos;
 
 
2293
 
 
 
2294
        if(!UpperAirlockDoorOpen)
 
 
2295
            return;
 
 
2296
 
 
 
2297
        if(PlayerInTrench)
 
 
2298
            return;
 
 
2299
 
 
 
2300
        if(queenStatusPointer->QueenState == QBS_ClimbingOutOfAirlock)
 
 
2301
        {
 
 
2302
            //not much point in trying to avoid airlock now!
 
 
2303
            return;
 
 
2304
        }
 
 
2305
 
 
 
2306
        if(!queenStatusPointer->BeenInAirlock)
 
 
2307
        {
 
 
2308
            //if the queen hasn't fallen in yet , then she isn't careful while
 
 
2309
            //charging at the player
 
 
2310
            if(queenStatusPointer->current_move == QM_ButtCharge)
 
 
2311
                return;
 
 
2312
        }
 
 
2313
 
 
 
2314
        if(qpos->vx > AirlockMaxX - 1000)
 
 
2315
        {
 
 
2316
            if(tpos->vx < AirlockMaxX - 1000)
 
 
2317
            {
 
 
2318
                //queen and target are on opposite sides of the max X side
 
 
2319
                //find out where the queen's path will intersect the side
 
 
2320
 
 
 
2321
                int scale = DIV_FIXED((AirlockMaxX-1000)-qpos->vx,tpos->vx-qpos->vx);
 
 
2322
                int zintercept = MUL_FIXED(tpos->vz-qpos->vz,scale)+qpos->vz;
 
 
2323
 
 
 
2324
                if(zintercept >= AirlockMinZ && zintercept <= AirlockMaxZ)
 
 
2325
                {
 
 
2326
                    //printf("Airlock Max X\n");
 
 
2327
 
 
 
2328
                    //head for the corner that is closest to the current target
 
 
2329
                    queenStatusPointer->TargetPos.vx = AirlockMaxX;
 
 
2330
 
 
 
2331
                    if(abs(AirlockMinZ-tpos->vz) < abs(AirlockMaxZ-tpos->vz))
 
 
2332
                        queenStatusPointer->TargetPos.vz = AirlockMinZ;
 
 
2333
                    else
 
 
2334
                        queenStatusPointer->TargetPos.vz = AirlockMaxZ;
 
 
2335
 
 
 
2336
                    queenStatusPointer->TempTarget = 1;
 
 
2337
                    queenStatusPointer->TempTargetTimer = ONE_FIXED;
 
 
2338
                    queenStatusPointer->TargetInfoValid = 0;
 
 
2339
                return;
 
 
2340
                }
 
 
2341
            }
 
 
2342
        }
 
 
2343
        else if(qpos->vx < AirlockMinX + 1000)
 
 
2344
        {
 
 
2345
            if(tpos->vx > AirlockMinX + 1000)
 
 
2346
            {
 
 
2347
                //queen and target are on opposite sides of the min X side
 
 
2348
                //find out where the queen's path will intersect the side
 
 
2349
                int scale = DIV_FIXED(AirlockMinX+1000-qpos->vx,tpos->vx-qpos->vx);
 
 
2350
                int zintercept = MUL_FIXED(tpos->vz-qpos->vz,scale)+qpos->vz;
 
 
2351
 
 
 
2352
                if(zintercept >= AirlockMinZ && zintercept <= AirlockMaxZ)
 
 
2353
                {
 
 
2354
//                    printf("Airlock Min X\n");
 
 
2355
                    //head for the corner that is closest to the current target
 
 
2356
                    queenStatusPointer->TargetPos.vx = AirlockMinX;
 
 
2357
 
 
 
2358
                    if(abs(AirlockMinZ-tpos->vz) < abs(AirlockMaxZ-tpos->vz))
 
 
2359
                        queenStatusPointer->TargetPos.vz = AirlockMinZ;
 
 
2360
                    else
 
 
2361
                        queenStatusPointer->TargetPos.vz = AirlockMaxZ;
 
 
2362
 
 
 
2363
                    queenStatusPointer->TempTarget = 1;
 
 
2364
                    queenStatusPointer->TempTargetTimer = ONE_FIXED;
 
 
2365
                    queenStatusPointer->TargetInfoValid = 0;
 
 
2366
                return;
 
 
2367
                }
 
 
2368
            }
 
 
2369
        }
 
 
2370
 
 
 
2371
        if(qpos->vz > AirlockMaxZ - 1000)
 
 
2372
        {
 
 
2373
            if(tpos->vz < AirlockMaxZ - 1000)
 
 
2374
            {
 
 
2375
                //queen and target are on opposite sides of the max Z side
 
 
2376
                //find out where the queen's path will intersect the side
 
 
2377
                int scale = DIV_FIXED((AirlockMaxZ-1000)-qpos->vz,tpos->vz-qpos->vz);
 
 
2378
                int xintercept = MUL_FIXED(tpos->vx-qpos->vx,scale)+qpos->vx;
 
 
2379
 
 
 
2380
                if(xintercept >= AirlockMinX && xintercept <= AirlockMaxX)
 
 
2381
                {
 
 
2382
//                    printf("Airlock Max Z\n");
 
 
2383
                    //head for the corner that is closest to the current target
 
 
2384
                    queenStatusPointer->TargetPos.vz = AirlockMaxZ;
 
 
2385
 
 
 
2386
                    if(abs(AirlockMinX-tpos->vx) < abs(AirlockMaxX-tpos->vx))
 
 
2387
                        queenStatusPointer->TargetPos.vx = AirlockMinX;
 
 
2388
                    else
 
 
2389
                        queenStatusPointer->TargetPos.vx = AirlockMaxX;
 
 
2390
 
 
 
2391
                    queenStatusPointer->TempTarget = 1;
 
 
2392
                    queenStatusPointer->TempTargetTimer = ONE_FIXED;
 
 
2393
                    queenStatusPointer->TargetInfoValid = 0;
 
 
2394
                return;
 
 
2395
                }
 
 
2396
            }
 
 
2397
        }
 
 
2398
        else if(qpos->vz < AirlockMinZ + 1000)
 
 
2399
        {
 
 
2400
            if(tpos->vz > AirlockMinZ + 1000)
 
 
2401
            {
 
 
2402
                //queen and target are on opposite sides of the min Z side
 
 
2403
                //find out where the queen's path will intersect the side
 
 
2404
                int scale = DIV_FIXED(AirlockMinZ+1000-qpos->vz,tpos->vz-qpos->vz);
 
 
2405
                int xintercept = MUL_FIXED(tpos->vx-qpos->vx,scale)+qpos->vx;
 
 
2406
 
 
 
2407
                if(xintercept >= AirlockMinX && xintercept <= AirlockMaxX)
 
 
2408
                {
 
 
2409
//                    printf("Airlock Min Z\n");
 
 
2410
                    //head for the corner that is closest to the current target
 
 
2411
                    queenStatusPointer->TargetPos.vz = AirlockMinZ;
 
 
2412
 
 
 
2413
                    if(abs(AirlockMinX-tpos->vx) < abs(AirlockMaxX-tpos->vx))
 
 
2414
                        queenStatusPointer->TargetPos.vx = AirlockMinX;
 
 
2415
                    else
 
 
2416
                        queenStatusPointer->TargetPos.vx = AirlockMaxX;
 
 
2417
 
 
 
2418
                    queenStatusPointer->TempTarget = 1;
 
 
2419
                    queenStatusPointer->TempTargetTimer = ONE_FIXED;
 
 
2420
                    queenStatusPointer->TargetInfoValid = 0;
 
 
2421
                return;
 
 
2422
                }
 
 
2423
            }
 
 
2424
        }
 
 
2425
          //printf("Airlock not in the way\n");
 
 
2426
    }
 
 
2427
}
 
 
2428
 
 
 
2429
#define HangarLockerMinX 17104
 
 
2430
#define HangarLockerMaxX 19680
 
 
2431
#define HangarLockerMinZ -32700
 
 
2432
#define HangarLockerMaxZ -29661
 
 
2433
#define HangarLockerCentreZ ((HangarLockerMinZ+HangarLockerMaxZ)/2)
 
 
2434
 
 
 
2435
int ObjectIsInAirlock(STRATEGYBLOCK* sbPtr)
 
 
2436
{
 
 
2437
    assert(sbPtr);
 
 
2438
    assert(sbPtr->DynPtr);
 
 
2439
 
 
 
2440
    if(sbPtr->DynPtr->Position.vx > AirlockMinX && sbPtr->DynPtr->Position.vx < AirlockMaxX &&
 
 
2441
       sbPtr->DynPtr->Position.vz > AirlockMinZ && sbPtr->DynPtr->Position.vz < AirlockMaxZ &&
 
 
2442
       sbPtr->DynPtr->Position.vy > (HangarFloorLevel+1000))
 
 
2443
    {
 
 
2444
        return 1;
 
 
2445
    }
 
 
2446
 
 
 
2447
return 0;
 
 
2448
}
 
 
2449
 
 
 
2450
void QueenPickupTargetObject(STRATEGYBLOCK *sbPtr)
 
 
2451
{
 
 
2452
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2453
 
 
 
2454
    //queen must be going for an object
 
 
2455
    if(queenStatusPointer->QueenState != QBS_GoingForObject)
 
 
2456
        return;
 
 
2457
 
 
 
2458
    //disable gravity for object , while it is being carried
 
 
2459
    queenStatusPointer->QueenTargetSB->DynPtr->GravityOn = 0;
 
 
2460
 
 
 
2461
    //also stop it colliding with the queen
 
 
2462
    queenStatusPointer->QueenTargetSB->DynPtr->OnlyCollideWithEnvironment = 1;
 
 
2463
 
 
 
2464
    //change queen's state
 
 
2465
    queenStatusPointer->QueenState = QBS_CarryingObject;
 
 
2466
    queenStatusPointer->QueenStateTimer = 0;
 
 
2467
 
 
 
2468
    //now heading for the player
 
 
2469
    queenStatusPointer->QueenTargetSB = PlayerStatus.sbptr;
 
 
2470
    queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;                    
 
 
2471
    queenStatusPointer->TargetInfoValid = 0;
 
 
2472
    queenStatusPointer->next_move = QM_Close;
 
 
2473
}
 
 
2474
 
 
 
2475
static int TargetIsFiringFlamethrowerAtQueen(STRATEGYBLOCK *sbPtr)
 
 
2476
{
 
 
2477
    assert(sbPtr);
 
 
2478
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2479
 
 
 
2480
    //only marine has flamethrower
 
 
2481
    if(AvP.PlayerType != I_Marine)
 
 
2482
        return 0;
 
 
2483
 
 
 
2484
    //queen must be heading for the player
 
 
2485
    if(queenStatusPointer->QueenTargetSB != PlayerStatus.sbptr)
 
 
2486
        return 0;
 
 
2487
 
 
 
2488
    if(queenStatusPointer->TempTarget)
 
 
2489
        return 0;
 
 
2490
 
 
 
2491
    QueenCalculateTargetInfo(sbPtr);
 
 
2492
 
 
 
2493
    if(queenStatusPointer->TargetDistance > 30000)
 
 
2494
        return 0; //queen is too far away to be harmed
 
 
2495
 
 
 
2496
    //if(queenStatusPointer->TargetDistance < 3000) return 0; //queen close enough to attack , so she may as well go ahead
 
 
2497
 
 
 
2498
    /*
 
 
2499
    if (queenStatusPointer->attack_delta->timer != (ONE_FIXED-1) &&
 
 
2500
        queenStatusPointer->attack_delta->timer != 0)
 
 
2501
    {
 
 
2502
        //currently attacking
 
 
2503
        return 0;
 
 
2504
    }
 
 
2505
    */
 
 
2506
 
 
 
2507
    /* Is the player firing a flamethrower? */
 
 
2508
 
 
 
2509
    if (PlayerStatus.SelectedWeapon->WeaponIDNumber != WEAPON_FLAMETHROWER) 
 
 
2510
        return 0;
 
 
2511
 
 
 
2512
    if (PlayerStatus.WeaponState != WEAPONSTATE_FIRING_PRIMARY) 
 
 
2513
        return 0;
 
 
2514
 
 
 
2515
    //The player is firing the flamethrower.
 
 
2516
    //are the queen and player facing each other
 
 
2517
 
 
 
2518
    {
 
 
2519
        MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
2520
        VECTORCH offset;
 
 
2521
 
 
 
2522
        offset.vx = sbPtr->DynPtr->Position.vx - PlayerStatus.DisplayBlock->ObWorld.vx;
 
 
2523
        offset.vy = sbPtr->DynPtr->Position.vy - PlayerStatus.DisplayBlock->ObWorld.vy;
 
 
2524
        offset.vz = sbPtr->DynPtr->Position.vz - PlayerStatus.DisplayBlock->ObWorld.vz;
 
 
2525
 
 
 
2526
        TransposeMatrixCH(&WtoL);
 
 
2527
        RotateVector(&offset, &WtoL);
 
 
2528
 
 
 
2529
        if ( (offset.vz < 0) 
 
 
2530
            && (offset.vz <  offset.vx) 
 
 
2531
            && (offset.vz < -offset.vx) 
 
 
2532
            && (offset.vz <  offset.vy) 
 
 
2533
            && (offset.vz < -offset.vy) )
 
 
2534
        {
 
 
2535
 
 
 
2536
            /* 90 horizontal, 90 vertical... continue. */
 
 
2537
        }
 
 
2538
        else
 
 
2539
        {
 
 
2540
            return 0;
 
 
2541
        }
 
 
2542
 
 
 
2543
        /* Now test it for the other way round. */
 
 
2544
 
 
 
2545
        WtoL = PlayerStatus.DisplayBlock->ObMat;
 
 
2546
 
 
 
2547
        offset.vx = PlayerStatus.DisplayBlock->ObWorld.vx - sbPtr->DynPtr->Position.vx;
 
 
2548
        offset.vy = PlayerStatus.DisplayBlock->ObWorld.vy - sbPtr->DynPtr->Position.vy;
 
 
2549
        offset.vz = PlayerStatus.DisplayBlock->ObWorld.vz - sbPtr->DynPtr->Position.vz;
 
 
2550
 
 
 
2551
        TransposeMatrixCH(&WtoL);
 
 
2552
        RotateVector(&offset,&WtoL);
 
 
2553
 
 
 
2554
        if ( (offset.vz < 0) 
 
 
2555
            && (offset.vz <  offset.vx) 
 
 
2556
            && (offset.vz < -offset.vx) 
 
 
2557
            && (offset.vz <  offset.vy) 
 
 
2558
            && (offset.vz < -offset.vy) )
 
 
2559
        {
 
 
2560
 
 
 
2561
            /* 90 horizontal, 90 vertical... continue. */
 
 
2562
        }
 
 
2563
        else
 
 
2564
        {
 
 
2565
            return 0;
 
 
2566
        }
 
 
2567
    }
 
 
2568
 
 
 
2569
/* If here, then it must be true! */
 
 
2570
return 1;
 
 
2571
}
 
 
2572
 
 
 
2573
static int LockerDoorIsClosed()
 
 
2574
{
 
 
2575
    assert(LockerDoorSbptr);
 
 
2576
 
 
 
2577
    if(LockerDoorSbptr->destroyed_but_preserved)
 
 
2578
        return 0;
 
 
2579
 
 
 
2580
    assert(LockerDoorSbptr->dataptr);
 
 
2581
 
 
 
2582
    TRACK_OBJECT_BEHAV_BLOCK* door = (TRACK_OBJECT_BEHAV_BLOCK*)LockerDoorSbptr->dataptr;
 
 
2583
 
 
 
2584
    assert(door->to_track);
 
 
2585
 
 
 
2586
    if(door->to_track->reverse && !door->to_track->playing)
 
 
2587
        return 1;
 
 
2588
 
 
 
2589
return 0;
 
 
2590
}
 
 
2591
 
 
 
2592
void HandleHangarAirlock()
 
 
2593
{
 
 
2594
    //only need to look out for the airlock in hangar
 
 
2595
    int wind_multiplier = 0;
 
 
2596
 
 
 
2597
    if(!strcmp(AvP.LevelName, "hangar"))
 
 
2598
    {
 
 
2599
        assert(UpperAirlockDoorSbptr);
 
 
2600
        assert(UpperAirlockDoorSbptr->DynPtr);
 
 
2601
        assert(LowerAirlockDoorSbptr);
 
 
2602
        assert(LowerAirlockDoorSbptr->DynPtr);
 
 
2603
 
 
 
2604
        //check to see which of the airlock doors are open
 
 
2605
        {
 
 
2606
            VECTORCH* door_pos = &UpperAirlockDoorSbptr->DynPtr->Position;
 
 
2607
            int upper_open_amount = 0;
 
 
2608
            int lower_open_amount = 0;
 
 
2609
 
 
 
2610
            if(door_pos->vz == UpperAirlockDoorStart.vz)
 
 
2611
            {
 
 
2612
                UpperAirlockDoorOpen = 0;
 
 
2613
            }
 
 
2614
            else
 
 
2615
            {
 
 
2616
                UpperAirlockDoorOpen = 1;
 
 
2617
                upper_open_amount = DIV_FIXED(door_pos->vz-UpperAirlockDoorStart.vz,AirlockOpeningDistance);
 
 
2618
            }
 
 
2619
 
 
 
2620
            door_pos = &LowerAirlockDoorSbptr->DynPtr->Position;
 
 
2621
 
 
 
2622
            if(door_pos->vz == LowerAirlockDoorStart.vz)
 
 
2623
            {
 
 
2624
                LowerAirlockDoorOpen = 0;
 
 
2625
            }
 
 
2626
            else
 
 
2627
            {
 
 
2628
                LowerAirlockDoorOpen = 1;
 
 
2629
                lower_open_amount = DIV_FIXED(door_pos->vz-LowerAirlockDoorStart.vz,AirlockOpeningDistance);
 
 
2630
            }
 
 
2631
 
 
 
2632
            wind_multiplier = MUL_FIXED(upper_open_amount,lower_open_amount);
 
 
2633
 
 
 
2634
            if(wind_multiplier < 0)
 
 
2635
                wind_multiplier = -wind_multiplier;
 
 
2636
 
 
 
2637
            //get a multiplier for the wind strength , based on how far the two pairs of doors are open
 
 
2638
            if(wind_multiplier > ONE_FIXED)
 
 
2639
                wind_multiplier = ONE_FIXED;
 
 
2640
 
 
 
2641
            if(wind_multiplier >= ONE_FIXED)
 
 
2642
                AirlockTimeOpen += NormalFrameTime;
 
 
2643
            else
 
 
2644
                AirlockTimeOpen = 0;
 
 
2645
        }
 
 
2646
 
 
 
2647
        if(LowerAirlockDoorOpen && UpperAirlockDoorOpen)
 
 
2648
        {
 
 
2649
            extern int NumActiveBlocks;
 
 
2650
 
 
 
2651
            int i = NumActiveBlocks;
 
 
2652
            extern DISPLAYBLOCK *ActiveBlockList[];
 
 
2653
 
 
 
2654
            printf("Wind strength %d\n",wind_multiplier);
 
 
2655
 
 
 
2656
            for(i=0; i < NumActiveBlocks; i++)
 
 
2657
            {
 
 
2658
                STRATEGYBLOCK *sbPtr = ActiveBlockList[i]->ObStrategyBlock;
 
 
2659
 
 
 
2660
                if(sbPtr && sbPtr->DynPtr && !sbPtr->DynPtr->IsStatic)
 
 
2661
                {
 
 
2662
                    VECTORCH* pos = &sbPtr->DynPtr->Position;    
 
 
2663
                    VECTORCH* cur_impulse = &sbPtr->DynPtr->LinImpulse;
 
 
2664
                    VECTORCH impulse;
 
 
2665
                    int above_airlock = 0;
 
 
2666
                    static const DAMAGE_PROFILE vacuum_damage = {0,0,0,0,20,0,0,0,0,0,0,AMMO_NONE};
 
 
2667
 
 
 
2668
                    if(pos->vx > HangarLockerMinX && pos->vx < HangarLockerMaxX && pos->vz > HangarLockerMinZ &&
pos->vz < HangarLockerMaxZ)
 
 
2669
                    {
 
 
2670
                        if(LockerDoorIsClosed())
 
 
2671
                            continue;
 
 
2672
                    }
 
 
2673
 
 
 
2674
                    if(pos->vy > 20000)
 
 
2675
                    {
 
 
2676
                        //outside , so damage this object
 
 
2677
                        if(sbPtr->type == I_BehaviourQueenAlien) 
 
 
2678
                            //the queen has loads of health , so need to damage her quicker
 
 
2679
                            CauseDamageToObject(sbPtr, &vacuum_damage, NormalFrameTime*30, NULL);
 
 
2680
                        else
 
 
2681
                            CauseDamageToObject(sbPtr, &vacuum_damage, NormalFrameTime, NULL);
 
 
2682
 
 
 
2683
                        if(pos->vy > 21000)
 
 
2684
                        {
 
 
2685
                            //turn off gravity
 
 
2686
                            sbPtr->DynPtr->GravityOn = 0;
 
 
2687
                        }
 
 
2688
                    continue;
 
 
2689
                    }
 
 
2690
                    else if(AirlockTimeOpen > 10*ONE_FIXED)
 
 
2691
                    {
 
 
2692
                        /*
 
 
2693
                        After 10 seconds start doing damage to objects even if they aren't outside yet.
 
 
2694
                        Scale damage so it increases linearly until 30 seconds have passed
 
 
2695
                        */
 
 
2696
 
 
 
2697
                        AirlockTimeOpen = max(AirlockTimeOpen, 30*ONE_FIXED);
 
 
2698
                        int multiplier=MUL_FIXED(NormalFrameTime, (AirlockTimeOpen-10*ONE_FIXED)/20);
 
 
2699
 
 
 
2700
                        CauseDamageToObject(sbPtr, &vacuum_damage, multiplier, NULL);
 
 
2701
                    }
 
 
2702
 
 
 
2703
                    if(pos->vx > AirlockMinX && pos->vx < AirlockMaxX && pos->vz > AirlockMinZ && pos->vz <
AirlockMaxZ)
 
 
2704
                        above_airlock = 1;
 
 
2705
 
 
 
2706
                    impulse.vx = AirlockCentreX-pos->vx;
 
 
2707
                    impulse.vy = 0;
 
 
2708
                    impulse.vz = AirlockCentreZ-pos->vz;
 
 
2709
 
 
 
2710
                    if(!above_airlock && impulse.vx < 0)
 
 
2711
                    {
 
 
2712
                        if(impulse.vz*2 > impulse.vx && impulse.vz*2 < -impulse.vx)
 
 
2713
                        {
 
 
2714
                            if(impulse.vz > 0)
 
 
2715
                                impulse.vz -= 12000;
 
 
2716
                            else
 
 
2717
                                impulse.vz += 12000;
 
 
2718
                        }
 
 
2719
                    }
 
 
2720
 
 
 
2721
                    Normalise(&impulse);
 
 
2722
 
 
 
2723
                    impulse.vx /= 2;
 
 
2724
 
 
 
2725
                    if(above_airlock)
 
 
2726
                        impulse.vy = 30000;
 
 
2727
                    else
 
 
2728
                        impulse.vy = 0;
 
 
2729
 
 
 
2730
                    impulse.vz /= 2;
 
 
2731
 
 
 
2732
                    if(wind_multiplier < ONE_FIXED)
 
 
2733
                    {
 
 
2734
                        impulse.vx = MUL_FIXED(impulse.vx,wind_multiplier);
 
 
2735
                        impulse.vy = MUL_FIXED(impulse.vy,wind_multiplier);
 
 
2736
                        impulse.vz = MUL_FIXED(impulse.vz,wind_multiplier);
 
 
2737
                    }
 
 
2738
 
 
 
2739
                    if(impulse.vx > 0)
 
 
2740
                    {
 
 
2741
                        if(impulse.vx > cur_impulse->vx)
 
 
2742
                        {
 
 
2743
                            cur_impulse->vx += MUL_FIXED(impulse.vx,NormalFrameTime);
 
 
2744
                            cur_impulse->vx = min(cur_impulse->vx,impulse.vx);
 
 
2745
                        }
 
 
2746
                    }
 
 
2747
                    else
 
 
2748
                    {
 
 
2749
                        if(impulse.vx < cur_impulse->vx)
 
 
2750
                        {
 
 
2751
                            cur_impulse->vx += MUL_FIXED(impulse.vx,NormalFrameTime);
 
 
2752
                            cur_impulse->vx = max(cur_impulse->vx,impulse.vx);
 
 
2753
                        }
 
 
2754
                    }
 
 
2755
 
 
 
2756
                    if(impulse.vy > 0)
 
 
2757
                    {
 
 
2758
                        if(impulse.vy > cur_impulse->vy)
 
 
2759
                        {
 
 
2760
                            cur_impulse->vy += MUL_FIXED(impulse.vy,NormalFrameTime);
 
 
2761
                            cur_impulse->vy = min(cur_impulse->vy,impulse.vy);
 
 
2762
                        }
 
 
2763
                    }
 
 
2764
                    else
 
 
2765
                    {
 
 
2766
                        if(impulse.vy < cur_impulse->vy)
 
 
2767
                        {
 
 
2768
                            cur_impulse->vy += MUL_FIXED(impulse.vy,NormalFrameTime);
 
 
2769
                            cur_impulse->vy = max(cur_impulse->vy,impulse.vy);
 
 
2770
                        }
 
 
2771
                    }
 
 
2772
 
 
 
2773
                    if(impulse.vz > 0)
 
 
2774
                    {
 
 
2775
                        if(impulse.vz > cur_impulse->vz)
 
 
2776
                        {
 
 
2777
                            cur_impulse->vz += MUL_FIXED(impulse.vz,NormalFrameTime);
 
 
2778
                            cur_impulse->vz = min(cur_impulse->vz,impulse.vz);
 
 
2779
                        }
 
 
2780
                    }
 
 
2781
                    else
 
 
2782
                    {
 
 
2783
                        if(impulse.vz < cur_impulse->vz)
 
 
2784
                        {
 
 
2785
                            cur_impulse->vz += MUL_FIXED(impulse.vz,NormalFrameTime);
 
 
2786
                            cur_impulse->vz = max(cur_impulse->vz,impulse.vz);
 
 
2787
                        }
 
 
2788
                    }
 
 
2789
 
 
 
2790
                    if((pos->vy + ActiveBlockList[i]->extent.max_y) > 3950 && !above_airlock)
 
 
2791
                    {
 
 
2792
                        if(sbPtr->DynPtr->UseStandardGravity)
 
 
2793
                            cur_impulse->vy -= MUL_FIXED(MUL_FIXED(GRAVITY_STRENGTH+5000,NormalFrameTime),wind_multiplier);
 
 
2794
                        else
 
 
2795
                            cur_impulse->vy -= MUL_FIXED(MUL_FIXED(5000,NormalFrameTime),wind_multiplier);
 
 
2796
                    }
 
 
2797
                }
 
 
2798
            }
 
 
2799
        }
 
 
2800
    }
 
 
2801
}
 
 
2802
 
 
 
2803
void QueenBehaviour(STRATEGYBLOCK *sbPtr)
 
 
2804
{
 
 
2805
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
2806
    QUEEN_STATUS_BLOCK *queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2807
    int JumpDesired = 0;
 
 
2808
    int ConsiderJumping = 0;
 
 
2809
    int DistanceToPlayer;
 
 
2810
 
 
 
2811
    if(NumQueenObjects == -1)
 
 
2812
    {
 
 
2813
        //first frame...
 
 
2814
        //find all objects that the queen can chuck
 
 
2815
        FindQueenObjects();
 
 
2816
        queenStatusPointer->CurrentQueenObject = -1;
 
 
2817
        //get the queens hand section
 
 
2818
        queenStatusPointer->QueenRightHand = GetThisSectionData(queenStatusPointer->HModelController.section_data,"rrrr fing");
 
 
2819
        assert(queenStatusPointer->QueenRightHand);
 
 
2820
    }
 
 
2821
 
 
 
2822
    if(!queenStatusPointer->QueenActivated)
 
 
2823
    {
 
 
2824
        //is the queen in a visible module?
 
 
2825
        assert(sbPtr->containingModule);
 
 
2826
 
 
 
2827
        if(ModuleCurrVisArray[sbPtr->containingModule->m_index] > 1)
 
 
2828
            queenStatusPointer->QueenActivated = 1;
 
 
2829
        else
 
 
2830
            return;
 
 
2831
    }
 
 
2832
 
 
 
2833
    HandleHangarAirlock();    
 
 
2834
 
 
 
2835
    if(queenStatusPointer->QueenState == QBS_Dead)
 
 
2836
    {
 
 
2837
        //check for victory on marine level.
 
 
2838
        if(!strcmp(AvP.LevelName, "hangar"))
 
 
2839
        {
 
 
2840
            //is the player in the locker ('hangar')
 
 
2841
            if(PlayerStatus.DisplayBlock->ObWorld.vx > HangarLockerMinX && PlayerStatus.DisplayBlock->ObWorld.vx < HangarLockerMaxX
&&
 
 
2842
               PlayerStatus.DisplayBlock->ObWorld.vz > HangarLockerMinZ && PlayerStatus.DisplayBlock->ObWorld.vz < HangarLockerMaxZ)    
 
 
2843
                PlayerInLocker = 1;
 
 
2844
            else
 
 
2845
                PlayerInLocker = 0;
 
 
2846
 
 
 
2847
            //In the marine level the player can only win if he is inside the locker room area ,and 
 
 
2848
            //the locker door is shut
 
 
2849
 
 
 
2850
            if((PlayerInLocker && LockerDoorIsClosed()) || !(LowerAirlockDoorOpen && UpperAirlockDoorOpen))    
 
 
2851
            {
 
 
2852
                    AvP.LevelCompleted = 1;
 
 
2853
                    AvP.MainLoopRunning = 0;
 
 
2854
            }
 
 
2855
        } 
 
 
2856
 
 
 
2857
        Execute_Queen_Dying(sbPtr);
 
 
2858
    return;
 
 
2859
    }
 
 
2860
 
 
 
2861
    /*----------------------------------**
 
 
2862
    **     Check state of delta animations **
 
 
2863
    **----------------------------------*/
 
 
2864
 
 
 
2865
    if(queenStatusPointer->PlayingHitDelta)
 
 
2866
    {
 
 
2867
        //check to see if the queen is still stunned from an explosion
 
 
2868
 
 
 
2869
        if (!QueenPlayingStunAnimation(&queenStatusPointer->HModelController) && DeltaAnimation_IsFinished(queenStatusPointer->hit_delta)) 
 
 
2870
        {
 
 
2871
            queenStatusPointer->hit_delta->timer = 0;
 
 
2872
            queenStatusPointer->PlayingHitDelta = 0;
 
 
2873
            queenStatusPointer->current_move = QM_Close;
 
 
2874
            queenStatusPointer->next_move = QM_Standby;
 
 
2875
            queenStatusPointer->moveTimer = 0;
 
 
2876
        }
 
 
2877
    }
 
 
2878
 
 
 
2879
    if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta))
 
 
2880
    {
 
 
2881
        queenStatusPointer->attack_delta->timer = 0;
 
 
2882
    }
 
 
2883
 
 
 
2884
    queenStatusPointer->TargetInfoValid = 0;
 
 
2885
 
 
 
2886
    if(queenStatusPointer->CurrentQueenObject != -1)
 
 
2887
    {
 
 
2888
        if(QueenObjectList[queenStatusPointer->CurrentQueenObject]->destroyed_but_preserved)
 
 
2889
        {
 
 
2890
            //the object that the queen was going for has been destroyed
 
 
2891
            queenStatusPointer->CurrentQueenObject = -1;
 
 
2892
            queenStatusPointer->QueenState = QBS_Reconsider;
 
 
2893
        }
 
 
2894
    }
 
 
2895
 
 
 
2896
    if (sbPtr->DisplayBlock == NULL)
 
 
2897
        return; /* No far behaviour. */
 
 
2898
 
 
 
2899
    if(!dynPtr->IsInContactWithFloor && queenStatusPointer->current_move != QM_Jump && queenStatusPointer->current_move != QM_Climbing)
 
 
2900
    {
 
 
2901
        //if queen is not on the ground , and not currently jumping switch to standby
 
 
2902
        queenStatusPointer->current_move = QM_Standby;
 
 
2903
    }
 
 
2904
 
 
 
2905
    if(dynPtr->IsInContactWithFloor)
 
 
2906
    {
 
 
2907
        if(!strcmp(AvP.LevelName, "hangar"))
 
 
2908
        {
 
 
2909
            //is the player in the trench
 
 
2910
            if((dynPtr->Position.vy + 1500) < PlayerStatus.DisplayBlock->ObWorld.vy)
 
 
2911
            {
 
 
2912
                PlayerInTrench = 1;
 
 
2913
                if(queenStatusPointer->QueenState != QBS_Engagement)
 
 
2914
                    QueenForceReconsider(sbPtr);
 
 
2915
            }
 
 
2916
            else
 
 
2917
            {
 
 
2918
                PlayerInTrench = 0;
 
 
2919
            }
 
 
2920
 
 
 
2921
            //is the player in the locker ('hangar')
 
 
2922
            if(PlayerStatus.DisplayBlock->ObWorld.vx > HangarLockerMinX && PlayerStatus.DisplayBlock->ObWorld.vx < HangarLockerMaxX
&&
 
 
2923
               PlayerStatus.DisplayBlock->ObWorld.vz > HangarLockerMinZ && PlayerStatus.DisplayBlock->ObWorld.vz < HangarLockerMaxZ)    
 
 
2924
                PlayerInLocker = 1;
 
 
2925
            else
 
 
2926
                PlayerInLocker = 0;
 
 
2927
 
 
 
2928
            //is the queen in the airlock?
 
 
2929
            if(UpperAirlockDoorOpen && !LowerAirlockDoorOpen)
 
 
2930
            {
 
 
2931
                //has the queen fallen into the airlock
 
 
2932
                if(ObjectIsInAirlock(sbPtr) && !ObjectIsInAirlock(PlayerStatus.sbptr) && queenStatusPointer->QueenState !=
QBS_ClimbingOutOfAirlock)
 
 
2933
                        QueenForceReconsider(sbPtr);
 
 
2934
            }
 
 
2935
        }
 
 
2936
    }
 
 
2937
 
 
 
2938
    queenStatusPointer->QueenStateTimer += NormalFrameTime;
 
 
2939
 
 
 
2940
    {
 
 
2941
        VECTORCH pos = PlayerStatus.DisplayBlock->ObWorld;
 
 
2942
 
 
 
2943
        pos.vx -= dynPtr->Position.vx;
 
 
2944
        pos.vy -= dynPtr->Position.vy;
 
 
2945
        pos.vz -= dynPtr->Position.vz;
 
 
2946
 
 
 
2947
        DistanceToPlayer = Approximate3dMagnitude(&pos);
 
 
2948
    }
 
 
2949
 
 
 
2950
        /*-------------------------------------------------------**
 
 
2951
        **     Check collision reports , and check for need to jump **
 
 
2952
        **-------------------------------------------------------*/
 
 
2953
 
 
 
2954
    {
 
 
2955
        int ignore_obstacles = 0;
 
 
2956
 
 
 
2957
        if(queenStatusPointer->LastVelocity.vx || queenStatusPointer->LastVelocity.vz || queenStatusPointer->current_move == QM_Climbing)
 
 
2958
        {
 
 
2959
            /* Now, smash stuff. */
 
 
2960
 
 
 
2961
            COLLISIONREPORT *nextReport = dynPtr->CollisionReportPtr;
 
 
2962
 
 
 
2963
            while(nextReport) 
 
 
2964
            {
 
 
2965
                int normalDotWithVelocity;
 
 
2966
                int ConsiderJumpingForThisObject = 0;
 
 
2967
 
 
 
2968
                {
 
 
2969
                    VECTORCH normVelocity = sbPtr->DynPtr->LinVelocity;
 
 
2970
                    normVelocity.vy = 0;
 
 
2971
                    Normalise(&normVelocity);
 
 
2972
                    normalDotWithVelocity = DotProduct(&(nextReport->ObstacleNormal),&(normVelocity));
 
 
2973
                }
 
 
2974
 
 
 
2975
                if(normalDotWithVelocity < -20000)//is the object in the way
 
 
2976
                {
 
 
2977
                    if(nextReport->ObstacleNormal.vy < 20000 && nextReport->ObstacleNormal.vy > -20000)
 
 
2978
                    {
 
 
2979
                        //obstacle is reasonably vertical , may need to jump
 
 
2980
                        ConsiderJumpingForThisObject = 1;
 
 
2981
                    }
 
 
2982
 
 
 
2983
                    if (nextReport->ObstacleSBPtr)
 
 
2984
                    {
 
 
2985
                        if(nextReport->ObstacleSBPtr->type == I_BehaviourInanimateObject)
 
 
2986
                        {
 
 
2987
                            if(!nextReport->ObstacleSBPtr->DamageBlock.Indestructable)
 
 
2988
                            {
 
 
2989
                                INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = nextReport->ObstacleSBPtr->dataptr;
 
 
2990
 
 
 
2991
                                if(objectstatusptr)
 
 
2992
                                {
 
 
2993
                                    int i=0;
 
 
2994
                                    int AllowedToDestroy = 1;
 
 
2995
                                    //is this one of the queen's objects?
 
 
2996
 
 
 
2997
                                    for(;i < NumQueenObjects; i++)
 
 
2998
                                    {
 
 
2999
                                        if(QueenObjectList[i] == nextReport->ObstacleSBPtr)
 
 
3000
                                            AllowedToDestroy = 0;
 
 
3001
                                    }
 
 
3002
 
 
 
3003
                                    if(AllowedToDestroy)
 
 
3004
                                    {
 
 
3005
                                        /* aha: an object which the queen can destroy... */
 
 
3006
                    CauseDamageToObject(nextReport->ObstacleSBPtr,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage, ONE_FIXED,NULL);
 
 
3007
                                        //no need to jump over this
 
 
3008
                                        ConsiderJumpingForThisObject = 0;
 
 
3009
                                    }
 
 
3010
                                }
 
 
3011
                            }
 
 
3012
                        }
 
 
3013
                        else if(nextReport->ObstacleSBPtr->type == I_BehaviourTrackObject)
 
 
3014
                        {
 
 
3015
                            /* aha: an object which the queen can destroy... */
 
 
3016
                CauseDamageToObject(nextReport->ObstacleSBPtr,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage, ONE_FIXED,NULL);
 
 
3017
                            //no need to jump over this
 
 
3018
                            ConsiderJumpingForThisObject = 0;
 
 
3019
                        }
 
 
3020
                        else
 
 
3021
                        {
 
 
3022
                            ConsiderJumpingForThisObject = 0;
 
 
3023
                        }
 
 
3024
 
 
 
3025
                        if(queenStatusPointer->QueenState == QBS_GoingForObject)
 
 
3026
                        {
 
 
3027
                            //is this the object that the queen was heading for?
 
 
3028
                            if(nextReport->ObstacleSBPtr == queenStatusPointer->QueenTargetSB)
 
 
3029
                            {
 
 
3030
                                QueenPickupTargetObject(sbPtr);
 
 
3031
 
 
 
3032
                                //no need to jump over this
 
 
3033
                                ConsiderJumpingForThisObject = 0;
 
 
3034
                            }
 
 
3035
                        }
 
 
3036
                        else if(queenStatusPointer->QueenState == QBS_CarryingObject)
 
 
3037
                        {
 
 
3038
                            //if the queen is colliding with the object she is carrying , ignore it
 
 
3039
 
 
 
3040
                            if(QueenObjectList[queenStatusPointer->CurrentQueenObject] == nextReport->ObstacleSBPtr)
 
 
3041
                            {
 
 
3042
                                //no need to jump over this
 
 
3043
                                ConsiderJumpingForThisObject = 0;
 
 
3044
                            }
 
 
3045
                        }
 
 
3046
 
 
 
3047
                        if(nextReport->ObstacleSBPtr == PlayerStatus.sbptr)
 
 
3048
                        {
 
 
3049
                            ConsiderJumpingForThisObject = 0;
 
 
3050
 
 
 
3051
                            //have we connected with a butt attack
 
 
3052
                            if(queenStatusPointer->current_move == QM_ButtCharge)
 
 
3053
                            {
 
 
3054
                                queenStatusPointer->current_move = QM_ButtAttack;
 
 
3055
                                queenStatusPointer->next_move = QM_Standby;
 
 
3056
                                queenStatusPointer->moveTimer = 0;
 
 
3057
 
 
 
3058
                                {
 
 
3059
                                    //knock the player back
 
 
3060
                                    VECTORCH* player_impulse;
 
 
3061
                                    player_impulse = &PlayerStatus.sbptr->DynPtr->LinImpulse;
 
 
3062
                                    player_impulse->vx += dynPtr->OrientMat.mat31/4;
 
 
3063
                                    player_impulse->vy -= 6000;
 
 
3064
                                    player_impulse->vz += dynPtr->OrientMat.mat33/4;
 
 
3065
                                }
 
 
3066
 
 
 
3067
                                static const DAMAGE_PROFILE queen_butt = {40,0,0,0,0,0,0,0,0,0,0,AMMO_NONE};
 
 
3068
                                CauseDamageToObject(PlayerStatus.sbptr, &queen_butt, ONE_FIXED,NULL);
 
 
3069
                            }
 
 
3070
                            else if(queenStatusPointer->current_move == QM_Climbing)
 
 
3071
                            {
 
 
3072
                                //need to push he player out of the way
 
 
3073
                                PlayerStatus.sbptr->DynPtr->LinImpulse.vx = min(PlayerStatus.sbptr->DynPtr->LinImpulse.vx, -3000);
 
 
3074
                            }
 
 
3075
                            else if(queenStatusPointer->QueenState != QBS_Engagement && queenStatusPointer->QueenState != QBS_CarryingObject)
 
 
3076
                            {
 
 
3077
                                QueenForceReconsider(sbPtr);
 
 
3078
                            }
 
 
3079
                        }
 
 
3080
                    }
 
 
3081
 
 
 
3082
                    /*Queen climbing out of the airlock?*/
 
 
3083
                    if(queenStatusPointer->QueenState == QBS_ClimbingOutOfAirlock && queenStatusPointer->current_move != QM_Climbing)    
 
 
3084
                    {
 
 
3085
                        QueenCalculateTargetInfo(sbPtr);
 
 
3086
 
 
 
3087
                        if((dynPtr->Position.vx-AirlockMinX) < 2800)        
 
 
3088
                        {
 
 
3089
                            //queen has hit the end wall , so start climbing
 
 
3090
                            queenStatusPointer->current_move = QM_Climbing;
 
 
3091
                            queenStatusPointer->moveTimer = 0;
 
 
3092
                        }
 
 
3093
                    }
 
 
3094
                }
 
 
3095
 
 
 
3096
                if(ConsiderJumpingForThisObject)
 
 
3097
                    ConsiderJumping = 1;
 
 
3098
 
 
 
3099
                nextReport = nextReport->NextCollisionReportPtr;
 
 
3100
            }
 
 
3101
        }
 
 
3102
 
 
 
3103
        //if the queen is approaching the player in the locker
 
 
3104
        //ignore obstacles to allow the quuen to get to the player
 
 
3105
 
 
 
3106
        if(PlayerInLocker && !queenStatusPointer->TempTarget && queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr)
 
 
3107
        {
 
 
3108
            QueenCalculateTargetInfo(sbPtr);
 
 
3109
 
 
 
3110
            if(queenStatusPointer->TargetDistance < 12000)    
 
 
3111
                ignore_obstacles = 1;
 
 
3112
        }
 
 
3113
 
 
 
3114
        /*If the queen is trying to get out of the airlock , then we don't want to deviate because of walls getting in the way*/
 
 
3115
 
 
 
3116
        if(queenStatusPointer->QueenState == QBS_ClimbingOutOfAirlock)
 
 
3117
            ignore_obstacles = 1;
 
 
3118
 
 
 
3119
        //check for nearby obstacles , and decide whether to jump.
 
 
3120
        if(!ignore_obstacles)
 
 
3121
        {
 
 
3122
            VECTORCH direction;
 
 
3123
            VECTORCH position = sbPtr->DisplayBlock->ObWorld;
 
 
3124
 
 
 
3125
            QueenCalculateTargetInfo(sbPtr);
 
 
3126
 
 
 
3127
            direction.vx = dynPtr->OrientMat.mat31;
 
 
3128
            direction.vy = 0;
 
 
3129
            direction.vz = dynPtr->OrientMat.mat33;
 
 
3130
            Normalise(&direction);
 
 
3131
 
 
 
3132
            //only bother to think of jumping if the queen is facing her target
 
 
3133
 
 
 
3134
            if(queenStatusPointer->TargetDirection.vz > (queenStatusPointer->TargetDirection.vx*2) && 
 
 
3135
               queenStatusPointer->TargetDirection.vz > -(queenStatusPointer->TargetDirection.vx*2))
 
 
3136
            {
 
 
3137
                //do several line of sight tests one metre above ground , in front of queen.
 
 
3138
                //if there is nothing near by , then queen should be able to jump over
 
 
3139
 
 
 
3140
                position.vy -= 1000;
 
 
3141
 
 
 
3142
                FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget, &position, sbPtr->DisplayBlock);
 
 
3143
                int centre_dist = LOS_Lambda;
 
 
3144
                VECTORCH centre_point = LOS_Point;
 
 
3145
 
 
 
3146
                if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock)
 
 
3147
                {
 
 
3148
                    switch(LOS_ObjectHitPtr->ObStrategyBlock->type)
 
 
3149
                    {
 
 
3150
                        case I_BehaviourInanimateObject:
 
 
3151
                        case I_BehaviourTrackObject:
 
 
3152
                        case I_BehaviourMarinePlayer:
 
 
3153
                        case I_BehaviourPredatorPlayer:
 
 
3154
                            //not an obstacle
 
 
3155
                            centre_dist = 1000000;
 
 
3156
                        default:
 
 
3157
                        break;
 
 
3158
                    }
 
 
3159
                }
 
 
3160
 
 
 
3161
                //check on the right
 
 
3162
                position.vx += dynPtr->OrientMat.mat11/32;
 
 
3163
                position.vy += dynPtr->OrientMat.mat12/32;
 
 
3164
                position.vz += dynPtr->OrientMat.mat13/32;
 
 
3165
 
 
 
3166
                FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget, &position, sbPtr->DisplayBlock);
 
 
3167
                int right_dist = LOS_Lambda;
 
 
3168
                VECTORCH right_point = LOS_Point;
 
 
3169
 
 
 
3170
                if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock)
 
 
3171
                {
 
 
3172
                    switch(LOS_ObjectHitPtr->ObStrategyBlock->type)
 
 
3173
                    {
 
 
3174
                        case I_BehaviourInanimateObject:
 
 
3175
                        case I_BehaviourTrackObject:
 
 
3176
                        case I_BehaviourMarinePlayer:
 
 
3177
                        case I_BehaviourPredatorPlayer:
 
 
3178
                            //not an obstacle
 
 
3179
                            right_dist = 1000000;
 
 
3180
                        default:
 
 
3181
                        break;
 
 
3182
                    }
 
 
3183
                }
 
 
3184
 
 
 
3185
                //check on the left
 
 
3186
                position.vx -= dynPtr->OrientMat.mat11/16;
 
 
3187
                position.vy -= dynPtr->OrientMat.mat12/16;
 
 
3188
                position.vz -= dynPtr->OrientMat.mat13/16;
 
 
3189
 
 
 
3190
                FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget, &position, sbPtr->DisplayBlock);
 
 
3191
                int left_dist = LOS_Lambda;
 
 
3192
                VECTORCH left_point = LOS_Point;
 
 
3193
 
 
 
3194
                if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock)
 
 
3195
                {
 
 
3196
                    switch(LOS_ObjectHitPtr->ObStrategyBlock->type)
 
 
3197
                    {
 
 
3198
                        case I_BehaviourInanimateObject:
 
 
3199
                        case I_BehaviourTrackObject:
 
 
3200
                        case I_BehaviourMarinePlayer:
 
 
3201
                        case I_BehaviourPredatorPlayer:
 
 
3202
                            //not an obstacle
 
 
3203
                            left_dist = 1000000;
 
 
3204
                        default:
 
 
3205
                        break;
 
 
3206
                    }
 
 
3207
                }
 
 
3208
 
 
 
3209
                int distance = (queenStatusPointer->TargetDistance > 10000) ? 10000 : queenStatusPointer->TargetDistance;
 
 
3210
 
 
 
3211
                if(right_dist < distance || centre_dist < distance || left_dist < distance)
 
 
3212
                {
 
 
3213
                    if(centre_dist < left_dist && centre_dist < right_dist)
 
 
3214
                    {
 
 
3215
                        queenStatusPointer->TargetPos = centre_point;        
 
 
3216
                    }
 
 
3217
                    else if(right_dist < left_dist)
 
 
3218
                    {
 
 
3219
                        queenStatusPointer->TargetPos = right_point;        
 
 
3220
                    }
 
 
3221
                    else
 
 
3222
                    {
 
 
3223
                        queenStatusPointer->TargetPos = left_point;        
 
 
3224
                    }
 
 
3225
            /*
 
 
3226
                    if(right_dist < left_dist)
 
 
3227
                    {
 
 
3228
                        queenStatusPointer->TargetPos.vx -= dynPtr->OrientMat.mat11/8;
 
 
3229
                        queenStatusPointer->TargetPos.vz -= dynPtr->OrientMat.mat13/8;
 
 
3230
                    }
 
 
3231
                    else
 
 
3232
                    {
 
 
3233
                        queenStatusPointer->TargetPos.vx += dynPtr->OrientMat.mat11/8;
 
 
3234
                        queenStatusPointer->TargetPos.vz += dynPtr->OrientMat.mat13/8;
 
 
3235
                    }
 
 
3236
 
 
 
3237
                    queenStatusPointer->TempTarget = 1;
 
 
3238
                    queenStatusPointer->TempTargetTimer = 6*ONE_FIXED;
 
 
3239
                    queenStatusPointer->TargetInfoValid = 0;
 
 
3240
            */
 
 
3241
                }
 
 
3242
                else if(ConsiderJumping)
 
 
3243
                {
 
 
3244
                    JumpDesired = 1;
 
 
3245
                }
 
 
3246
            }
 
 
3247
        }
 
 
3248
    }
 
 
3249
 
 
 
3250
    if(queenStatusPointer->QueenState == QBS_GoingForObject)
 
 
3251
    {
 
 
3252
        //if the queen is close enought to the object she is going for
 
 
3253
        //pick it up even without a collision
 
 
3254
        QueenCalculateTargetInfo(sbPtr);
 
 
3255
 
 
 
3256
        if(queenStatusPointer->TargetDistance < 1000)
 
 
3257
            QueenPickupTargetObject(sbPtr);
 
 
3258
    }
 
 
3259
 
 
 
3260
    /*---------------------------------------------------**
 
 
3261
    **     consider if queen should change her current plan **
 
 
3262
    **---------------------------------------------------*/
 
 
3263
 
 
 
3264
    switch(queenStatusPointer->QueenState)
 
 
3265
    {
 
 
3266
        case QBS_Reconsider:
 
 
3267
        {
 
 
3268
            //find closest object that is on the ground
 
 
3269
            int closest = -1;
 
 
3270
            int DistanceToObject = 1000000000;
 
 
3271
            int i;
 
 
3272
 
 
 
3273
            //printf("Queen Reconsider\n");
 
 
3274
            if(queenStatusPointer->PlayingHitDelta)
 
 
3275
                break;
 
 
3276
 
 
 
3277
            if(UpperAirlockDoorOpen && !LowerAirlockDoorOpen)
 
 
3278
            {
 
 
3279
                //has the queen fallen into the airlock
 
 
3280
                if(ObjectIsInAirlock(sbPtr))
 
 
3281
                {
 
 
3282
                    //the queen is in the airlock
 
 
3283
                    if(ObjectIsInAirlock(PlayerStatus.sbptr))
 
 
3284
                    {
 
 
3285
                        //player is in the airlock with the queen
 
 
3286
                        //splat him
 
 
3287
                        queenStatusPointer->QueenState = QBS_Engagement;
 
 
3288
                        queenStatusPointer->QueenTargetSB = PlayerStatus.sbptr;
 
 
3289
                        queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;                    
 
 
3290
                    }
 
 
3291
                    else
 
 
3292
                    {
 
 
3293
                        //go into get out of airlock mode in that case
 
 
3294
                        queenStatusPointer->QueenState = QBS_ClimbingOutOfAirlock;
 
 
3295
                        queenStatusPointer->TempTarget = 1;
 
 
3296
                        queenStatusPointer->TempTargetTimer = 50*ONE_FIXED;
 
 
3297
                        queenStatusPointer->TargetPos.vx = AirlockMinX-6000;
 
 
3298
                        queenStatusPointer->TargetPos.vz = AirlockCentreZ;
 
 
3299
                        queenStatusPointer->BeenInAirlock = 1;
 
 
3300
                    }
 
 
3301
                    queenStatusPointer->QueenStateTimer = 0;
 
 
3302
                    queenStatusPointer->TargetInfoValid = 0;
 
 
3303
                break;
 
 
3304
                }
 
 
3305
            }
 
 
3306
 
 
 
3307
            for(i=0; i < NumQueenObjects;i++)
 
 
3308
            {
 
 
3309
                if(!QueenObjectList[i]->destroyed_but_preserved)
 
 
3310
                {
 
 
3311
                    if(QueenObjectList[i]->DynPtr->IsInContactWithFloor)
 
 
3312
                    {
 
 
3313
                        VECTORCH pos = QueenObjectList[i]->DynPtr->Position;
 
 
3314
 
 
 
3315
                        pos.vx -= dynPtr->Position.vx;
 
 
3316
                        pos.vy -= dynPtr->Position.vy;
 
 
3317
                        pos.vz -= dynPtr->Position.vz;
 
 
3318
 
 
 
3319
                        if(!strcmp(AvP.LevelName, "hangar"))
 
 
3320
                        {
 
 
3321
                            //In battle , the objects near the egg sack are hard for the queen to get to.
 
 
3322
                            //So best ignore them.
 
 
3323
                            if(QueenObjectList[i]->DynPtr->Position.vz > 0)
 
 
3324
                                    continue;
 
 
3325
                        }
 
 
3326
 
 
 
3327
                        //if the y distance is more than 1500 , the object is probably inaccesible
 
 
3328
                        if(pos.vy <= 1500)
 
 
3329
                        {
 
 
3330
                            int dist = Approximate3dMagnitude(&pos);
 
 
3331
 
 
 
3332
                            if(dist < DistanceToObject)
 
 
3333
                            {
 
 
3334
                                DistanceToObject = dist;
 
 
3335
                                closest = i;
 
 
3336
                            }
 
 
3337
                        }
 
 
3338
                    }
 
 
3339
                }
 
 
3340
            }
 
 
3341
 
 
 
3342
            {
 
 
3343
                int player_value = MUL_FIXED(FastRandom() & 0xffff, DistanceToPlayer / queenStatusPointer->QueenPlayerBias);
 
 
3344
                int object_value = MUL_FIXED(FastRandom() & 0xffff, DistanceToObject / queenStatusPointer->QueenObjectBias);
 
 
3345
 
 
 
3346
                if(object_value < player_value && closest != -1 && !PlayerInTrench)
 
 
3347
                {
 
 
3348
                    //go for the object
 
 
3349
                    queenStatusPointer->QueenState = QBS_GoingForObject;
 
 
3350
                    queenStatusPointer->CurrentQueenObject = closest;
 
 
3351
                    queenStatusPointer->QueenTargetSB = QueenObjectList[queenStatusPointer->CurrentQueenObject];
 
 
3352
 
 
 
3353
                    if(!strcmp(AvP.LevelName, "hangar"))
 
 
3354
                    {
 
 
3355
                        queenStatusPointer->QueenPlayerBias++;
 
 
3356
                    }
 
 
3357
                    else
 
 
3358
                    {
 
 
3359
                        //int he predator version , make it more likely for the queen to go after the player
 
 
3360
                        queenStatusPointer->QueenPlayerBias += 3;
 
 
3361
                    }
 
 
3362
 
 
 
3363
                    queenStatusPointer->QueenObjectBias--;
 
 
3364
 
 
 
3365
                    if(!queenStatusPointer->QueenObjectBias)
 
 
3366
                        queenStatusPointer->QueenObjectBias = 1;
 
 
3367
                }
 
 
3368
                else
 
 
3369
                {
 
 
3370
                    //go for the player
 
 
3371
                    queenStatusPointer->QueenState = QBS_Engagement;
 
 
3372
                    queenStatusPointer->CurrentQueenObject = -1;
 
 
3373
                    queenStatusPointer->QueenTargetSB = PlayerStatus.sbptr;
 
 
3374
                    queenStatusPointer->QueenObjectBias++;
 
 
3375
                    queenStatusPointer->QueenPlayerBias--;
 
 
3376
 
 
 
3377
                    if(!queenStatusPointer->QueenPlayerBias)
 
 
3378
                        queenStatusPointer->QueenPlayerBias = 1;
 
 
3379
                }
 
 
3380
 
 
 
3381
                queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;                    
 
 
3382
                queenStatusPointer->QueenStateTimer = 0;
 
 
3383
                queenStatusPointer->TargetInfoValid = 0;
 
 
3384
            }
 
 
3385
        }
 
 
3386
        break;
 
 
3387
        case QBS_Engagement:
 
 
3388
        {
 
 
3389
            if(queenStatusPointer->QueenStateTimer > 10*ONE_FIXED && DistanceToPlayer > 4000)
 
 
3390
            {
 
 
3391
                queenStatusPointer->QueenState = QBS_Reconsider;
 
 
3392
                queenStatusPointer->QueenStateTimer = 0;
 
 
3393
            }
 
 
3394
        }
 
 
3395
        //printf("Queen Engagement\n");
 
 
3396
        break;
 
 
3397
        case QBS_GoingForObject:
 
 
3398
        {
 
 
3399
            if(queenStatusPointer->QueenStateTimer > 15*ONE_FIXED)
 
 
3400
                QueenForceReconsider(sbPtr);
 
 
3401
        }
 
 
3402
        //printf("Queen Going for object\n");
 
 
3403
        break;
 
 
3404
        case QBS_CarryingObject :
 
 
3405
        {
 
 
3406
            if(queenStatusPointer->QueenStateTimer > 15*ONE_FIXED)
 
 
3407
                QueenForceReconsider(sbPtr);
 
 
3408
        }
 
 
3409
        //printf("Queen Carrying object\n");
 
 
3410
        break;
 
 
3411
        case QBS_ClimbingOutOfAirlock :
 
 
3412
            printf("Queen climbing out of airlock\n");
 
 
3413
        break;
 
 
3414
        default: ;
 
 
3415
    }
 
 
3416
    //printf("Queen Bias - Object %d  Player %d\n", queenStatusPointer->QueenObjectBias, queenStatusPointer->QueenPlayerBias);
 
 
3417
    //printf("Queen Health %d\n",sbPtr->DamageBlock.Health>>16);    
 
 
3418
 
 
 
3419
        /*--------------------**
 
 
3420
        **     Can queen attack? **
 
 
3421
        **--------------------*/
 
 
3422
 
 
 
3423
    //queen must be in engagement mode , and not avoiding stuff
 
 
3424
    if(!queenStatusPointer->TempTarget && queenStatusPointer->QueenState == QBS_Engagement)
 
 
3425
    {
 
 
3426
        //player must be close enough and in front 90 degree arc
 
 
3427
        QueenCalculateTargetInfo(sbPtr);
 
 
3428
 
 
 
3429
        if (queenStatusPointer->TargetDistance < 4000 ||
 
 
3430
            (queenStatusPointer->TargetDistance < 8000 && queenStatusPointer->TargetRelSpeed < 1000))  
 
 
3431
        {
 
 
3432
            switch(queenStatusPointer->current_move)
 
 
3433
            {
 
 
3434
                case QM_Standby:
 
 
3435
                case QM_Close:
 
 
3436
                case QM_Charge:
 
 
3437
                {
 
 
3438
 
 
 
3439
                    if(queenStatusPointer->TargetDirection.vz > queenStatusPointer->TargetDirection.vx &&
 
 
3440
                       queenStatusPointer->TargetDirection.vz > -queenStatusPointer->TargetDirection.vx)
 
 
3441
                    {
 
 
3442
                        int x = queenStatusPointer->TargetDirection.vx;
 
 
3443
                        x += (FastRandom() % 80000);
 
 
3444
                        x -= 40000;
 
 
3445
 
 
 
3446
                        if (x > 0) 
 
 
3447
                        {
 
 
3448
                            if(PlayerInTrench)
 
 
3449
                                Queen_Do_Swipe(sbPtr,Queen_Swipe_Right_Low);
 
 
3450
                            else
 
 
3451
                                Queen_Do_Swipe(sbPtr,Queen_Swipe_Right);
 
 
3452
                        } 
 
 
3453
                        else 
 
 
3454
                        {
 
 
3455
                            if(PlayerInTrench)
 
 
3456
                                Queen_Do_Swipe(sbPtr,Queen_Swipe_Left_Low);
 
 
3457
                            else
 
 
3458
                                Queen_Do_Swipe(sbPtr,Queen_Swipe_Left);
 
 
3459
                        }
 
 
3460
                    }
 
 
3461
                }
 
 
3462
                default:
 
 
3463
                break;
 
 
3464
            }
 
 
3465
        }
 
 
3466
    }
 
 
3467
 
 
 
3468
    /*------------------------------------------**
 
 
3469
    ** Decide if new movement state is required **
 
 
3470
    **------------------------------------------*/
 
 
3471
 
 
 
3472
    if(queenStatusPointer->QueenState == QBS_CarryingObject)
 
 
3473
    {
 
 
3474
        //Queen is lining up to throw object
 
 
3475
        QueenCalculateTargetInfo(sbPtr);
 
 
3476
 
 
 
3477
        if(queenStatusPointer->TargetDirection.vz > (queenStatusPointer->TargetDirection.vx*2) && 
 
 
3478
           queenStatusPointer->TargetDirection.vz > -(queenStatusPointer->TargetDirection.vx*2) && !queenStatusPointer->TempTarget)
 
 
3479
        {
 
 
3480
            //Time to throw object at player.
 
 
3481
            VECTORCH impulse;
 
 
3482
 
 
 
3483
            if(CalculateTrajectory(&QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->Position,
 
 
3484
                                   &PlayerStatus.sbptr->DynPtr->Position,
 
 
3485
                                   &PlayerStatus.sbptr->DynPtr->LinVelocity,
 
 
3486
                                   QUEEN_THROWN_OBJECT_SPEED,
 
 
3487
                                   &impulse))
 
 
3488
            {
 
 
3489
                //give the object an impulse ,and reinstate gravity
 
 
3490
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse = impulse;
 
 
3491
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn = 1;
 
 
3492
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment = 0;    
 
 
3493
                QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat = IdentityMatrix;
 
 
3494
                //queen will need to choose a new objective
 
 
3495
                queenStatusPointer->QueenState = QBS_Reconsider;
 
 
3496
                queenStatusPointer->QueenTargetSB = PlayerStatus.sbptr;
 
 
3497
                queenStatusPointer->TargetInfoValid = 0;
 
 
3498
            }
 
 
3499
            else
 
 
3500
            {
 
 
3501
                //continue heading for target
 
 
3502
                if(queenStatusPointer->current_move == QM_Standby)
 
 
3503
                    queenStatusPointer->next_move = QM_Close;
 
 
3504
            }
 
 
3505
        }
 
 
3506
        else
 
 
3507
        {
 
 
3508
            //Queen needs to turn some more
 
 
3509
            if(queenStatusPointer->current_move == QM_Standby)
 
 
3510
                queenStatusPointer->next_move=QM_Close;
 
 
3511
        }
 
 
3512
    }
 
 
3513
    //if in standby , need to choose a move
 
 
3514
    else if(queenStatusPointer->current_move == QM_Standby && queenStatusPointer->QueenState != QBS_Reconsider)
 
 
3515
    {
 
 
3516
        QueenCalculateTargetInfo(sbPtr);
 
 
3517
        //queen is heading towards object , or player
 
 
3518
 
 
 
3519
        if(((queenStatusPointer->TargetDistance > 8000)||(queenStatusPointer->TargetDistance > 2000 && queenStatusPointer->TargetRelSpeed
> QUEEN_CLOSE_SPEED))  &&
 
 
3520
           queenStatusPointer->TargetDirection.vz > queenStatusPointer->TargetDirection.vx &&
 
 
3521
           queenStatusPointer->TargetDirection.vz > -queenStatusPointer->TargetDirection.vx)
 
 
3522
        {
 
 
3523
            queenStatusPointer->next_move = QM_Charge;
 
 
3524
            if(queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr)
 
 
3525
            {
 
 
3526
                //going for player. possibility of butting player
 
 
3527
                //Nb. queen can't actually colide with player , if the player is in the locker area
 
 
3528
 
 
 
3529
                if((FastRandom()&0xffff) < (ONE_FIXED/2) && !PlayerInLocker)
 
 
3530
                    queenStatusPointer->next_move = QM_ButtCharge;
 
 
3531
            }
 
 
3532
 
 
 
3533
            if(PlayerInTrench)
 
 
3534
                queenStatusPointer->next_move = QM_ComeToPoint;
 
 
3535
        } 
 
 
3536
        else if (queenStatusPointer->TargetDistance > 3000 || queenStatusPointer->TargetRelSpeed > 0) 
 
 
3537
        {
 
 
3538
            if(queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr && !queenStatusPointer->TempTarget)
 
 
3539
                queenStatusPointer->next_move = QM_Close;
 
 
3540
            else
 
 
3541
                queenStatusPointer->next_move = QM_ComeToPoint;
 
 
3542
        } 
 
 
3543
        else 
 
 
3544
        {
 
 
3545
            if(queenStatusPointer->QueenState != QBS_ClimbingOutOfAirlock)
 
 
3546
            {
 
 
3547
                if(queenStatusPointer->TempTarget)
 
 
3548
                {
 
 
3549
                    queenStatusPointer->TempTarget = 0;
 
 
3550
                    queenStatusPointer->TargetInfoValid = 0;
 
 
3551
                }
 
 
3552
            }
 
 
3553
 
 
 
3554
            if(queenStatusPointer->QueenState == QBS_GoingForObject)
 
 
3555
            {
 
 
3556
                //have to keep going until queen hits object
 
 
3557
                queenStatusPointer->next_move = QM_Close;
 
 
3558
            }
 
 
3559
            else
 
 
3560
            {
 
 
3561
                //queen right next to target now , so wait
 
 
3562
                queenStatusPointer->next_move = QM_Standby;
 
 
3563
                //assuming queen is facing her target , that is. 
 
 
3564
 
 
 
3565
                if(queenStatusPointer->TargetDirection.vz < queenStatusPointer->TargetDirection.vx*2 ||
 
 
3566
                   queenStatusPointer->TargetDirection.vz < -queenStatusPointer->TargetDirection.vx*2)
 
 
3567
                {
 
 
3568
                    //queen isn't facing target , so she needs to continue closing after all
 
 
3569
                    queenStatusPointer->next_move = QM_Close;
 
 
3570
                }
 
 
3571
            }
 
 
3572
        }
 
 
3573
    }
 
 
3574
    //printf("Queen target distance %d\n",queenStatusPointer->TargetDistance);
 
 
3575
    //printf("Queen target position %d : %d :
%d\n",queenStatusPointer->TargetPos.vx,queenStatusPointer->TargetPos.vy,queenStatusPointer->TargetPos.vz);
 
 
3576
 
 
 
3577
    QueenCheckForAvoidAirlock(sbPtr);
 
 
3578
 
 
 
3579
    if(queenStatusPointer->TempTarget)
 
 
3580
    {
 
 
3581
        QueenCalculateTargetInfo(sbPtr);
 
 
3582
 
 
 
3583
        if(queenStatusPointer->TargetDistance < 4000)
 
 
3584
        {
 
 
3585
            queenStatusPointer->TempTarget = 0;
 
 
3586
            queenStatusPointer->TargetInfoValid = 0;
 
 
3587
        }
 
 
3588
 
 
 
3589
        queenStatusPointer->TempTargetTimer -= NormalFrameTime;
 
 
3590
 
 
 
3591
        if(queenStatusPointer->TempTargetTimer < 0)
 
 
3592
        {
 
 
3593
            queenStatusPointer->TempTarget = 0;
 
 
3594
            queenStatusPointer->TargetInfoValid = 0;
 
 
3595
        }
 
 
3596
    }
 
 
3597
 
 
 
3598
    /*-------------------------------------------------------------------**
 
 
3599
    **     check for redirecting the queen , if the player is in the locker **
 
 
3600
    **-------------------------------------------------------------------*/
 
 
3601
 
 
 
3602
    if(!queenStatusPointer->TempTarget && queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr && PlayerInLocker)
 
 
3603
    {
 
 
3604
        //is the queen in line with the locker area?
 
 
3605
        if((dynPtr->Position.vz-HangarLockerMaxZ)*2 > dynPtr->Position.vx-HangarLockerMaxX ||
 
 
3606
           (HangarLockerMinZ-dynPtr->Position.vz)*2 > dynPtr->Position.vx-HangarLockerMaxX)
 
 
3607
        {
 
 
3608
            //nope
 
 
3609
            queenStatusPointer->TempTarget = 1;
 
 
3610
            queenStatusPointer->TempTargetTimer = 2*ONE_FIXED;
 
 
3611
            queenStatusPointer->TargetInfoValid = 0;
 
 
3612
 
 
 
3613
            //move the queen so that she is lined up with the locker
 
 
3614
            queenStatusPointer->TargetPos.vx = dynPtr->Position.vx;
 
 
3615
            queenStatusPointer->TargetPos.vy = dynPtr->Position.vy;
 
 
3616
            queenStatusPointer->TargetPos.vz = HangarLockerCentreZ;
 
 
3617
        }
 
 
3618
    }
 
 
3619
 
 
 
3620
    if(queenStatusPointer->QueenTauntTimer > 0)
 
 
3621
    {
 
 
3622
        queenStatusPointer->QueenTauntTimer -= NormalFrameTime;
 
 
3623
 
 
 
3624
        if(queenStatusPointer->QueenTargetSB == PlayerStatus.sbptr && DistanceToPlayer > 10000)
 
 
3625
        {
 
 
3626
            QueenCalculateTargetInfo(sbPtr);
 
 
3627
 
 
 
3628
               if(queenStatusPointer->TargetDirection.vz > queenStatusPointer->TargetDirection.vx &&
 
 
3629
               queenStatusPointer->TargetDirection.vz > -queenStatusPointer->TargetDirection.vx)
 
 
3630
            {
 
 
3631
                queenStatusPointer->QueenTauntTimer = 0;
 
 
3632
                //Queen has recently hit player , and is facing player time to taunt
 
 
3633
                queenStatusPointer->next_move = QM_Taunt;
 
 
3634
            }
 
 
3635
        }
 
 
3636
    }
 
 
3637
 
 
 
3638
    /*-------------------------------**
 
 
3639
    **     Flamethrower avoidance stuff **
 
 
3640
    **-------------------------------*/
 
 
3641
 
 
 
3642
    //only if queen is trying to attack the player in close combat
 
 
3643
    if(queenStatusPointer->QueenState == QBS_Engagement)
 
 
3644
    {
 
 
3645
        if(queenStatusPointer->QueenFireTimer > QueenMinimumFireTime)
 
 
3646
        {
 
 
3647
            /*stop and hiss for a bit*/
 
 
3648
            switch(queenStatusPointer->current_move)
 
 
3649
            {
 
 
3650
                case QM_Standby:
 
 
3651
                case QM_ComeToPoint:
 
 
3652
                case QM_ButtCharge:
 
 
3653
                case QM_Charge:
 
 
3654
                case QM_Close:
 
 
3655
                    queenStatusPointer->current_move = QM_Hiss;
 
 
3656
                    queenStatusPointer->moveTimer = 0;
 
 
3657
                default:
 
 
3658
                break;
 
 
3659
            }
 
 
3660
        }
 
 
3661
        else if(!queenStatusPointer->QueenFireTimer)
 
 
3662
        {
 
 
3663
            if(queenStatusPointer->next_move == QM_Hiss)
 
 
3664
                queenStatusPointer->next_move = QM_Standby;
 
 
3665
 
 
 
3666
            if(queenStatusPointer->current_move == QM_Hiss)
 
 
3667
            {
 
 
3668
                queenStatusPointer->moveTimer = 0;
 
 
3669
                queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
3670
                queenStatusPointer->next_move = QM_Standby;
 
 
3671
            }
 
 
3672
        }
 
 
3673
 
 
 
3674
        //update the timer
 
 
3675
        if(TargetIsFiringFlamethrowerAtQueen(sbPtr))
 
 
3676
        {
 
 
3677
            queenStatusPointer->QueenFireTimer+=NormalFrameTime;
 
 
3678
 
 
 
3679
            if(queenStatusPointer->QueenFireTimer > 2*ONE_FIXED)
 
 
3680
                queenStatusPointer->QueenFireTimer = 2*ONE_FIXED;
 
 
3681
        }
 
 
3682
        else
 
 
3683
        {
 
 
3684
            queenStatusPointer->QueenFireTimer -= NormalFrameTime;
 
 
3685
 
 
 
3686
            if(queenStatusPointer->QueenFireTimer < 0)
 
 
3687
                queenStatusPointer->QueenFireTimer = 0;
 
 
3688
        }
 
 
3689
    }
 
 
3690
    else
 
 
3691
    {
 
 
3692
        //make sure queen isn't hissing
 
 
3693
        if(queenStatusPointer->next_move == QM_Hiss)
 
 
3694
            queenStatusPointer->next_move = QM_Standby;
 
 
3695
 
 
 
3696
        if(queenStatusPointer->current_move == QM_Hiss)
 
 
3697
        {
 
 
3698
            queenStatusPointer->moveTimer = 0;
 
 
3699
            queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
3700
            queenStatusPointer->next_move = QM_Standby;
 
 
3701
        }
 
 
3702
 
 
 
3703
        queenStatusPointer->QueenFireTimer = 0;
 
 
3704
    }
 
 
3705
 
 
 
3706
    if(!queenStatusPointer->TempTarget)
 
 
3707
    {
 
 
3708
        //update target location
 
 
3709
        queenStatusPointer->TargetPos = queenStatusPointer->QueenTargetSB->DynPtr->Position;                    
 
 
3710
    }
 
 
3711
 
 
 
3712
    /*---------------------------**
 
 
3713
    **     Handle Queeen's movement **
 
 
3714
    **---------------------------*/
 
 
3715
 
 
 
3716
    dynPtr->Displacement.vx = dynPtr->Displacement.vy = dynPtr->Displacement.vz = 0;
 
 
3717
 
 
 
3718
    if (queenStatusPointer->QueenState != QBS_Dead) 
 
 
3719
    {
 
 
3720
        switch (queenStatusPointer->current_move)
 
 
3721
        {
 
 
3722
            case QM_Standby:
 
 
3723
            {
 
 
3724
                //printf("Queen State: Standby\n");
 
 
3725
 
 
 
3726
                if (queenStatusPointer->next_move == QM_Standby || queenStatusPointer->PlayingHitDelta) 
 
 
3727
                {
 
 
3728
                    /* Do not much. */
 
 
3729
                    QueenMove_Standby(sbPtr);
 
 
3730
                }
 
 
3731
                else
 
 
3732
                {
 
 
3733
                    queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
3734
                    queenStatusPointer->next_move = QM_Standby;
 
 
3735
                    queenStatusPointer->moveTimer = 0;
 
 
3736
                }
 
 
3737
 
 
 
3738
            }
 
 
3739
            break;
 
 
3740
            case QM_Stun:
 
 
3741
            {
 
 
3742
                //printf("Queen State: Stunned\n");
 
 
3743
                //don't do anything
 
 
3744
                sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
3745
            }
 
 
3746
            break;
 
 
3747
            case QM_StepForward:
 
 
3748
            {
 
 
3749
                //printf("Queen State: Step Forward\n");
 
 
3750
                /* Move function. */
 
 
3751
           //        QueenMove_StepForward(sbPtr);
 
 
3752
            }
 
 
3753
            break;
 
 
3754
            case QM_StepBack:
 
 
3755
            {
 
 
3756
                //printf("Queen State: Step Back\n");
 
 
3757
                /* Move function. */
 
 
3758
                   QueenMove_StepBack(sbPtr);
 
 
3759
            }
 
 
3760
            break;
 
 
3761
            case QM_TurnLeft:
 
 
3762
            {
 
 
3763
                //printf("Queen State: Turn Left\n");
 
 
3764
                /* Move function. */
 
 
3765
            }
 
 
3766
            break;
 
 
3767
            case QM_TurnRight:
 
 
3768
            {
 
 
3769
                //printf("Queen State: Turn Right\n");
 
 
3770
                /* Move function. */
 
 
3771
            }
 
 
3772
            break;
 
 
3773
            case QM_ComeToPoint:
 
 
3774
            {
 
 
3775
                //printf("Queen State: Come To Point\n");
 
 
3776
                /* Move function. */
 
 
3777
 
 
 
3778
                if(JumpDesired)
 
 
3779
                {
 
 
3780
                    printf("Jumping\n");
 
 
3781
                    sbPtr->DynPtr->LinImpulse.vy -= 10000;
 
 
3782
                    queenStatusPointer->next_move = QM_Standby;
 
 
3783
                    queenStatusPointer->current_move = QM_Jump;
 
 
3784
                }
 
 
3785
                else
 
 
3786
                {
 
 
3787
                    QueenMove_Walk(sbPtr);
 
 
3788
                }
 
 
3789
 
 
 
3790
            }
 
 
3791
            break;
 
 
3792
            case QM_Taunt:
 
 
3793
            {
 
 
3794
                //printf("Queen State: Taunt\n");
 
 
3795
                /* Move function. */
 
 
3796
                QueenMove_Taunt(sbPtr);
 
 
3797
            }
 
 
3798
            break;
 
 
3799
            case QM_Hiss:
 
 
3800
            {
 
 
3801
                //printf("Queen State: Hiss\n");
 
 
3802
                /* Move function. */
 
 
3803
                QueenMove_Hiss(sbPtr);
 
 
3804
            }
 
 
3805
            break;
 
 
3806
            case QM_LeftSwipe:
 
 
3807
            {
 
 
3808
                //printf("Queen State: Left Swipe\n");
 
 
3809
            //    QueenMove_LeftSwipe(sbPtr);
 
 
3810
            }
 
 
3811
            break;
 
 
3812
            case QM_RightSwipe:
 
 
3813
            {
 
 
3814
                //printf("Queen State: Right Swipe\n");
 
 
3815
            //    QueenMove_RightSwipe(sbPtr);
 
 
3816
            }
 
 
3817
            break;
 
 
3818
            case QM_ButtAttack:
 
 
3819
            {
 
 
3820
                //printf("Queen State: Butt attack\n");
 
 
3821
                QueenMove_ButtAttack(sbPtr);
 
 
3822
            }
 
 
3823
            break;
 
 
3824
            case QM_Charge:
 
 
3825
            {
 
 
3826
                //printf("Queen State: Charging\n");
 
 
3827
                /* Move function. */
 
 
3828
 
 
 
3829
                if(JumpDesired)
 
 
3830
                {
 
 
3831
                    //printf("Jumping\n");
 
 
3832
                    sbPtr->DynPtr->LinImpulse.vy-=10000;
 
 
3833
                    queenStatusPointer->next_move=QM_Standby;
 
 
3834
                    queenStatusPointer->current_move=QM_Jump;
 
 
3835
                }
 
 
3836
                else
 
 
3837
                {
 
 
3838
                       QueenMove_Charge(sbPtr);
 
 
3839
                }
 
 
3840
 
 
 
3841
            }
 
 
3842
            break;
 
 
3843
            case QM_Close:
 
 
3844
            {
 
 
3845
                //printf("Queen State: Closing\n");
 
 
3846
                /* Move function. */
 
 
3847
 
 
 
3848
                if(JumpDesired)
 
 
3849
                {
 
 
3850
                    printf("Jumping\n");
 
 
3851
                    sbPtr->DynPtr->LinImpulse.vy -= 10000;
 
 
3852
                    queenStatusPointer->next_move = QM_Standby;
 
 
3853
                    queenStatusPointer->current_move = QM_Jump;
 
 
3854
                }
 
 
3855
                else
 
 
3856
                {
 
 
3857
                    QueenMove_Close(sbPtr);
 
 
3858
                }
 
 
3859
            }
 
 
3860
            break;
 
 
3861
            case QM_ButtCharge:
 
 
3862
            {
 
 
3863
                //printf("Queen State: Butt charging\n");
 
 
3864
                /* Move function. */
 
 
3865
 
 
 
3866
                if(JumpDesired)
 
 
3867
                {
 
 
3868
                    printf("Jumping\n");
 
 
3869
                    sbPtr->DynPtr->LinImpulse.vy -= 10000;
 
 
3870
                    queenStatusPointer->next_move = QM_Standby;
 
 
3871
                    queenStatusPointer->current_move = QM_Jump;
 
 
3872
                }
 
 
3873
                else
 
 
3874
                {
 
 
3875
                    QueenMove_ButtCharge(sbPtr);
 
 
3876
                }
 
 
3877
            }
 
 
3878
            break;
 
 
3879
            case QM_Jump:
 
 
3880
            {
 
 
3881
                //printf("Queen State: Jumping\n");
 
 
3882
                //stay in jump mode until queen hits the floor again
 
 
3883
 
 
 
3884
                if(!dynPtr->IsInContactWithFloor)
 
 
3885
                {
 
 
3886
                    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->OrientMat.mat31/10;
 
 
3887
                    sbPtr->DynPtr->LinVelocity.vy = 0;
 
 
3888
                    sbPtr->DynPtr->LinVelocity.vz = sbPtr->DynPtr->OrientMat.mat33/10;
 
 
3889
                }
 
 
3890
                else
 
 
3891
                {
 
 
3892
                    queenStatusPointer->current_move = queenStatusPointer->next_move;
 
 
3893
                    queenStatusPointer->next_move = QM_Standby;
 
 
3894
                    queenStatusPointer->moveTimer = 0;
 
 
3895
                }
 
 
3896
            }
 
 
3897
            break;
 
 
3898
            case QM_Climbing:
 
 
3899
            {
 
 
3900
                //printf("Queen State: Climbing\n");
 
 
3901
                sbPtr->DynPtr->LinVelocity.vx = 0;
 
 
3902
                sbPtr->DynPtr->LinVelocity.vy = 0;
 
 
3903
                sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
3904
                QueenMove_Climb(sbPtr);
 
 
3905
            }
 
 
3906
            break;
 
 
3907
            default:
 
 
3908
            {
 
 
3909
                assert(0);
 
 
3910
                return;
 
 
3911
            }
 
 
3912
        }
 
 
3913
 
 
 
3914
        HModel_Regen(&queenStatusPointer->HModelController,(20*ONE_FIXED));
 
 
3915
    }
 
 
3916
 
 
 
3917
    queenStatusPointer->LastVelocity = dynPtr->LinVelocity;
 
 
3918
 
 
 
3919
    /*----------------------------------**
 
 
3920
    **     Update object queen is carrying **
 
 
3921
    **----------------------------------*/
 
 
3922
 
 
 
3923
    if(queenStatusPointer->QueenState == QBS_CarryingObject)
 
 
3924
    {
 
 
3925
        ProveHModel(sbPtr->DisplayBlock->HModelControlBlock,sbPtr->DisplayBlock);
 
 
3926
 
 
 
3927
        QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->Position = queenStatusPointer->QueenRightHand->World_Offset;
 
 
3928
        QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->PrevPosition = queenStatusPointer->QueenRightHand->World_Offset;
 
 
3929
        QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat = queenStatusPointer->QueenRightHand->SecMat;
 
 
3930
    }
 
 
3931
 
 
 
3932
    sbPtr->DamageBlock.IsOnFire = 0;
 
 
3933
    /* That would be silly. */
 
 
3934
 
 
 
3935
/*----------------------------------------------------------------------------------------**
 
 
3936
**     Monitor the queen's objects , and check for any high speed collisions with the player **
 
 
3937
**----------------------------------------------------------------------------------------*/
 
 
3938
    {
 
 
3939
        int i=0;
 
 
3940
        for(; i < NumQueenObjects; i++)
 
 
3941
        {
 
 
3942
            if(!QueenObjectList[i]->destroyed_but_preserved)
 
 
3943
            {
 
 
3944
                int doneBounceNoise = 0;
 
 
3945
                COLLISIONREPORT *nextReport = QueenObjectList[i]->DynPtr->CollisionReportPtr;
 
 
3946
 
 
 
3947
                while(nextReport) 
 
 
3948
                {
 
 
3949
                    int impulse = Approximate3dMagnitude(&QueenObjectList[i]->DynPtr->LinImpulse);
 
 
3950
 
 
 
3951
                    if(impulse > 10000)
 
 
3952
                    {
 
 
3953
                        //object hit something while moving quickly , so play a bounce sound
 
 
3954
                        if(!doneBounceNoise)
 
 
3955
                        {
 
 
3956
                            ThrownObjectBounceNoise(i,&nextReport->ObstaclePoint);
 
 
3957
                            doneBounceNoise = 1;
 
 
3958
                        }
 
 
3959
 
 
 
3960
                        if(nextReport->ObstacleSBPtr)
 
 
3961
                        {
 
 
3962
                            if(nextReport->ObstacleSBPtr == PlayerStatus.sbptr ||
 
 
3963
                               nextReport->ObstacleSBPtr->type == I_BehaviourInanimateObject ||
 
 
3964
                               (nextReport->ObstacleSBPtr->name && !strcmp(nextReport->ObstacleSBPtr->name, "locker door")))
 
 
3965
                            {
 
 
3966
                                //object has hit the player at speed.
 
 
3967
 
 
 
3968
                                DAMAGE_PROFILE impact_damage = {0,0,0,0,0,0,0,0,0,0,0,AMMO_NONE};
 
 
3969
                                VECTORCH direction;
 
 
3970
                                VECTORCH hit_object_direction;
 
 
3971
                                int dotproduct;
 
 
3972
 
 
 
3973
                                //adjust the object's position so it is ear the player 
 
 
3974
                                //back in the direction that it came from
 
 
3975
 
 
 
3976
                                direction = QueenObjectList[i]->DynPtr->Position;
 
 
3977
 
 
 
3978
                                direction.vx -= QueenObjectList[i]->DynPtr->PrevPosition.vx;
 
 
3979
                                direction.vy -= QueenObjectList[i]->DynPtr->PrevPosition.vy;
 
 
3980
                                direction.vz -= QueenObjectList[i]->DynPtr->PrevPosition.vz;
 
 
3981
 
 
 
3982
                                if(direction.vx || direction.vy || direction.vz)
 
 
3983
                                    Normalise(&direction);
 
 
3984
 
 
 
3985
                                hit_object_direction.vx = nextReport->ObstacleSBPtr->DynPtr->Position.vx -
nextReport->ObstacleSBPtr->DynPtr->PrevPosition.vx;
 
 
3986
                                hit_object_direction.vy = nextReport->ObstacleSBPtr->DynPtr->Position.vy -
nextReport->ObstacleSBPtr->DynPtr->PrevPosition.vy;
 
 
3987
                                hit_object_direction.vz = nextReport->ObstacleSBPtr->DynPtr->Position.vz -
nextReport->ObstacleSBPtr->DynPtr->PrevPosition.vz;
 
 
3988
 
 
 
3989
                                if(hit_object_direction.vx || hit_object_direction.vy || hit_object_direction.vz)
 
 
3990
                                    Normalise(&hit_object_direction);
 
 
3991
 
 
 
3992
                                dotproduct = DotProduct(&direction,&hit_object_direction);
 
 
3993
 
 
 
3994
                                //damage the player
 
 
3995
                                impact_damage.Impact = 40+MUL_FIXED(15,dotproduct);
 
 
3996
                                CauseDamageToObject(nextReport->ObstacleSBPtr, &impact_damage, ONE_FIXED,NULL);
 
 
3997
 
 
 
3998
                                //damage the thrown object as well (almost certainly destroying it)
 
 
3999
                                impact_damage.Impact *= 10;
 
 
4000
                                CauseDamageToObject(QueenObjectList[i], &impact_damage, ONE_FIXED,NULL);
 
 
4001
 
 
 
4002
                                {
 
 
4003
                                    //knock the object back
 
 
4004
                                    VECTORCH* impulse;
 
 
4005
                                    impulse = &nextReport->ObstacleSBPtr->DynPtr->LinImpulse;
 
 
4006
                                    impulse->vx += direction.vx/4;
 
 
4007
                                    impulse->vz += direction.vz/4;
 
 
4008
                                }
 
 
4009
 
 
 
4010
                            QueenObjectList[i]->DynPtr->Position.vx=nextReport->ObstacleSBPtr->DynPtr->Position.vx+direction.vx/100;
 
 
4011
                            QueenObjectList[i]->DynPtr->Position.vz=nextReport->ObstacleSBPtr->DynPtr->Position.vz+direction.vz/100;
 
 
4012
                            QueenObjectList[i]->DynPtr->PrevPosition.vx=QueenObjectList[i]->DynPtr->Position.vx;
 
 
4013
                            QueenObjectList[i]->DynPtr->PrevPosition.vz=QueenObjectList[i]->DynPtr->Position.vz;
 
 
4014
 
 
 
4015
                                //set the taunt timer
 
 
4016
                                queenStatusPointer->QueenTauntTimer = ONE_FIXED/2;                        
 
 
4017
 
 
 
4018
                            break;
 
 
4019
                            }
 
 
4020
                        }
 
 
4021
                    }
 
 
4022
                    nextReport = nextReport->NextCollisionReportPtr;
 
 
4023
                }
 
 
4024
            }
 
 
4025
        }
 
 
4026
    }
 
 
4027
 
 
 
4028
    QueenSoundHiss(sbPtr);
 
 
4029
}
 
 
4030
 
 
 
4031
/*--------------------**
 
 
4032
** Loading and Saving **
 
 
4033
**--------------------*/
 
 
4034
#include "savegame.h"
 
 
4035
 
 
 
4036
typedef struct queen_save_block
 
 
4037
{
 
 
4038
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
4039
 
 
 
4040
//behaviour block stuff
 
 
4041
 
 
 
4042
    QUEEN_BEHAVIOUR_STATE QueenState;
 
 
4043
    QUEEN_MANOEUVRE current_move;
 
 
4044
    QUEEN_MANOEUVRE next_move;
 
 
4045
 
 
 
4046
    QUEEN_FOOT fixed_foot;
 
 
4047
    VECTORCH fixed_foot_oldpos;
 
 
4048
 
 
 
4049
    VECTORCH TargetPos;
 
 
4050
 
 
 
4051
    int moveTimer;
 
 
4052
 
 
 
4053
    NPC_WANDERDATA wanderData;
 
 
4054
 
 
 
4055
    int TempTarget;//going for an intermediate point
 
 
4056
    int TempTargetTimer;//time before queen gives up going for intermediate point
 
 
4057
    int CurrentQueenObject;
 
 
4058
    int QueenStateTimer;
 
 
4059
    int QueenObjectBias;
 
 
4060
    int QueenPlayerBias;
 
 
4061
    int QueenTauntTimer;
 
 
4062
    int QueenFireTimer;
 
 
4063
    VECTORCH LastVelocity;
 
 
4064
    int BeenInAirlock;
 
 
4065
    int QueenActivated; //queen is inactive until seen
 
 
4066
 
 
 
4067
    int TargetInfoValid; //have the next three items been set
 
 
4068
    int TargetDistance; //distance of current target from queen
 
 
4069
    int TargetRelSpeed; //targets speed in queen's direction
 
 
4070
    VECTORCH TargetDirection; //targets direction relative to queen
 
 
4071
    VECTORCH VectToTarget;
 
 
4072
 
 
 
4073
    unsigned int PlayingHitDelta :1;
 
 
4074
 
 
 
4075
    int SwerveTimer;
 
 
4076
    int SwerveDirection;
 
 
4077
 
 
 
4078
    QUEEN_SOUND_CATEGORY lastSoundCategory;
 
 
4079
 
 
 
4080
    VECTORCH ClimbStartPosition; //used when climing out of the airlock
 
 
4081
    int AttackDoneItsDamage;
 
 
4082
 
 
 
4083
//and now those evil globals...
 
 
4084
    int PlayerInTrench;
 
 
4085
    int PlayerInLocker;
 
 
4086
    int AirlockTimeOpen;
 
 
4087
    int UpperAirlockDoorOpen;
 
 
4088
    int LowerAirlockDoorOpen;
 
 
4089
    VECTORCH UpperAirlockDoorStart;
 
 
4090
    VECTORCH LowerAirlockDoorStart;
 
 
4091
 
 
 
4092
//annoying pointer related things
 
 
4093
    char Target_SBname[SB_NAME_LENGTH];
 
 
4094
 
 
 
4095
    SECTION_DATA *fixed_foot_section;
 
 
4096
    SECTION_DATA* QueenRightHand;
 
 
4097
 
 
 
4098
//strategyblock stuff
 
 
4099
    DAMAGEBLOCK DamageBlock;
 
 
4100
    DYNAMICSBLOCK dynamics;
 
 
4101
 
 
 
4102
} QUEEN_SAVE_BLOCK;
 
 
4103
 
 
 
4104
//defines for load/save macros
 
 
4105
#define SAVELOAD_BLOCK block
 
 
4106
#define SAVELOAD_BEHAV queenStatusPointer
 
 
4107
 
 
 
4108
void LoadStrategy_Queen(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
4109
{
 
 
4110
    STRATEGYBLOCK* sbPtr;
 
 
4111
    QUEEN_STATUS_BLOCK* queenStatusPointer;
 
 
4112
    QUEEN_SAVE_BLOCK* block = (QUEEN_SAVE_BLOCK*) header; 
 
 
4113
 
 
 
4114
    //check the size of the save block
 
 
4115
    if(header->size != sizeof(*block))
 
 
4116
        return;
 
 
4117
 
 
 
4118
    //find the existing strategy block
 
 
4119
    sbPtr = FindSBWithName(header->SBname);
 
 
4120
 
 
 
4121
    if(!sbPtr)
 
 
4122
        return;
 
 
4123
 
 
 
4124
    //make sure the strategy found is of the right type
 
 
4125
    if(sbPtr->type != I_BehaviourQueenAlien)
 
 
4126
        return;
 
 
4127
 
 
 
4128
    queenStatusPointer =(QUEEN_STATUS_BLOCK*) sbPtr->dataptr;
 
 
4129
 
 
 
4130
    //normally done on first frame , but need to do this here when loading
 
 
4131
    FindQueenObjects();
 
 
4132
 
 
 
4133
    //start copying stuff
 
 
4134
    COPYELEMENT_LOAD(QueenState)
 
 
4135
    COPYELEMENT_LOAD(current_move)
 
 
4136
    COPYELEMENT_LOAD(next_move)
 
 
4137
 
 
 
4138
    COPYELEMENT_LOAD(fixed_foot)
 
 
4139
    COPYELEMENT_LOAD(fixed_foot_oldpos)
 
 
4140
 
 
 
4141
    COPYELEMENT_LOAD(TargetPos)
 
 
4142
 
 
 
4143
    COPYELEMENT_LOAD(moveTimer)
 
 
4144
 
 
 
4145
    COPYELEMENT_LOAD(wanderData)
 
 
4146
 
 
 
4147
    COPYELEMENT_LOAD(TempTarget)//going for an intermediate point
 
 
4148
    COPYELEMENT_LOAD(TempTargetTimer)//time before queen gives up going for intermediate point
 
 
4149
 
 
 
4150
    COPYELEMENT_LOAD(CurrentQueenObject)
 
 
4151
    COPYELEMENT_LOAD(QueenStateTimer)
 
 
4152
    COPYELEMENT_LOAD(QueenObjectBias)
 
 
4153
    COPYELEMENT_LOAD(QueenPlayerBias)
 
 
4154
    COPYELEMENT_LOAD(QueenTauntTimer)
 
 
4155
    COPYELEMENT_LOAD(QueenFireTimer)
 
 
4156
    COPYELEMENT_LOAD(LastVelocity)
 
 
4157
 
 
 
4158
    COPYELEMENT_LOAD(BeenInAirlock)
 
 
4159
    COPYELEMENT_LOAD(QueenActivated) //queen is inactive until seen
 
 
4160
 
 
 
4161
    COPYELEMENT_LOAD(TargetInfoValid) //have the next three items been set
 
 
4162
    COPYELEMENT_LOAD(TargetDistance) //distance of current target from queen
 
 
4163
    COPYELEMENT_LOAD(TargetRelSpeed) //targets speed in queen's direction
 
 
4164
    COPYELEMENT_LOAD(TargetDirection) //targets direction relative to queen
 
 
4165
    COPYELEMENT_LOAD(VectToTarget)
 
 
4166
 
 
 
4167
    COPYELEMENT_LOAD(PlayingHitDelta)
 
 
4168
    COPYELEMENT_LOAD(SwerveTimer)
 
 
4169
    COPYELEMENT_LOAD(SwerveDirection)
 
 
4170
    COPYELEMENT_LOAD(lastSoundCategory)
 
 
4171
 
 
 
4172
    COPYELEMENT_LOAD(ClimbStartPosition) //used when climing out of the airlock
 
 
4173
    COPYELEMENT_LOAD(AttackDoneItsDamage)
 
 
4174
 
 
 
4175
    //load globals
 
 
4176
    PlayerInTrench = block->PlayerInTrench;
 
 
4177
    PlayerInLocker = block->PlayerInLocker;
 
 
4178
    AirlockTimeOpen = block->AirlockTimeOpen;
 
 
4179
    UpperAirlockDoorOpen = block->UpperAirlockDoorOpen;
 
 
4180
    LowerAirlockDoorOpen = block->LowerAirlockDoorOpen;
 
 
4181
    UpperAirlockDoorStart = block->UpperAirlockDoorStart;
 
 
4182
    LowerAirlockDoorStart =    block->LowerAirlockDoorStart;
 
 
4183
 
 
 
4184
    //load target
 
 
4185
    queenStatusPointer->QueenTargetSB = FindSBWithName(block->Target_SBname);
 
 
4186
 
 
 
4187
    //copy strategy block stuff
 
 
4188
    *sbPtr->DynPtr = block->dynamics;
 
 
4189
    sbPtr->DamageBlock = block->DamageBlock;
 
 
4190
 
 
 
4191
    //load hierarchy
 
 
4192
    {
 
 
4193
        SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
4194
        if(hier_header)
 
 
4195
            LoadHierarchy(hier_header,&queenStatusPointer->HModelController);
 
 
4196
    }
 
 
4197
 
 
 
4198
    //get delta controller pointers
 
 
4199
    queenStatusPointer->attack_delta = Get_Delta_Sequence(&queenStatusPointer->HModelController,"attack");
 
 
4200
     queenStatusPointer->hit_delta = Get_Delta_Sequence(&queenStatusPointer->HModelController,"hit");
 
 
4201
 
 
 
4202
    //get section data pointers
 
 
4203
 
 
 
4204
    if(queenStatusPointer->fixed_foot == LeftFoot)
 
 
4205
        queenStatusPointer->fixed_foot_section = GetThisSectionData(queenStatusPointer->HModelController.section_data, "left foot");
 
 
4206
    else
 
 
4207
        queenStatusPointer->fixed_foot_section = GetThisSectionData(queenStatusPointer->HModelController.section_data, "right foot");
 
 
4208
 
 
 
4209
    queenStatusPointer->QueenRightHand = GetThisSectionData(queenStatusPointer->HModelController.section_data,"rrrr fing");
 
 
4210
 
 
 
4211
    Load_SoundState(&queenStatusPointer->soundHandle);
 
 
4212
}
 
 
4213
 
 
 
4214
void SaveStrategy_Queen(STRATEGYBLOCK* sbPtr)
 
 
4215
{
 
 
4216
    QUEEN_STATUS_BLOCK* queenStatusPointer;
 
 
4217
    QUEEN_SAVE_BLOCK* block;
 
 
4218
 
 
 
4219
    GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
 
 
4220
    queenStatusPointer = (QUEEN_STATUS_BLOCK*) sbPtr->dataptr;
 
 
4221
 
 
 
4222
    //start copying stuff
 
 
4223
    COPYELEMENT_SAVE(QueenState)
 
 
4224
    COPYELEMENT_SAVE(current_move)
 
 
4225
    COPYELEMENT_SAVE(next_move)
 
 
4226
 
 
 
4227
    COPYELEMENT_SAVE(fixed_foot)
 
 
4228
    COPYELEMENT_SAVE(fixed_foot_oldpos)
 
 
4229
 
 
 
4230
    COPYELEMENT_SAVE(TargetPos)
 
 
4231
 
 
 
4232
    COPYELEMENT_SAVE(moveTimer)
 
 
4233
 
 
 
4234
    COPYELEMENT_SAVE(wanderData)
 
 
4235
 
 
 
4236
    COPYELEMENT_SAVE(TempTarget)//going for an intermediate point
 
 
4237
    COPYELEMENT_SAVE(TempTargetTimer)//time before queen gives up going for intermediate point
 
 
4238
 
 
 
4239
    COPYELEMENT_SAVE(CurrentQueenObject)
 
 
4240
    COPYELEMENT_SAVE(QueenStateTimer)
 
 
4241
    COPYELEMENT_SAVE(QueenObjectBias)
 
 
4242
    COPYELEMENT_SAVE(QueenPlayerBias)
 
 
4243
    COPYELEMENT_SAVE(QueenTauntTimer)
 
 
4244
    COPYELEMENT_SAVE(QueenFireTimer)
 
 
4245
    COPYELEMENT_SAVE(LastVelocity)
 
 
4246
 
 
 
4247
    COPYELEMENT_SAVE(BeenInAirlock)
 
 
4248
    COPYELEMENT_SAVE(QueenActivated) //queen is inactive until seen
 
 
4249
 
 
 
4250
    COPYELEMENT_SAVE(TargetInfoValid) //have the next three items been set
 
 
4251
    COPYELEMENT_SAVE(TargetDistance) //distance of current target from queen
 
 
4252
    COPYELEMENT_SAVE(TargetRelSpeed) //targets speed in queen's direction
 
 
4253
    COPYELEMENT_SAVE(TargetDirection) //targets direction relative to queen
 
 
4254
    COPYELEMENT_SAVE(VectToTarget)
 
 
4255
 
 
 
4256
    COPYELEMENT_SAVE(PlayingHitDelta)
 
 
4257
    COPYELEMENT_SAVE(SwerveTimer)
 
 
4258
    COPYELEMENT_SAVE(SwerveDirection)
 
 
4259
    COPYELEMENT_SAVE(lastSoundCategory)
 
 
4260
 
 
 
4261
    COPYELEMENT_SAVE(ClimbStartPosition) //used when climing out of the airlock
 
 
4262
    COPYELEMENT_SAVE(AttackDoneItsDamage)
 
 
4263
 
 
 
4264
    //save globals
 
 
4265
    block->PlayerInTrench = PlayerInTrench;
 
 
4266
    block->PlayerInLocker = PlayerInLocker;
 
 
4267
    block->AirlockTimeOpen = AirlockTimeOpen;
 
 
4268
    block->UpperAirlockDoorOpen = UpperAirlockDoorOpen;
 
 
4269
    block->LowerAirlockDoorOpen = LowerAirlockDoorOpen;
 
 
4270
    block->UpperAirlockDoorStart = UpperAirlockDoorStart;
 
 
4271
    block->LowerAirlockDoorStart =    LowerAirlockDoorStart;
 
 
4272
 
 
 
4273
    //save target
 
 
4274
    if(queenStatusPointer->QueenTargetSB)
 
 
4275
    {
 
 
4276
        COPY_NAME(block->Target_SBname,queenStatusPointer->QueenTargetSB->SBname);
 
 
4277
    }
 
 
4278
    else
 
 
4279
    {
 
 
4280
        COPY_NAME(block->Target_SBname,Null_Name);
 
 
4281
    }
 
 
4282
 
 
 
4283
    //save strategy block stuff
 
 
4284
    block->dynamics = *sbPtr->DynPtr;
 
 
4285
    block->dynamics.CollisionReportPtr=0;
 
 
4286
    block->DamageBlock = sbPtr->DamageBlock;
 
 
4287
 
 
 
4288
    //save the hierarchy
 
 
4289
    SaveHierarchy(&queenStatusPointer->HModelController);
 
 
4290
 
 
 
4291
    Save_SoundState(&queenStatusPointer->soundHandle);
 
 
4292
}