4b825dc642cb6eb9a060e54bf8d69288fbee490494a6641b73026d662261604d7d192beae70b11dc
 
 
1
#include "system.h"
 
 
2
#include "prototyp.h"
 
 
3
#include "stratdef.h"
 
 
4
#include "pfarlocs.h"
 
 
5
#include "pheromon.h"
 
 
6
#include "bh_ais.h"
 
 
7
#include "bh_types.h"
 
 
8
#include "bh_far.h"
 
 
9
#include "npc_marine.h"
 
 
10
#include "npc_alien.h"
 
 
11
#include "weapons.h"
 
 
12
#include "weaponbehaviour.h"
 
 
13
#include "los.h"
 
 
14
#include "targeting.h"
 
 
15
#include "pldghost.h"
 
 
16
#include "generator.h"
 
 
17
#include "corpse.h"
 
 
18
#include "npc_dummy.h"
 
 
19
#include "scream.h"
 
 
20
#include "extents.h"
 
 
21
#include "game_statistics.h"
 
 
22
#include <assert.h>
 
 
23
#include <stdlib.h>
 
 
24
#include <stdio.h>
 
 
25
#include <string.h>
 
 
26
 
 
 
27
extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
 
 
28
extern uint8_t Null_Name[8];
 
 
29
extern const VECTORCH null_vec;
 
 
30
 
 
 
31
static const PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id);
 
 
32
 
 
 
33
extern void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output);
 
 
34
 
 
 
35
/* Patrick 21/8/97 --------------------------------------------------
 
 
36
Predator personalisation parameters:
 
 
37
format: health,speed,defenceHealth,useShoulderCannon,
 
 
38
timebetweenRangedAttacks,maxShotsPerRangedAttack,
 
 
39
timeBetweenEachShot,closeAttackDamage,chanceOfCloaking(1-8)
 
 
40
---------------------------------------------------------------------*/
 
 
41
static const PREDATOR_PERSONALPARAMETERS predatorCV[] = 
 
 
42
{
 
 
43
    {800,8000,200,1,(2*ONE_FIXED),3,(ONE_FIXED),25,200,2},
 
 
44
    {1000,7000,500,0,(ONE_FIXED),1,(ONE_FIXED>>1),20,400,4},
 
 
45
    {600,10000,10,1,(4*ONE_FIXED),2,(ONE_FIXED>>1),50,300,8},
 
 
46
    {600,8000,200,0,(2*ONE_FIXED),2,(ONE_FIXED),25,500,2},
 
 
47
    {1000,9000,100,1,(ONE_FIXED),1,(ONE_FIXED>>1),35,400,6},
 
 
48
};
 
 
49
 
 
 
50
static enum AMMO_ID GetPredatorAttackDamageType(STRATEGYBLOCK *sbPtr,int flagnum)
 
 
51
{
 
 
52
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
53
 
 
 
54
return (predatorStatusPointer->current_attack == NULL) ? AMMO_NONE : predatorStatusPointer->current_attack->flag_damage[flagnum];
 
 
55
}
 
 
56
 
 
 
57
static int make_new_predator(STRATEGYBLOCK *sbPtr)
 
 
58
{
 
 
59
    sbPtr->dataptr = malloc(sizeof(PREDATOR_STATUS_BLOCK));
 
 
60
    sbPtr->maintainVisibility = 1;
 
 
61
    sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
62
 
 
 
63
    if(NULL == sbPtr->dataptr)
 
 
64
    {
 
 
65
        RemoveBehaviourStrategy(sbPtr);
 
 
66
        return 0;
 
 
67
    }
 
 
68
 
 
 
69
    {
 
 
70
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
71
        sbPtr->DamageBlock = NpcData->StartingStats;
 
 
72
        sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT;
 
 
73
        sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT;
 
 
74
    }
 
 
75
 
 
 
76
    PREDATOR_STATUS_BLOCK *new_predator = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
77
 
 
 
78
    NPC_InitMovementData(&new_predator->moveData);
 
 
79
    NPC_InitWanderData(&new_predator->wanderData);
 
 
80
 
 
 
81
    new_predator->HModelController.Deltas = NULL;
 
 
82
    new_predator->HModelController.Root_Section = NULL;
 
 
83
    new_predator->HModelController.section_data = NULL;
 
 
84
    new_predator->personalNumber = FastRandom() % 5;
 
 
85
    new_predator->health = predatorCV[new_predator->personalNumber].startingHealth;
 
 
86
    new_predator->behaviourState = PBS_Wandering;
 
 
87
    new_predator->lastState = PBS_Wandering;
 
 
88
 
 
 
89
    new_predator->stateTimer = PRED_FAR_MOVE_TIME;
 
 
90
    new_predator->internalState = 0;
 
 
91
    new_predator->patience = PRED_PATIENCE_TIME;
 
 
92
    new_predator->enableSwap = 0;
 
 
93
    new_predator->enableTaunt = 0;
 
 
94
    new_predator->weaponTarget.vx = 0;
 
 
95
    new_predator->weaponTarget.vy = 0;
 
 
96
    new_predator->weaponTarget.vz = 0;
 
 
97
    new_predator->volleySize = 0;
 
 
98
 
 
 
99
    new_predator->obstruction.environment = 0;
 
 
100
    new_predator->obstruction.destructableObject = 0;
 
 
101
    new_predator->obstruction.otherCharacter = 0;
 
 
102
    new_predator->obstruction.anySingleObstruction = 0;
 
 
103
 
 
 
104
    Initialise_AvoidanceManager(&new_predator->avoidanceManager);
 
 
105
    InitWaypointManager(&new_predator->waypointManager);
 
 
106
 
 
 
107
    new_predator->IAmCrouched = 0;
 
 
108
    new_predator->nearSpeed = predatorCV[new_predator->personalNumber].speed;
 
 
109
    new_predator->GibbFactor = 0;
 
 
110
    new_predator->incidentFlag = 0;
 
 
111
    new_predator->incidentTimer = 0;
 
 
112
 
 
 
113
    new_predator->MeleeWeapon = GetThisNPCPredatorWeapon((FastRandom() & 1) ? PNPCW_Wristblade : PNPCW_Staff);
 
 
114
    new_predator->SecondaryWeapon = (FastRandom() & 1) ? PNPCW_Pistol : PNPCW_Speargun;
 
 
115
    new_predator->Selected_Weapon = new_predator->MeleeWeapon;
 
 
116
 
 
 
117
    new_predator->ChangeToWeapon = PNPCW_End;
 
 
118
    new_predator->current_attack = NULL;
 
 
119
 
 
 
120
    new_predator->closets_target = NULL;
 
 
121
    new_predator->Targets[0] = NULL;
 
 
122
    new_predator->Targets[1] = NULL;
 
 
123
    new_predator->Targets[2] = NULL;
 
 
124
    new_predator->Targets[3] = NULL;
 
 
125
 
 
 
126
    COPY_NAME(new_predator->Target_SBname, Null_Name);
 
 
127
    new_predator->soundHandle = SOUND_NOACTIVEINDEX;
 
 
128
 
 
 
129
    new_predator->CloakStatus = PCLOAK_Off;
 
 
130
    new_predator->CloakingEffectiveness = 0;
 
 
131
    new_predator->CloakTimer = 0;
 
 
132
 
 
 
133
    new_predator->Pred_Laser_Sight.TargetID = 0;
 
 
134
    new_predator->Pred_Laser_Sight.DotIsOnPlayer = 0;
 
 
135
    new_predator->Pred_Laser_Sight.LightSource = null_vec;
 
 
136
    new_predator->Pred_Laser_Sight.Normal[0] = null_vec;
 
 
137
    new_predator->Pred_Laser_Sight.Normal[1] = null_vec;
 
 
138
    new_predator->Pred_Laser_Sight.Normal[2] = null_vec;
 
 
139
 
 
 
140
    new_predator->Pred_Laser_Sight.Position[0] = null_vec;
 
 
141
    new_predator->Pred_Laser_Sight.Position[1] = null_vec;
 
 
142
    new_predator->Pred_Laser_Sight.Position[2] = null_vec;
 
 
143
 
 
 
144
    new_predator->Pred_Laser_On = 0;
 
 
145
    new_predator->Angry = 0;
 
 
146
    new_predator->RifleArrows = (PNPCW_Speargun == new_predator->SecondaryWeapon) ? 20 : 0;
 
 
147
    new_predator->path = -1;
 
 
148
    new_predator->stepnumber = -1;
 
 
149
    new_predator->missionmodule = NULL;
 
 
150
    new_predator->fearmodule = NULL;
 
 
151
 
 
 
152
    //a generated predator won't have a death target
 
 
153
    {
 
 
154
        int i;
 
 
155
        for(i=0;i<SB_NAME_LENGTH;i++)
 
 
156
            new_predator->death_target_ID[i] = 0; 
 
 
157
    }
 
 
158
 
 
 
159
    new_predator->death_target_sbptr = NULL;
 
 
160
    new_predator->death_target_request = 0;
 
 
161
 
 
 
162
    SECTION *root_section = GetNamedHierarchyFromLibrary("hnpcpredator", new_predator->Selected_Weapon->HierarchyName);
 
 
163
 
 
 
164
    if (!root_section || !sbPtr->containingModule)
 
 
165
    {
 
 
166
        RemoveBehaviourStrategy(sbPtr);
 
 
167
        return 0;
 
 
168
    }
 
 
169
 
 
 
170
    Create_HModel(&new_predator->HModelController, root_section);
 
 
171
    InitHModelSequence(&new_predator->HModelController, 0, 0, ONE_FIXED);
 
 
172
 
 
 
173
    if (new_predator->Selected_Weapon->UseElevation)
 
 
174
    {
 
 
175
        DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_predator->HModelController, "Elevation", (int)HMSQT_PredatorStand,
(int)PSSS_Elevation, 0);
 
 
176
        assert(delta);
 
 
177
        delta->timer = 32767;
 
 
178
    }
 
 
179
 
 
 
180
    new_predator->My_Elevation_Section = GetThisSectionData(new_predator->HModelController.section_data,
new_predator->Selected_Weapon->ElevationName);
 
 
181
 
 
 
182
    if (HModelSequence_Exists(&new_predator->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_HitChestFront))
 
 
183
    {
 
 
184
        DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_predator->HModelController, "HitDelta", (int)HMSQT_PredatorStand,
(int)PSSS_HitChestFront, -1);
 
 
185
        assert(delta);
 
 
186
        delta->Playing = 0;
 
 
187
    }
 
 
188
 
 
 
189
    ProveHModel_Far(&new_predator->HModelController, sbPtr);
 
 
190
 
 
 
191
return 1;
 
 
192
}
 
 
193
 
 
 
194
static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus)
 
 
195
{
 
 
196
    switch(predStatus->CloakStatus)
 
 
197
    {
 
 
198
        case PCLOAK_Activating:
 
 
199
        case PCLOAK_On:
 
 
200
        break;
 
 
201
        case PCLOAK_Deactivating:
 
 
202
            predStatus->CloakStatus = PCLOAK_Activating;
 
 
203
        break; /* Don't reset timer. */
 
 
204
        default:
 
 
205
        {
 
 
206
            /* Cloak ust be Off. */
 
 
207
            predStatus->CloakStatus = PCLOAK_Activating;            
 
 
208
            predStatus->CloakTimer = ONE_FIXED-1;
 
 
209
        }
 
 
210
    }
 
 
211
}
 
 
212
 
 
 
213
static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus)
 
 
214
{
 
 
215
    switch(predStatus->CloakStatus)
 
 
216
    {
 
 
217
        case PCLOAK_Deactivating:
 
 
218
        case PCLOAK_Off:
 
 
219
        break;
 
 
220
        case PCLOAK_Activating:
 
 
221
            predStatus->CloakStatus = PCLOAK_Deactivating;
 
 
222
        break; /* Don't reset timer. */
 
 
223
        default:
 
 
224
        {
 
 
225
            /* Cloak must be On. */
 
 
226
            predStatus->CloakStatus = PCLOAK_Deactivating;          
 
 
227
            predStatus->CloakTimer = 0;
 
 
228
        }
 
 
229
    }
 
 
230
}
 
 
231
 
 
 
232
static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus, DYNAMICSBLOCK *dynPtr)
 
 
233
{
 
 
234
    switch(predStatus->CloakStatus)
 
 
235
    {
 
 
236
        case PCLOAK_On:
 
 
237
        case PCLOAK_Off:
 
 
238
        break; /* do nothing */
 
 
239
        case PCLOAK_Activating:
 
 
240
        {
 
 
241
            predStatus->CloakTimer -= NormalFrameTime;
 
 
242
 
 
 
243
            if(predStatus->CloakTimer <= 0)
 
 
244
            {
 
 
245
                predStatus->CloakTimer = 0;
 
 
246
                predStatus->CloakStatus = PCLOAK_On;
 
 
247
            }
 
 
248
        }
 
 
249
        break;
 
 
250
        case PCLOAK_Deactivating:
 
 
251
        {
 
 
252
            predStatus->CloakTimer += NormalFrameTime;
 
 
253
 
 
 
254
            if(predStatus->CloakTimer >= ONE_FIXED)
 
 
255
            {
 
 
256
                predStatus->CloakTimer = 0;
 
 
257
                predStatus->CloakStatus = PCLOAK_Off;
 
 
258
            }
 
 
259
        }
 
 
260
        break;
 
 
261
        default:
 
 
262
            assert(1==0);
 
 
263
            break;
 
 
264
    }
 
 
265
 
 
 
266
    if(predStatus->CloakStatus != PCLOAK_Off)
 
 
267
    {
 
 
268
        VECTORCH velocity;
 
 
269
 
 
 
270
        velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx;
 
 
271
        velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy;
 
 
272
        velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz;
 
 
273
 
 
 
274
        int maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*4, NormalFrameTime);
 
 
275
 
 
 
276
        if (maxPossibleEffectiveness < 0)
 
 
277
            maxPossibleEffectiveness = 0;
 
 
278
 
 
 
279
        predStatus->CloakingEffectiveness += NormalFrameTime;
 
 
280
 
 
 
281
        if (predStatus->CloakingEffectiveness > maxPossibleEffectiveness)
 
 
282
            predStatus->CloakingEffectiveness = maxPossibleEffectiveness;
 
 
283
    }
 
 
284
    else
 
 
285
    {
 
 
286
        predStatus->CloakingEffectiveness -= NormalFrameTime;
 
 
287
 
 
 
288
        if (predStatus->CloakingEffectiveness < 0)
 
 
289
            predStatus->CloakingEffectiveness = 0;
 
 
290
    }
 
 
291
 
 
 
292
    //printf("cloaking effectiveness %d\n", predStatus->CloakingEffectiveness);
 
 
293
}
 
 
294
 
 
 
295
static void PredatorNearDamageShell(STRATEGYBLOCK *sbPtr)
 
 
296
{
 
 
297
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
298
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
299
 
 
 
300
    /* Damage shell! */
 
 
301
    int workingflags = predatorStatusPointer->HModelController.keyframe_flags >> 1;
 
 
302
    int flagnum = 0;
 
 
303
    int dist = VectorDistance(&dynPtr->Position, &predatorStatusPointer->closets_target->DynPtr->Position);
 
 
304
    int dodamage = (dist <= predatorStatusPointer->MeleeWeapon->MaxRange);
 
 
305
    int a = 0;
 
 
306
 
 
 
307
    for (; a < NUM_ATTACKFLAGS; a++)
 
 
308
    {
 
 
309
        if (workingflags & 1)
 
 
310
        {
 
 
311
            /* Oops, check range first. */
 
 
312
            if (dodamage)
 
 
313
            {
 
 
314
                if (predatorStatusPointer->closets_target->DisplayBlock)
 
 
315
                {
 
 
316
                    VECTORCH rel_pos,attack_dir;
 
 
317
 
 
 
318
                    rel_pos.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
319
                    rel_pos.vy = predatorStatusPointer->closets_target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy;
 
 
320
                    rel_pos.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
321
 
 
 
322
                    GetDirectionOfAttack(predatorStatusPointer->closets_target, &rel_pos, &attack_dir);
 
 
323
 
 
 
324
                    if (predatorStatusPointer->closets_target->DisplayBlock->HModelControlBlock)
 
 
325
    HtoHDamageToHModel(predatorStatusPointer->closets_target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage, ONE_FIXED, sbPtr,
&attack_dir);
 
 
326
                    else
 
 
327
    CauseDamageToObject(predatorStatusPointer->closets_target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage,
ONE_FIXED,&attack_dir);
 
 
328
                }
 
 
329
                else
 
 
330
                {
 
 
331
                    VECTORCH rel_pos, attack_dir;
 
 
332
 
 
 
333
                    rel_pos.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
334
                    rel_pos.vy = predatorStatusPointer->closets_target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy;
 
 
335
                    rel_pos.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
336
 
 
 
337
                    GetDirectionOfAttack(predatorStatusPointer->closets_target, &rel_pos, &attack_dir);
 
 
338
 
 
 
339
    CauseDamageToObject(predatorStatusPointer->closets_target, &TemplateAmmo[GetPredatorAttackDamageType(sbPtr, flagnum)].MaxDamage, ONE_FIXED,
&attack_dir);
 
 
340
                }
 
 
341
            }
 
 
342
 
 
 
343
            PlayPredatorSound(0, PSC_Swipe, 0, NULL, &sbPtr->DynPtr->Position);
 
 
344
        }
 
 
345
        /* Prepare next flag. */
 
 
346
        workingflags >>= 1;
 
 
347
        flagnum++;
 
 
348
    }
 
 
349
}
 
 
350
 
 
 
351
static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening)
 
 
352
{
 
 
353
    assert(sbPtr);
 
 
354
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
355
    assert(predatorStatusPointer);
 
 
356
 
 
 
357
    assert(length != 0);
 
 
358
 
 
 
359
    if (tweening <= 0)
 
 
360
        InitHModelSequence(&predatorStatusPointer->HModelController, (int)type, subtype, length);
 
 
361
    else
 
 
362
        InitHModelTweening(&predatorStatusPointer->HModelController, tweening, (int)type,subtype,length, 1);
 
 
363
}
 
 
364
 
 
 
365
static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr)
 
 
366
{
 
 
367
    return (sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT);
 
 
368
}
 
 
369
 
 
 
370
static void CentrePredatorElevation(STRATEGYBLOCK *sbPtr)
 
 
371
{
 
 
372
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
373
 
 
 
374
    if (predatorStatusPointer->Selected_Weapon->UseElevation)
 
 
375
    {
 
 
376
        DELTA_CONTROLLER *elevation_controller = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation");
 
 
377
 
 
 
378
        if (elevation_controller)
 
 
379
        {
 
 
380
            /* You can't be too careful with swap weapon stuff...? */
 
 
381
            elevation_controller->timer = 32767;
 
 
382
        }
 
 
383
    }
 
 
384
}
 
 
385
 
 
 
386
void MakePredatorNear(STRATEGYBLOCK *sbPtr)
 
 
387
{
 
 
388
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
389
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
390
    assert(sbPtr->DisplayBlock == NULL);
 
 
391
 
 
 
392
    DISPLAYBLOCK *dPtr = CreateActiveObject();
 
 
393
 
 
 
394
    if(dPtr == NULL)
 
 
395
        return; /* cannot allocate displayblock, so leave far */
 
 
396
 
 
 
397
    sbPtr->DisplayBlock = dPtr;
 
 
398
    dPtr->ObStrategyBlock = sbPtr;
 
 
399
 
 
 
400
    /* need to initialise positional information in the new display block */ 
 
 
401
    dPtr->ObWorld = dynPtr->Position;
 
 
402
    dPtr->ObEuler = dynPtr->OrientEuler;
 
 
403
    dPtr->ObMat = dynPtr->OrientMat;
 
 
404
 
 
 
405
    predatorStatusPointer->weaponTarget.vx = predatorStatusPointer->weaponTarget.vy = predatorStatusPointer->weaponTarget.vz = 0;                   
 
 
406
    predatorStatusPointer->volleySize = 0;
 
 
407
    predatorStatusPointer->CloakStatus = PCLOAK_Off;
 
 
408
    predatorStatusPointer->CloakingEffectiveness = 0;            
 
 
409
    predatorStatusPointer->CloakTimer = 0;
 
 
410
 
 
 
411
    /* regenerate health (before deciding whether to attack or defend) */
 
 
412
    if(predatorStatusPointer->health < predatorCV[predatorStatusPointer->personalNumber].startingHealth)
 
 
413
    {
 
 
414
        predatorStatusPointer->health += predatorCV[predatorStatusPointer->personalNumber].regenerationUnit;    
 
 
415
 
 
 
416
        if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].startingHealth)
 
 
417
            predatorStatusPointer->health = predatorCV[predatorStatusPointer->personalNumber].startingHealth;
 
 
418
    }
 
 
419
 
 
 
420
    dPtr->HModelControlBlock = &predatorStatusPointer->HModelController;
 
 
421
 
 
 
422
    CentrePredatorElevation(sbPtr);
 
 
423
 
 
 
424
    ProveHModel(dPtr->HModelControlBlock, dPtr);
 
 
425
 
 
 
426
    predatorStatusPointer->IAmCrouched = PredatorShouldBeCrawling(sbPtr);
 
 
427
 
 
 
428
    InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
429
 
 
 
430
    switch(predatorStatusPointer->behaviourState)
 
 
431
    {
 
 
432
        case PBS_Recovering:
 
 
433
        {
 
 
434
            if(predatorStatusPointer->IAmCrouched)
 
 
435
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
436
            else
 
 
437
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
438
        }
 
 
439
        break;
 
 
440
        case PBS_SwapWeapon:
 
 
441
        case PBS_SelfDestruct:
 
 
442
        break;
 
 
443
        default:
 
 
444
        {
 
 
445
            if(predatorStatusPointer->IAmCrouched)
 
 
446
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
447
            else
 
 
448
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
449
        }
 
 
450
    }
 
 
451
}
 
 
452
 
 
 
453
static void CreatePredoBot(VECTORCH *position)
 
 
454
{
 
 
455
    STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourPredator);
 
 
456
 
 
 
457
    if(NULL != sbPtr)
 
 
458
    {
 
 
459
        sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
460
 
 
 
461
        if(sbPtr->DynPtr)
 
 
462
        {
 
 
463
            DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
464
            dynPtr->PrevPosition = dynPtr->Position = *position;
 
 
465
            CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
466
            TransposeMatrixCH(&dynPtr->OrientMat);      
 
 
467
            dynPtr->Mass = 180;
 
 
468
            make_new_predator(sbPtr);
 
 
469
            AssignNewSBName(sbPtr);
 
 
470
        }
 
 
471
        else
 
 
472
        {
 
 
473
            RemoveBehaviourStrategy(sbPtr);
 
 
474
            GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
 
 
475
        }
 
 
476
    }
 
 
477
}
 
 
478
 
 
 
479
void CastPredoBot() 
 
 
480
{
 
 
481
    #define BOTRANGE 2000
 
 
482
 
 
 
483
    VECTORCH position;
 
 
484
 
 
 
485
    position = PlayerStatus.sbptr->DynPtr->Position;
 
 
486
    position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE);              
 
 
487
    position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE);              
 
 
488
    position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE);              
 
 
489
 
 
 
490
    CreatePredoBot(&position);
 
 
491
}
 
 
492
 
 
 
493
/* Patrick 4/7/97 --------------------------------------------------
 
 
494
Basic NPC functions for predator:
 
 
495
Initialiser, visibility management,behaviour shell, and damage functions
 
 
496
---------------------------------------------------------------------*/
 
 
497
void InitPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
 
 
498
{
 
 
499
    TOOLS_DATA_PREDATOR *toolsData = (TOOLS_DATA_PREDATOR *)bhdata; 
 
 
500
 
 
 
501
    {
 
 
502
    int i;
 
 
503
    for(i=0;i<SB_NAME_LENGTH;i++)
 
 
504
        sbPtr->SBname[i] = toolsData->nameID[i];
 
 
505
    }
 
 
506
 
 
 
507
    sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT);
 
 
508
 
 
 
509
    if(sbPtr->DynPtr)
 
 
510
    {
 
 
511
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
512
        dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
 
 
513
        CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
 
 
514
        TransposeMatrixCH(&dynPtr->OrientMat);      
 
 
515
        dynPtr->Mass = 180;
 
 
516
 
 
 
517
        if(make_new_predator(sbPtr))
 
 
518
        {
 
 
519
            PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->dataptr;
 
 
520
 
 
 
521
            predatorStatus->SecondaryWeapon = toolsData->secondary;
 
 
522
            predatorStatus->path = toolsData->path;
 
 
523
            predatorStatus->stepnumber = toolsData->stepnumber;
 
 
524
 
 
 
525
            if ((predatorStatus->path != -1) && (predatorStatus->stepnumber != -1))
 
 
526
                predatorStatus->behaviourState = PBS_Pathfinding;
 
 
527
 
 
 
528
            {
 
 
529
 
 
 
530
            int i;
 
 
531
            for(i=0; i < SB_NAME_LENGTH; i++)
 
 
532
                predatorStatus->death_target_ID[i] = toolsData->death_target_ID[i];
 
 
533
            }
 
 
534
 
 
 
535
            predatorStatus->death_target_request = toolsData->death_target_request;
 
 
536
        }
 
 
537
    }
 
 
538
    else
 
 
539
    {
 
 
540
        RemoveBehaviourStrategy(sbPtr);
 
 
541
    }
 
 
542
}
 
 
543
 
 
 
544
void InitDormantPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
 
 
545
{
 
 
546
    assert(sbPtr);
 
 
547
    DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv = malloc(sizeof(DORMANT_PREDATOR_STATUS_BLOCK));
 
 
548
 
 
 
549
    pred_bhv->bhvr_type = I_BehaviourDormantPredator;
 
 
550
    pred_bhv->toolsData = bhdata;
 
 
551
 
 
 
552
    sbPtr->dataptr = (void*) pred_bhv;
 
 
553
}
 
 
554
 
 
 
555
void ActivateDormantPredator(STRATEGYBLOCK* sbPtr)
 
 
556
{
 
 
557
    assert(sbPtr);
 
 
558
    assert(sbPtr->dataptr);
 
 
559
    DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv = (DORMANT_PREDATOR_STATUS_BLOCK*)sbPtr->dataptr;
 
 
560
    void* toolsData = pred_bhv->toolsData;
 
 
561
 
 
 
562
    //convert this strategyblock to a predator      
 
 
563
    free(pred_bhv);
 
 
564
 
 
 
565
    sbPtr->type = I_BehaviourPredator;
 
 
566
    EnableBehaviourType(sbPtr, toolsData);
 
 
567
 
 
 
568
    //find strategyblock of death target
 
 
569
    {
 
 
570
        PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->dataptr;
 
 
571
        predatorStatus->death_target_sbptr = FindSBWithName(predatorStatus->death_target_ID);
 
 
572
    }
 
 
573
 
 
 
574
    sbPtr->maintainVisibility = 1;
 
 
575
    sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL);
 
 
576
}
 
 
577
 
 
 
578
static void SetPredatorElevation(STRATEGYBLOCK *sbPtr)
 
 
579
{
 
 
580
    VECTORCH gunpos;
 
 
581
 
 
 
582
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
583
 
 
 
584
    if (!predatorStatusPointer->Selected_Weapon->UseElevation)
 
 
585
        return; /* Non elevating weapon. */
 
 
586
 
 
 
587
    /* Get gun position? */
 
 
588
 
 
 
589
    if (predatorStatusPointer->My_Elevation_Section)
 
 
590
        gunpos = predatorStatusPointer->My_Elevation_Section->World_Offset;
 
 
591
    else
 
 
592
        GetTargetingPointOfObject_Far(sbPtr,&gunpos);
 
 
593
 
 
 
594
    /* Aim at weaponTarget. */
 
 
595
 
 
 
596
    int offsetx = predatorStatusPointer->weaponTarget.vx - gunpos.vx;
 
 
597
    int offsety = predatorStatusPointer->weaponTarget.vz - gunpos.vz;
 
 
598
    int offseta = -(predatorStatusPointer->weaponTarget.vy - gunpos.vy);
 
 
599
 
 
 
600
    while( (offsetx > (ONE_FIXED>>2))
 
 
601
        ||(offsety > (ONE_FIXED>>2))
 
 
602
        ||(offseta > (ONE_FIXED>>2))
 
 
603
        ||(offsetx < -(ONE_FIXED>>2))
 
 
604
        ||(offsety < -(ONE_FIXED>>2))
 
 
605
        ||(offseta < -(ONE_FIXED>>2)))
 
 
606
    {
 
 
607
        offsetx >>= 1;
 
 
608
        offsety >>= 1;
 
 
609
        offseta >>= 1;
 
 
610
    }
 
 
611
 
 
 
612
    int offsetz = SqRoot32((offsetx*offsetx)+(offsety*offsety));
 
 
613
    int angle1 = ArcTan(offseta,offsetz);
 
 
614
 
 
 
615
    if (angle1 >= 3072) angle1 -= 4096;
 
 
616
    if (angle1 >= 2048) angle1 = angle1-3072;
 
 
617
    if (angle1 > 1024) angle1 =2048-angle1;
 
 
618
 
 
 
619
    assert(angle1 >= -1024);
 
 
620
    assert(angle1 <= 1024);
 
 
621
 
 
 
622
    DELTA_CONTROLLER *elevation_controller = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
 
 
623
 
 
 
624
    assert(elevation_controller);
 
 
625
 
 
 
626
    {
 
 
627
        int fake_timer=1024-angle1;
 
 
628
        fake_timer <<= 5;
 
 
629
 
 
 
630
        if (fake_timer > 65536)
 
 
631
            fake_timer = 65535;
 
 
632
 
 
 
633
        assert(fake_timer >= 0);
 
 
634
        assert(fake_timer < 65536);
 
 
635
 
 
 
636
        elevation_controller->timer = fake_timer;
 
 
637
    }
 
 
638
}
 
 
639
 
 
 
640
static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
 
 
641
{
 
 
642
    assert(targetModule);
 
 
643
 
 
 
644
    NPC_TARGETMODULESTATUS targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule, 0);
 
 
645
 
 
 
646
    switch(targetStatus)
 
 
647
    {
 
 
648
        case NPCTM_NoEntryPoint:
 
 
649
            /* do nothing: can't get in. reset lastVisitedModule to avoid getting 
 
 
650
            stuck in a conceptual dead end (?)*/
 
 
651
        case NPCTM_LiftTeleport:
 
 
652
        case NPCTM_LiftDoorOpen:
 
 
653
        case NPCTM_LiftDoorNotOpen:
 
 
654
            FarNpc_FlipAround(sbPtr);
 
 
655
        break;
 
 
656
        case NPCTM_NormalRoom:
 
 
657
        case NPCTM_AirDuct:
 
 
658
        case NPCTM_SecurityDoorOpen:
 
 
659
        case NPCTM_ProxDoorOpen:
 
 
660
            LocateFarNPCInAIModule(sbPtr, targetModule);
 
 
661
        break;
 
 
662
        case NPCTM_ProxDoorNotOpen:
 
 
663
        {
 
 
664
            /* trigger the door, and set timer to quick so we can catch the door when it's open */
 
 
665
            MODULE *renderModule = *(targetModule->m_module_ptrs);
 
 
666
            /* trigger the door, and set timer to quick so we can catch the door when it's open */
 
 
667
            ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->dataptr)->alienTrigger = 1;
 
 
668
        }
 
 
669
        break;
 
 
670
        case NPCTM_SecurityDoorNotOpen:
 
 
671
        {
 
 
672
            MODULE *renderModule = *(targetModule->m_module_ptrs);
 
 
673
            /* do some door opening stuff here. Door should stay open for long enough
 
 
674
            for us to catch it open next time */
 
 
675
            RequestState(renderModule->m_sbptr, 1, 0);
 
 
676
        }
 
 
677
        break;
 
 
678
        default:
 
 
679
        {
 
 
680
            assert(1==0);
 
 
681
            break;
 
 
682
        }
 
 
683
    }
 
 
684
}
 
 
685
 
 
 
686
static void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr)
 
 
687
{
 
 
688
    VECTORCH offset;
 
 
689
    int animfactor;
 
 
690
 
 
 
691
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
692
 
 
 
693
    offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx;
 
 
694
    offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy;
 
 
695
    offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz;
 
 
696
 
 
 
697
    /* ...compute speed factor... */
 
 
698
    int speed = Magnitude(&offset);
 
 
699
 
 
 
700
    if ((speed < (MUL_FIXED(NormalFrameTime, 50))) && !predatorStatusPointer->HModelController.Tweening)
 
 
701
    {
 
 
702
        /* Not moving much, are we?  Be stationary! */
 
 
703
 
 
 
704
        #ifdef SHOWPREDOSTATS
 
 
705
            printf("Forced stationary animation!\n");
 
 
706
        #endif
 
 
707
 
 
 
708
           if(predatorStatusPointer->IAmCrouched)
 
 
709
           {
 
 
710
            if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorCrouch)
 
 
711
                ||(predatorStatusPointer->HModelController.Sub_Sequence != PCrSS_Standard))
 
 
712
            {
 
 
713
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,-1,(ONE_FIXED>>3));
 
 
714
            }
 
 
715
        }
 
 
716
        else
 
 
717
        {
 
 
718
            if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorStand)
 
 
719
             || (predatorStatusPointer->HModelController.Sub_Sequence != PSSS_Standard))
 
 
720
            {
 
 
721
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,-1,(ONE_FIXED>>3));
 
 
722
                 // Alex: this is a bit of a fudge
 
 
723
                (predatorStatusPointer->avoidanceManager.avoidanceDirection).vx = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vx;
 
 
724
                (predatorStatusPointer->avoidanceManager.avoidanceDirection).vz = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vz;
 
 
725
            }
 
 
726
        }
 
 
727
    return;
 
 
728
    }
 
 
729
 
 
 
730
    speed = DIV_FIXED(speed, NormalFrameTime);
 
 
731
 
 
 
732
    if (!speed)
 
 
733
        animfactor = ONE_FIXED;
 
 
734
    else
 
 
735
        animfactor = DIV_FIXED(625,speed); // Was 512!  Difference to correct for rounding down...
 
 
736
 
 
 
737
    assert(animfactor > 0);
 
 
738
 
 
 
739
    #ifdef SHOWPREDOSTATS
 
 
740
        printf("Anim Factor %d, Tweening %d, Speed %d\n",animfactor,predatorStatusPointer->HModelController.Tweening,speed);
 
 
741
    #endif
 
 
742
 
 
 
743
    int walking = 0;
 
 
744
 
 
 
745
    if (HModelSequence_Exists(&predatorStatusPointer->HModelController, HMSQT_PredatorRun, PRSS_Walk))
 
 
746
    {
 
 
747
        /* Are we currently walking? */
 
 
748
        if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun)
 
 
749
        && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Walk))
 
 
750
        {
 
 
751
            if (speed < PRED_WALKING_SPEED_MAX)
 
 
752
                walking = 1;
 
 
753
        }
 
 
754
        else
 
 
755
        {
 
 
756
            if (speed < PRED_WALKING_SPEED_MIN)
 
 
757
                walking = 1;
 
 
758
        }
 
 
759
    }
 
 
760
 
 
 
761
    /* Start animation? */
 
 
762
    if (!predatorStatusPointer->HModelController.Tweening)
 
 
763
    {
 
 
764
        /* If still tweening, probably best to leave it alone... */
 
 
765
 
 
 
766
        if (PredatorShouldBeCrawling(sbPtr))
 
 
767
        {
 
 
768
            predatorStatusPointer->IAmCrouched = 1;
 
 
769
 
 
 
770
            /* Only one possible sequence here. */
 
 
771
            if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorCrawl)
 
 
772
            || (predatorStatusPointer->HModelController.Sub_Sequence != PCSS_Standard))
 
 
773
            {
 
 
774
                SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
775
            }
 
 
776
 
 
 
777
        }
 
 
778
        else if (!walking)
 
 
779
        {
 
 
780
            predatorStatusPointer->IAmCrouched = 0;
 
 
781
 
 
 
782
            /* Are we doing the right anim? */
 
 
783
            if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorRun)
 
 
784
            || (predatorStatusPointer->HModelController.Sub_Sequence != PRSS_Standard))
 
 
785
            {
 
 
786
                /* If we're currently walking, tween over. */
 
 
787
                if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun)
 
 
788
                    && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Walk))
 
 
789
                {
 
 
790
                    InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun,
 
 
791
                        PRSS_Standard,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1);
 
 
792
                }
 
 
793
                else
 
 
794
                {
 
 
795
                    SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
 
 
796
                }
 
 
797
            }
 
 
798
        }
 
 
799
        else
 
 
800
        {
 
 
801
            predatorStatusPointer->IAmCrouched = 0;
 
 
802
 
 
 
803
            /* Are we doing the right anim? */
 
 
804
            if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorRun)
 
 
805
                ||(predatorStatusPointer->HModelController.Sub_Sequence != PRSS_Walk))
 
 
806
            {
 
 
807
                /* If we're currently running, tween over. */
 
 
808
                if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun)
 
 
809
                && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Standard))
 
 
810
                {
 
 
811
                    InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun,
 
 
812
                        PRSS_Walk,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1);
 
 
813
                }
 
 
814
                else
 
 
815
                {
 
 
816
                    SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Walk,ONE_FIXED,(ONE_FIXED>>3));
 
 
817
                }
 
 
818
            }
 
 
819
        }
 
 
820
    }
 
 
821
 
 
 
822
    if (!predatorStatusPointer->HModelController.Tweening)
 
 
823
        HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor);
 
 
824
}
 
 
825
 
 
 
826
static void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr)
 
 
827
{
 
 
828
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
829
 
 
 
830
    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
831
    NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
832
    InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
833
    predatorStatusPointer->volleySize = 0;
 
 
834
    predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
835
    predatorStatusPointer->behaviourState = PBS_Attacking;
 
 
836
    predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;                                                         
 
 
837
    predatorStatusPointer->Pred_Laser_On = 0;
 
 
838
    predatorStatusPointer->internalState = 0;
 
 
839
    /* Become patient again. */
 
 
840
    predatorStatusPointer->patience = PRED_PATIENCE_TIME;
 
 
841
 
 
 
842
    switch(predatorStatusPointer->Selected_Weapon->id)
 
 
843
    {
 
 
844
        case PNPCW_Wristblade:
 
 
845
        {
 
 
846
            ATTACK_DATA *thisAttack = GetWristbladeAttackSequence(&predatorStatusPointer->HModelController,0, predatorStatusPointer->IAmCrouched);
 
 
847
            SetPredatorAnimationSequence(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime);
 
 
848
            predatorStatusPointer->current_attack = thisAttack;
 
 
849
        }
 
 
850
        break;
 
 
851
        case PNPCW_Staff:
 
 
852
        {
 
 
853
            ATTACK_DATA *thisAttack = GetPredStaffAttackSequence(&predatorStatusPointer->HModelController,0, predatorStatusPointer->IAmCrouched);
 
 
854
            SetPredatorAnimationSequence(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime);
 
 
855
            predatorStatusPointer->current_attack = thisAttack;
 
 
856
        }
 
 
857
        break;
 
 
858
        default:    
 
 
859
        {
 
 
860
            if(predatorStatusPointer->IAmCrouched)
 
 
861
                SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorCrouch, PCrSS_Attack_Primary, -1, (ONE_FIXED>>3));        
 
 
862
            else
 
 
863
                SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Attack_Primary, -1, (ONE_FIXED>>3));
 
 
864
        }
 
 
865
    }
 
 
866
}
 
 
867
 
 
 
868
static void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) 
 
 
869
{
 
 
870
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
871
 
 
 
872
    assert(predatorStatusPointer->path != -1);
 
 
873
    assert(predatorStatusPointer->stepnumber != -1);
 
 
874
 
 
 
875
    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
876
    NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
877
    InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
878
    predatorStatusPointer->volleySize = 0;
 
 
879
    predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
880
    predatorStatusPointer->behaviourState = PBS_Pathfinding;
 
 
881
    predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;                                                         
 
 
882
    predatorStatusPointer->Pred_Laser_On = 0;
 
 
883
}
 
 
884
 
 
 
885
static void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr) 
 
 
886
{
 
 
887
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
888
    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
889
    NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
890
    InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
891
    predatorStatusPointer->volleySize = 0;
 
 
892
    predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
893
    predatorStatusPointer->behaviourState = PBS_Wandering;
 
 
894
    predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;                                                         
 
 
895
    predatorStatusPointer->Pred_Laser_On = 0;
 
 
896
}
 
 
897
 
 
 
898
static int Predator_TargetFilter(STRATEGYBLOCK *candidate, STRATEGYBLOCK *sbPtr) 
 
 
899
{
 
 
900
    switch (candidate->type)
 
 
901
    {
 
 
902
        case I_BehaviourAlien:
 
 
903
        case I_BehaviourMarine:
 
 
904
        case I_BehaviourMarinePlayer:
 
 
905
        case I_BehaviourAlienPlayer:
 
 
906
        case I_BehaviourAutoGun:
 
 
907
        case I_BehaviourFaceHugger:
 
 
908
        case I_BehaviourXenoborg:
 
 
909
        case I_BehaviourQueenAlien:
 
 
910
            return 1;
 
 
911
        case I_BehaviourRocket:
 
 
912
        case I_BehaviourPulseGrenade:
 
 
913
        case I_BehaviourGrenade:
 
 
914
        case I_BehaviourFlare:
 
 
915
        case I_BehaviourProximityGrenade:
 
 
916
        case I_BehaviourFragmentationGrenade:
 
 
917
        case I_BehaviourFrisbee:
 
 
918
        case I_BehaviourMolotov:
 
 
919
        {
 
 
920
            PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
921
            return (PNPCW_PlasmaCaster == predatorStatusPointer->Selected_Weapon->id);
 
 
922
        }
 
 
923
        //case I_BehaviourSpeargunBolt:
 
 
924
        //case I_BehaviourPlacedLight: // ???
 
 
925
        case I_BehaviourNetGhost:
 
 
926
        {
 
 
927
            NETGHOSTDATABLOCK *dataptr = candidate->dataptr;
 
 
928
 
 
 
929
            switch (dataptr->type)
 
 
930
            {
 
 
931
                case I_BehaviourMarinePlayer:
 
 
932
                case I_BehaviourAlienPlayer:
 
 
933
                case I_BehaviourPredatorPlayer:
 
 
934
                    //return 1;
 
 
935
                    return 0;
 
 
936
                default:
 
 
937
                    return 0;
 
 
938
            }
 
 
939
        }
 
 
940
        case I_BehaviourDummy:
 
 
941
        {
 
 
942
            DUMMY_STATUS_BLOCK *dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->dataptr);    
 
 
943
            assert(dummyStatusPointer);
 
 
944
            switch (dummyStatusPointer->PlayerType)
 
 
945
            {
 
 
946
                case I_Marine:
 
 
947
                case I_Alien:
 
 
948
                    return 1;
 
 
949
                default:
 
 
950
                    return 0;
 
 
951
            }
 
 
952
        }
 
 
953
        break;
 
 
954
        default:
 
 
955
            return 0;
 
 
956
    }
 
 
957
}
 
 
958
 
 
 
959
static STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *sbPtr) 
 
 
960
{
 
 
961
    int neardist = ONE_FIXED;
 
 
962
    STRATEGYBLOCK *nearest = NULL;
 
 
963
    int a;
 
 
964
    assert(sbPtr);
 
 
965
    int target_count=0;
 
 
966
    int wraps = 0;
 
 
967
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
968
 
 
 
969
    MODULE *dmod = ModuleFromPosition(&sbPtr->DynPtr->Position, PlayerStatus.sbptr->containingModule);
 
 
970
    assert(dmod);
 
 
971
 
 
 
972
    MATRIXCH WtoL = sbPtr->DynPtr->OrientMat;
 
 
973
    TransposeMatrixCH(&WtoL);
 
 
974
 
 
 
975
    for (a=0; a < NumActiveStBlocks; a++)
 
 
976
    {
 
 
977
        STRATEGYBLOCK *candidate = ActiveStBlockList[a];
 
 
978
 
 
 
979
        if ((candidate != sbPtr) && candidate->DynPtr)
 
 
980
        {
 
 
981
            VECTORCH offset;
 
 
982
            /* Arc reject. */
 
 
983
 
 
 
984
            offset.vx = sbPtr->DynPtr->Position.vx - candidate->DynPtr->Position.vx;
 
 
985
            offset.vy = sbPtr->DynPtr->Position.vy - candidate->DynPtr->Position.vy;
 
 
986
            offset.vz = sbPtr->DynPtr->Position.vz - candidate->DynPtr->Position.vz;
 
 
987
 
 
 
988
            RotateVector(&offset, &WtoL);
 
 
989
 
 
 
990
            if (offset.vz <= 0)
 
 
991
            {
 
 
992
                if (Predator_TargetFilter(candidate, sbPtr))
 
 
993
                {
 
 
994
                    int dist = Approximate3dMagnitude(&offset);
 
 
995
 
 
 
996
                    if (dist < neardist)
 
 
997
                    {
 
 
998
                        /* Check visibility? */
 
 
999
                        if (candidate->DisplayBlock)
 
 
1000
                        {
 
 
1001
                            /* Near case. */
 
 
1002
                            if (!NPC_IsDead(candidate) && NPCCanSeeTarget(sbPtr, candidate))
 
 
1003
                            {
 
 
1004
                                nearest = candidate;
 
 
1005
                                neardist = dist;
 
 
1006
                                predatorStatusPointer->Targets[target_count] = candidate;
 
 
1007
 
 
 
1008
                                if(++target_count > NUMBER_OF_TRACKED_TARGETS)
 
 
1009
                                {
 
 
1010
                                    target_count = 0;
 
 
1011
                                    wraps++;
 
 
1012
                                }
 
 
1013
                            }
 
 
1014
                        }
 
 
1015
                        else
 
 
1016
                        {
 
 
1017
                            if (!NPC_IsDead(candidate) && IsModuleVisibleFromModule(dmod, candidate->containingModule))
 
 
1018
                            {
 
 
1019
                                nearest = candidate;
 
 
1020
                                neardist = dist;
 
 
1021
                                predatorStatusPointer->Targets[target_count] = candidate;
 
 
1022
 
 
 
1023
                                if(++target_count > NUMBER_OF_TRACKED_TARGETS)
 
 
1024
                                {
 
 
1025
                                    target_count = 0;
 
 
1026
                                    wraps++;
 
 
1027
                                }
 
 
1028
                            }
 
 
1029
                        }
 
 
1030
                    }
 
 
1031
                }
 
 
1032
            }
 
 
1033
        }
 
 
1034
    }
 
 
1035
 
 
 
1036
if(0)
 
 
1037
{
 
 
1038
    if (!wraps)
 
 
1039
    {
 
 
1040
        target_count = NUMBER_OF_TRACKED_TARGETS;
 
 
1041
 
 
 
1042
        int j=a;
 
 
1043
 
 
 
1044
        for (; j < a; j++)
 
 
1045
            predatorStatusPointer->Targets[j] = NULL;
 
 
1046
    }
 
 
1047
 
 
 
1048
    a = 0;
 
 
1049
    while (predatorStatusPointer->Targets[a])
 
 
1050
    {
 
 
1051
        printf("PREDATROR TAGET %d\n", predatorStatusPointer->Targets[a]->type);
 
 
1052
    a++;
 
 
1053
    }
 
 
1054
}
 
 
1055
 
 
 
1056
return nearest;
 
 
1057
}
 
 
1058
 
 
 
1059
static void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr)
 
 
1060
{
 
 
1061
    int rand = FastRandom();
 
 
1062
    int pitch = (rand & 255) - 128;
 
 
1063
 
 
 
1064
    assert(sbPtr);
 
 
1065
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1066
    assert(predatorStatusPointer);
 
 
1067
 
 
 
1068
    if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
1069
        PlayPredatorSound(0, PSC_Scream_General, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
1070
}
 
 
1071
 
 
 
1072
static void predator_change_behaviour(STRATEGYBLOCK *sbPtr)
 
 
1073
{
 
 
1074
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1075
    assert(predatorStatusPointer);
 
 
1076
 
 
 
1077
    predatorStatusPointer->patience = PRED_PATIENCE_TIME;
 
 
1078
    predatorStatusPointer->volleySize = 0;
 
 
1079
 
 
 
1080
    switch(predatorStatusPointer->behaviourState)
 
 
1081
    {
 
 
1082
        case PBS_Withdrawing:
 
 
1083
        {
 
 
1084
            /* Force re-evaluation of priorities. */
 
 
1085
            predatorStatusPointer->missionmodule = NULL;
 
 
1086
            predatorStatusPointer->fearmodule = NULL;
 
 
1087
        } // no break
 
 
1088
        case PBS_Engaging:
 
 
1089
        case PBS_Hunting:
 
 
1090
        case PBS_Returning:
 
 
1091
        {
 
 
1092
            NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1093
            NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
1094
            InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
1095
            predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
1096
            predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;                                                         
 
 
1097
        }
 
 
1098
        break;
 
 
1099
        case PBS_Wandering:
 
 
1100
        {
 
 
1101
            if ((predatorStatusPointer->path != -1) && (predatorStatusPointer->stepnumber != -1))
 
 
1102
            {
 
 
1103
                /* Pathfinding mission. */
 
 
1104
                switch(predatorStatusPointer->behaviourState)
 
 
1105
                {
 
 
1106
                    case PBS_Returning:
 
 
1107
                    case PBS_Pathfinding:
 
 
1108
                        Predator_Enter_Wander_State(sbPtr); /* A real order. */
 
 
1109
                    break;
 
 
1110
                    default:
 
 
1111
                        Predator_Enter_Pathfinder_State(sbPtr);
 
 
1112
                }
 
 
1113
            }
 
 
1114
            else
 
 
1115
            {
 
 
1116
                Predator_Enter_Wander_State(sbPtr);
 
 
1117
            }
 
 
1118
        }
 
 
1119
        break;
 
 
1120
        case PBS_Avoidance:
 
 
1121
        {
 
 
1122
            NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1123
            NPCGetAvoidanceDirection(sbPtr, &predatorStatusPointer->moveData.avoidanceDirn, &predatorStatusPointer->obstruction);
 
 
1124
            InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
1125
            predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
1126
            predatorStatusPointer->stateTimer = NPC_AVOIDTIME;
 
 
1127
        }
 
 
1128
        break;
 
 
1129
        case PBS_Recovering:
 
 
1130
        {
 
 
1131
            NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1132
            NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
1133
            InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
1134
            predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
1135
 
 
 
1136
            if (predatorStatusPointer->Selected_Weapon->id != PNPCW_Medicomp)
 
 
1137
            {
 
 
1138
                predatorStatusPointer->ChangeToWeapon = PNPCW_Medicomp;
 
 
1139
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
1140
                predatorStatusPointer->stateTimer = 0; /* Just starting. */
 
 
1141
                predatorStatusPointer->IAmCrouched = ((FastRandom() & 65535) > 32767/2);
 
 
1142
 
 
 
1143
                if(predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
1144
                    PredatorCloakOn(predatorStatusPointer);
 
 
1145
 
 
 
1146
                predator_change_behaviour(sbPtr);
 
 
1147
            }
 
 
1148
            else
 
 
1149
            {
 
 
1150
                predatorStatusPointer->behaviourState = PBS_Recovering;
 
 
1151
                predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;                                                         
 
 
1152
 
 
 
1153
                if(predatorStatusPointer->IAmCrouched)
 
 
1154
                    SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorCrouch, PCrSS_Attack_Primary, ONE_FIXED,(ONE_FIXED>>3));         
 
 
1155
                else
 
 
1156
                    SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Attack_Primary, ONE_FIXED,(ONE_FIXED>>3));
 
 
1157
            }
 
 
1158
        }
 
 
1159
        break;
 
 
1160
        case PBS_SwapWeapon:
 
 
1161
        {
 
 
1162
            /* What are we swapping to? */
 
 
1163
            if (predatorStatusPointer->ChangeToWeapon == PNPCW_End)
 
 
1164
            {
 
 
1165
                /* Use default. */
 
 
1166
                if (predatorStatusPointer->Selected_Weapon == predatorStatusPointer->MeleeWeapon)
 
 
1167
                    predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->SecondaryWeapon;
 
 
1168
                else
 
 
1169
                {
 
 
1170
                    predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id;
 
 
1171
 
 
 
1172
                    if ((FastRandom() & 65535) > 32767)
 
 
1173
                    if (PCLOAK_On == predatorStatusPointer->CloakStatus)
 
 
1174
                        PredatorCloakOff(predatorStatusPointer);
 
 
1175
                }
 
 
1176
            }
 
 
1177
 
 
 
1178
            NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1179
            NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
1180
            InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
1181
            predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
1182
            predatorStatusPointer->stateTimer = 0; /* Just starting. */
 
 
1183
            predatorStatusPointer->enableSwap = 0;
 
 
1184
        }
 
 
1185
        break;
 
 
1186
        case PBS_Pathfinding:
 
 
1187
            Predator_Enter_Pathfinder_State(sbPtr);
 
 
1188
        default:
 
 
1189
        break;
 
 
1190
    }
 
 
1191
}
 
 
1192
 
 
 
1193
 
 
 
1194
void PredatorBehaviour(STRATEGYBLOCK *sbPtr)
 
 
1195
{
 
 
1196
    int predatorIsNear = 0;
 
 
1197
    char *descriptor;
 
 
1198
 
 
 
1199
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
1200
    //sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1201
 
 
 
1202
    if(sbPtr->DisplayBlock) 
 
 
1203
    {
 
 
1204
        //assert(ModuleCurrVisArray[sbPtr->containingModule->m_index]);                                            
 
 
1205
        predatorIsNear = 1;
 
 
1206
    }
 
 
1207
 
 
 
1208
    if (sbPtr->DamageBlock.IsOnFire)
 
 
1209
    {
 
 
1210
        CauseDamageToObject(sbPtr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL);
 
 
1211
 
 
 
1212
        if (sbPtr->type == I_BehaviourCorpse)
 
 
1213
            return; /* Gettin' out of here... */
 
 
1214
 
 
 
1215
        if (predatorStatusPointer->incidentFlag && ((FastRandom() & 65535) < 32767))
 
 
1216
            sbPtr->DamageBlock.IsOnFire = 0;
 
 
1217
    }
 
 
1218
 
 
 
1219
    InitWaypointSystem(0);
 
 
1220
    predatorStatusPointer->Pred_Laser_On = 0;
 
 
1221
 
 
 
1222
    //DoPredatorCloak(predatorStatusPointer, sbPtr->DynPtr);
 
 
1223
 
 
 
1224
    predatorStatusPointer->incidentFlag = 0;
 
 
1225
    predatorStatusPointer->incidentTimer -= NormalFrameTime;
 
 
1226
 
 
 
1227
    if (predatorStatusPointer->incidentTimer < 0)
 
 
1228
    {
 
 
1229
        predatorStatusPointer->incidentFlag = 1;
 
 
1230
        predatorStatusPointer->incidentTimer = 32767 + (FastRandom() & 65535);
 
 
1231
    }
 
 
1232
 
 
 
1233
    switch(predatorStatusPointer->behaviourState)
 
 
1234
    {
 
 
1235
        case PBS_Taunting:
 
 
1236
        {
 
 
1237
            if (predatorIsNear)
 
 
1238
                CentrePredatorElevation(sbPtr);
 
 
1239
            else
 
 
1240
                ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr);
 
 
1241
 
 
 
1242
            if(HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))
 
 
1243
            {
 
 
1244
                predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
1245
                predator_change_behaviour(sbPtr);
 
 
1246
            }
 
 
1247
        }
 
 
1248
        return;
 
 
1249
        case PBS_Recovering:
 
 
1250
        {
 
 
1251
            descriptor = "Recovering";
 
 
1252
 
 
 
1253
            if (predatorIsNear)
 
 
1254
                CentrePredatorElevation(sbPtr);
 
 
1255
            else
 
 
1256
                ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr);
 
 
1257
 
 
 
1258
            {
 
 
1259
                /* Stay where you are and regain health. */
 
 
1260
 
 
 
1261
                const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
1262
 
 
 
1263
                if (sbPtr->DamageBlock.Health > 0)
 
 
1264
                {
 
 
1265
                    int health_increment = DIV_FIXED((NpcData->StartingStats.Health * NormalFrameTime),  PRED_REGEN_TIME);
 
 
1266
 
 
 
1267
                    sbPtr->DamageBlock.Health += health_increment;
 
 
1268
 
 
 
1269
                    if (sbPtr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT))
 
 
1270
                        sbPtr->DamageBlock.Health = (NpcData->StartingStats.Health << ONE_FIXED_SHIFT);
 
 
1271
 
 
 
1272
                    HModel_Regen(&predatorStatusPointer->HModelController, PRED_REGEN_TIME);
 
 
1273
                }
 
 
1274
 
 
 
1275
                if (sbPtr->DamageBlock.Health == (NpcData->StartingStats.Health << ONE_FIXED_SHIFT))
 
 
1276
                {
 
 
1277
                    DoPredatorRandomSound(sbPtr);
 
 
1278
                    predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
1279
                    predator_change_behaviour(sbPtr);
 
 
1280
                }
 
 
1281
            }
 
 
1282
        }
 
 
1283
        return;
 
 
1284
        case PBS_SelfDestruct:
 
 
1285
        {
 
 
1286
            /* No elevation should be present. */
 
 
1287
 
 
 
1288
            if (!sbPtr->DisplayBlock)
 
 
1289
            {
 
 
1290
                /* We're far... do the timer! */
 
 
1291
                ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr);
 
 
1292
            }
 
 
1293
 
 
 
1294
            /* And if we're playing Laugh, we'd better laugh... */
 
 
1295
 
 
 
1296
            if (PCrSS_Det_Prog == predatorStatusPointer->HModelController.Sub_Sequence)
 
 
1297
            {
 
 
1298
                if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))
 
 
1299
                {
 
 
1300
                    InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED >> 2), HMSQT_PredatorCrouch, PCrSS_Det_Laugh, -1, 0);
 
 
1301
                }
 
 
1302
                else if (predatorStatusPointer->HModelController.keyframe_flags & 1)
 
 
1303
                {
 
 
1304
                    predatorStatusPointer->stateTimer = PRED_SELF_DESTRUCT_TIMER;
 
 
1305
                    predatorStatusPointer->internalState = 1;
 
 
1306
                }
 
 
1307
            }
 
 
1308
            else
 
 
1309
            {
 
 
1310
                predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
1311
 
 
 
1312
                if (predatorStatusPointer->stateTimer <= 0)
 
 
1313
                {
 
 
1314
                    predatorStatusPointer->internalState = 2;
 
 
1315
                    predatorStatusPointer->GibbFactor = ONE_FIXED;
 
 
1316
                    Sound_Play(SID_NICE_EXPLOSION, "d", &sbPtr->DynPtr->Position);
 
 
1317
                    MakeVolumetricExplosionAt(&sbPtr->DynPtr->Position, EXPLOSION_SADAR_BLAST);
 
 
1318
                }
 
 
1319
            }
 
 
1320
        }
 
 
1321
        return;
 
 
1322
        default:
 
 
1323
        break;
 
 
1324
 
 
 
1325
    }
 
 
1326
 
 
 
1327
    if (predatorStatusPointer->closets_target == NULL)
 
 
1328
    {
 
 
1329
        if (predatorIsNear || predatorStatusPointer->incidentFlag)
 
 
1330
        {
 
 
1331
            predatorStatusPointer->closets_target = Predator_GetNewTarget(sbPtr);
 
 
1332
 
 
 
1333
            if (predatorStatusPointer->closets_target)
 
 
1334
            {
 
 
1335
                VECTORCH orientationDirn;
 
 
1336
                NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
1337
                orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
1338
                orientationDirn.vy = 0;
 
 
1339
                orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
1340
                NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
1341
 
 
 
1342
                COPY_NAME(predatorStatusPointer->Target_SBname, predatorStatusPointer->closets_target->SBname);
 
 
1343
 
 
 
1344
                int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position);
 
 
1345
 
 
 
1346
                if(range < predatorStatusPointer->Selected_Weapon->MaxRange)
 
 
1347
                {
 
 
1348
                    if (predatorStatusPointer->MeleeWeapon == predatorStatusPointer->Selected_Weapon)
 
 
1349
                    {
 
 
1350
                        switch(predatorStatusPointer->closets_target->type)
 
 
1351
                        {
 
 
1352
                            case I_BehaviourMarine:
 
 
1353
                            case I_BehaviourMarinePlayer:
 
 
1354
                                if ((FastRandom() & 65535) < 32767)
 
 
1355
                                    break;
 
 
1356
                            default:
 
 
1357
                                if (PCLOAK_On == predatorStatusPointer->CloakStatus)
 
 
1358
                                    PredatorCloakOff(predatorStatusPointer);
 
 
1359
                        }
 
 
1360
                    }
 
 
1361
                }
 
 
1362
            }
 
 
1363
        }
 
 
1364
    }
 
 
1365
    else
 
 
1366
    {
 
 
1367
        if (NPC_IsDead(predatorStatusPointer->closets_target) || !NAME_ISEQUAL(predatorStatusPointer->closets_target->SBname,
predatorStatusPointer->Target_SBname))
 
 
1368
        {
 
 
1369
            predatorStatusPointer->closets_target = NULL;
 
 
1370
        }
 
 
1371
        else // valid target
 
 
1372
        {
 
 
1373
            if(NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target))
 
 
1374
            {
 
 
1375
                VECTORCH orientationDirn;
 
 
1376
                NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
1377
                orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
1378
                orientationDirn.vy = 0;
 
 
1379
                orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
1380
 
 
 
1381
                if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE))
 
 
1382
                {
 
 
1383
                    int distance_to_target = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position,
&sbPtr->DynPtr->Position);
 
 
1384
 
 
 
1385
                    if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange)
 
 
1386
                    {
 
 
1387
                        if (predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
1388
                            PredatorCloakOn(predatorStatusPointer);
 
 
1389
 
 
 
1390
                        PredatorHandleMovingAnimation(sbPtr);
 
 
1391
 
 
 
1392
                        const PREDATOR_WEAPON_DATA* test_we = GetThisNPCPredatorWeapon(PNPCW_PlasmaCaster);
 
 
1393
 
 
 
1394
                        if(distance_to_target > test_we->MaxRange/2)
 
 
1395
                        {
 
 
1396
                            predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
1397
                            //Predator_Enter_Swapping_State(sbPtr);
 
 
1398
                            predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
1399
                            predatorStatusPointer->enableSwap = 0;
 
 
1400
                        }
 
 
1401
 
 
 
1402
                        VECTORCH velocityDirection = {0,0,0};
 
 
1403
                        VECTORCH targetPosition; 
 
 
1404
                        /* See which way we want to go. */
 
 
1405
                        {
 
 
1406
                            AIMODULE *targetModule = NULL;
 
 
1407
 
 
 
1408
                            MODULE *tcm = predatorStatusPointer->closets_target->containingModule ?
 
 
1409
                                    predatorStatusPointer->closets_target->containingModule :
 
 
1410
                                    ModuleFromPosition(&predatorStatusPointer->closets_target->DynPtr->Position, sbPtr->containingModule);
 
 
1411
 
 
 
1412
                            if (tcm)
 
 
1413
                                targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, tcm->m_aimodule, 7, 0);
 
 
1414
 
 
 
1415
                            if (targetModule == sbPtr->containingModule->m_aimodule)
 
 
1416
                            {
 
 
1417
                                int targetIsAirduct = 0;
 
 
1418
                                /* Try going for it, we still can't see them. */
 
 
1419
                                NPCGetMovementTarget(sbPtr, predatorStatusPointer->closets_target, &targetPosition, &targetIsAirduct, 0);
 
 
1420
                                NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition, &predatorStatusPointer->waypointManager);
 
 
1421
                            }
 
 
1422
                            else if (!targetModule)
 
 
1423
                            {
 
 
1424
                                /* Must be inaccessible. */
 
 
1425
                                #ifdef SHOWPREDOSTATS
 
 
1426
                                if (predatorStatusPointer->closets_target->containingModule)
 
 
1427
                                    printf("I can see you, but I can't get there!\n");
 
 
1428
                                else
 
 
1429
                                    printf("Hey, you've got no Containing Module!\n");
 
 
1430
                                #endif
 
 
1431
                            }
 
 
1432
                            else
 
 
1433
                            {
 
 
1434
                                FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
1435
 
 
 
1436
                                if (thisEp)
 
 
1437
                                {
 
 
1438
                                    predatorStatusPointer->wanderData.worldPosition = thisEp->position;
 
 
1439
                                    predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx;
 
 
1440
                                    predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy;
 
 
1441
                                    predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz;
 
 
1442
                                    //predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
 
 
1443
                                }
 
 
1444
                                else
 
 
1445
                                {
 
 
1446
                                    printf("This assert is a busted adjacency!\nNo EP between %s and %s.",
 
 
1447
                                        (*(targetModule->m_module_ptrs))->name, sbPtr->containingModule->name);
 
 
1448
 
 
 
1449
                                    assert(thisEp);
 
 
1450
                                    //predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE;
 
 
1451
                                    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1452
                                    //predatorStatusPointer->moveData.lastModule = predatorStatusPointer->lastmodule;
 
 
1453
                                    NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0);
 
 
1454
                                }
 
 
1455
 
 
 
1456
                                NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
1457
 
 
 
1458
                                /* If that fired, there's a farped adjacency. */
 
 
1459
                            }
 
 
1460
                        }
 
 
1461
 
 
 
1462
                        /* Should have a velocity set now. */
 
 
1463
                        NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);    
 
 
1464
 
 
 
1465
                        /* test here for impeding collisions, and not being able to reach target... */
 
 
1466
                        //if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager)) predatorStatusPointer->behaviourState =
PBS_Avoidance;
 
 
1467
                    }
 
 
1468
                    else
 
 
1469
                    {
 
 
1470
                        /* if our state timer has run out in approach state, see if we can fire*/
 
 
1471
                        predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
1472
 
 
 
1473
                        if(predatorStatusPointer->stateTimer <= 0)
 
 
1474
                            Predator_Enter_Attacking_State(sbPtr);
 
 
1475
                    }
 
 
1476
                }
 
 
1477
                else
 
 
1478
                {
 
 
1479
                    sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
 
 
1480
                }
 
 
1481
            }
 
 
1482
            else // let's hunt/stalk target
 
 
1483
            {
 
 
1484
                if (PCLOAK_Off == predatorStatusPointer->CloakStatus)
 
 
1485
                    PredatorCloakOn(predatorStatusPointer);
 
 
1486
 
 
 
1487
                if (predatorIsNear)
 
 
1488
                {
 
 
1489
                    VECTORCH velocityDirection = {0,0,0};
 
 
1490
puts("hunt near");
 
 
1491
                    {
 
 
1492
                        AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 0);
 
 
1493
 
 
 
1494
                        #ifdef SHOWPREDOSTATS
 
 
1495
                        {
 
 
1496
                            if (targetModule)
 
 
1497
                                printf("closets_target Module %s.\n", (*(targetModule->m_module_ptrs))->name);
 
 
1498
                            else
 
 
1499
                                printf("closets_target Module NULL.\n");
 
 
1500
                        }
 
 
1501
                        #endif
 
 
1502
 
 
 
1503
                        if (targetModule == sbPtr->containingModule->m_aimodule) /* Hey, it'll drop through. */
 
 
1504
                        {
 
 
1505
                            predatorStatusPointer->behaviourState = predatorStatusPointer->closets_target ? PBS_Engaging : PBS_Wandering;
 
 
1506
                            predator_change_behaviour(sbPtr);
 
 
1507
                        }
 
 
1508
                        else
 
 
1509
                        {
 
 
1510
                            if (!targetModule)
 
 
1511
                            {
 
 
1512
                                predatorStatusPointer->behaviourState = PBS_Recovering;
 
 
1513
                                predator_change_behaviour(sbPtr);
 
 
1514
                            }
 
 
1515
                            else
 
 
1516
                            {
 
 
1517
                                FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
1518
 
 
 
1519
                                if (!thisEp)
 
 
1520
                                {
 
 
1521
                                    printf("This assert is a busted adjacency!");
 
 
1522
                                    assert(thisEp);
 
 
1523
                                }
 
 
1524
                                /* If that fired, there's a farped adjacency. */
 
 
1525
 
 
 
1526
                                predatorStatusPointer->wanderData.worldPosition = thisEp->position;
 
 
1527
                                predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx;
 
 
1528
                                predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy;
 
 
1529
                                predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz;
 
 
1530
                            }
 
 
1531
                        }
 
 
1532
                    }
 
 
1533
 
 
 
1534
                    /* ok: should have a current target at this stage... */
 
 
1535
                    NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
1536
                    NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);    
 
 
1537
 
 
 
1538
                    /* test here for impeding collisions, and not being able to reach target... */
 
 
1539
 
 
 
1540
                    if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager))
 
 
1541
                    {
 
 
1542
                        predatorStatusPointer->behaviourState = PBS_Avoidance;
 
 
1543
                        predator_change_behaviour(sbPtr);
 
 
1544
                    }
 
 
1545
                }
 
 
1546
                else
 
 
1547
                {
 
 
1548
puts("hunt FAR");
 
 
1549
                    /* Decrement the Far state timer */
 
 
1550
                    predatorStatusPointer->stateTimer -= NormalFrameTime;   
 
 
1551
                    /* check if far state timer has timed-out. If so, it is time 
 
 
1552
                    to do something. Otherwise just return. */
 
 
1553
 
 
 
1554
                    if(predatorStatusPointer->stateTimer < 0)
 
 
1555
                    {
 
 
1556
                        /* timer has timed-out in hunting mode: */
 
 
1557
                        AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 0);
 
 
1558
 
 
 
1559
                        /* if there is no target module, it means that the pred is trapped in an
 
 
1560
                        unlinked module. In this case, reset the timer and return. */                   
 
 
1561
                        predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
1562
 
 
 
1563
                        if(targetModule)
 
 
1564
                        {
 
 
1565
                            /* NB don't need to check for state changes... will regen health on makenear */
 
 
1566
                            /* Examine target, and decide what to do */
 
 
1567
                            //assert(AIModuleIsPhysical(targetModule));         
 
 
1568
                            ProcessFarPredatorTargetAIModule(sbPtr, targetModule);  
 
 
1569
                        }
 
 
1570
                    }
 
 
1571
                }
 
 
1572
            }
 
 
1573
        }
 
 
1574
    }
 
 
1575
 
 
 
1576
 
 
 
1577
            /*
 
 
1578
                predatorStatusPointer->patience -= NormalFrameTime;
 
 
1579
 
 
 
1580
                if (predatorStatusPointer->patience <= 0)
 
 
1581
                {
 
 
1582
                    predatorStatusPointer->behaviourState = PBS_Hunting;
 
 
1583
                    predator_change_behaviour(sbPtr);
 
 
1584
                }
 
 
1585
            */
 
 
1586
 
 
 
1587
    switch(predatorStatusPointer->behaviourState)
 
 
1588
    {
 
 
1589
        case PBS_Attacking:
 
 
1590
        {
 
 
1591
            descriptor = "Attacking";
 
 
1592
 
 
 
1593
if(0)
 
 
1594
            if (predatorIsNear)
 
 
1595
            {
 
 
1596
                if(predatorStatusPointer->Angry)
 
 
1597
                {
 
 
1598
    /*
 
 
1599
        VECTORCH orientationDirn;
 
 
1600
        //NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
1601
        orientationDirn = sbPtr->DynPtr->Position;
 
 
1602
 
 
 
1603
        //orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
 
 
1604
        //orientationDirn.vy = 0;
 
 
1605
        //orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
 
 
1606
 
 
 
1607
        printf("x %d y %d z %d\n", orientationDirn.vx, orientationDirn.vy, orientationDirn.vz);
 
 
1608
        puts("REAL");
 
 
1609
    */
 
 
1610
        printf("x %d y %d z %d\n", sbPtr->DynPtr->Position.vx, sbPtr->DynPtr->Position.vy, sbPtr->DynPtr->Position.vz);
 
 
1611
                    //if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE))
 
 
1612
                    if(NPCOrientateToVector(sbPtr, &predatorStatusPointer->weaponTarget, NPC_TURNRATE))
 
 
1613
                    {
 
 
1614
                        predatorStatusPointer->Angry -= NormalFrameTime;
 
 
1615
 
 
 
1616
                        if(predatorStatusPointer->Angry < 0)
 
 
1617
                        {
 
 
1618
                            predatorStatusPointer->Angry = 0;
 
 
1619
 
 
 
1620
                            if(sbPtr == predatorStatusPointer->closets_target)
 
 
1621
                                predatorStatusPointer->closets_target = NULL;
 
 
1622
 
 
 
1623
                            if ((FastRandom() & 65535) < 32767)
 
 
1624
                            {
 
 
1625
                                if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Taunt_One))
 
 
1626
                                {
 
 
1627
                                    int rand = FastRandom();
 
 
1628
                                    int pitch = (rand & 255) - 128;
 
 
1629
                                    predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
1630
                                    predatorStatusPointer->behaviourState = PBS_Taunting;
 
 
1631
                                    predatorStatusPointer->stateTimer = NPC_AVOIDTIME;
 
 
1632
                                    /* Become patient again. */
 
 
1633
                                    predatorStatusPointer->patience = PRED_PATIENCE_TIME;
 
 
1634
                                    predatorStatusPointer->enableTaunt = 0;
 
 
1635
 
 
 
1636
                                    SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Taunt_One, -1, (ONE_FIXED >> 3));               
 
 
1637
 
 
 
1638
                                    predatorStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
1639
 
 
 
1640
                                    if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
1641
                                        PlayPredatorSound(0, PSC_Taunt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
1642
                                }
 
 
1643
                            }
 
 
1644
                            else
 
 
1645
                            {
 
 
1646
                                predatorStatusPointer->behaviourState = PBS_Wandering;
 
 
1647
                                predator_change_behaviour(sbPtr);
 
 
1648
                            }
 
 
1649
                        }
 
 
1650
                        else 
 
 
1651
                        {
 
 
1652
                            if (!predatorStatusPointer->internalState)
 
 
1653
                            {
 
 
1654
                                if (predatorStatusPointer->HModelController.Tweening == Controller_NoTweening)
 
 
1655
                                    predatorStatusPointer->HModelController.Playing = 0;
 
 
1656
                            }
 
 
1657
 
 
 
1658
    if(0)
 
 
1659
                            if ((FastRandom() & 65535) < 2767)
 
 
1660
                            {
 
 
1661
                                predatorStatusPointer->enableTaunt = 1;
 
 
1662
                                predatorStatusPointer->HModelController.Playing = 1;
 
 
1663
                                predatorStatusPointer->HModelController.Looped = 0;
 
 
1664
                                predatorStatusPointer->HModelController.sequence_timer = 0;
 
 
1665
                                predatorStatusPointer->internalState = 2;
 
 
1666
 
 
 
1667
                                /* look after the sound */
 
 
1668
                                Sound_Play(SID_PRED_LAUNCHER, "d", &sbPtr->DynPtr->Position);
 
 
1669
 
 
 
1670
                                VECTORCH shotVector;
 
 
1671
                                SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash");
 
 
1672
 
 
 
1673
                                shotVector.vx = muzzle->SecMat.mat31;
 
 
1674
                                shotVector.vy = muzzle->SecMat.mat32;
 
 
1675
                                shotVector.vz = muzzle->SecMat.mat33;
 
 
1676
 
 
 
1677
                                shotVector.vx += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11));
 
 
1678
                                shotVector.vy += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11));
 
 
1679
                                shotVector.vz += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11));
 
 
1680
                                Normalise(&shotVector);
 
 
1681
 
 
 
1682
                                //predatorStatusPointer->weaponTarget = shotVector;
 
 
1683
 
 
 
1684
                                InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat, 0,
&TemplateAmmo[AMMO_PLASMACASTER].MaxDamage, 65536);
 
 
1685
 
 
 
1686
                                //predatorStatusPointer->stateTimer = ONE_FIXED;
 
 
1687
                            }
 
 
1688
 
 
 
1689
                        }
 
 
1690
    //puts("YES!!");
 
 
1691
                    }
 
 
1692
                    else
 
 
1693
                    {
 
 
1694
    //puts("NO!!");
 
 
1695
                        DoPredatorRandomSound(sbPtr);
 
 
1696
                    }
 
 
1697
                    //return;
 
 
1698
                }
 
 
1699
                else
 
 
1700
                {
 
 
1701
                    SetPredatorElevation(sbPtr);
 
 
1702
 
 
 
1703
                    VECTORCH orientationDirn;
 
 
1704
                    NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
1705
                    orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx;
 
 
1706
                    orientationDirn.vy = 0;
 
 
1707
                    orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz;
 
 
1708
 
 
 
1709
                    if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE))
 
 
1710
                    {
 
 
1711
                        int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position);
 
 
1712
                        (*predatorStatusPointer->Selected_Weapon->WeaponFireFunction)(sbPtr, range);
 
 
1713
                    }
 
 
1714
                }
 
 
1715
            }
 
 
1716
            else
 
 
1717
            {
 
 
1718
                predatorStatusPointer->behaviourState = PBS_Hunting;
 
 
1719
                predator_change_behaviour(sbPtr);
 
 
1720
            }
 
 
1721
        }
 
 
1722
        break;
 
 
1723
        case PBS_Wandering:
 
 
1724
        {
 
 
1725
            descriptor = "Wandering";
 
 
1726
 
 
 
1727
            if (predatorIsNear)
 
 
1728
            {
 
 
1729
                VECTORCH velocityDirection = {0,0,0};
 
 
1730
 
 
 
1731
                //PredatorHandleMovingAnimation(sbPtr);
 
 
1732
 
 
 
1733
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
1734
                {
 
 
1735
                    predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */
 
 
1736
                    predator_change_behaviour(sbPtr);
 
 
1737
                    break;
 
 
1738
                }
 
 
1739
 
 
 
1740
                /* Are we using bimble rules? */
 
 
1741
 
 
 
1742
                if (predatorStatusPointer->wanderData.currentModule == NPC_BIMBLINGINMODULE)
 
 
1743
                {
 
 
1744
                    int range = VectorDistance(&predatorStatusPointer->wanderData.worldPosition, &sbPtr->DynPtr->Position);
 
 
1745
 
 
 
1746
                    if (range < 2000)
 
 
1747
                        predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; /* Reset system, try again. */
 
 
1748
                }
 
 
1749
                else
 
 
1750
                {
 
 
1751
                    /* wander target aquisition: if no target, or moved module */
 
 
1752
 
 
 
1753
                    if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
1754
                    {
 
 
1755
                        NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1756
                        NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0);
 
 
1757
                    }
 
 
1758
                    else if(predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index)
 
 
1759
                    {
 
 
1760
                        NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0);
 
 
1761
                    }
 
 
1762
 
 
 
1763
                    /* if we still haven't got one, bimble about in this one for a bit. */
 
 
1764
                    if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
1765
                    {
 
 
1766
                        NPC_GetBimbleTarget(sbPtr, &predatorStatusPointer->wanderData.worldPosition);
 
 
1767
                        predatorStatusPointer->wanderData.currentModule = NPC_BIMBLINGINMODULE;
 
 
1768
                    }
 
 
1769
                }
 
 
1770
 
 
 
1771
                /* ok: should have a current target at this stage... */
 
 
1772
                NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
1773
                NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
 
 
1774
 
 
 
1775
                /* test here for impeding collisions, and not being able to reach target... */
 
 
1776
                if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager))
 
 
1777
                    predatorStatusPointer->behaviourState = PBS_Avoidance;
 
 
1778
 
 
 
1779
                CentrePredatorElevation(sbPtr);
 
 
1780
            }
 
 
1781
            else
 
 
1782
            {
 
 
1783
                /* Patrick 4/7/97 --------------------------------------------------
 
 
1784
                  The various far state behaviour execution functions for predator...
 
 
1785
 
 
 
1786
                  1. Wandering is the initial far state, to which the predator never
 
 
1787
                  returns: after becoming visible for the first time, it will use only
 
 
1788
                  hunt and retreat
 
 
1789
                  2. Hunting is used if the predator feels confident enough to engage
 
 
1790
                  the player.
 
 
1791
                  3. Retreating is used if the predator is not confident    
 
 
1792
                ---------------------------------------------------------------------*/
 
 
1793
 
 
 
1794
                predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
1795
                /* check if far state timer has timed-out. If so, it is time 
 
 
1796
                to do something. Otherwise just return. */
 
 
1797
 
 
 
1798
                if(predatorStatusPointer->stateTimer > 0)
 
 
1799
                    break;
 
 
1800
 
 
 
1801
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
1802
                {
 
 
1803
                    predatorStatusPointer->behaviourState = PBS_Engaging; /* we should be hunting */
 
 
1804
                    predator_change_behaviour(sbPtr);
 
 
1805
                    break;
 
 
1806
                }
 
 
1807
 
 
 
1808
                /* Preds NEVER camp.  I mean, get tired of wandering. */
 
 
1809
 
 
 
1810
                /* timer has timed-out in roving mode */
 
 
1811
                AIMODULE *targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 0);
 
 
1812
 
 
 
1813
                /* if there is no target module, it means that the pred is trapped in an
 
 
1814
                unlinked module. In this case, reset the timer and return. */
 
 
1815
 
 
 
1816
                if(!targetModule)
 
 
1817
                {
 
 
1818
                    predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
1819
                    break;
 
 
1820
                }
 
 
1821
 
 
 
1822
                /* Examine target, and decide what to do */
 
 
1823
                //assert(AIModuleIsPhysical(targetModule));
 
 
1824
                ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
 
 
1825
                /* reset timer */
 
 
1826
                predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
1827
            }
 
 
1828
        }
 
 
1829
        break;
 
 
1830
        case PBS_Avoidance:
 
 
1831
        {
 
 
1832
            switch (predatorStatusPointer->avoidanceManager.substate)
 
 
1833
            {
 
 
1834
                default:
 
 
1835
                case AvSS_FreeMovement:
 
 
1836
                    descriptor = "Avoidance Level 0";
 
 
1837
                break;
 
 
1838
                case AvSS_FirstAvoidance:
 
 
1839
                    descriptor = "Avoidance Level 1";
 
 
1840
                break;
 
 
1841
                case AvSS_SecondAvoidance:
 
 
1842
                    descriptor = "Avoidance Level 2";
 
 
1843
                break;
 
 
1844
                case AvSS_ThirdAvoidance:
 
 
1845
                    descriptor = "Avoidance Level 3";
 
 
1846
            }
 
 
1847
 
 
 
1848
            if (predatorIsNear)
 
 
1849
            {
 
 
1850
                /* first check for a close attack... */
 
 
1851
                //if(VectorDistance(&PlayerStatus.sbptr->DynPtr->Position, &sbPtr->DynPtr->Position) < PRED_CLOSE_ATTACK_RANGE) return
PRC_Request_Attack;
 
 
1852
 
 
 
1853
                NPCSetVelocity(sbPtr, &predatorStatusPointer->avoidanceManager.avoidanceDirection, predatorStatusPointer->nearSpeed);
 
 
1854
 
 
 
1855
                /* Velocity CANNOT be zero, unless deliberately so! */  
 
 
1856
 
 
 
1857
                //PredatorHandleMovingAnimation(sbPtr);
 
 
1858
 
 
 
1859
                if (AllNewAvoidanceKernel(sbPtr, &predatorStatusPointer->avoidanceManager) != AvRC_Avoidance)
 
 
1860
                {
 
 
1861
                    /* Better exit. */
 
 
1862
                    switch (predatorStatusPointer->lastState)
 
 
1863
                    {
 
 
1864
                        case PBS_Avoidance:
 
 
1865
                        default:
 
 
1866
                            /* switch to approach */
 
 
1867
                            if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].defenceHealth)
 
 
1868
                            {
 
 
1869
                                /* go to approach */
 
 
1870
                                NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
1871
                                predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
1872
                            }
 
 
1873
                            else
 
 
1874
                            {
 
 
1875
                                /* go to retreat */
 
 
1876
                                NPC_InitMovementData(&predatorStatusPointer->moveData);               
 
 
1877
                                predatorStatusPointer->behaviourState = PBS_Withdrawing;
 
 
1878
                            }
 
 
1879
                        break;
 
 
1880
                        case PBS_Wandering:
 
 
1881
                        case PBS_Hunting:
 
 
1882
                        case PBS_Withdrawing:
 
 
1883
                        case PBS_Returning:
 
 
1884
                        case PBS_Pathfinding:
 
 
1885
                            predatorStatusPointer->behaviourState = predatorStatusPointer->lastState;
 
 
1886
                        break;
 
 
1887
                        case PBS_Engaging:
 
 
1888
                        case PBS_Attacking:
 
 
1889
                            predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
1890
                    }
 
 
1891
                    predator_change_behaviour(sbPtr);
 
 
1892
                }
 
 
1893
 
 
 
1894
                CentrePredatorElevation(sbPtr);
 
 
1895
            }
 
 
1896
            else
 
 
1897
            {
 
 
1898
                /* High on the list of Things Not To Be Doing. */
 
 
1899
 
 
 
1900
                Initialise_AvoidanceManager(&predatorStatusPointer->avoidanceManager);
 
 
1901
 
 
 
1902
                switch (predatorStatusPointer->lastState)
 
 
1903
                {
 
 
1904
                    case PBS_Recovering:
 
 
1905
                    case PBS_Hunting:
 
 
1906
                    case PBS_Engaging:
 
 
1907
                        /* Go directly to approach.  Do not pass GO.  Do not collect 200 zorkmids. */
 
 
1908
                        predatorStatusPointer->behaviourState = predatorStatusPointer->lastState;
 
 
1909
                        break;
 
 
1910
                    default:
 
 
1911
                        predatorStatusPointer->behaviourState = PBS_Wandering;
 
 
1912
                }
 
 
1913
 
 
 
1914
                predator_change_behaviour(sbPtr);
 
 
1915
            }
 
 
1916
        }
 
 
1917
        break;
 
 
1918
        case PBS_SwapWeapon:
 
 
1919
        {
 
 
1920
            descriptor = "Swapping";
 
 
1921
 
 
 
1922
            Verify_Positions_In_HModel(sbPtr, &predatorStatusPointer->HModelController, "Predator Swap Weapon Start");
 
 
1923
 
 
 
1924
            if (!predatorStatusPointer->stateTimer)
 
 
1925
            {
 
 
1926
                /* Haven't started yet. */
 
 
1927
 
 
 
1928
                #ifdef SHOWPREDOSTATS
 
 
1929
                    printf("Part one ");
 
 
1930
                #endif
 
 
1931
 
 
 
1932
                /* Right.  Is there a 'deselect' anim? */
 
 
1933
                if (predatorStatusPointer->IAmCrouched)
 
 
1934
                {
 
 
1935
                    if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon))
 
 
1936
                    {
 
 
1937
                        /* It's there! */
 
 
1938
                        if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0)
 
 
1939
                        {
 
 
1940
                            /* Valid swap time, too. */
 
 
1941
                            InitHModelTweening_Backwards(&predatorStatusPointer->HModelController, (ONE_FIXED >> 2),
 
 
1942
                            (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon, predatorStatusPointer->Selected_Weapon->SwappingTime,0);
 
 
1943
                            predatorStatusPointer->HModelController.Looped = 0;
 
 
1944
                            predatorStatusPointer->stateTimer = 1; /* Swapping Out. */
 
 
1945
                        }
 
 
1946
                    }
 
 
1947
                }
 
 
1948
                else if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon))
 
 
1949
                {
 
 
1950
                    /* It's there! */
 
 
1951
                    if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0)
 
 
1952
                    {
 
 
1953
                        /* Valid swap time, too. */
 
 
1954
                        InitHModelTweening_Backwards(&predatorStatusPointer->HModelController,
(ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon,
 
 
1955
                        predatorStatusPointer->Selected_Weapon->SwappingTime,0);
 
 
1956
                        predatorStatusPointer->HModelController.Looped = 0;
 
 
1957
                        predatorStatusPointer->stateTimer = 1; /* Swapping Out. */
 
 
1958
                    }
 
 
1959
                }
 
 
1960
 
 
 
1961
                /* If you're still here, there must be no swapping out sequence. */
 
 
1962
                predatorStatusPointer->stateTimer = 2;
 
 
1963
                /* Ah well, go directly to the middle. */
 
 
1964
            }
 
 
1965
            else if (predatorStatusPointer->stateTimer == 1)
 
 
1966
            {
 
 
1967
                /* You are in the process of swapping out. */
 
 
1968
 
 
 
1969
                #ifdef SHOWPREDOSTATS
 
 
1970
                    printf("Part two ");
 
 
1971
                #endif
 
 
1972
 
 
 
1973
                if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))
 
 
1974
                    predatorStatusPointer->stateTimer = 2;
 
 
1975
            }
 
 
1976
            else if (predatorStatusPointer->stateTimer == 2)
 
 
1977
            {
 
 
1978
                /* In the middle! */
 
 
1979
                const PREDATOR_WEAPON_DATA *targetWeapon = GetThisNPCPredatorWeapon(predatorStatusPointer->ChangeToWeapon);
 
 
1980
 
 
 
1981
                #ifdef SHOWPREDOSTATS
 
 
1982
                    printf("Part three ");
 
 
1983
                #endif
 
 
1984
 
 
 
1985
                predatorStatusPointer->Selected_Weapon = targetWeapon;
 
 
1986
 
 
 
1987
                SECTION *root_section = GetNamedHierarchyFromLibrary("hnpcpredator", predatorStatusPointer->Selected_Weapon->HierarchyName);
 
 
1988
                assert(root_section);
 
 
1989
 
 
 
1990
                /* Strip out HitDelta for now, if any... */
 
 
1991
                {
 
 
1992
                    DELTA_CONTROLLER *delta = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
 
 
1993
 
 
 
1994
                    if (delta)
 
 
1995
                        Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta");
 
 
1996
                }
 
 
1997
 
 
 
1998
                /* Strip off elevation too. */
 
 
1999
                {
 
 
2000
                    DELTA_CONTROLLER *delta = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
 
 
2001
 
 
 
2002
                    if (delta)
 
 
2003
                        Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation");
 
 
2004
                }
 
 
2005
 
 
 
2006
                Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Two");
 
 
2007
 
 
 
2008
                /* In the interests of getting the new sections right... */
 
 
2009
                predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorStand;
 
 
2010
                predatorStatusPointer->HModelController.Sub_Sequence = (int)PSSS_Get_Weapon;
 
 
2011
 
 
 
2012
                Transmogrify_HModels(sbPtr, &predatorStatusPointer->HModelController, root_section, 0, 1, 0);
 
 
2013
 
 
 
2014
                if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront))
 
 
2015
                {
 
 
2016
                    /* This ritual in case _one_ of the hierarchies doesn't have hitdeltas. */
 
 
2017
                    DELTA_CONTROLLER *delta = Add_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta",
(int)HMSQT_PredatorStand, (int)PSSS_HitChestFront, -1);
 
 
2018
                    assert(delta);
 
 
2019
                    delta->Playing = 0;
 
 
2020
                }
 
 
2021
 
 
 
2022
                /* Replace elevation. */
 
 
2023
                if (predatorStatusPointer->Selected_Weapon->UseElevation)
 
 
2024
                {
 
 
2025
                    if (Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation") == NULL)
 
 
2026
                    {
 
 
2027
                    DELTA_CONTROLLER *delta = Add_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation",
(int)HMSQT_PredatorStand, (int)PSSS_Elevation, 0);
 
 
2028
                    assert(delta);
 
 
2029
                    delta->timer = 32767;
 
 
2030
                    }
 
 
2031
                }
 
 
2032
                else
 
 
2033
                {
 
 
2034
                    /* Better make sure it's gone... */
 
 
2035
                    Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation");
 
 
2036
                }
 
 
2037
 
 
 
2038
                Verify_Positions_In_HModel(sbPtr, &predatorStatusPointer->HModelController, "Predator Swap Weapon Two A");
 
 
2039
 
 
 
2040
                DeInitialise_HModel(&predatorStatusPointer->HModelController);
 
 
2041
                ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
 
 
2042
                Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Three");
 
 
2043
 
 
 
2044
                predatorStatusPointer->My_Elevation_Section =
GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName);
 
 
2045
 
 
 
2046
                /* Now go for the Get_Weapon sequence. */
 
 
2047
                if (predatorStatusPointer->IAmCrouched)
 
 
2048
                {
 
 
2049
                    if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon))
 
 
2050
                    {
 
 
2051
                        /* It's there! */
 
 
2052
                        if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0)
 
 
2053
                        {
 
 
2054
                            /* Valid swap time, too. */
 
 
2055
                            predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorCrouch;
 
 
2056
                            predatorStatusPointer->HModelController.Sub_Sequence = (int)PCrSS_Get_Weapon;
 
 
2057
                            predatorStatusPointer->HModelController.Seconds_For_Sequence = predatorStatusPointer->Selected_Weapon->SwappingTime;
 
 
2058
                            /* That to get the new sections right. */
 
 
2059
            InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_PredatorCrouch, (int)PCrSS_Get_Weapon,
predatorStatusPointer->Selected_Weapon->SwappingTime, 0);
 
 
2060
                            predatorStatusPointer->HModelController.Looped = 0;
 
 
2061
                            predatorStatusPointer->stateTimer = 3; /* Swapping In. */
 
 
2062
 
 
 
2063
                            Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Three A");
 
 
2064
                            ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr);
 
 
2065
                            Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Four");
 
 
2066
                        }
 
 
2067
                    }
 
 
2068
                }
 
 
2069
                else
 
 
2070
                {
 
 
2071
                    if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Get_Weapon))
 
 
2072
                    {
 
 
2073
                        /* It's there! */
 
 
2074
                        if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0)
 
 
2075
                        {
 
 
2076
                            /* Valid swap time, too. */
 
 
2077
                            predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorStand;
 
 
2078
                            predatorStatusPointer->HModelController.Sub_Sequence = (int)PSSS_Get_Weapon;
 
 
2079
                            predatorStatusPointer->HModelController.Seconds_For_Sequence = predatorStatusPointer->Selected_Weapon->SwappingTime;
 
 
2080
                            /* That to get the new sections right. */
 
 
2081
                        InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon,
predatorStatusPointer->Selected_Weapon->SwappingTime,0);
 
 
2082
                            predatorStatusPointer->HModelController.Looped = 0;
 
 
2083
                            predatorStatusPointer->stateTimer = 3; /* Swapping In. */
 
 
2084
 
 
 
2085
                            Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Four A");
 
 
2086
                            ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); 
 
 
2087
                            Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Five");
 
 
2088
                        }
 
 
2089
                    }
 
 
2090
                }
 
 
2091
 
 
 
2092
                /* If you're still here, there must be no swapping in sequence. */
 
 
2093
                predatorStatusPointer->stateTimer = 4;
 
 
2094
                /* Ah well, go directly to the end. */
 
 
2095
 
 
 
2096
                Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Six");
 
 
2097
            }
 
 
2098
            else if (predatorStatusPointer->stateTimer == 3)
 
 
2099
            {
 
 
2100
                /* You are in the process of swapping in. */
 
 
2101
 
 
 
2102
                #ifdef SHOWPREDOSTATS
 
 
2103
                    printf("Part four ");
 
 
2104
                #endif
 
 
2105
 
 
 
2106
                if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))
 
 
2107
                    predatorStatusPointer->stateTimer = 4;
 
 
2108
            }
 
 
2109
            else if (predatorStatusPointer->stateTimer == 4)
 
 
2110
            {
 
 
2111
                /* All (valid) conclusions arrive here. */
 
 
2112
 
 
 
2113
                #ifdef SHOWPREDOSTATS
 
 
2114
                    printf("Part five ");
 
 
2115
                #endif
 
 
2116
 
 
 
2117
                predatorStatusPointer->ChangeToWeapon = PNPCW_End;
 
 
2118
 
 
 
2119
                if(predatorStatusPointer->Angry)
 
 
2120
                    predatorStatusPointer->behaviourState = PBS_Attacking;
 
 
2121
                else
 
 
2122
                    predatorStatusPointer->behaviourState = (predatorStatusPointer->Selected_Weapon->id == PNPCW_Medicomp) ? PBS_Recovering :
PBS_Engaging;
 
 
2123
 
 
 
2124
                predator_change_behaviour(sbPtr);
 
 
2125
            }
 
 
2126
 
 
 
2127
            #ifdef SHOWPREDOSTATS
 
 
2128
                printf("No Part %d ", predatorStatusPointer->stateTimer);
 
 
2129
            #endif
 
 
2130
 
 
 
2131
            if (predatorIsNear)
 
 
2132
                CentrePredatorElevation(sbPtr);
 
 
2133
            else
 
 
2134
                ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr);
 
 
2135
        }
 
 
2136
        break;
 
 
2137
        case PBS_Withdrawing:
 
 
2138
        {
 
 
2139
            descriptor = "Withdrawing";
 
 
2140
 
 
 
2141
            if (predatorIsNear)
 
 
2142
            {
 
 
2143
                VECTORCH velocityDirection = {0,0,0};
 
 
2144
 
 
 
2145
                /* Your mission: to advance out of trouble, even if near. */
 
 
2146
 
 
 
2147
                //PredatorHandleMovingAnimation(sbPtr);
 
 
2148
 
 
 
2149
                AIMODULE *old_fearmodule = predatorStatusPointer->fearmodule;
 
 
2150
 
 
 
2151
                if (!(predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)))
 
 
2152
                {
 
 
2153
                    predatorStatusPointer->behaviourState = PBS_Recovering; /* What am I running from? */
 
 
2154
                    predator_change_behaviour(sbPtr);
 
 
2155
                    break;
 
 
2156
                }
 
 
2157
                else
 
 
2158
                {
 
 
2159
                    predatorStatusPointer->fearmodule = predatorStatusPointer->closets_target->containingModule->m_aimodule;
 
 
2160
 
 
 
2161
                    if (predatorStatusPointer->fearmodule == NULL)
 
 
2162
                        predatorStatusPointer->fearmodule = sbPtr->containingModule->m_aimodule;
 
 
2163
                }
 
 
2164
 
 
 
2165
                if ((predatorStatusPointer->missionmodule == NULL) || (predatorStatusPointer->fearmodule != old_fearmodule))
 
 
2166
                {
 
 
2167
                    /* Recompute mission module. */
 
 
2168
                    if (predatorStatusPointer->fearmodule)
 
 
2169
                        predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5);
 
 
2170
                    else
 
 
2171
                        predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,PlayerStatus.sbptr->containingModule->m_aimodule,
5);
 
 
2172
                }
 
 
2173
 
 
 
2174
                {
 
 
2175
                    if (predatorStatusPointer->missionmodule == NULL)
 
 
2176
                    {
 
 
2177
                        predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */
 
 
2178
                        break;
 
 
2179
                    }
 
 
2180
 
 
 
2181
                    AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, predatorStatusPointer->missionmodule, 6, 0);
 
 
2182
 
 
 
2183
                #ifdef SHOWPREDOSTATS
 
 
2184
 
 
 
2185
                    printf("closets_target Module %s.\n",(*(predatorStatusPointer->missionmodule->m_module_ptrs))->name);
 
 
2186
 
 
 
2187
                    if (targetModule)
 
 
2188
                        printf("Next Module is %s.\n", (*(targetModule->m_module_ptrs))->name);
 
 
2189
                    else
 
 
2190
                        printf("Next Module is NULL!\n");
 
 
2191
                #endif
 
 
2192
 
 
 
2193
                    if ((targetModule == sbPtr->containingModule->m_aimodule) || (targetModule == NULL))
 
 
2194
                    {
 
 
2195
                        predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */
 
 
2196
                        predator_change_behaviour(sbPtr);
 
 
2197
                        break;
 
 
2198
                    }
 
 
2199
 
 
 
2200
                    FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
2201
 
 
 
2202
                    if (!thisEp)
 
 
2203
                    {
 
 
2204
                        printf("This assert is a busted adjacency!");
 
 
2205
                        assert(thisEp);
 
 
2206
                    }
 
 
2207
                    /* If that fired, there's a farped adjacency. */
 
 
2208
 
 
 
2209
                    predatorStatusPointer->wanderData.worldPosition = thisEp->position;
 
 
2210
                    predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx;
 
 
2211
                    predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy;
 
 
2212
                    predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz;
 
 
2213
                }
 
 
2214
 
 
 
2215
                /* ok: should have a current target at this stage... */
 
 
2216
                NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
2217
                NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
 
 
2218
 
 
 
2219
                /* test here for impeding collisions, and not being able to reach target... */
 
 
2220
                if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager))
 
 
2221
                    predatorStatusPointer->behaviourState = PBS_Avoidance; /* Go to all new avoidance. */
 
 
2222
 
 
 
2223
                CentrePredatorElevation(sbPtr);
 
 
2224
            }
 
 
2225
            else
 
 
2226
            {
 
 
2227
                AIMODULE *old_fearmodule = predatorStatusPointer->fearmodule;
 
 
2228
 
 
 
2229
                /* Decrement the state timer */
 
 
2230
                predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
2231
 
 
 
2232
                /* check for state changes: randomly decide to switch to recover... */
 
 
2233
                if(!(predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2234
                || (predatorStatusPointer->incidentFlag && !NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target)))
 
 
2235
                {
 
 
2236
                    predatorStatusPointer->behaviourState = PBS_Recovering; /* What am I running from? */
 
 
2237
                    predator_change_behaviour(sbPtr);
 
 
2238
                    break;
 
 
2239
                }
 
 
2240
 
 
 
2241
                if(predatorStatusPointer->stateTimer > 0)
 
 
2242
                    break;
 
 
2243
 
 
 
2244
                /* timer has timed-out in retreat mode: */
 
 
2245
 
 
 
2246
                /* Yeah, from where _am_ I running? */
 
 
2247
 
 
 
2248
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2249
                {
 
 
2250
                    predatorStatusPointer->fearmodule = predatorStatusPointer->closets_target->containingModule->m_aimodule;
 
 
2251
                }
 
 
2252
                else if (predatorStatusPointer->fearmodule == NULL)
 
 
2253
                {
 
 
2254
                    predatorStatusPointer->fearmodule = sbPtr->containingModule->m_aimodule;
 
 
2255
                }       
 
 
2256
 
 
 
2257
                if ((predatorStatusPointer->missionmodule == NULL) || (predatorStatusPointer->fearmodule != old_fearmodule))
 
 
2258
                {
 
 
2259
                    /* Recompute mission module. */
 
 
2260
                    if (predatorStatusPointer->fearmodule)
 
 
2261
                        predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5);
 
 
2262
                    else
 
 
2263
                        predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,PlayerStatus.sbptr->containingModule->m_aimodule,5);
 
 
2264
                }
 
 
2265
 
 
 
2266
                if (predatorStatusPointer->missionmodule == NULL)
 
 
2267
                {
 
 
2268
                    predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */
 
 
2269
                    predator_change_behaviour(sbPtr);
 
 
2270
                    break;
 
 
2271
                }
 
 
2272
 
 
 
2273
                AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0);
 
 
2274
 
 
 
2275
                predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
2276
 
 
 
2277
                if(!targetModule)
 
 
2278
                {
 
 
2279
                    predatorStatusPointer->behaviourState = PBS_Recovering;
 
 
2280
                    predator_change_behaviour(sbPtr);
 
 
2281
                    break;
 
 
2282
                }
 
 
2283
 
 
 
2284
                /* Examine target, and decide what to do */
 
 
2285
                //assert(AIModuleIsPhysical(targetModule));         
 
 
2286
                ProcessFarPredatorTargetAIModule(sbPtr, targetModule);  
 
 
2287
            }
 
 
2288
        }
 
 
2289
        break;
 
 
2290
        case PBS_Returning:
 
 
2291
        {
 
 
2292
            descriptor = "Returning";
 
 
2293
 
 
 
2294
            if (predatorIsNear)
 
 
2295
            {
 
 
2296
                VECTORCH velocityDirection = {0,0,0};
 
 
2297
 
 
 
2298
                //PredatorHandleMovingAnimation(sbPtr);
 
 
2299
 
 
 
2300
                /* should we change to approach state? */
 
 
2301
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2302
                {
 
 
2303
                    predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */
 
 
2304
                    predator_change_behaviour(sbPtr);
 
 
2305
                    break;
 
 
2306
                }
 
 
2307
 
 
 
2308
                predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
2309
 
 
 
2310
                /* Are we there yet? */
 
 
2311
                if (sbPtr->containingModule->m_aimodule == predatorStatusPointer->missionmodule)
 
 
2312
                {
 
 
2313
                    predatorStatusPointer->behaviourState = PBS_Pathfinding;
 
 
2314
                }
 
 
2315
 
 
 
2316
                /* closets_target module aquisition. */
 
 
2317
 
 
 
2318
                if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2319
                    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
2320
 
 
 
2321
                if ((predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2322
                ||(predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index))
 
 
2323
                {
 
 
2324
                    AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0);
 
 
2325
 
 
 
2326
                    if (targetModule)
 
 
2327
                    {
 
 
2328
                        FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
2329
 
 
 
2330
                        if(thisEp)
 
 
2331
                        {
 
 
2332
                            /* aha. an ep!... */ 
 
 
2333
                            VECTORCH thisEpWorld = thisEp->position;
 
 
2334
 
 
 
2335
                            thisEpWorld.vx += targetModule->m_world.vx;
 
 
2336
                            thisEpWorld.vy += targetModule->m_world.vy;
 
 
2337
                            thisEpWorld.vz += targetModule->m_world.vz;                     
 
 
2338
 
 
 
2339
                            predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
 
 
2340
                            predatorStatusPointer->wanderData.worldPosition = thisEpWorld;
 
 
2341
                        }
 
 
2342
                        else
 
 
2343
                        {
 
 
2344
                            /* Failure case. */
 
 
2345
                            predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE;
 
 
2346
                        }
 
 
2347
                    }
 
 
2348
                    else
 
 
2349
                    {
 
 
2350
                        /* Another failure case. */
 
 
2351
                        predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE;
 
 
2352
                    }
 
 
2353
                }
 
 
2354
 
 
 
2355
                /* if we still haven't got one, bimble about in this one for a bit. */
 
 
2356
                if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2357
                {
 
 
2358
                    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
2359
                    NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0);
 
 
2360
 
 
 
2361
                    if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2362
                    {
 
 
2363
                        predatorStatusPointer->behaviourState = PBS_Wandering; /* STILL broken!  Okay, just... wander, then. */
 
 
2364
                        predator_change_behaviour(sbPtr);
 
 
2365
                        break;
 
 
2366
                    }
 
 
2367
                }
 
 
2368
 
 
 
2369
                /* ok: should have a current target at this stage... */
 
 
2370
                NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
2371
                NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
 
 
2372
 
 
 
2373
                /* test here for impeding collisions, and not being able to reach target... */
 
 
2374
                if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager))
 
 
2375
                {
 
 
2376
                    predatorStatusPointer->behaviourState = PBS_Avoidance;
 
 
2377
                    predator_change_behaviour(sbPtr);
 
 
2378
                }
 
 
2379
 
 
 
2380
                CentrePredatorElevation(sbPtr);
 
 
2381
            }
 
 
2382
            else
 
 
2383
            {
 
 
2384
                /* Decrement the Far state timer */
 
 
2385
                predatorStatusPointer->stateTimer -= NormalFrameTime;   
 
 
2386
                /* check if far state timer has timed-out. If so, it is time 
 
 
2387
                to do something. Otherwise just return. */
 
 
2388
 
 
 
2389
                if(predatorStatusPointer->stateTimer > 0)
 
 
2390
                    break;
 
 
2391
 
 
 
2392
                /* check for state changes */
 
 
2393
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2394
                {
 
 
2395
                    predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
2396
                    predator_change_behaviour(sbPtr);
 
 
2397
                    break;
 
 
2398
                }
 
 
2399
 
 
 
2400
                if (sbPtr->containingModule->m_aimodule == predatorStatusPointer->missionmodule)
 
 
2401
                {
 
 
2402
                    predatorStatusPointer->behaviourState = PBS_Pathfinding;
 
 
2403
                    predator_change_behaviour(sbPtr);
 
 
2404
                }
 
 
2405
 
 
 
2406
                /* get the target module... */
 
 
2407
 
 
 
2408
                AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, predatorStatusPointer->missionmodule, 7, 0);
 
 
2409
 
 
 
2410
                /* If there is no target module, we're way out there.  Better wander a bit more. */
 
 
2411
 
 
 
2412
                if(!targetModule)
 
 
2413
                    targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 0);
 
 
2414
 
 
 
2415
                /* Examine target, and decide what to do */
 
 
2416
 
 
 
2417
                //assert(AIModuleIsPhysical(targetModule));
 
 
2418
 
 
 
2419
                ProcessFarPredatorTargetAIModule(sbPtr, targetModule);
 
 
2420
 
 
 
2421
                /* reset timer */
 
 
2422
                predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
2423
            }
 
 
2424
        }
 
 
2425
        break;
 
 
2426
        case PBS_Pathfinding:
 
 
2427
        {
 
 
2428
            descriptor = "Pathfinding";
 
 
2429
 
 
 
2430
            if (predatorIsNear)
 
 
2431
            {
 
 
2432
                VECTORCH velocityDirection = {0,0,0};
 
 
2433
 
 
 
2434
                //PredatorHandleMovingAnimation(sbPtr);
 
 
2435
 
 
 
2436
                /* should we change to approach state? */
 
 
2437
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2438
                {
 
 
2439
                    predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */
 
 
2440
                    predator_change_behaviour(sbPtr);
 
 
2441
                    break;
 
 
2442
                }
 
 
2443
 
 
 
2444
                predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
2445
 
 
 
2446
                if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2447
                    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
2448
 
 
 
2449
                if ((predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2450
                || (predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index))
 
 
2451
                {
 
 
2452
                    /* Okay, so where are we exactly? */
 
 
2453
 
 
 
2454
                    if ((predatorStatusPointer->stepnumber < 0) || (predatorStatusPointer->path < 0))
 
 
2455
                    {
 
 
2456
                        predatorStatusPointer->behaviourState = PBS_Wandering; /* Get OUT! */
 
 
2457
                        predator_change_behaviour(sbPtr);
 
 
2458
                        break;
 
 
2459
                    }
 
 
2460
 
 
 
2461
                    AIMODULE *targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber, predatorStatusPointer->path);
 
 
2462
 
 
 
2463
                    if (targetModule == NULL)
 
 
2464
                    {
 
 
2465
                        predatorStatusPointer->behaviourState = PBS_Wandering; /* Oh, to heck with this.  Try to wander. */
 
 
2466
                    }
 
 
2467
 
 
 
2468
                    /* Right, so there is a somewhere to get to. */
 
 
2469
 
 
 
2470
                    if (targetModule != sbPtr->containingModule->m_aimodule)
 
 
2471
                    {
 
 
2472
                        /* But we're nowhere near it.  Geeze... */
 
 
2473
                        predatorStatusPointer->missionmodule=targetModule;
 
 
2474
                        predatorStatusPointer->behaviourState = PBS_Returning;
 
 
2475
                        predator_change_behaviour(sbPtr);
 
 
2476
                        break;
 
 
2477
                    }
 
 
2478
 
 
 
2479
                    /* Okay, so now we need to know where to go now. */
 
 
2480
 
 
 
2481
                    int nextModuleIndex = GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
 
 
2482
                    assert(nextModuleIndex>=0);
 
 
2483
                    /* If that fires, it's Richard's fault. */
 
 
2484
                    targetModule = TranslatePathIndex(nextModuleIndex, predatorStatusPointer->path);
 
 
2485
                    assert(targetModule);
 
 
2486
                    /* Ditto. */
 
 
2487
                    predatorStatusPointer->stepnumber= nextModuleIndex;
 
 
2488
 
 
 
2489
                    FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
2490
 
 
 
2491
                    if(thisEp)
 
 
2492
                    {
 
 
2493
                        /* aha. an ep!... */ 
 
 
2494
                        VECTORCH thisEpWorld = thisEp->position;
 
 
2495
 
 
 
2496
                        thisEpWorld.vx += targetModule->m_world.vx;
 
 
2497
                        thisEpWorld.vy += targetModule->m_world.vy;
 
 
2498
                        thisEpWorld.vz += targetModule->m_world.vz;                     
 
 
2499
 
 
 
2500
                        predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
 
 
2501
                        predatorStatusPointer->wanderData.worldPosition = thisEpWorld;
 
 
2502
                    }
 
 
2503
                    else
 
 
2504
                    {
 
 
2505
                        /* Failure case. */
 
 
2506
                        predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE;
 
 
2507
                    }
 
 
2508
                }
 
 
2509
 
 
 
2510
                /* if we still haven't got one, wander for a bit. */
 
 
2511
                if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2512
                {
 
 
2513
                    NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
2514
                    NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0);
 
 
2515
 
 
 
2516
                    if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE)
 
 
2517
                    {
 
 
2518
                        predatorStatusPointer->behaviourState = PBS_Wandering; /* STILL broken!  Okay, just... wander forever, then. */
 
 
2519
                        predator_change_behaviour(sbPtr);
 
 
2520
                        break;
 
 
2521
                    }
 
 
2522
                }
 
 
2523
 
 
 
2524
                /* ok: should have a current target at this stage... */
 
 
2525
                NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager);
 
 
2526
                NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed);
 
 
2527
 
 
 
2528
                /* test here for impeding collisions, and not being able to reach target... */
 
 
2529
                if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager))
 
 
2530
                {
 
 
2531
                    predatorStatusPointer->behaviourState = PBS_Avoidance;
 
 
2532
                    predator_change_behaviour(sbPtr);
 
 
2533
                }
 
 
2534
 
 
 
2535
                CentrePredatorElevation(sbPtr);
 
 
2536
            }
 
 
2537
            else
 
 
2538
            {
 
 
2539
                /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */
 
 
2540
 
 
 
2541
                /* Decrement the Far state timer */
 
 
2542
                predatorStatusPointer->stateTimer -= NormalFrameTime;   
 
 
2543
 
 
 
2544
                /* check if far state timer has timed-out. If so, it is time 
 
 
2545
                to do something. Otherwise just return. */
 
 
2546
                if(predatorStatusPointer->stateTimer > 0)
 
 
2547
                    break;
 
 
2548
 
 
 
2549
                /* check for state changes */ /* Hack! */
 
 
2550
                if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))
 
 
2551
                {
 
 
2552
                    predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
2553
                    predator_change_behaviour(sbPtr);
 
 
2554
                    break;
 
 
2555
                }
 
 
2556
 
 
 
2557
                /* Ignore alerts. */
 
 
2558
 
 
 
2559
                /* Never break out of pathfinder unless your life is in danger! */
 
 
2560
 
 
 
2561
                /* Okay, so where are we exactly? */
 
 
2562
 
 
 
2563
                if ((predatorStatusPointer->stepnumber < 0) || (predatorStatusPointer->path < 0))
 
 
2564
                {
 
 
2565
                    predatorStatusPointer->behaviourState = PBS_Wandering; /* Get OUT! */
 
 
2566
                    predator_change_behaviour(sbPtr);
 
 
2567
                    break;
 
 
2568
                }
 
 
2569
 
 
 
2570
                AIMODULE *targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path);
 
 
2571
 
 
 
2572
                if (targetModule == NULL)
 
 
2573
                {
 
 
2574
                    predatorStatusPointer->behaviourState = PBS_Wandering; /* Oh, to heck with this.  Try to wander. */
 
 
2575
                    predator_change_behaviour(sbPtr);
 
 
2576
                    break;
 
 
2577
                }
 
 
2578
 
 
 
2579
                /* Right, so there is a somewhere to get to. */
 
 
2580
 
 
 
2581
                    if (targetModule != sbPtr->containingModule->m_aimodule)
 
 
2582
                {
 
 
2583
                    /* But we're nowhere near it.  Geeze... */
 
 
2584
                    predatorStatusPointer->missionmodule = targetModule;
 
 
2585
                    predatorStatusPointer->behaviourState = PBS_Returning;
 
 
2586
                    predator_change_behaviour(sbPtr);
 
 
2587
                    break;
 
 
2588
                }
 
 
2589
 
 
 
2590
                /* Okay, so now we need to know where to go now. */
 
 
2591
 
 
 
2592
                int nextModuleIndex = GetNextModuleInPath(predatorStatusPointer->stepnumber, predatorStatusPointer->path);
 
 
2593
                assert(nextModuleIndex >= 0);
 
 
2594
 
 
 
2595
                /* If that fires, it's Richard's fault. */
 
 
2596
 
 
 
2597
                targetModule = TranslatePathIndex(nextModuleIndex, predatorStatusPointer->path);
 
 
2598
 
 
 
2599
                assert(targetModule);
 
 
2600
                /* Ditto. */
 
 
2601
                predatorStatusPointer->stepnumber = nextModuleIndex;
 
 
2602
 
 
 
2603
                /* Examine target, and decide what to do */
 
 
2604
 
 
 
2605
                //assert(AIModuleIsPhysical(targetModule));
 
 
2606
 
 
 
2607
                ProcessFarPredatorTargetAIModule(sbPtr, targetModule);  
 
 
2608
 
 
 
2609
                /* reset timer */
 
 
2610
                predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
2611
            }
 
 
2612
        }
 
 
2613
        break;
 
 
2614
        default:
 
 
2615
        {
 
 
2616
            assert(1==0);
 
 
2617
            break;
 
 
2618
        }
 
 
2619
    }
 
 
2620
 
 
 
2621
    HModel_Regen(&predatorStatusPointer->HModelController, PRED_REGEN_TIME);
 
 
2622
 
 
 
2623
    /* Update delta playing flag. */
 
 
2624
    {
 
 
2625
        DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta");
 
 
2626
 
 
 
2627
        if (hitdelta && DeltaAnimation_IsFinished(hitdelta))
 
 
2628
            hitdelta->Playing = 0;
 
 
2629
    }
 
 
2630
 
 
 
2631
#ifdef SHOWPREDOSTATS
 
 
2632
    switch (predatorStatusPointer->CloakStatus)
 
 
2633
    {
 
 
2634
        case PCLOAK_Off:
 
 
2635
            printf("DeCloaked ");
 
 
2636
        break;
 
 
2637
        case PCLOAK_On:
 
 
2638
            printf("Cloaked ");
 
 
2639
        break;
 
 
2640
        case PCLOAK_Activating:
 
 
2641
            printf("Cloaking (%d) ",predatorStatusPointer->CloakTimer);
 
 
2642
        break;
 
 
2643
        case PCLOAK_Deactivating:
 
 
2644
            printf("DeCloaking (%d) ",predatorStatusPointer->CloakTimer);
 
 
2645
        default:
 
 
2646
        break;
 
 
2647
    }
 
 
2648
 
 
 
2649
    printf("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name,
(sbPtr->DamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->DamageBlock.Armour>>ONE_FIXED_SHIFT));
 
 
2650
#endif
 
 
2651
    printf("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name,
(sbPtr->DamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->DamageBlock.Armour>>ONE_FIXED_SHIFT)); // jadda
 
 
2652
    printf("prdator STATE %d\n", predatorStatusPointer->behaviourState); // jadda
 
 
2653
}
 
 
2654
 
 
 
2655
void MakePredatorFar(STRATEGYBLOCK *sbPtr)
 
 
2656
{
 
 
2657
    /* get the predator's status block */
 
 
2658
 
 
 
2659
    assert(sbPtr);     
 
 
2660
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2661
    assert(predatorStatusPointer);
 
 
2662
 
 
 
2663
    /* get rid of the displayblock */
 
 
2664
    DestroyActiveObject(&sbPtr->DisplayBlock);
 
 
2665
 
 
 
2666
    predatorStatusPointer->CloakStatus = PCLOAK_Off;
 
 
2667
    predatorStatusPointer->CloakingEffectiveness = 0;            
 
 
2668
    predatorStatusPointer->CloakTimer = 0;
 
 
2669
 
 
 
2670
    /* status block init */
 
 
2671
    switch(predatorStatusPointer->behaviourState)
 
 
2672
    {
 
 
2673
        case PBS_SwapWeapon:
 
 
2674
        case PBS_SelfDestruct:
 
 
2675
        break;
 
 
2676
        default:
 
 
2677
        {
 
 
2678
            predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME;
 
 
2679
        }
 
 
2680
    }
 
 
2681
}
 
 
2682
 
 
 
2683
void PredatorIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *Section, VECTORCH *incoming)
 
 
2684
{
 
 
2685
    assert(sbPtr);
 
 
2686
    assert(sbPtr->DynPtr);
 
 
2687
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
2688
    assert(predatorStatusPointer);
 
 
2689
 
 
 
2690
    if(!sbPtr->DisplayBlock)
 
 
2691
    {
 
 
2692
        sbPtr->please_destroy_me = 1;
 
 
2693
        return;
 
 
2694
    }
 
 
2695
 
 
 
2696
    if(sbPtr->DamageBlock.Health <= 0)
 
 
2697
    {
 
 
2698
        int deathtype = 0;
 
 
2699
 
 
 
2700
        if (AvP.PlayerType != I_Predator)
 
 
2701
            CurrentGameStats_CreatureKilled(sbPtr, Section);        
 
 
2702
 
 
 
2703
        /*notify death target ,if predator has one*/
 
 
2704
        if(predatorStatusPointer->death_target_sbptr)
 
 
2705
            RequestState(predatorStatusPointer->death_target_sbptr, predatorStatusPointer->death_target_request, 0);
 
 
2706
 
 
 
2707
        /* Set deathtype */
 
 
2708
        {
 
 
2709
            int tkd = TotalKineticDamage(damage);
 
 
2710
 
 
 
2711
/*
 
 
2712
            if (damage->ExplosivePower == 1)
 
 
2713
            {
 
 
2714
                if (MUL_FIXED(tkd, (multiple & ((ONE_FIXED<<1)-1))) > 20)
 
 
2715
                {
 
 
2716
                    // Okay, you can... splat now.
 
 
2717
                    predatorStatusPointer->GibbFactor = -(ONE_FIXED >> 1);
 
 
2718
                    deathtype = 2;
 
 
2719
                }
 
 
2720
            }
 
 
2721
            else
 
 
2722
*/
 
 
2723
 
 
 
2724
            if (damage->ExplosivePower)
 
 
2725
            {
 
 
2726
                predatorStatusPointer->GibbFactor = ONE_FIXED;
 
 
2727
                deathtype = 3;
 
 
2728
            }
 
 
2729
            else if ((tkd < 40) && ((multiple >> 16) > 1))
 
 
2730
            {
 
 
2731
                int newmult = DIV_FIXED(multiple, NormalFrameTime);
 
 
2732
 
 
 
2733
                if (MUL_FIXED(tkd,newmult) > 500)
 
 
2734
                {
 
 
2735
                    predatorStatusPointer->GibbFactor = -(ONE_FIXED >> 2);
 
 
2736
                    deathtype = 2;
 
 
2737
                }
 
 
2738
            }
 
 
2739
        }
 
 
2740
 
 
 
2741
        if (damage->ForceBoom)
 
 
2742
            deathtype += damage->ForceBoom;
 
 
2743
 
 
 
2744
        {
 
 
2745
            SECTION_DATA *chest = GetThisSectionData(predatorStatusPointer->HModelController.section_data,"chest");
 
 
2746
 
 
 
2747
            if (chest == NULL)
 
 
2748
            {
 
 
2749
                /* I'm impressed. */
 
 
2750
                deathtype += 2;
 
 
2751
            }
 
 
2752
            else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here))
 
 
2753
            {
 
 
2754
                /* That's gotta hurt. */
 
 
2755
                deathtype++;
 
 
2756
            }
 
 
2757
        }
 
 
2758
 
 
 
2759
        if (!predatorStatusPointer->GibbFactor)
 
 
2760
        {
 
 
2761
            /* make a sound... if you have a head. */
 
 
2762
            SECTION_DATA *head = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "head");
 
 
2763
 
 
 
2764
            /* Is it still attached? */
 
 
2765
            if (head && !(head->flags & section_data_notreal))
 
 
2766
            {
 
 
2767
                if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
2768
                {
 
 
2769
                    int rand = FastRandom();
 
 
2770
                    int pitch = (rand & 255) - 128;
 
 
2771
 
 
 
2772
                    PlayPredatorSound(0, PSC_Scream_Dying, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
2773
                }
 
 
2774
            }
 
 
2775
        }
 
 
2776
        else
 
 
2777
        {
 
 
2778
            if (predatorStatusPointer->GibbFactor > 0)
 
 
2779
                Extreme_Gibbing(sbPtr, predatorStatusPointer->HModelController.section_data, predatorStatusPointer->GibbFactor, incoming);
 
 
2780
 
 
 
2781
            predatorStatusPointer->GibbFactor = 0;
 
 
2782
        }
 
 
2783
 
 
 
2784
        {
 
 
2785
            HIT_FACING facing = { 0,0,0,0 };
 
 
2786
            int burning = 0;
 
 
2787
            int wounds = 0;
 
 
2788
 
 
 
2789
            SECTION *root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template");
 
 
2790
 
 
 
2791
            if (incoming)
 
 
2792
            {
 
 
2793
                if (incoming->vz > 0)
 
 
2794
                    facing.Back = 1;
 
 
2795
                else
 
 
2796
                    facing.Front = 1;
 
 
2797
 
 
 
2798
                if (incoming->vx > 0)
 
 
2799
                    facing.Right = 1;
 
 
2800
                else
 
 
2801
                    facing.Left = 1;
 
 
2802
            }
 
 
2803
 
 
 
2804
            if (!damage->Impact
 
 
2805
                &&!damage->Cutting
 
 
2806
                &&!damage->Penetrative
 
 
2807
                &&damage->Fire
 
 
2808
                &&!damage->Electrical
 
 
2809
                &&!damage->Acid)
 
 
2810
            {
 
 
2811
                burning = 1;
 
 
2812
            }
 
 
2813
 
 
 
2814
            if (Section)
 
 
2815
                wounds = (Section->flags & section_flags_wounding);
 
 
2816
 
 
 
2817
            DEATH_DATA *this_death = GetPredatorDeathSequence(&predatorStatusPointer->HModelController, root, wounds,
 
 
2818
                    wounds, deathtype, &facing, burning, predatorStatusPointer->IAmCrouched, 0);
 
 
2819
 
 
 
2820
            assert(this_death);
 
 
2821
 
 
 
2822
            Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation");
 
 
2823
            Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta");
 
 
2824
 
 
 
2825
            Convert_Predator_To_Corpse(sbPtr, this_death);
 
 
2826
        }
 
 
2827
    }
 
 
2828
    else
 
 
2829
    {
 
 
2830
        /* If not dead, play a hit delta. */
 
 
2831
        int frontback = 1;
 
 
2832
 
 
 
2833
        if (!damage->Impact
 
 
2834
            &&!damage->Cutting
 
 
2835
            &&!damage->Penetrative
 
 
2836
            &&!damage->Fire
 
 
2837
            &&!damage->Electrical
 
 
2838
            && damage->Acid)
 
 
2839
        {
 
 
2840
            if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
2841
            {
 
 
2842
                int pitch = (FastRandom() & 255) - 128;
 
 
2843
                PlayPredatorSound(0, PSC_Acid, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
2844
            }
 
 
2845
        }
 
 
2846
        else
 
 
2847
        {
 
 
2848
            if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
2849
            {
 
 
2850
                int pitch = (FastRandom() & 255) - 128;
 
 
2851
                PlayPredatorSound(0, PSC_Scream_Hurt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
2852
            }
 
 
2853
        }
 
 
2854
 
 
 
2855
        DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta");
 
 
2856
 
 
 
2857
        if (incoming)
 
 
2858
        {
 
 
2859
            if (incoming->vz >= 0)
 
 
2860
            {
 
 
2861
                frontback = 0;
 
 
2862
 
 
 
2863
                if(damage->Impact > 40)
 
 
2864
                {
 
 
2865
                    if(PNPCW_PlasmaCaster == predatorStatusPointer->Selected_Weapon->id)
 
 
2866
                    {
 
 
2867
                        predatorStatusPointer->Angry = ONE_FIXED * 10;
 
 
2868
                        predatorStatusPointer->weaponTarget.vx = -sbPtr->DynPtr->Position.vx;
 
 
2869
                        predatorStatusPointer->weaponTarget.vy = -sbPtr->DynPtr->Position.vy;
 
 
2870
                        predatorStatusPointer->weaponTarget.vz = -sbPtr->DynPtr->Position.vz;
 
 
2871
                        Normalise(&predatorStatusPointer->weaponTarget);
 
 
2872
 
 
 
2873
                        predatorStatusPointer->weaponTarget.vx >>= 3;
 
 
2874
                        predatorStatusPointer->weaponTarget.vy >>= 3;
 
 
2875
                        predatorStatusPointer->weaponTarget.vz >>= 3;
 
 
2876
 
 
 
2877
                        if(NULL == predatorStatusPointer->closets_target)
 
 
2878
                            predatorStatusPointer->closets_target = sbPtr;
 
 
2879
 
 
 
2880
                        if(PCLOAK_Off == predatorStatusPointer->CloakStatus)
 
 
2881
                            predatorStatusPointer->Angry /= 2;
 
 
2882
 
 
 
2883
                        predatorStatusPointer->behaviourState = PBS_Attacking;
 
 
2884
                    }
 
 
2885
                }
 
 
2886
            }
 
 
2887
        }
 
 
2888
 
 
 
2889
        if (hitdelta)
 
 
2890
        {
 
 
2891
            /* A hierarchy with hit deltas! */
 
 
2892
            if (!hitdelta->Playing)
 
 
2893
            {
 
 
2894
                int CrouchSubSequence;
 
 
2895
                int StandSubSequence;
 
 
2896
 
 
 
2897
                if (Section == NULL)
 
 
2898
                {
 
 
2899
                    if (!frontback)
 
 
2900
                    {
 
 
2901
                        CrouchSubSequence = PCrSS_HitChestBack;
 
 
2902
                        StandSubSequence = PSSS_HitChestBack;
 
 
2903
                    }
 
 
2904
                    else
 
 
2905
                    {
 
 
2906
                        CrouchSubSequence = PCrSS_HitChestFront;
 
 
2907
                        StandSubSequence = PSSS_HitChestFront;
 
 
2908
                    }
 
 
2909
                }
 
 
2910
                else if (Section->sempai->flags & section_flag_head)
 
 
2911
                {
 
 
2912
                    if (!frontback)
 
 
2913
                    {
 
 
2914
                        CrouchSubSequence = PCrSS_HitHeadBack;
 
 
2915
                        StandSubSequence = PSSS_HitHeadBack;
 
 
2916
                    }
 
 
2917
                    else
 
 
2918
                    {
 
 
2919
                        CrouchSubSequence = PCrSS_HitHeadFront;
 
 
2920
                        StandSubSequence = PSSS_HitHeadFront;
 
 
2921
                    }
 
 
2922
                }
 
 
2923
                else if ((Section->sempai->flags & section_flag_left_arm) || (Section->sempai->flags & section_flag_left_hand))
 
 
2924
                {
 
 
2925
                    if (!frontback)
 
 
2926
                    {
 
 
2927
                        CrouchSubSequence = PCrSS_HitRightArm;
 
 
2928
                        StandSubSequence = PSSS_HitRightArm;
 
 
2929
                    }
 
 
2930
                    else
 
 
2931
                    {
 
 
2932
                        CrouchSubSequence = PCrSS_HitLeftArm;
 
 
2933
                        StandSubSequence = PSSS_HitLeftArm;
 
 
2934
                    }
 
 
2935
                }
 
 
2936
                else if ((Section->sempai->flags & section_flag_right_arm) || (Section->sempai->flags & section_flag_right_hand))
 
 
2937
                {
 
 
2938
                    if (!frontback)
 
 
2939
                    {
 
 
2940
                        CrouchSubSequence = PCrSS_HitLeftArm;
 
 
2941
                        StandSubSequence = PSSS_HitLeftArm;
 
 
2942
                    }
 
 
2943
                    else
 
 
2944
                    {
 
 
2945
                        CrouchSubSequence = PCrSS_HitRightArm;
 
 
2946
                        StandSubSequence = PSSS_HitRightArm;
 
 
2947
                    }
 
 
2948
                }
 
 
2949
                else if ((Section->sempai->flags & section_flag_left_leg) ||(Section->sempai->flags & section_flag_left_foot))
 
 
2950
                {
 
 
2951
                    if (!frontback)
 
 
2952
                    {
 
 
2953
                        CrouchSubSequence = PCrSS_HitRightLeg;
 
 
2954
                        StandSubSequence = PSSS_HitRightLeg;
 
 
2955
                    }
 
 
2956
                    else
 
 
2957
                    {
 
 
2958
                        CrouchSubSequence = PCrSS_HitLeftLeg;
 
 
2959
                        StandSubSequence = PSSS_HitLeftLeg;
 
 
2960
                    }
 
 
2961
                }
 
 
2962
                else if ((Section->sempai->flags & section_flag_right_leg) ||(Section->sempai->flags & section_flag_right_foot))
 
 
2963
                {
 
 
2964
                    if (!frontback)
 
 
2965
                    {
 
 
2966
                        CrouchSubSequence = PCrSS_HitLeftLeg;
 
 
2967
                        StandSubSequence = PSSS_HitLeftLeg;
 
 
2968
                    }
 
 
2969
                    else
 
 
2970
                    {
 
 
2971
                        CrouchSubSequence = PCrSS_HitRightLeg;
 
 
2972
                        StandSubSequence = PSSS_HitRightLeg;
 
 
2973
                    }
 
 
2974
                }
 
 
2975
                else
 
 
2976
                {
 
 
2977
                    /* Chest or misc. hit. */
 
 
2978
                    if (!frontback)
 
 
2979
                    {
 
 
2980
                        CrouchSubSequence = PCrSS_HitChestBack;
 
 
2981
                        StandSubSequence = PSSS_HitChestBack;
 
 
2982
                    }
 
 
2983
                    else
 
 
2984
                    {
 
 
2985
                        CrouchSubSequence = PCrSS_HitChestFront;
 
 
2986
                        StandSubSequence = PSSS_HitChestFront;
 
 
2987
                    }
 
 
2988
                }
 
 
2989
 
 
 
2990
                if(predatorStatusPointer->IAmCrouched)
 
 
2991
                {
 
 
2992
                    if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorCrouch,CrouchSubSequence))
 
 
2993
                        Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorCrouch,CrouchSubSequence,-1);
 
 
2994
                }
 
 
2995
                else
 
 
2996
                {
 
 
2997
                    if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,StandSubSequence))
 
 
2998
                        Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorStand,StandSubSequence,-1);
 
 
2999
                }
 
 
3000
 
 
 
3001
                hitdelta->Playing = 1;
 
 
3002
                /* Not looped. */
 
 
3003
            }
 
 
3004
        }
 
 
3005
 
 
 
3006
        if (predatorStatusPointer->behaviourState != PBS_SelfDestruct)
 
 
3007
        {
 
 
3008
            const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
3009
 
 
 
3010
                /* 12.5% health? */
 
 
3011
            if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-3)))
 
 
3012
            {
 
 
3013
                /* Switch to template. */       
 
 
3014
                SECTION *root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template");
 
 
3015
                assert(root);
 
 
3016
                RemoveAllDeltas(&predatorStatusPointer->HModelController);
 
 
3017
                /* Set 'new' sequence. */
 
 
3018
                predatorStatusPointer->HModelController.Sequence_Type = HMSQT_PredatorCrouch;
 
 
3019
                predatorStatusPointer->HModelController.Sub_Sequence = PCrSS_Det_Prog;
 
 
3020
                Transmogrify_HModels(sbPtr, &predatorStatusPointer->HModelController, root, 1, 0, 0);
 
 
3021
                ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr);
 
 
3022
 
 
 
3023
                InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>3), HMSQT_PredatorCrouch, PCrSS_Det_Prog, -1, 0);
 
 
3024
 
 
 
3025
                if (predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
3026
                    PredatorCloakOn(predatorStatusPointer);
 
 
3027
 
 
 
3028
                NPC_InitMovementData(&predatorStatusPointer->moveData);
 
 
3029
                NPC_InitWanderData(&predatorStatusPointer->wanderData);
 
 
3030
                InitWaypointManager(&predatorStatusPointer->waypointManager);
 
 
3031
                predatorStatusPointer->volleySize = 0;
 
 
3032
                predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
3033
                predatorStatusPointer->behaviourState = PBS_SelfDestruct;
 
 
3034
                predatorStatusPointer->stateTimer = 0;
 
 
3035
                predatorStatusPointer->Pred_Laser_On = 0;
 
 
3036
                predatorStatusPointer->internalState = 0; /* Not yet primed. */
 
 
3037
                predatorStatusPointer->IAmCrouched = 1;
 
 
3038
            }
 
 
3039
if(0)
 
 
3040
            if (predatorStatusPointer->behaviourState == PBS_Recovering)
 
 
3041
            {
 
 
3042
                int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position);
 
 
3043
 
 
 
3044
                if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 8)
 
 
3045
                {
 
 
3046
                    if (PNPCW_PlasmaCaster != predatorStatusPointer->Selected_Weapon->id)
 
 
3047
                    {
 
 
3048
                        predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3049
                        //Predator_Enter_Swapping_State(sbPtr);
 
 
3050
                    }
 
 
3051
                }
 
 
3052
                else
 
 
3053
                {
 
 
3054
                    if (predatorStatusPointer->MeleeWeapon != predatorStatusPointer->Selected_Weapon)
 
 
3055
                    {
 
 
3056
                        predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id;
 
 
3057
                        //Predator_Enter_Swapping_State(sbPtr);
 
 
3058
                    }
 
 
3059
                }
 
 
3060
            }
 
 
3061
            else
 
 
3062
            {
 
 
3063
                STRATEGYBLOCK *closest_target = Predator_GetNewTarget(sbPtr);
 
 
3064
puts("HELLO");
 
 
3065
            printf("vehave %d\n", predatorStatusPointer->behaviourState);
 
 
3066
 
 
 
3067
                if (NULL != closest_target)
 
 
3068
                {
 
 
3069
            printf("target %d\n", predatorStatusPointer->closets_target->type);
 
 
3070
                    puts("new TAGET");
 
 
3071
                    int range = VectorDistance(&closest_target->DynPtr->Position, &sbPtr->DynPtr->Position);
 
 
3072
 
 
 
3073
                    if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 10)
 
 
3074
                    {
 
 
3075
                        if (PNPCW_PlasmaCaster != predatorStatusPointer->Selected_Weapon->id)
 
 
3076
                        {
 
 
3077
                            predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3078
                            //Predator_Enter_Swapping_State(sbPtr);
 
 
3079
                        }
 
 
3080
                    }
 
 
3081
                    else
 
 
3082
                    {
 
 
3083
                        if (predatorStatusPointer->MeleeWeapon != predatorStatusPointer->Selected_Weapon)
 
 
3084
                        {
 
 
3085
                            predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id;
 
 
3086
                            //Predator_Enter_Swapping_State(sbPtr);
 
 
3087
                        }
 
 
3088
                    }
 
 
3089
 
 
 
3090
                    /*
 
 
3091
                    if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 10)
 
 
3092
                    {
 
 
3093
                        predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3094
                        //Predator_Enter_Swapping_State(sbPtr);
 
 
3095
                    }
 
 
3096
                    */
 
 
3097
 
 
 
3098
                    if(closest_target != predatorStatusPointer->closets_target)
 
 
3099
                    {
 
 
3100
                        predatorStatusPointer->closets_target = closest_target;
 
 
3101
                        COPY_NAME(predatorStatusPointer->Target_SBname, predatorStatusPointer->closets_target->SBname);
 
 
3102
                    }
 
 
3103
                }
 
 
3104
 
 
 
3105
                if(predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
3106
                    PredatorCloakOn(predatorStatusPointer);
 
 
3107
            }
 
 
3108
        }
 
 
3109
    }
 
 
3110
}
 
 
3111
 
 
 
3112
static void Execute_PNS_AttackWithMeleeWeapon(STRATEGYBLOCK *sbPtr, int distance_to_target)
 
 
3113
{
 
 
3114
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3115
 
 
 
3116
    if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange)
 
 
3117
    {
 
 
3118
        int target_previous_distance = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position);
 
 
3119
 
 
 
3120
        if(distance_to_target < target_previous_distance)
 
 
3121
        {
 
 
3122
            if(PNPCW_Pistol == predatorStatusPointer->SecondaryWeapon)
 
 
3123
            {
 
 
3124
                switch(predatorStatusPointer->closets_target->type)
 
 
3125
                {
 
 
3126
                    case I_BehaviourAlien:
 
 
3127
                    case I_BehaviourAlienPlayer:
 
 
3128
                    case I_BehaviourFaceHugger:
 
 
3129
                        if ((distance_to_target > 9000) && (distance_to_target < 20000))
 
 
3130
                        {
 
 
3131
                            if ((FastRandom() & 65535) > 32767)
 
 
3132
                            {
 
 
3133
                                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3134
                                predator_change_behaviour(sbPtr);
 
 
3135
                                return;
 
 
3136
                            }
 
 
3137
                        }
 
 
3138
                    default:
 
 
3139
                    break;
 
 
3140
                }
 
 
3141
            }
 
 
3142
            else if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange * 10)
 
 
3143
            {
 
 
3144
                predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3145
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3146
                predator_change_behaviour(sbPtr);
 
 
3147
                return;
 
 
3148
            }
 
 
3149
        }
 
 
3150
        else
 
 
3151
        {
 
 
3152
            if ((FastRandom() & 65535) > 32767/2)
 
 
3153
            if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange * 8)
 
 
3154
            {
 
 
3155
                if(predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
3156
                    PredatorCloakOn(predatorStatusPointer);
 
 
3157
 
 
 
3158
                if(PNPCW_Pistol == predatorStatusPointer->SecondaryWeapon)
 
 
3159
                    predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3160
 
 
 
3161
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3162
                predator_change_behaviour(sbPtr);
 
 
3163
                return;
 
 
3164
            }
 
 
3165
        }
 
 
3166
 
 
 
3167
        predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
3168
    }
 
 
3169
    else
 
 
3170
    {
 
 
3171
        /* Decrement the near state timer */
 
 
3172
        predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
3173
 
 
 
3174
        PredatorNearDamageShell(sbPtr);
 
 
3175
 
 
 
3176
        if (predatorStatusPointer->HModelController.keyframe_flags & 1)
 
 
3177
        {
 
 
3178
            predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME;
 
 
3179
            Predator_Enter_Attacking_State(sbPtr);
 
 
3180
        }
 
 
3181
    }
 
 
3182
}
 
 
3183
 
 
 
3184
static int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr) 
 
 
3185
{
 
 
3186
    static const VECTORCH offset[3] = { {0,-50,0}, {43,25,0}, {-43,25,0}, };
 
 
3187
    VECTORCH z_vec;
 
 
3188
    int hits = 0;
 
 
3189
    STRATEGYBLOCK *laserhits[3];
 
 
3190
 
 
 
3191
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
3192
 
 
 
3193
    predatorStatusPointer->Pred_Laser_On = 1;
 
 
3194
 
 
 
3195
    SECTION_DATA *plasma_muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash");
 
 
3196
 
 
 
3197
    MATRIXCH matrix = plasma_muzzle->SecMat;
 
 
3198
 
 
 
3199
    z_vec.vx = matrix.mat31;
 
 
3200
    z_vec.vy = matrix.mat32;
 
 
3201
    z_vec.vz = matrix.mat33;
 
 
3202
 
 
 
3203
    TransposeMatrixCH(&matrix);
 
 
3204
 
 
 
3205
    predatorStatusPointer->Pred_Laser_Sight.LightSource = plasma_muzzle->World_Offset;
 
 
3206
 
 
 
3207
    int i;
 
 
3208
 
 
 
3209
    for (i = 0; i < 3; i++)
 
 
3210
    {
 
 
3211
        VECTORCH position = offset[i];
 
 
3212
 
 
 
3213
        RotateVector(&position, &matrix);
 
 
3214
        position.vx += plasma_muzzle->World_Offset.vx;
 
 
3215
        position.vy += plasma_muzzle->World_Offset.vy;
 
 
3216
        position.vz += plasma_muzzle->World_Offset.vz;
 
 
3217
        FindPolygonInLineOfSight(&z_vec, &position, 0, sbPtr->DisplayBlock);
 
 
3218
 
 
 
3219
        predatorStatusPointer->Pred_Laser_Sight.Normal[i] = LOS_ObjectNormal;
 
 
3220
        predatorStatusPointer->Pred_Laser_Sight.Position[i] = LOS_Point;
 
 
3221
 
 
 
3222
        if (LOS_ObjectHitPtr)
 
 
3223
        {
 
 
3224
            if (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock)
 
 
3225
                predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 1;
 
 
3226
 
 
 
3227
            laserhits[i] = LOS_ObjectHitPtr->ObStrategyBlock;
 
 
3228
            hits++;
 
 
3229
        }
 
 
3230
        else
 
 
3231
        {
 
 
3232
            laserhits[i] = NULL;
 
 
3233
        }
 
 
3234
 
 
 
3235
    }
 
 
3236
 
 
 
3237
    if(hits && (laserhits[0] == laserhits[1]) && (laserhits[1] == laserhits[2]))
 
 
3238
    {
 
 
3239
        if (laserhits[0] == PlayerStatus.sbptr)
 
 
3240
            predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 1;
 
 
3241
 
 
 
3242
        return (laserhits[0] == predatorStatusPointer->closets_target);
 
 
3243
    }
 
 
3244
 
 
 
3245
    predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 0;
 
 
3246
    return 0;
 
 
3247
}
 
 
3248
 
 
 
3249
static void Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr, int distance_to_target)
 
 
3250
{
 
 
3251
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3252
 
 
 
3253
    if (!predatorStatusPointer->internalState)
 
 
3254
    {
 
 
3255
        if (predatorStatusPointer->HModelController.Tweening == Controller_NoTweening)
 
 
3256
            predatorStatusPointer->HModelController.Playing = 0;
 
 
3257
    }
 
 
3258
 
 
 
3259
    /* Always turn to face... */
 
 
3260
    NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
3261
 
 
 
3262
    VECTORCH orientationDirn;
 
 
3263
    /* orientate to firing point first */
 
 
3264
    if (predatorStatusPointer->My_Elevation_Section)
 
 
3265
    {
 
 
3266
        /* Assume range large w.r.t. half shoulder width... */
 
 
3267
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
 
 
3268
        orientationDirn.vy = 0;
 
 
3269
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
 
 
3270
    }
 
 
3271
    else
 
 
3272
    {
 
 
3273
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
 
 
3274
        orientationDirn.vy = 0;
 
 
3275
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
 
 
3276
    }
 
 
3277
 
 
 
3278
    int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
3279
 
 
 
3280
    if(!correctlyOrientated)
 
 
3281
        return;
 
 
3282
 
 
 
3283
    if (predatorStatusPointer->closets_target->type == I_BehaviourAutoGun)
 
 
3284
        predatorStatusPointer->stateTimer -= NormalFrameTime << 2;
 
 
3285
    else
 
 
3286
        predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
3287
 
 
 
3288
    if (predatorStatusPointer->internalState == 1)
 
 
3289
    {
 
 
3290
        /* Using stateTimer, thanks! */
 
 
3291
    }
 
 
3292
    else if(predatorStatusPointer->stateTimer > 0)
 
 
3293
    {
 
 
3294
        return;
 
 
3295
    }
 
 
3296
 
 
 
3297
    /* State timed out - try to fire! */
 
 
3298
 
 
 
3299
    /* we are not correctly orientated to the target: this could happen because we have
 
 
3300
    just entered this state, or the target has moved during firing*/
 
 
3301
 
 
 
3302
    if ((predatorStatusPointer->internalState != 2) && (predatorStatusPointer->internalState != 1))
 
 
3303
    {
 
 
3304
        predatorStatusPointer->internalState = 1;
 
 
3305
        /* Pausing. */
 
 
3306
        predatorStatusPointer->stateTimer = ONE_FIXED;
 
 
3307
    }
 
 
3308
 
 
 
3309
    int onTarget = DoPredatorLaserTargeting(sbPtr);
 
 
3310
 
 
 
3311
    if ((predatorStatusPointer->internalState == 1) && (predatorStatusPointer->stateTimer <= 0))
 
 
3312
    {
 
 
3313
        if (onTarget)
 
 
3314
        {
 
 
3315
            /* If you are correctly oriented, you can now fire!  Or taunt instead? */
 
 
3316
            /* Fire at least once! */
 
 
3317
            predatorStatusPointer->enableTaunt = 1;
 
 
3318
            predatorStatusPointer->HModelController.Playing = 1;
 
 
3319
            predatorStatusPointer->HModelController.Looped = 0;
 
 
3320
            predatorStatusPointer->HModelController.sequence_timer = 0;
 
 
3321
            predatorStatusPointer->internalState = 2;
 
 
3322
 
 
 
3323
            /* look after the sound */
 
 
3324
            Sound_Play(SID_PRED_LAUNCHER, "d", &sbPtr->DynPtr->Position);
 
 
3325
 
 
 
3326
            /* Now fire a bolt. */
 
 
3327
 
 
 
3328
            {
 
 
3329
                SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash");
 
 
3330
 
 
 
3331
                InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat, 0, &TemplateAmmo[AMMO_PLASMACASTER].MaxDamage,
65536);
 
 
3332
                predatorStatusPointer->volleySize++;
 
 
3333
            }
 
 
3334
 
 
 
3335
            if (predatorStatusPointer->CloakStatus == PCLOAK_Off)
 
 
3336
            if (((FastRandom() & 65535) < 32767) && predatorStatusPointer->enableTaunt &&
(predatorStatusPointer->closets_target->type != I_BehaviourAutoGun))
 
 
3337
            {
 
 
3338
                if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Taunt_One))
 
 
3339
                {
 
 
3340
                    int rand = FastRandom();
 
 
3341
                    int pitch = (rand & 255) - 128;
 
 
3342
                    predatorStatusPointer->lastState = predatorStatusPointer->behaviourState;
 
 
3343
                    predatorStatusPointer->behaviourState = PBS_Taunting;
 
 
3344
                    predatorStatusPointer->stateTimer = NPC_AVOIDTIME;
 
 
3345
                    predatorStatusPointer->enableTaunt = 0;
 
 
3346
 
 
 
3347
                    SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Taunt_One, -1, (ONE_FIXED >> 3));               
 
 
3348
 
 
 
3349
                    predatorStatusPointer->HModelController.LoopAfterTweening = 0;
 
 
3350
 
 
 
3351
                    if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX)
 
 
3352
                        PlayPredatorSound(0, PSC_Taunt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position);
 
 
3353
                }
 
 
3354
            }
 
 
3355
 
 
 
3356
            predatorStatusPointer->patience = PRED_PATIENCE_TIME;
 
 
3357
            predatorStatusPointer->stateTimer = ONE_FIXED;
 
 
3358
            predatorStatusPointer->enableSwap = 1;
 
 
3359
            return;
 
 
3360
        }
 
 
3361
        else
 
 
3362
        {
 
 
3363
            if (distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 4)
 
 
3364
            {
 
 
3365
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3366
                predator_change_behaviour(sbPtr);
 
 
3367
                return;
 
 
3368
            }
 
 
3369
            else
 
 
3370
            {
 
 
3371
                /* You think you're correctly orientated - but you're still not hitting. */
 
 
3372
                predatorStatusPointer->patience -= NormalFrameTime;
 
 
3373
 
 
 
3374
                if (predatorStatusPointer->patience <= 0)
 
 
3375
                {
 
 
3376
                    predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3377
                    predator_change_behaviour(sbPtr);
 
 
3378
                    return;
 
 
3379
                }
 
 
3380
 
 
 
3381
                if (predatorStatusPointer->stateTimer <= 0)
 
 
3382
                {
 
 
3383
                    /* Oh, just give up. */
 
 
3384
                    predatorStatusPointer->HModelController.Playing = 1;
 
 
3385
                    predatorStatusPointer->HModelController.Looped = 0;
 
 
3386
                    predatorStatusPointer->HModelController.sequence_timer = 0;
 
 
3387
                    predatorStatusPointer->internalState = 2;
 
 
3388
                }
 
 
3389
                else
 
 
3390
                {
 
 
3391
                    return;
 
 
3392
                }
 
 
3393
            }
 
 
3394
        }
 
 
3395
    }
 
 
3396
 
 
 
3397
    if (predatorStatusPointer->internalState == 2)
 
 
3398
    {
 
 
3399
        /* After shot. */
 
 
3400
        if (predatorStatusPointer->HModelController.sequence_timer < (ONE_FIXED - 1))
 
 
3401
            return; /* Still playing. */
 
 
3402
 
 
 
3403
        if(distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 2)
 
 
3404
        {
 
 
3405
            if(PCLOAK_On == predatorStatusPointer->CloakStatus)
 
 
3406
                PredatorCloakOff(predatorStatusPointer);
 
 
3407
 
 
 
3408
            predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3409
            predator_change_behaviour(sbPtr);
 
 
3410
        }
 
 
3411
        else
 
 
3412
        {
 
 
3413
            const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
3414
 
 
 
3415
            if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1)))
 
 
3416
            {
 
 
3417
                if(distance_to_target > 15000)
 
 
3418
                {
 
 
3419
                    int target_previous_distance = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position); // target retreating?
 
 
3420
 
 
 
3421
                    switch(predatorStatusPointer->closets_target->type)
 
 
3422
                    {
 
 
3423
                        case I_BehaviourMarinePlayer:
 
 
3424
                        case I_BehaviourMarine:
 
 
3425
                        case I_BehaviourAlienPlayer:
 
 
3426
                            if(PCLOAK_Off == predatorStatusPointer->CloakStatus)
 
 
3427
                                PredatorCloakOn(predatorStatusPointer);
 
 
3428
                        //break;
 
 
3429
                        //case I_BehaviourAlien:
 
 
3430
                        default:
 
 
3431
                        break;
 
 
3432
 
 
 
3433
                    }
 
 
3434
 
 
 
3435
                    if(distance_to_target > target_previous_distance)
 
 
3436
                    {
 
 
3437
                        predatorStatusPointer->behaviourState = PBS_Recovering;
 
 
3438
                    }
 
 
3439
                }
 
 
3440
                else
 
 
3441
                {
 
 
3442
                    predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
 
 
3443
                    predatorStatusPointer->internalState = 0;
 
 
3444
                }
 
 
3445
            }
 
 
3446
            else
 
 
3447
            {
 
 
3448
                if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize)
 
 
3449
                {
 
 
3450
                    predatorStatusPointer->behaviourState = (distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 2) ? PBS_SwapWeapon
: PBS_Engaging;
 
 
3451
                    predator_change_behaviour(sbPtr);
 
 
3452
                }
 
 
3453
                else
 
 
3454
                {
 
 
3455
                    /* And another! */
 
 
3456
                    predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;                                 
 
 
3457
                    predatorStatusPointer->internalState = 0;
 
 
3458
                }
 
 
3459
            }
 
 
3460
        }
 
 
3461
    }       
 
 
3462
}
 
 
3463
 
 
 
3464
static void Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr, int distance_to_target)
 
 
3465
{
 
 
3466
    VECTORCH orientationDirn;
 
 
3467
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);
 
 
3468
 
 
 
3469
    /* Always turn to face... */
 
 
3470
    NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
3471
 
 
 
3472
    /* Fix weapon target! */
 
 
3473
    predatorStatusPointer->weaponTarget.vx -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat21, 300);
 
 
3474
    predatorStatusPointer->weaponTarget.vy -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat22, 300);
 
 
3475
    predatorStatusPointer->weaponTarget.vz -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat23, 300);
 
 
3476
 
 
 
3477
    /* orientate to firing point first */
 
 
3478
    if (predatorStatusPointer->My_Elevation_Section)
 
 
3479
    {
 
 
3480
        /* Assume range large w.r.t. half shoulder width... */
 
 
3481
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
 
 
3482
        orientationDirn.vy = 0;
 
 
3483
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
 
 
3484
    }
 
 
3485
    else
 
 
3486
    {
 
 
3487
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
 
 
3488
        orientationDirn.vy = 0;
 
 
3489
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
 
 
3490
    }
 
 
3491
 
 
 
3492
    /* closets_target shift? */
 
 
3493
    int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
3494
 
 
 
3495
    /* If still tweening, pause. */
 
 
3496
    if (predatorStatusPointer->HModelController.Tweening != Controller_NoTweening)
 
 
3497
        return;
 
 
3498
 
 
 
3499
    predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
3500
 
 
 
3501
    /* You must have fired already. */
 
 
3502
 
 
 
3503
    if(predatorStatusPointer->stateTimer > 0)
 
 
3504
        return;
 
 
3505
 
 
 
3506
    //if (predatorStatusPointer->stateTimer == predatorStatusPointer->Selected_Weapon->FiringRate)
 
 
3507
    if (predatorStatusPointer->stateTimer < 0)
 
 
3508
    {
 
 
3509
        predatorStatusPointer->HModelController.Playing = 0;
 
 
3510
 
 
 
3511
        /* we are not correctly orientated to the target: this could happen because we have
 
 
3512
        just entered this state, or the target has moved during firing*/
 
 
3513
 
 
 
3514
        if(!correctlyOrientated)
 
 
3515
            return;
 
 
3516
 
 
 
3517
        /* If you are correctly oriented, you can now fire! */
 
 
3518
 
 
 
3519
        predatorStatusPointer->HModelController.Playing = 1;
 
 
3520
        predatorStatusPointer->HModelController.sequence_timer = 0;
 
 
3521
 
 
 
3522
        /* look after the sound */
 
 
3523
        Sound_Play(SID_PRED_LASER, "d", &sbPtr->DynPtr->Position);
 
 
3524
 
 
 
3525
        /* Now fire a spear... */
 
 
3526
        {
 
 
3527
            VECTORCH shotVector;
 
 
3528
            SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash");
 
 
3529
 
 
 
3530
            shotVector.vx = muzzle->SecMat.mat31;
 
 
3531
            shotVector.vy = muzzle->SecMat.mat32;
 
 
3532
            shotVector.vz = muzzle->SecMat.mat33;
 
 
3533
 
 
 
3534
            FindPolygonInLineOfSight(&shotVector, &muzzle->World_Offset, 0, sbPtr->DisplayBlock);
 
 
3535
 
 
 
3536
            /* Now deal with LOS_ObjectHitPtr. */
 
 
3537
            if (LOS_ObjectHitPtr)
 
 
3538
                ShotPredRifleArrow(&muzzle->World_Offset, &muzzle->SecMat);
 
 
3539
 
 
 
3540
            predatorStatusPointer->volleySize++;
 
 
3541
        }
 
 
3542
 
 
 
3543
        predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate * 5;
 
 
3544
 
 
 
3545
        if(predatorStatusPointer->RifleArrows-- < 0)
 
 
3546
        {
 
 
3547
            predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster;
 
 
3548
            predatorStatusPointer->SecondaryWeapon = PNPCW_PlasmaCaster;
 
 
3549
            predatorStatusPointer->RifleArrows = 0;
 
 
3550
            predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3551
            predator_change_behaviour(sbPtr);
 
 
3552
            return;
 
 
3553
        }
 
 
3554
    }
 
 
3555
 
 
 
3556
    if(distance_to_target < 1000)
 
 
3557
    {
 
 
3558
        predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3559
        predator_change_behaviour(sbPtr);
 
 
3560
    }
 
 
3561
    else
 
 
3562
    {
 
 
3563
        /* we are far enough away, so return to approach? */
 
 
3564
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
3565
 
 
 
3566
        if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1)))
 
 
3567
        {
 
 
3568
            /* 50% health? */
 
 
3569
            if (General_GetAIModuleForRetreat(sbPtr, predatorStatusPointer->closets_target->containingModule->m_aimodule, 5))
 
 
3570
                predatorStatusPointer->behaviourState = PBS_Withdrawing;
 
 
3571
            else
 
 
3572
                predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;                                 
 
 
3573
        return;
 
 
3574
        }
 
 
3575
 
 
 
3576
        if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize)
 
 
3577
        {
 
 
3578
            if (predatorStatusPointer->enableSwap && ((FastRandom() & 65535) > 32767))
 
 
3579
            {
 
 
3580
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3581
                predator_change_behaviour(sbPtr);
 
 
3582
                return;
 
 
3583
            }
 
 
3584
        }
 
 
3585
        else
 
 
3586
        {
 
 
3587
            /* And another! */
 
 
3588
            predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;                                 
 
 
3589
        }
 
 
3590
    }
 
 
3591
}
 
 
3592
 
 
 
3593
static void Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr, int distance_to_target)
 
 
3594
{
 
 
3595
    VECTORCH orientationDirn;
 
 
3596
    PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr);    
 
 
3597
 
 
 
3598
    /* Always turn to face... */
 
 
3599
    NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target);
 
 
3600
 
 
 
3601
    /* Fix weapon target! */
 
 
3602
    {
 
 
3603
        predatorStatusPointer->weaponTarget.vx -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, 200);
 
 
3604
        predatorStatusPointer->weaponTarget.vy -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, 200);
 
 
3605
        predatorStatusPointer->weaponTarget.vz -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, 200);
 
 
3606
    }
 
 
3607
 
 
 
3608
    /* Aim up a little? */
 
 
3609
    int range = VectorDistance(&predatorStatusPointer->weaponTarget, &sbPtr->DynPtr->Position);
 
 
3610
 
 
 
3611
    if (range > 5000)
 
 
3612
    {
 
 
3613
        /* Out of range? */
 
 
3614
        if(range > 20000)
 
 
3615
        {
 
 
3616
            predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
3617
            predator_change_behaviour(sbPtr);
 
 
3618
            return;
 
 
3619
        }
 
 
3620
 
 
 
3621
        predatorStatusPointer->weaponTarget.vy -= range / 6;
 
 
3622
    }
 
 
3623
    else
 
 
3624
    {
 
 
3625
        /* I'm afraid it just won't work. */
 
 
3626
        predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3627
        predator_change_behaviour(sbPtr);
 
 
3628
        return;
 
 
3629
    }
 
 
3630
 
 
 
3631
    /* orientate to firing point first */
 
 
3632
    if (predatorStatusPointer->My_Elevation_Section)
 
 
3633
    {
 
 
3634
        /* Assume range large w.r.t. half shoulder width... */
 
 
3635
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx;
 
 
3636
        orientationDirn.vy = 0;
 
 
3637
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz;
 
 
3638
    }
 
 
3639
    else
 
 
3640
    {
 
 
3641
        orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
 
 
3642
        orientationDirn.vy = 0;
 
 
3643
        orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
 
 
3644
    }
 
 
3645
 
 
 
3646
    /* closets_target shift? */
 
 
3647
    int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE);
 
 
3648
 
 
 
3649
    /* If still tweening, pause. */
 
 
3650
    if (predatorStatusPointer->HModelController.Tweening != Controller_NoTweening)
 
 
3651
        return;
 
 
3652
 
 
 
3653
    predatorStatusPointer->stateTimer -= NormalFrameTime;
 
 
3654
 
 
 
3655
    /* You must have fired already. */
 
 
3656
 
 
 
3657
    if(predatorStatusPointer->stateTimer > 0)
 
 
3658
        return;
 
 
3659
 
 
 
3660
    if (predatorStatusPointer->stateTimer == predatorStatusPointer->Selected_Weapon->FiringRate)
 
 
3661
    {
 
 
3662
        predatorStatusPointer->HModelController.Playing = 0;
 
 
3663
 
 
 
3664
        /* Only terminate if you haven't fired yet... */
 
 
3665
        if (!NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target))
 
 
3666
        {
 
 
3667
            predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
3668
            predator_change_behaviour(sbPtr);
 
 
3669
            return;
 
 
3670
        }
 
 
3671
 
 
 
3672
        /* we are not correctly orientated to the target: this could happen because we have
 
 
3673
        just entered this state, or the target has moved during firing*/
 
 
3674
 
 
 
3675
        if(!correctlyOrientated)
 
 
3676
            return;
 
 
3677
 
 
 
3678
        /* If you are correctly oriented, you can now fire! */
 
 
3679
 
 
 
3680
        predatorStatusPointer->HModelController.Playing = 1;
 
 
3681
        predatorStatusPointer->HModelController.sequence_timer = 0;
 
 
3682
 
 
 
3683
        /* Now fire a bolt. */
 
 
3684
 
 
 
3685
        {
 
 
3686
            SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash");
 
 
3687
 
 
 
3688
            Pred_Pistol_Bolt(&muzzle->World_Offset, &muzzle->SecMat, 0);
 
 
3689
            predatorStatusPointer->volleySize++;
 
 
3690
        }
 
 
3691
 
 
 
3692
        Sound_Play(SID_PRED_PISTOL, "d", &sbPtr->DynPtr->Position);
 
 
3693
 
 
 
3694
        if (predatorStatusPointer->volleySize > 3)
 
 
3695
            predatorStatusPointer->enableSwap = 1;
 
 
3696
    }       
 
 
3697
 
 
 
3698
    {
 
 
3699
        /* we are far enough away, so return to approach? */
 
 
3700
        const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator];
 
 
3701
 
 
 
3702
        if ((sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1))) && (sbPtr->DamageBlock.Health >
0))
 
 
3703
        {
 
 
3704
            /* 50% health? */
 
 
3705
            if (General_GetAIModuleForRetreat(sbPtr, predatorStatusPointer->closets_target->containingModule->m_aimodule, 5))
 
 
3706
                predatorStatusPointer->behaviourState = PBS_Withdrawing;
 
 
3707
            else
 
 
3708
                predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;
 
 
3709
        }
 
 
3710
        else if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize)
 
 
3711
        {
 
 
3712
            if (((FastRandom() & 65535) > 32767) && predatorStatusPointer->enableSwap)
 
 
3713
                predatorStatusPointer->behaviourState = PBS_SwapWeapon;
 
 
3714
            else
 
 
3715
                predatorStatusPointer->behaviourState = PBS_Engaging;
 
 
3716
 
 
 
3717
            predator_change_behaviour(sbPtr);
 
 
3718
        }
 
 
3719
        else
 
 
3720
        {
 
 
3721
            /* And another! */
 
 
3722
            predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate;                                 
 
 
3723
        }
 
 
3724
    }
 
 
3725
}
 
 
3726
 
 
 
3727
static const PREDATOR_WEAPON_DATA NPC_Predator_Weapons[] =
 
 
3728
{
 
 
3729
    {
 
 
3730
        PNPCW_Wristblade,            /* ID */
 
 
3731
        Execute_PNS_AttackWithMeleeWeapon,    /* Fire Func. */
 
 
3732
        "pred with wristblade",            /* HierarchyName */
 
 
3733
        NULL,                    /* GunName */
 
 
3734
        "R shoulder",                /* ElevationName */
 
 
3735
        "predator",                /* HitLocationTableName */
 
 
3736
        0,                    // MinRange
 
 
3737
        1500,                    // MaxRange
 
 
3738
        65536<<1,                /* Firing Rate */
 
 
3739
        10,                    /* VolleySize */
 
 
3740
        65536>>1,                /* SwappingTime */
 
 
3741
        1,                    /* UseElevation */
 
 
3742
    },
 
 
3743
    {
 
 
3744
        PNPCW_Medicomp,                /* ID */
 
 
3745
        Execute_PNS_DischargePistol,        /* Fire Func. */
 
 
3746
        "medicomp",                /* HierarchyName */
 
 
3747
        "P caster box",                /* GunName */
 
 
3748
        "R shoulder",                /* ElevationName */
 
 
3749
        "predator",                /* HitLocationTableName */
 
 
3750
        15000,                    // MinRange
 
 
3751
        0,                    // MaxRange
 
 
3752
        65536>>3,                /* Firing Rate */
 
 
3753
        8,                    /* VolleySize */
 
 
3754
        65536>>1,                /* SwappingTime */
 
 
3755
        1,                    /* UseElevation */
 
 
3756
    },
 
 
3757
    {
 
 
3758
        PNPCW_PlasmaCaster,            /* ID */
 
 
3759
        Execute_PNS_AttackWithPlasmaCaster,    /* Fire Func. */
 
 
3760
        "pred with Plasma Caster",        /* HierarchyName */
 
 
3761
        "Plasma caster",            /* GunName */
 
 
3762
        "Plasma caster",            /* ElevationName */
 
 
3763
        "predator",                /* HitLocationTableName */
 
 
3764
        0,                    // MinRange
 
 
3765
        40000,                    // MaxRange
 
 
3766
        65536,                    /* Firing Rate */
 
 
3767
        10,                    /* VolleySize */
 
 
3768
        65536,                    /* SwappingTime */
 
 
3769
        1,                    /* UseElevation */
 
 
3770
    },
 
 
3771
    {
 
 
3772
        PNPCW_Staff,                /* ID */
 
 
3773
        Execute_PNS_AttackWithMeleeWeapon,    /* Fire Func. */
 
 
3774
        "pred with staff",            /* HierarchyName */
 
 
3775
        NULL,                    /* GunName */
 
 
3776
        "R shoulder",                /* ElevationName */
 
 
3777
        "predator",                /* HitLocationTableName */
 
 
3778
        0,                    // MinRange
 
 
3779
        2000,                    // MaxRange
 
 
3780
        65536<<1,                /* Firing Rate */
 
 
3781
        10,                    /* VolleySize */
 
 
3782
        65536>>1,                /* SwappingTime */
 
 
3783
        0,                    /* UseElevation */
 
 
3784
    },
 
 
3785
    {
 
 
3786
        PNPCW_Speargun,                /* ID */
 
 
3787
        Execute_PNS_DischargeSpeargun,        /* Fire Func. */
 
 
3788
        "Speargun",                /* HierarchyName */
 
 
3789
        "staff gun root",            /* GunName */
 
 
3790
        "R shoulder",                /* ElevationName */
 
 
3791
        "predator",                /* HitLocationTableName */
 
 
3792
        0,                    // MinRange
 
 
3793
        50000,                    // MaxRange
 
 
3794
        65536>>2,                /* Firing Rate */
 
 
3795
        10,                    /* VolleySize */
 
 
3796
        65536>>1,                /* SwappingTime */
 
 
3797
        1,                    /* UseElevation */
 
 
3798
    },
 
 
3799
    {
 
 
3800
        PNPCW_Pistol,            /* ID */
 
 
3801
        Execute_PNS_DischargePistol,    /* Fire Func. */
 
 
3802
        "pred + pistol",        /* HierarchyName */
 
 
3803
        "pistol",            /* GunName */
 
 
3804
        "R shoulder",            /* ElevationName */
 
 
3805
        "predator",            /* HitLocationTableName */
 
 
3806
        5000,                // MinRange
 
 
3807
        20000,                // MaxRange
 
 
3808
        65536,                /* Firing Rate */
 
 
3809
        8,                /* VolleySize */
 
 
3810
        65536>>1,            /* SwappingTime */
 
 
3811
        1,                /* UseElevation */
 
 
3812
    }
 
 
3813
};
 
 
3814
 
 
 
3815
const PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id)
 
 
3816
{
 
 
3817
    return &NPC_Predator_Weapons[this_id];
 
 
3818
}
 
 
3819
 
 
 
3820
/*--------------------**
 
 
3821
** Loading and Saving **
 
 
3822
**--------------------*/
 
 
3823
#include "savegame.h"
 
 
3824
typedef struct predator_save_block
 
 
3825
{
 
 
3826
    SAVE_BLOCK_STRATEGY_HEADER header;
 
 
3827
 
 
 
3828
//behaviour block stuff
 
 
3829
    signed int health;
 
 
3830
    PRED_BHSTATE behaviourState;
 
 
3831
    PRED_BHSTATE lastState;
 
 
3832
 
 
 
3833
    int stateTimer;
 
 
3834
    int internalState;
 
 
3835
    int patience;
 
 
3836
    int enableSwap;
 
 
3837
    int enableTaunt;
 
 
3838
    VECTORCH weaponTarget;            /* target position for firing weapon at */
 
 
3839
    int volleySize;                /* used for weapon control */
 
 
3840
    NPC_OBSTRUCTIONREPORT obstruction;
 
 
3841
    NPC_WANDERDATA wanderData;
 
 
3842
 
 
 
3843
    int IAmCrouched;
 
 
3844
    int personalNumber;            /* for predator personalisation */
 
 
3845
    int nearSpeed;
 
 
3846
    int GibbFactor;
 
 
3847
    int incidentFlag;
 
 
3848
    int incidentTimer;
 
 
3849
 
 
 
3850
    PREDATOR_NPC_WEAPONS MeleeWeapon;
 
 
3851
    PREDATOR_NPC_WEAPONS SecondaryWeapon;
 
 
3852
    PREDATOR_NPC_WEAPONS ChangeToWeapon;
 
 
3853
 
 
 
3854
    /* these are for cloaking... */
 
 
3855
    PRED_CLOAKSTATE CloakStatus;
 
 
3856
    int CloakingEffectiveness;
 
 
3857
    int CloakTimer;
 
 
3858
 
 
 
3859
    /* And these for the laser dots. */
 
 
3860
    THREE_LASER_DOT_DESC Pred_Laser_Sight;
 
 
3861
    int Pred_Laser_On:1;
 
 
3862
    int Angry;
 
 
3863
    int RifleArrows;
 
 
3864
    int path;
 
 
3865
    int stepnumber;
 
 
3866
 
 
 
3867
//annoying pointer related things
 
 
3868
 
 
 
3869
    int weapon_id;
 
 
3870
    int currentAttackCode;
 
 
3871
    char Target_SBname[SB_NAME_LENGTH];
 
 
3872
 
 
 
3873
    int missionmodule_index;
 
 
3874
    int fearmodule_index;
 
 
3875
 
 
 
3876
//strategyblock stuff
 
 
3877
    DAMAGEBLOCK DamageBlock;
 
 
3878
    DYNAMICSBLOCK dynamics;
 
 
3879
 
 
 
3880
} PREDATOR_SAVE_BLOCK;
 
 
3881
 
 
 
3882
//defines for load/save macros
 
 
3883
#define SAVELOAD_BLOCK block
 
 
3884
#define SAVELOAD_BEHAV predatorStatusPointer
 
 
3885
 
 
 
3886
void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header)
 
 
3887
{
 
 
3888
    PREDATOR_SAVE_BLOCK* block = (PREDATOR_SAVE_BLOCK*) header; 
 
 
3889
 
 
 
3890
    //check the size of the save block
 
 
3891
    if(header->size != sizeof(*block))
 
 
3892
        return;
 
 
3893
 
 
 
3894
    //find the existing strategy block
 
 
3895
    STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname);
 
 
3896
 
 
 
3897
    if(!sbPtr)
 
 
3898
        return;
 
 
3899
    /*
 
 
3900
    Check the strategy type.
 
 
3901
    Slight complication here , since it might be a dormant predator
 
 
3902
    (assuming that they are actually used in any of the levels)
 
 
3903
    */
 
 
3904
 
 
 
3905
    switch(sbPtr->type)
 
 
3906
    {
 
 
3907
        case I_BehaviourDormantPredator:
 
 
3908
        {
 
 
3909
            //best make it un-dormant then
 
 
3910
            ActivateDormantPredator(sbPtr);    
 
 
3911
        }
 
 
3912
        case I_BehaviourPredator:
 
 
3913
        break;
 
 
3914
        default:
 
 
3915
        return;
 
 
3916
    }
 
 
3917
 
 
 
3918
    PREDATOR_STATUS_BLOCK* predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->dataptr;
 
 
3919
 
 
 
3920
    COPYELEMENT_LOAD(health)
 
 
3921
    COPYELEMENT_LOAD(behaviourState)
 
 
3922
    COPYELEMENT_LOAD(lastState)
 
 
3923
    COPYELEMENT_LOAD(stateTimer)
 
 
3924
    COPYELEMENT_LOAD(internalState)
 
 
3925
    COPYELEMENT_LOAD(patience)
 
 
3926
    COPYELEMENT_LOAD(enableSwap)
 
 
3927
    COPYELEMENT_LOAD(enableTaunt)
 
 
3928
    COPYELEMENT_LOAD(weaponTarget)        /* target position for firing weapon at */
 
 
3929
    COPYELEMENT_LOAD(volleySize)        /* used for weapon control */
 
 
3930
    COPYELEMENT_LOAD(obstruction)
 
 
3931
    COPYELEMENT_LOAD(wanderData)
 
 
3932
    COPYELEMENT_LOAD(IAmCrouched)
 
 
3933
    COPYELEMENT_LOAD(personalNumber)    /* for predator personalisation */
 
 
3934
    COPYELEMENT_LOAD(nearSpeed)
 
 
3935
    COPYELEMENT_LOAD(GibbFactor)
 
 
3936
    COPYELEMENT_LOAD(incidentFlag)
 
 
3937
    COPYELEMENT_LOAD(incidentTimer)
 
 
3938
    COPYELEMENT_LOAD(SecondaryWeapon)
 
 
3939
    COPYELEMENT_LOAD(ChangeToWeapon)
 
 
3940
    COPYELEMENT_LOAD(CloakStatus)
 
 
3941
    COPYELEMENT_LOAD(CloakingEffectiveness)
 
 
3942
    COPYELEMENT_LOAD(CloakTimer)
 
 
3943
    COPYELEMENT_LOAD(Pred_Laser_Sight)
 
 
3944
    COPYELEMENT_LOAD(Pred_Laser_On)
 
 
3945
    COPYELEMENT_LOAD(Angry)
 
 
3946
    COPYELEMENT_LOAD(RifleArrows)
 
 
3947
    COPYELEMENT_LOAD(path)
 
 
3948
    COPYELEMENT_LOAD(stepnumber)
 
 
3949
 
 
 
3950
    predatorStatusPointer->MeleeWeapon = GetThisNPCPredatorWeapon(block->MeleeWeapon);
 
 
3951
 
 
 
3952
    //load ai module pointers
 
 
3953
    predatorStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index);
 
 
3954
    predatorStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index);
 
 
3955
 
 
 
3956
    //load target
 
 
3957
    COPY_NAME(predatorStatusPointer->Target_SBname,block->Target_SBname);
 
 
3958
    predatorStatusPointer->closets_target = FindSBWithName(predatorStatusPointer->Target_SBname);
 
 
3959
 
 
 
3960
    //get the predator's attack from the attack code
 
 
3961
    predatorStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode);
 
 
3962
 
 
 
3963
    predatorStatusPointer->Selected_Weapon = GetThisNPCPredatorWeapon(block->weapon_id);
 
 
3964
 
 
 
3965
    //copy strategy block stuff
 
 
3966
    *sbPtr->DynPtr = block->dynamics;
 
 
3967
    sbPtr->DamageBlock = block->DamageBlock;
 
 
3968
 
 
 
3969
    //load hierarchy
 
 
3970
    {
 
 
3971
        SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
 
 
3972
        if(hier_header)
 
 
3973
            LoadHierarchy(hier_header,&predatorStatusPointer->HModelController);
 
 
3974
    }
 
 
3975
 
 
 
3976
    //sort out section pointers
 
 
3977
    predatorStatusPointer->My_Elevation_Section =
GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName);
 
 
3978
 
 
 
3979
    Load_SoundState(&predatorStatusPointer->soundHandle);
 
 
3980
}
 
 
3981
 
 
 
3982
void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr)
 
 
3983
{
 
 
3984
    PREDATOR_SAVE_BLOCK *block;
 
 
3985
 
 
 
3986
    GET_STRATEGY_SAVE_BLOCK(block, sbPtr);
 
 
3987
    PREDATOR_STATUS_BLOCK* predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->dataptr;
 
 
3988
 
 
 
3989
    //start copying stuff
 
 
3990
 
 
 
3991
    COPYELEMENT_SAVE(health)
 
 
3992
    COPYELEMENT_SAVE(behaviourState)
 
 
3993
    COPYELEMENT_SAVE(lastState)
 
 
3994
    COPYELEMENT_SAVE(stateTimer)
 
 
3995
    COPYELEMENT_SAVE(internalState)
 
 
3996
    COPYELEMENT_SAVE(patience)
 
 
3997
    COPYELEMENT_SAVE(enableSwap)
 
 
3998
    COPYELEMENT_SAVE(enableTaunt)
 
 
3999
    COPYELEMENT_SAVE(weaponTarget)            /* target position for firing weapon at */
 
 
4000
    COPYELEMENT_SAVE(volleySize)            /* used for weapon control */
 
 
4001
    COPYELEMENT_SAVE(obstruction)
 
 
4002
    COPYELEMENT_SAVE(wanderData)
 
 
4003
    COPYELEMENT_SAVE(IAmCrouched)
 
 
4004
    COPYELEMENT_SAVE(personalNumber)        /* for predator personalisation */
 
 
4005
    COPYELEMENT_SAVE(nearSpeed)
 
 
4006
    COPYELEMENT_SAVE(GibbFactor)
 
 
4007
    COPYELEMENT_SAVE(incidentFlag)
 
 
4008
    COPYELEMENT_SAVE(incidentTimer)
 
 
4009
    COPYELEMENT_SAVE(SecondaryWeapon)
 
 
4010
    COPYELEMENT_SAVE(ChangeToWeapon)
 
 
4011
    COPYELEMENT_SAVE(CloakStatus)
 
 
4012
    COPYELEMENT_SAVE(CloakingEffectiveness)
 
 
4013
    COPYELEMENT_SAVE(CloakTimer)
 
 
4014
    COPYELEMENT_SAVE(Pred_Laser_Sight)
 
 
4015
    COPYELEMENT_SAVE(Pred_Laser_On)
 
 
4016
    COPYELEMENT_SAVE(Angry)
 
 
4017
    COPYELEMENT_SAVE(RifleArrows)
 
 
4018
    COPYELEMENT_SAVE(path)
 
 
4019
    COPYELEMENT_SAVE(stepnumber)
 
 
4020
    block->MeleeWeapon = predatorStatusPointer->MeleeWeapon->id;
 
 
4021
 
 
 
4022
    //save ai module pointers
 
 
4023
    block->missionmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->missionmodule);
 
 
4024
    block->fearmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->fearmodule);
 
 
4025
 
 
 
4026
    //save target
 
 
4027
    COPY_NAME(block->Target_SBname, predatorStatusPointer->Target_SBname);
 
 
4028
 
 
 
4029
    if(predatorStatusPointer->current_attack)
 
 
4030
        block->currentAttackCode = predatorStatusPointer->current_attack->Unique_Code;
 
 
4031
    else
 
 
4032
        block->currentAttackCode = -1;
 
 
4033
 
 
 
4034
    //save predator's weapon
 
 
4035
    if(predatorStatusPointer->Selected_Weapon) 
 
 
4036
        block->weapon_id = predatorStatusPointer->Selected_Weapon->id;
 
 
4037
    else 
 
 
4038
        block->weapon_id = -1;
 
 
4039
 
 
 
4040
    //copy strategy block stuff
 
 
4041
    block->dynamics = *sbPtr->DynPtr;
 
 
4042
    block->dynamics.CollisionReportPtr = 0;
 
 
4043
    block->DamageBlock = sbPtr->DamageBlock;
 
 
4044
 
 
 
4045
    //save the hierarchy
 
 
4046
    SaveHierarchy(&predatorStatusPointer->HModelController);
 
 
4047
 
 
 
4048
    Save_SoundState(&predatorStatusPointer->soundHandle);
 
 
4049
}