4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
#include "system.h"
 
 
2
#include "stratdef.h"
 
 
3
#include "bh_types.h"
 
 
4
#include "pheromon.h"
 
 
5
#include "bh_far.h"
 
 
6
#include "pfarlocs.h"
 
 
7
#include "dynamics.h"
 
 
8
#include "pvisible.h"
 
 
9
#include "bh_ais.h"
 
 
10
#include "net.h"
 
 
11
#include <stdio.h>
 
 
12
#include <assert.h>
 
 
13
 
 
 
14
//static int entryPointFailures = 0;
 
 
15
 
 
 
16
/* Patrick 2/7/97:
 
 
17
This function turns the npc around (in y) a random amount: this is used to
 
 
18
turn the npc around if it reaches an impasse in the environment, and the
 
 
19
orientation is used to select a target module for wandering behaviour */
 
 
20
 
 
 
21
void FarNpc_FlipAround(STRATEGYBLOCK *sbPtr)
 
 
22
{
 
 
23
    assert(sbPtr);
 
 
24
     /* get the dynamics block */
 
 
25
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
26
    assert(dynPtr);
 
 
27
 
 
 
28
    dynPtr->OrientEuler.EulerY += (1024 + FastRandom() % 1024);
 
 
29
    dynPtr->OrientEuler.EulerY &= wrap360;
 
 
30
}
 
 
31
 
 
 
32
AIMODULE *FarNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr)
 
 
33
{
 
 
34
    extern unsigned int PlayerSmell;
 
 
35
 
 
 
36
    AIMODULE* targetModule = NULL;
 
 
37
    unsigned int targetSmell = PlayerSmell + 1;    /* should be higher than any smell anywhere this frame */
 
 
38
    unsigned int targetNumAdj = 0;
 
 
39
 
 
 
40
    assert(sbPtr);
 
 
41
 
 
 
42
    if(sbPtr->containingModule == NULL)
 
 
43
        return NULL;
 
 
44
 
 
 
45
    AIMODULE **AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs;
 
 
46
 
 
 
47
    /* check that there is a list of adjacent modules, and that it is not
 
 
48
    empty (ie points to zero) */
 
 
49
 
 
 
50
    if(AdjModuleRefPtr)
 
 
51
    {
 
 
52
        while(*AdjModuleRefPtr != 0)
 
 
53
        {
 
 
54
            /* get the index */
 
 
55
            int AdjModuleIndex = (*AdjModuleRefPtr)->m_index;
 
 
56
            int AdjModuleSmell = PherPl_ReadBuf[AdjModuleIndex];
 
 
57
            int AdjModuleNumAdjacencies = NumAdjacentModules((*AdjModuleRefPtr));
 
 
58
 
 
 
59
            /* if this adjacent module's smell value is lower than
 
 
60
            the current 'highest smell' record the new module as the
 
 
61
            target.  If they're equal, tie-break on number of adjacencies*/
 
 
62
            if( (!targetModule) ||
 
 
63
                (AdjModuleSmell < targetSmell)||
 
 
64
                ((AdjModuleSmell == targetSmell) && (AdjModuleNumAdjacencies > targetNumAdj)))
 
 
65
            {
 
 
66
                targetSmell = PherPl_ReadBuf[AdjModuleIndex];
 
 
67
                targetModule = *AdjModuleRefPtr;
 
 
68
                targetNumAdj = NumAdjacentModules((*AdjModuleRefPtr));
 
 
69
            }
 
 
70
            /* next adjacent module reference pointer */
 
 
71
            AdjModuleRefPtr++;
 
 
72
        }
 
 
73
    }
 
 
74
 
 
 
75
return targetModule;
 
 
76
}
 
 
77
 
 
 
78
void LocateFarNPCInAIModule(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule)
 
 
79
{
 
 
80
    VECTORCH newPosition;
 
 
81
    MODULE *renderModule;
 
 
82
    int targetLocInx;
 
 
83
 
 
 
84
    /* now: a few tests for npc's that are generated... (aliens and marines) */
 
 
85
/*
 
 
86
    switch(sbPtr->type)
 
 
87
    {
 
 
88
        case I_BehaviourAlien:
 
 
89
        case I_BehaviourMarine:
 
 
90
        {
 
 
91
            //if(ModuleCurrVisArray[(*(targetModule->m_module_ptrs))->m_index])
 
 
92
            if (AIModuleIsVisible(targetModule)) 
 
 
93
            {
 
 
94
                if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS)
 
 
95
                    return;
 
 
96
            }
 
 
97
        }
 
 
98
        default:
 
 
99
        break;
 
 
100
    }
 
 
101
*/
 
 
102
 
 
 
103
    /* now move the npc to it's target... */
 
 
104
    int noOfAuxLocs = FALLP_AuxLocs[(targetModule->m_index)].numLocations;
 
 
105
    VECTORCH *auxLocsList = FALLP_AuxLocs[(targetModule->m_index)].locationsList;  
 
 
106
 
 
 
107
    /* find the entry point for the target */
 
 
108
    assert(sbPtr->containingModule);
 
 
109
    FARENTRYPOINT *targetEntryPoint = GetAIModuleEP(targetModule,(sbPtr->containingModule->m_aimodule));
 
 
110
    assert(targetEntryPoint);
 
 
111
 
 
 
112
    /* if it's visible, use the entry point.
 
 
113
    if it's not visible, use an auxilary location. If there aren't any auxilary
 
 
114
    locations, use the entry point. */
 
 
115
 
 
 
116
    //if(ModuleCurrVisArray[(*(targetModule->m_module_ptrs))->m_index])
 
 
117
    if (AIModuleIsVisible(targetModule)) 
 
 
118
    {
 
 
119
        newPosition = targetEntryPoint->position;
 
 
120
        targetLocInx = -1;
 
 
121
       }
 
 
122
    else
 
 
123
    {
 
 
124
           /* pick an auxilary location: if there aren't any, use the entry point */
 
 
125
        if(noOfAuxLocs)
 
 
126
        {
 
 
127
               targetLocInx = FastRandom() % noOfAuxLocs;
 
 
128
               newPosition = auxLocsList[targetLocInx];
 
 
129
               /* move up 1/2 npc height, plus a bit more(100). this only applies
 
 
130
               to auxilary locations, not eps */            
 
 
131
 
 
 
132
            if(SinglePlayer != AvP.PlayMode)
 
 
133
            {
 
 
134
                //Multiplayer game
 
 
135
                //send this new position to the other players
 
 
136
                AddNetMsg_FarAlienPosition(sbPtr, targetModule->m_index, targetLocInx, 0);
 
 
137
            }
 
 
138
           }
 
 
139
        else
 
 
140
        {
 
 
141
            newPosition = targetEntryPoint->position;
 
 
142
 
 
 
143
            if(SinglePlayer != AvP.PlayMode)
 
 
144
            {
 
 
145
                //Multiplayer game
 
 
146
                //send this new position to the other players
 
 
147
                AddNetMsg_FarAlienPosition(sbPtr, targetModule->m_index, sbPtr->containingModule->m_aimodule->m_index, 1);
 
 
148
            }
 
 
149
        }
 
 
150
       }
 
 
151
 
 
 
152
    {
 
 
153
        VECTORCH temp_Pos;
 
 
154
 
 
 
155
        temp_Pos.vx = newPosition.vx+targetModule->m_world.vx;
 
 
156
        temp_Pos.vy = newPosition.vy+targetModule->m_world.vy;
 
 
157
        temp_Pos.vz = newPosition.vz+targetModule->m_world.vz;
 
 
158
 
 
 
159
        renderModule = ModuleFromPosition(&temp_Pos, sbPtr->containingModule);
 
 
160
 
 
 
161
        if (renderModule == NULL)
 
 
162
            return;
 
 
163
    }
 
 
164
 
 
 
165
       /* now set the alien's new position and current module. 
 
 
166
       NB this is world position + alien height in y + a little extra in y to make sure */
 
 
167
    {
 
 
168
        DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
169
        assert(dynPtr);
 
 
170
 
 
 
171
        dynPtr->Position = newPosition;
 
 
172
        dynPtr->Position.vx += targetModule->m_world.vx;
 
 
173
        dynPtr->Position.vy += targetModule->m_world.vy;
 
 
174
        dynPtr->Position.vz += targetModule->m_world.vz;
 
 
175
        dynPtr->PrevPosition = dynPtr->Position;
 
 
176
           dynPtr->OrientEuler.EulerX = dynPtr->OrientEuler.EulerZ = 0;
 
 
177
 
 
 
178
           {
 
 
179
            VECTORCH vec; 
 
 
180
            vec.vx = targetModule->m_world.vx - sbPtr->containingModule->m_world.vx;
 
 
181
            vec.vz = targetModule->m_world.vz - sbPtr->containingModule->m_world.vz;
 
 
182
            vec.vy = 0;
 
 
183
            Normalise(&vec);
 
 
184
               dynPtr->OrientEuler.EulerY = ArcTan(vec.vx, vec.vz);
 
 
185
        }
 
 
186
    }
 
 
187
 
 
 
188
    /* finally, update the alien's module */
 
 
189
    sbPtr->containingModule = renderModule;    
 
 
190
 
 
 
191
    #if UseLocalAssert   
 
 
192
    {
 
 
193
        VECTORCH localCoords;
 
 
194
        MODULE *thisModule = sbPtr->containingModule;
 
 
195
 
 
 
196
        assert(thisModule);
 
 
197
 
 
 
198
        localCoords = sbPtr->DynPtr->Position;
 
 
199
        localCoords.vx -= thisModule->m_world.vx;
 
 
200
        localCoords.vy -= thisModule->m_world.vy;
 
 
201
        localCoords.vz -= thisModule->m_world.vz;
 
 
202
 
 
 
203
        if(!PointIsInModule(thisModule, &localCoords))
 
 
204
        {
 
 
205
            //printf("FAR ALIEN MODULE CONTAINMENT FAILURE \n");
 
 
206
 
 
 
207
            printf("Alien containment failure: alien is in %s, position is %d,%d,%d:\nModule extents are: %d:%d, %d:%d, %d:%d",
 
 
208
                thisModule->name,localCoords.vx,localCoords.vy,localCoords.vz,
 
 
209
                thisModule->m_maxx,thisModule->m_minx,thisModule->m_maxy,thisModule->m_miny,
 
 
210
                thisModule->m_maxz,thisModule->m_minz);
 
 
211
 
 
 
212
            assert(1==0);
 
 
213
        }  
 
 
214
    }
 
 
215
    #endif
 
 
216
}
 
 
217
 
 
 
218
/*--------------------Patrick 10/12/96----------------------
 
 
219
  This function returns the status of a passed target 
 
 
220
  module that an NPC might want to move to.
 
 
221
  ----------------------------------------------------------*/
 
 
222
 
 
 
223
NPC_TARGETMODULESTATUS GetTargetAIModuleStatus(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule, int alien)
 
 
224
{
 
 
225
    /* first check for entry point from current module */
 
 
226
 
 
 
227
    {
 
 
228
        FARENTRYPOINT *targetEntryPoint = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
 
 
229
 
 
 
230
        if((NULL == targetEntryPoint) || (!alien && targetEntryPoint->alien_only))
 
 
231
            return NPCTM_NoEntryPoint;
 
 
232
    }
 
 
233
 
 
 
234
    MODULE *renderModule = *(targetModule->m_module_ptrs);
 
 
235
    MODULEDOORTYPE doorStatus = ModuleIsADoor(renderModule);
 
 
236
 
 
 
237
    switch(doorStatus)
 
 
238
    {
 
 
239
        case MDT_ProxDoor:
 
 
240
        {    
 
 
241
             if(GetState(renderModule->m_sbptr)) 
 
 
242
                 return NPCTM_ProxDoorOpen;
 
 
243
            else
 
 
244
                return NPCTM_ProxDoorNotOpen;
 
 
245
        }
 
 
246
        break;
 
 
247
        case MDT_LiftDoor:
 
 
248
        {    
 
 
249
             if(GetState(renderModule->m_sbptr)) 
 
 
250
                 return NPCTM_LiftDoorOpen;
 
 
251
            else
 
 
252
                return NPCTM_LiftDoorNotOpen;
 
 
253
        }
 
 
254
        break;
 
 
255
        case MDT_SecurityDoor:
 
 
256
        {
 
 
257
             if(GetState(renderModule->m_sbptr)) 
 
 
258
                 return NPCTM_SecurityDoorOpen;
 
 
259
            else
 
 
260
                return NPCTM_SecurityDoorNotOpen;
 
 
261
        }
 
 
262
        break;
 
 
263
        default:
 
 
264
        {
 
 
265
            assert(doorStatus==MDT_NotADoor);
 
 
266
        }
 
 
267
    }
 
 
268
 
 
 
269
    /* now check for lift */
 
 
270
    if(sbPtr->type == I_BehaviourLift)
 
 
271
        return NPCTM_LiftTeleport;
 
 
272
 
 
 
273
    /* check for air duct */
 
 
274
    if(renderModule->m_flags & MODULEFLAG_AIRDUCT)
 
 
275
        return NPCTM_AirDuct;
 
 
276
 
 
 
277
/* at this point, we know it's a room (or stairs) ... */
 
 
278
return NPCTM_NormalRoom;         
 
 
279
}
 
 
280
 
 
 
281
/* Patrick 1/7/97-----------------------------------------
 
 
282
  A suit of functions for general far NPC use which return a 
 
 
283
  target module for hunting, wandering, and retreating
 
 
284
  ----------------------------------------------------------*/
 
 
285
 
 
 
286
AIMODULE *FarNPC_GetTargetAIModuleForHunt(STRATEGYBLOCK *sbPtr, int alien)
 
 
287
{
 
 
288
    unsigned int highestSmell = 0;
 
 
289
    AIMODULE* targetModule = NULL;
 
 
290
 
 
 
291
    AIMODULE **AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs;
 
 
292
 
 
 
293
    /* check that there is a list of adjacent modules, and that it is not
 
 
294
    empty (ie points to zero) */
 
 
295
 
 
 
296
    if(AdjModuleRefPtr)    
 
 
297
    {
 
 
298
        while(*AdjModuleRefPtr != 0)
 
 
299
        {
 
 
300
            /* get the index */
 
 
301
            int AdjModuleIndex = (*AdjModuleRefPtr)->m_index;
 
 
302
 
 
 
303
            if (CheckAdjacencyValidity((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule, alien))
 
 
304
            {
 
 
305
                /* if this adjacent module's smell value is higher than
 
 
306
                the current 'highest smell' record the new module as the
 
 
307
                target. */
 
 
308
 
 
 
309
                if(PherPl_ReadBuf[AdjModuleIndex] > highestSmell)
 
 
310
                {                        
 
 
311
                    highestSmell = PherPl_ReadBuf[AdjModuleIndex];
 
 
312
                    targetModule = *AdjModuleRefPtr;                            
 
 
313
                }
 
 
314
            }
 
 
315
            /* next adjacent module reference pointer */
 
 
316
            AdjModuleRefPtr++;
 
 
317
        }
 
 
318
    }
 
 
319
 
 
 
320
    /* Consider my module being the target. */
 
 
321
    if (PherPl_ReadBuf[sbPtr->containingModule->m_aimodule->m_index] > highestSmell)
 
 
322
        return sbPtr->containingModule->m_aimodule;
 
 
323
    else
 
 
324
        return targetModule;
 
 
325
}
 
 
326
 
 
 
327
/* Patrick 2/7/96: this function returns a module for wandering to */
 
 
328
AIMODULE *FarNPC_GetTargetAIModuleForWander(STRATEGYBLOCK *sbPtr, AIMODULE *exception, int alien)
 
 
329
{
 
 
330
    AIMODULE* targetModule = NULL;
 
 
331
    int bestDirn = -100000;    /* lower than the lowest */
 
 
332
    VECTORCH npcDirn;
 
 
333
 
 
 
334
    /* some checks */
 
 
335
    if(!sbPtr)
 
 
336
        return NULL;    
 
 
337
 
 
 
338
    DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
 
 
339
 
 
 
340
    if(!dynPtr)
 
 
341
        return NULL;    
 
 
342
 
 
 
343
    /* get npc 2d directional vector */
 
 
344
    npcDirn.vx = GetSin(dynPtr->OrientEuler.EulerY);
 
 
345
    npcDirn.vz = GetCos(dynPtr->OrientEuler.EulerY);
 
 
346
    npcDirn.vy = 0;
 
 
347
    Normalise(&npcDirn);
 
 
348
 
 
 
349
    /* init adjacent module pointer */
 
 
350
    AIMODULE **AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs;
 
 
351
 
 
 
352
    /* check that there is a list of adjacent modules, and that it is not
 
 
353
    empty (ie points to zero) */
 
 
354
 
 
 
355
    if(AdjModuleRefPtr)    
 
 
356
    {
 
 
357
        while(*AdjModuleRefPtr != 0)
 
 
358
        {
 
 
359
            AIMODULE *nextAdjModule = *AdjModuleRefPtr;
 
 
360
            VECTORCH moduleDirn;    
 
 
361
 
 
 
362
            if (CheckAdjacencyValidity((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule,alien))
 
 
363
            {
 
 
364
                moduleDirn.vx = nextAdjModule->m_world.vx - sbPtr->containingModule->m_world.vx;
 
 
365
                moduleDirn.vz = nextAdjModule->m_world.vz - sbPtr->containingModule->m_world.vz;
 
 
366
                moduleDirn.vy = 0;
 
 
367
                Normalise(&moduleDirn);
 
 
368
 
 
 
369
                int thisDirn = DotProduct(&npcDirn,&moduleDirn);
 
 
370
 
 
 
371
                if( (thisDirn > bestDirn) && (exception != nextAdjModule))
 
 
372
                {
 
 
373
                    targetModule = nextAdjModule;
 
 
374
                    bestDirn = thisDirn;
 
 
375
                }
 
 
376
            }
 
 
377
            AdjModuleRefPtr++;
 
 
378
        }
 
 
379
    }
 
 
380
 
 
 
381
return targetModule;
 
 
382
}