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