4b825dc642cb6eb9a060e54bf8d69288fbee4904ebd360ec63ec976c05699f3180e866b3f69e5472
 
 
1
/*------------------------Patrick 13/12/96-----------------------------
 
 
2
  Source file for FAR AI alien module locations, as used by far alien
 
 
3
  behaviours....
 
 
4
  --------------------------------------------------------------------*/
 
 
5
 
 
 
6
#include "system.h"
 
 
7
#include "stratdef.h"
 
 
8
#include "dynamics.h"
 
 
9
#include "pfarlocs.h"
 
 
10
#include <stdlib.h>
 
 
11
#include <assert.h>
 
 
12
 
 
 
13
/* external global variables used in this file */
 
 
14
extern int ModuleArraySize;
 
 
15
extern int memoryInitialisationFailure;
 
 
16
 
 
 
17
/* globals for this file */
 
 
18
FARENTRYPOINTSHEADER *FALLP_EntryPoints = NULL;
 
 
19
FARLOCATIONSHEADER *FALLP_AuxLocs = NULL;
 
 
20
 
 
 
21
int AIModuleArraySize = 0;
 
 
22
AIMODULE *AIModuleArray = NULL;
 
 
23
 
 
 
24
/* static globals for this file */
 
 
25
static FARVALIDATEDLOCATION *auxLocsGrid = NULL;
 
 
26
 
 
 
27
static int FL_TotalNumAuxLocs = 0;
 
 
28
static VECTORCH    *FL_AuxData = NULL;
 
 
29
 
 
 
30
/* a define for logging location data */
 
 
31
#define logFarLocData    0
 
 
32
#if logFarLocData
 
 
33
static FILE *logfile;
 
 
34
#endif
 
 
35
 
 
 
36
#define logFarLocPositions    0
 
 
37
#if logFarLocPositions
 
 
38
static FILE *logfile2;
 
 
39
#endif
 
 
40
 
 
 
41
/*------------------ Patrick 3/12/96 ----------------------
 
 
42
  This function determines whether an x/z position lies
 
 
43
  within the x/z projection of a polygon.
 
 
44
 
 
 
45
  NB is not entirely accurate for concave polygons.
 
 
46
  ---------------------------------------------------------*/
 
 
47
static int IsXZinPoly(VECTORCH* location, struct ColPolyTag *polygonData)
 
 
48
{
 
 
49
    int x = location->vx;
 
 
50
    int z = location->vz;
 
 
51
    int xa,za,xb,zb;
 
 
52
    int intersections = 0;
 
 
53
    int intersectMinz, intersectMaxz;
 
 
54
    int linesToTest;
 
 
55
    int nextLine;
 
 
56
 
 
 
57
    linesToTest = polygonData->NumberOfVertices;
 
 
58
 
 
 
59
    if(linesToTest == 3)
 
 
60
    {
 
 
61
        xa = polygonData->PolyPoint[2].vx;
 
 
62
        za = polygonData->PolyPoint[2].vz;
 
 
63
    }
 
 
64
    else
 
 
65
    {
 
 
66
        assert(linesToTest == 4);
 
 
67
        xa = polygonData->PolyPoint[3].vx;
 
 
68
        za = polygonData->PolyPoint[3].vz;
 
 
69
    }
 
 
70
 
 
 
71
    nextLine = 0;
 
 
72
 
 
 
73
    while(nextLine < linesToTest)
 
 
74
    {
 
 
75
        /* copy last first point to next last point (?) */
 
 
76
        xb = xa;
 
 
77
        zb = za;
 
 
78
 
 
 
79
        /* get next first point */
 
 
80
        xa = polygonData->PolyPoint[nextLine].vx;
 
 
81
        za = polygonData->PolyPoint[nextLine].vz;
 
 
82
 
 
 
83
        if(((x >= xb) && (x <= xa)) || ((x < xb) && (x >= xa)))
 
 
84
        {
 
 
85
              /* intesection ! */
 
 
86
            intersections++;
 
 
87
 
 
 
88
            if(!(intersections < 4))
 
 
89
                return 0;
 
 
90
 
 
 
91
            {
 
 
92
                int zPosn;
 
 
93
 
 
 
94
                if(xb == xa)
 
 
95
                    zPosn = za;
 
 
96
                else
 
 
97
                    zPosn = zb + WideMulNarrowDiv((za-zb),(x-xb),(xa-xb));
 
 
98
 
 
 
99
                if(intersections == 1)
 
 
100
                    intersectMinz = intersectMaxz = zPosn;
 
 
101
                else
 
 
102
                {
 
 
103
                    if(zPosn < intersectMinz)
 
 
104
                        intersectMinz = zPosn;
 
 
105
                    else if(zPosn > intersectMaxz)
 
 
106
                        intersectMaxz = zPosn;
 
 
107
                }
 
 
108
            }
 
 
109
        }
 
 
110
      nextLine++;
 
 
111
    }
 
 
112
 
 
 
113
    if(intersections == 0)
 
 
114
        return 0;
 
 
115
 
 
 
116
    if(intersections == 1)
 
 
117
        return (z == intersectMinz);    
 
 
118
    else 
 
 
119
        return ((z >= intersectMinz)&&(z <= intersectMaxz));
 
 
120
}
 
 
121
 
 
 
122
/*----------------------Patrick 1/12/96--------------------------
 
 
123
  Given an x/z position for the shape, this function returns a 
 
 
124
  height value, by examining upwards facing polygons....
 
 
125
  To validate the height, there must also be a downwards facing
 
 
126
  polgon above the upwards facing polygon (so that we know that
 
 
127
  the location iiiiis inside the shape): if there is no up &
 
 
128
  down polygon, the location is invalidated, and an error code
 
 
129
  returned (either no up poly, no down poly, no up-or-down poly)
 
 
130
 
 
 
131
  ----------------------------------------------------------------*/
 
 
132
 
 
 
133
static void GetFarLocHeight(FARVALIDATEDLOCATION *location, MODULE *thisModule)
 
 
134
{
 
 
135
    int heightOfUpPoly = thisModule->m_maxy; /* init to lowest module extent */
 
 
136
    int heightOfDownPoly = thisModule->m_miny; /* init to heighest module extent */
 
 
137
    int polyCounter    = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape);
 
 
138
    int upPolyFound = 0;
 
 
139
    int downPolyFound = 0;
 
 
140
    struct ColPolyTag polygonData;
 
 
141
 
 
 
142
    /* loop through the item list, then ... */
 
 
143
    while(polyCounter > 0)
 
 
144
    {
 
 
145
        {
 
 
146
            int *itemPtr = *(ItemArrayPtr++);
 
 
147
            PolyheaderPtr = (POLYHEADER *) itemPtr;
 
 
148
        }
 
 
149
 
 
 
150
        GetPolygonVertices(&polygonData);
 
 
151
        GetPolygonNormal(&polygonData);
 
 
152
 
 
 
153
        /* first test if poly is vertical */
 
 
154
        if((polygonData.PolyNormal.vy > FAR_MIN_INCLINE)||(polygonData.PolyNormal.vy < -FAR_MIN_INCLINE))
 
 
155
        {
 
 
156
        int XZcontainment = IsXZinPoly(&(location->position), &polygonData);
 
 
157
 
 
 
158
            if(XZcontainment)
 
 
159
            {                
 
 
160
                if(polygonData.PolyNormal.vy > 0) /* downwards facing */
 
 
161
                {
 
 
162
                    downPolyFound++;
 
 
163
                    {
 
 
164
                        /* find height of this poly: height of lowest vertex */
 
 
165
                        int tmpHeight = polygonData.PolyPoint[0].vy;
 
 
166
 
 
 
167
                        if(polygonData.PolyPoint[1].vy > tmpHeight)
 
 
168
                            tmpHeight = polygonData.PolyPoint[1].vy;
 
 
169
 
 
 
170
                        if(polygonData.PolyPoint[2].vy > tmpHeight)
 
 
171
                            tmpHeight = polygonData.PolyPoint[2].vy;
 
 
172
 
 
 
173
                        if(polygonData.NumberOfVertices == 4)
 
 
174
                        {
 
 
175
                            if(polygonData.PolyPoint[3].vy > tmpHeight)
 
 
176
                                tmpHeight = polygonData.PolyPoint[2].vy;
 
 
177
                        }
 
 
178
 
 
 
179
                        /* record height of lowest downward facing poly */
 
 
180
                        if(tmpHeight > heightOfDownPoly)
 
 
181
                            heightOfDownPoly = tmpHeight;                        
 
 
182
                    }
 
 
183
                }
 
 
184
                else /* upwards facing */
 
 
185
                {
 
 
186
                    upPolyFound++;
 
 
187
                    {
 
 
188
                        /* find height of this poly: height of highest vertex */
 
 
189
                        int tmpHeight = polygonData.PolyPoint[0].vy;
 
 
190
 
 
 
191
                        if(polygonData.PolyPoint[1].vy < tmpHeight)
 
 
192
                                tmpHeight = polygonData.PolyPoint[1].vy;
 
 
193
 
 
 
194
                        if(polygonData.PolyPoint[2].vy < tmpHeight)
 
 
195
                                tmpHeight = polygonData.PolyPoint[2].vy;
 
 
196
 
 
 
197
                        if(polygonData.NumberOfVertices == 4)
 
 
198
                        {
 
 
199
                            if(polygonData.PolyPoint[3].vy < tmpHeight)
 
 
200
                                tmpHeight = polygonData.PolyPoint[2].vy;
 
 
201
                        }
 
 
202
 
 
 
203
                        /* record height of heighest upward facing poly */
 
 
204
                        if(tmpHeight < heightOfUpPoly)
 
 
205
                            heightOfUpPoly = tmpHeight;                        
 
 
206
                    }
 
 
207
                }
 
 
208
            }
 
 
209
        }
 
 
210
    polyCounter--;
 
 
211
    }
 
 
212
 
 
 
213
    /* if up & down polys exist check their heights:
 
 
214
    if there is not enough clearance bewteen the lowest down poly and the heighest up poly, 
 
 
215
    invalidate the location.*/
 
 
216
 
 
 
217
    if((upPolyFound != 0) && (downPolyFound != 0))
 
 
218
    {
 
 
219
        int minclearance = FAR_BB_HEIGHT;
 
 
220
        if(thisModule->m_flags & MODULEFLAG_AIRDUCT)
 
 
221
            minclearance >>= 1;
 
 
222
 
 
 
223
        if((heightOfUpPoly-heightOfDownPoly) >= minclearance)
 
 
224
        {
 
 
225
            //position the aux location slightly above the polygon
 
 
226
            location->position.vy = heightOfUpPoly - 10;
 
 
227
        }
 
 
228
        else
 
 
229
            location->valid = 0;
 
 
230
    }
 
 
231
    else
 
 
232
        location->valid = 0;
 
 
233
}
 
 
234
 
 
 
235
/*--------------------Patrick 4/12/96--------------------
 
 
236
  This function checks a potential location for impinging
 
 
237
  downward or sideways facing polygons (ie ceiling or floor).  
 
 
238
  This is done using a bounding box containment test.  If 
 
 
239
  the test fails, it invalidates the location.
 
 
240
  -------------------------------------------------------*/
 
 
241
 
 
 
242
static int farbbox_maxx;
 
 
243
static int farbbox_minx;
 
 
244
static int farbbox_maxy;
 
 
245
static int farbbox_miny;
 
 
246
static int farbbox_maxz;
 
 
247
static int farbbox_minz;
 
 
248
static struct ColPolyTag farbbox_polygonData;
 
 
249
 
 
 
250
/*--------------------Patrick 5/12/96----------------------------------
 
 
251
 This does a bounding box extent test for a polygon.
 
 
252
 NB returns false if the poly definitely isn't in the bbox, and returns 
 
 
253
 true if the poly is in the bbox, and for unresolved cases.
 
 
254
 ----------------------------------------------------------------------*/
 
 
255
static int FarBoxContainsPolygon()
 
 
256
{
 
 
257
    if(farbbox_polygonData.NumberOfVertices == 3)
 
 
258
    {
 
 
259
        if(    (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&&
 
 
260
            (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&&
 
 
261
            (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny))    return 0;
 
 
262
 
 
 
263
        if(    (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&&
 
 
264
            (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&&
 
 
265
            (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx))    return 0;    
 
 
266
 
 
 
267
        if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&&
 
 
268
            (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&&
 
 
269
            (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz))    return 0;
 
 
270
 
 
 
271
        if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&&
 
 
272
            (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&&
 
 
273
            (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz))    return 0;
 
 
274
 
 
 
275
        if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&&
 
 
276
            (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&&
 
 
277
            (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx))    return 0;
 
 
278
 
 
 
279
        if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&&
 
 
280
            (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&&
 
 
281
            (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy))    return 0;
 
 
282
    }
 
 
283
    else
 
 
284
    {
 
 
285
        if(    (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&&
 
 
286
            (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&&
 
 
287
            (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny)&&
 
 
288
            (farbbox_polygonData.PolyPoint[3].vy<=farbbox_miny))    return 0;
 
 
289
 
 
 
290
        if(    (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&&
 
 
291
            (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&&
 
 
292
            (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx)&&
 
 
293
            (farbbox_polygonData.PolyPoint[3].vx<=farbbox_minx))    return 0;    
 
 
294
 
 
 
295
        if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&&
 
 
296
            (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&&
 
 
297
            (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz)&&
 
 
298
            (farbbox_polygonData.PolyPoint[3].vz<=farbbox_minz))    return 0;
 
 
299
 
 
 
300
        if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&&
 
 
301
            (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&&
 
 
302
            (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz)&&
 
 
303
            (farbbox_polygonData.PolyPoint[3].vz>=farbbox_maxz))    return 0;
 
 
304
 
 
 
305
        if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&&
 
 
306
            (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&&
 
 
307
            (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx)&&
 
 
308
            (farbbox_polygonData.PolyPoint[3].vx>=farbbox_maxx))    return 0;
 
 
309
 
 
 
310
        if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&&
 
 
311
            (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&&
 
 
312
            (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy)&&
 
 
313
            (farbbox_polygonData.PolyPoint[3].vy>=farbbox_maxy))    return 0;
 
 
314
    }    
 
 
315
    return 1;
 
 
316
}
 
 
317
 
 
 
318
static void FarLocVolumeTest(FARVALIDATEDLOCATION *location, MODULE *thisModule)
 
 
319
{
 
 
320
    int polyCounter;
 
 
321
    int containmentFailure = 0;
 
 
322
 
 
 
323
    assert(location->valid);
 
 
324
 
 
 
325
    /* the location is provided as an x,y,z:
 
 
326
    the x and z indicate the centre, and the y indicates the bottom.
 
 
327
    translate these into bounding box extents.... */
 
 
328
 
 
 
329
    /* 10/7/97: this test has been modified: the bbox is moved up slightly, and any
 
 
330
    impinging ploygon invalidates the location */
 
 
331
 
 
 
332
    farbbox_maxx = location->position.vx + (FAR_BB_WIDTH>>1);
 
 
333
    farbbox_minx = location->position.vx - (FAR_BB_WIDTH>>1);
 
 
334
    farbbox_maxz = location->position.vz + (FAR_BB_WIDTH>>1);
 
 
335
    farbbox_minz = location->position.vz - (FAR_BB_WIDTH>>1);
 
 
336
    farbbox_maxy = location->position.vy - 10;
 
 
337
 
 
 
338
    /* patrick 4/7/97: a little adittion for airducts: npc should be crouched in them */
 
 
339
    if(thisModule->m_flags & MODULEFLAG_AIRDUCT)
 
 
340
        farbbox_miny = location->position.vy - (FAR_BB_HEIGHT >> 1) - 10;    
 
 
341
    else
 
 
342
        farbbox_miny = location->position.vy - FAR_BB_HEIGHT - 10;
 
 
343
 
 
 
344
    /* now just run through the polygons in the shape. If a polygon is 
 
 
345
    inside (actually, not definitely outside) the bbox, invalidate the location */        
 
 
346
 
 
 
347
     polyCounter = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape);
 
 
348
 
 
 
349
    while((polyCounter > 0) && (!containmentFailure))
 
 
350
    {
 
 
351
        {
 
 
352
            int *itemPtr = *(ItemArrayPtr++);
 
 
353
            PolyheaderPtr = (POLYHEADER *) itemPtr;
 
 
354
        }
 
 
355
 
 
 
356
        GetPolygonVertices(&farbbox_polygonData);
 
 
357
        containmentFailure = FarBoxContainsPolygon();                    
 
 
358
        polyCounter--;
 
 
359
    }
 
 
360
 
 
 
361
    /* so, if there    has been a containmentFailure, invalidate the location */
 
 
362
    if(containmentFailure)
 
 
363
        location->valid = 0;
 
 
364
}
 
 
365
 
 
 
366
/*--------------------- Patrick 26/11/96 --------------------------
 
 
367
  This function attempts to construct a series of valid 
 
 
368
  auxilary locations inside the module (provided it has entry points)    
 
 
369
  -----------------------------------------------------------------*/
 
 
370
static void BuildFM_AuxilaryLocs(MODULE *thisModule)
 
 
371
{
 
 
372
    int gridStartX, gridStartZ, gridExtentX, gridExtentZ, XIndex, ZIndex;
 
 
373
    int NumLocsValid = 0;
 
 
374
    int NumLocsHeightFailed = 0;
 
 
375
    int NumLocsVolFailed = 0;
 
 
376
    int ThisModuleIndex;
 
 
377
    AIMODULE* aimodule = thisModule->m_aimodule;
 
 
378
 
 
 
379
    /* get the module index */
 
 
380
    assert(aimodule);
 
 
381
    ThisModuleIndex = aimodule->m_index;
 
 
382
    assert(ThisModuleIndex >= 0);
 
 
383
    assert(ThisModuleIndex < ModuleArraySize);    
 
 
384
 
 
 
385
    gridStartX = thisModule->m_minx + (FAR_BB_WIDTH>>1);
 
 
386
    gridStartZ = thisModule->m_minz + (FAR_BB_WIDTH>>1);
 
 
387
    gridExtentX = thisModule->m_maxx - thisModule->m_minx - FAR_BB_WIDTH;
 
 
388
    gridExtentZ = thisModule->m_maxz - thisModule->m_minz - FAR_BB_WIDTH;
 
 
389
 
 
 
390
    if(gridExtentX<=0 || gridExtentZ<=0)
 
 
391
    {
 
 
392
        //module is too narrow for auxilary locations
 
 
393
        return;
 
 
394
    }
 
 
395
 
 
 
396
    assert(gridStartX > thisModule->m_minx);
 
 
397
 
 
 
398
    /* step through each grid (index) location */
 
 
399
    for(XIndex = FAR_GRID_SIZE; XIndex > 0; XIndex--)
 
 
400
    {
 
 
401
        for(ZIndex = FAR_GRID_SIZE; ZIndex > 0; ZIndex--)
 
 
402
        {
 
 
403
            int locationsIndex = (XIndex-1)*FAR_GRID_SIZE + (ZIndex-1);
 
 
404
 
 
 
405
            auxLocsGrid[locationsIndex].position.vx = gridStartX + (gridExtentX*(XIndex-1))/(FAR_GRID_SIZE-1);
 
 
406
            auxLocsGrid[locationsIndex].position.vz = gridStartZ + (gridExtentZ*(ZIndex-1))/(FAR_GRID_SIZE-1);
 
 
407
            auxLocsGrid[locationsIndex].position.vy = 0;
 
 
408
            auxLocsGrid[locationsIndex].valid = 1; /* validated by default */
 
 
409
 
 
 
410
            /* get the floor height for this location.
 
 
411
            If no valid height is found, the location is set to
 
 
412
            minx,minz,miny, ie. outside of the grid, and abandoned */
 
 
413
 
 
 
414
            GetFarLocHeight(&auxLocsGrid[locationsIndex], thisModule);
 
 
415
 
 
 
416
            /* if there's a valid floor height, check the volume around the location
 
 
417
            for impinging polygons.  If volume is impinged, the location is set to 
 
 
418
            minx,minz,miny, ie. outside of the grid, and abandoned */
 
 
419
 
 
 
420
            if(auxLocsGrid[locationsIndex].valid)
 
 
421
            {
 
 
422
                FarLocVolumeTest(&auxLocsGrid[locationsIndex], thisModule); 
 
 
423
 
 
 
424
                if(auxLocsGrid[locationsIndex].valid)
 
 
425
                {
 
 
426
                    auxLocsGrid[locationsIndex].position.vx += thisModule->m_world.vx;
 
 
427
                    auxLocsGrid[locationsIndex].position.vy += thisModule->m_world.vy;
 
 
428
                    auxLocsGrid[locationsIndex].position.vz += thisModule->m_world.vz;
 
 
429
 
 
 
430
                    auxLocsGrid[locationsIndex].position.vx -= aimodule->m_world.vx;
 
 
431
                    auxLocsGrid[locationsIndex].position.vy -= aimodule->m_world.vy;
 
 
432
                    auxLocsGrid[locationsIndex].position.vz -= aimodule->m_world.vz;
 
 
433
 
 
 
434
                    NumLocsValid++;
 
 
435
                }
 
 
436
                else
 
 
437
                {
 
 
438
                    NumLocsVolFailed++;
 
 
439
                }
 
 
440
            }
 
 
441
            else
 
 
442
                NumLocsHeightFailed++;
 
 
443
        }
 
 
444
    }
 
 
445
 
 
 
446
    #if logFarLocData
 
 
447
    fprintf(logfile, "Num valid locs: %d \n", NumLocsValid);
 
 
448
    fprintf(logfile, "Num Height failed: %d \n", NumLocsHeightFailed);
 
 
449
    fprintf(logfile, "Num Vol failed: %d \n \n", NumLocsVolFailed);
 
 
450
    #endif
 
 
451
 
 
 
452
    /* now have a full list of locations.... 
 
 
453
    Those that are zero are invalid: hopefully some have survived */
 
 
454
    assert((NumLocsHeightFailed+NumLocsVolFailed+NumLocsValid) == (FAR_GRID_SIZE*FAR_GRID_SIZE));
 
 
455
 
 
 
456
    /* If there are any valid locations remaining, store them in the locations list */
 
 
457
    if(NumLocsValid > 0) 
 
 
458
    {
 
 
459
        /* Build a final and definitive list of valid locations for the module:
 
 
460
        look at the number of valid locations. If there are more than the maximum 
 
 
461
        number, take a reasonably distributed sample. Otherwise just put them all in.
 
 
462
 
 
 
463
        NB this wil be a list of Local Space coordinates.
 
 
464
        */               
 
 
465
 
 
 
466
        if(NumLocsValid > FAR_MAX_LOCS) 
 
 
467
        {
 
 
468
            VECTORCH *destinationPtr;
 
 
469
            int locationsIndex = 0;
 
 
470
 
 
 
471
            int numTaken = 0;
 
 
472
            int numFound = 0;
 
 
473
            int nextToTake = 0; 
 
 
474
 
 
 
475
            /* fill out the header (space is preallocated) */
 
 
476
            destinationPtr = &FALLP_AuxLocs[ThisModuleIndex].locationsList[FALLP_AuxLocs[ThisModuleIndex].numLocations];
 
 
477
            FALLP_AuxLocs[ThisModuleIndex].numLocations += FAR_MAX_LOCS;
 
 
478
 
 
 
479
            nextToTake = NumLocsValid / FAR_MAX_LOCS;                    
 
 
480
 
 
 
481
            while(numTaken < FAR_MAX_LOCS)
 
 
482
            {
 
 
483
                assert(nextToTake <= NumLocsValid);
 
 
484
                assert(locationsIndex < (FAR_GRID_SIZE*FAR_GRID_SIZE));            
 
 
485
 
 
 
486
                while(auxLocsGrid[locationsIndex].valid == 0)
 
 
487
                    locationsIndex++;
 
 
488
 
 
 
489
                assert(locationsIndex < (FAR_GRID_SIZE*FAR_GRID_SIZE));            
 
 
490
                numFound++;
 
 
491
                assert(numFound <= NumLocsValid);
 
 
492
 
 
 
493
                if(numFound == nextToTake)
 
 
494
                {
 
 
495
                    *destinationPtr++ = auxLocsGrid[locationsIndex].position;
 
 
496
                    numTaken++;
 
 
497
                    /* calc index of the next one to take */
 
 
498
                    nextToTake = ((numTaken + 1) * NumLocsValid) / FAR_MAX_LOCS;
 
 
499
                }
 
 
500
 
 
 
501
            /* move to next location */
 
 
502
            locationsIndex++;
 
 
503
            }
 
 
504
        }
 
 
505
        else
 
 
506
        {    
 
 
507
            VECTORCH *destinationPtr;
 
 
508
            int locationsIndex;
 
 
509
            int checkCount = 0; 
 
 
510
 
 
 
511
            /* fill out the header (space is preallocated) */
 
 
512
            destinationPtr = &FALLP_AuxLocs[ThisModuleIndex].locationsList[FALLP_AuxLocs[ThisModuleIndex].numLocations];
 
 
513
            FALLP_AuxLocs[ThisModuleIndex].numLocations += NumLocsValid;
 
 
514
 
 
 
515
            /* fill up the list with what we've got */
 
 
516
            locationsIndex = (FAR_GRID_SIZE*FAR_GRID_SIZE) - 1;
 
 
517
 
 
 
518
            do
 
 
519
            {
 
 
520
                if(auxLocsGrid[locationsIndex].valid)
 
 
521
                {
 
 
522
                    /* found a valid location: copy it into the list */
 
 
523
                    *(destinationPtr++) = auxLocsGrid[locationsIndex].position;
 
 
524
                    checkCount++;
 
 
525
                }            
 
 
526
 
 
 
527
            } while(locationsIndex--);
 
 
528
 
 
 
529
            assert(checkCount == NumLocsValid);
 
 
530
        }
 
 
531
 
 
 
532
        #if logFarLocData
 
 
533
        {
 
 
534
            /* log the final list */
 
 
535
            VECTORCH *tmpPtr;
 
 
536
            int tmpCounter;
 
 
537
            fprintf(logfile, "Locations list: \n");
 
 
538
 
 
 
539
            tmpCounter = FALLP_AuxLocs[ThisModuleIndex].numLocations;
 
 
540
            tmpPtr = FALLP_AuxLocs[ThisModuleIndex].locationsList;
 
 
541
 
 
 
542
            while(tmpCounter > 0)
 
 
543
            {
 
 
544
                fprintf(logfile, "%d %d %d \n", tmpPtr->vx, tmpPtr->vz, tmpPtr->vy);
 
 
545
                tmpPtr++;
 
 
546
                tmpCounter--;    
 
 
547
            }
 
 
548
 
 
 
549
            fprintf(logfile,"\n");
 
 
550
 
 
 
551
        }
 
 
552
        #endif
 
 
553
    }
 
 
554
    #if logFarLocData
 
 
555
    else
 
 
556
    {
 
 
557
        /* No valid locations */
 
 
558
        {
 
 
559
            /* log an error */
 
 
560
            fprintf(logfile,"All auxilary locations FAILED \n");
 
 
561
        }
 
 
562
    }                                    
 
 
563
    #endif    
 
 
564
}
 
 
565
 
 
 
566
/*-----------------------Patrick 20/12/96---------------------------
 
 
567
Returns TRUE if a module is a physical part of the environment,
 
 
568
ie is not infinite or a terminator, etc...
 
 
569
-------------------------------------------------------------------*/
 
 
570
int ModuleIsPhysical(MODULE* target)
 
 
571
{
 
 
572
    if(target->m_flags & m_flag_infinite)
 
 
573
        return 0;
 
 
574
 
 
 
575
    return !target->end_module;
 
 
576
}
 
 
577
 
 
 
578
int AIModuleIsPhysical(AIMODULE* target)
 
 
579
{
 
 
580
    return (NULL != target) ? (target->m_module_ptrs != NULL) : 0;
 
 
581
}
 
 
582
 
 
 
583
/*-----------------------Patrick 20/12/96---------------------------
 
 
584
Takes 2 modules, and returns TRUE if the centre of the target module
 
 
585
is within the bounding box of the source;
 
 
586
-------------------------------------------------------------------*/
 
 
587
int ModuleInModule(MODULE* source, MODULE* target)
 
 
588
{
 
 
589
    if(target->m_world.vx < (source->m_world.vx + source->m_minx)) return 0;
 
 
590
    if(target->m_world.vx > (source->m_world.vx + source->m_maxx)) return 0;
 
 
591
 
 
 
592
    if(target->m_world.vy < (source->m_world.vy + source->m_miny)) return 0;
 
 
593
    if(target->m_world.vy > (source->m_world.vy + source->m_maxy)) return 0;
 
 
594
 
 
 
595
    if(target->m_world.vz < (source->m_world.vz + source->m_minz)) return 0;
 
 
596
    if(target->m_world.vz > (source->m_world.vz + source->m_maxz)) return 0;
 
 
597
 
 
 
598
return 1;
 
 
599
}
 
 
600
 
 
 
601
/*-----------------------Patrick 20/12/96---------------------------
 
 
602
Returns the number of entries in a given module's adjacency list
 
 
603
If there is no adjacency list, return 0.
 
 
604
-------------------------------------------------------------------*/
 
 
605
int NumAdjacentModules(AIMODULE* target)
 
 
606
{
 
 
607
    AIMODULE **AdjAIModulePtr = (target->m_link_ptrs);
 
 
608
    int counter = 0;
 
 
609
 
 
 
610
    if(AdjAIModulePtr)    
 
 
611
    {
 
 
612
        while(*AdjAIModulePtr)
 
 
613
        {
 
 
614
            counter++;
 
 
615
            AdjAIModulePtr++;
 
 
616
        }
 
 
617
    }
 
 
618
    else
 
 
619
        return 0;
 
 
620
 
 
 
621
return counter;
 
 
622
}
 
 
623
 
 
 
624
 
 
 
625
/* allocates and initialises primitive data areas */
 
 
626
static void InitFarLocDataAreas(MODULE **moduleList, int numModules)
 
 
627
{
 
 
628
    int moduleCounter;
 
 
629
 
 
 
630
    /* first, the lists of data headers */    
 
 
631
    assert(numModules > 0);
 
 
632
    FALLP_AuxLocs = malloc(numModules*sizeof(FARLOCATIONSHEADER));
 
 
633
 
 
 
634
    if(!FALLP_AuxLocs) 
 
 
635
    {
 
 
636
        memoryInitialisationFailure = 1;
 
 
637
        return;
 
 
638
    }
 
 
639
 
 
 
640
    FL_TotalNumAuxLocs = 0;
 
 
641
    FL_AuxData = NULL;
 
 
642
 
 
 
643
    /* work out the number of adjacent modules/auxilary locations for each module, and add them up */
 
 
644
 
 
 
645
    for(moduleCounter=0; moduleCounter < numModules; moduleCounter++)
 
 
646
    {
 
 
647
        int thisModuleIndex;
 
 
648
        MODULE *thisModule = moduleList[moduleCounter]; 
 
 
649
 
 
 
650
        assert(thisModule);
 
 
651
        thisModuleIndex = thisModule->m_index;
 
 
652
        assert(thisModuleIndex >= 0);
 
 
653
        assert(thisModuleIndex < ModuleArraySize);
 
 
654
 
 
 
655
        if(ModuleIsPhysical(thisModule))
 
 
656
        {
 
 
657
            FL_TotalNumAuxLocs += FAR_MAX_LOCS;
 
 
658
        }    
 
 
659
    }
 
 
660
 
 
 
661
    /* allocate base data areas */
 
 
662
    assert(FL_TotalNumAuxLocs > 0);
 
 
663
    FL_AuxData = malloc(FL_TotalNumAuxLocs * sizeof(VECTORCH));;
 
 
664
 
 
 
665
    if(!FL_AuxData) 
 
 
666
    {
 
 
667
        memoryInitialisationFailure = 1;
 
 
668
        return;
 
 
669
    }
 
 
670
 
 
 
671
    /* init header lists */
 
 
672
    {
 
 
673
        VECTORCH *auxDataPtr = FL_AuxData;
 
 
674
 
 
 
675
        for(moduleCounter=0; moduleCounter < AIModuleArraySize; moduleCounter++)
 
 
676
        {
 
 
677
            AIMODULE* thisAIModule = &AIModuleArray[moduleCounter]; 
 
 
678
            int thisModuleIndex = thisAIModule->m_index;
 
 
679
            /* NB these pointers and indexes have been validated above */
 
 
680
 
 
 
681
            FALLP_AuxLocs[thisModuleIndex].numLocations = 0;
 
 
682
            FALLP_AuxLocs[thisModuleIndex].locationsList = NULL;
 
 
683
 
 
 
684
            {
 
 
685
                MODULE** modulearray = thisAIModule->m_module_ptrs;
 
 
686
 
 
 
687
                if(modulearray)
 
 
688
                {
 
 
689
                    FALLP_AuxLocs[thisModuleIndex].locationsList = auxDataPtr;
 
 
690
 
 
 
691
                    while(*modulearray)
 
 
692
                    {
 
 
693
                        modulearray++;
 
 
694
                        auxDataPtr += FAR_MAX_LOCS;
 
 
695
                    }
 
 
696
                }
 
 
697
            }
 
 
698
        }
 
 
699
 
 
 
700
        /* we can now validate this process... */
 
 
701
        assert(auxDataPtr == (FL_AuxData+FL_TotalNumAuxLocs));    
 
 
702
    }
 
 
703
}
 
 
704
 
 
 
705
/*----------------------Patrick 16/12/96------------------------
 
 
706
  This function builds a list of entry points and auxilary
 
 
707
  locations for    each module.
 
 
708
 
 
 
709
  NB this cannot be called until the module system has been 
 
 
710
  initialised for this environment.
 
 
711
----------------------------------------------------------------*/
 
 
712
 
 
 
713
void BuildFarModuleLocs()
 
 
714
{
 
 
715
    extern SCENEMODULE MainScene;
 
 
716
    /* now get a pointer to the list of modules in this environment. */ 
 
 
717
    int moduleCounter;
 
 
718
 
 
 
719
    assert(ModuleArraySize);
 
 
720
 
 
 
721
    #if logFarLocData
 
 
722
    logfile = fopen("E:/3DC/FARLOCS.TXT","w");
 
 
723
    fprintf(logfile, "MODULE FAR LOCATIONS DATA \n");
 
 
724
    fprintf(logfile, "LevelName: %s \n", AvP.LevelName);
 
 
725
    fprintf(logfile, "************************* \n");
 
 
726
    fprintf(logfile, "number of modules: %d \n", ModuleArraySize);
 
 
727
    fprintf(logfile, "grid size: %d \n", FAR_GRID_SIZE);
 
 
728
    fprintf(logfile, "max locs stored per module: %d \n \n", FAR_MAX_LOCS);
 
 
729
    fprintf(logfile, "alien box height: %d \n", FAR_BB_HEIGHT);
 
 
730
    fprintf(logfile, "alien box width: %d \n", FAR_BB_WIDTH);
 
 
731
    fprintf(logfile, "************************* \n \n");    
 
 
732
    #endif
 
 
733
 
 
 
734
    /* allocate some temporary work spaces..*/
 
 
735
    auxLocsGrid = malloc(FAR_GRID_SIZE*FAR_GRID_SIZE*sizeof(FARVALIDATEDLOCATION));
 
 
736
 
 
 
737
    if(!auxLocsGrid) 
 
 
738
    {
 
 
739
        memoryInitialisationFailure = 1;
 
 
740
        return;
 
 
741
    }
 
 
742
 
 
 
743
    /* Initialise the entry point list and auxilary location list.
 
 
744
    NB entry points are are pre-allocated, since they are evaluated in pairs.*/
 
 
745
    InitFarLocDataAreas(MainScene.sm_marray, ModuleArraySize);
 
 
746
 
 
 
747
    #if logFarLocData
 
 
748
    fprintf(logfile, "********************************* \n");
 
 
749
    fprintf(logfile, "STARTING ENTRY POINTS.... \n");
 
 
750
    fprintf(logfile, "********************************* \n \n");
 
 
751
    #endif
 
 
752
 
 
 
753
    /* Now go through the module list, and calculate entry points. This step should
 
 
754
    be done before auxilary locations, to be absolutely sure everything works out */
 
 
755
 
 
 
756
    #if logFarLocData
 
 
757
    fprintf(logfile, "********************************* \n");
 
 
758
    fprintf(logfile, "STARTING AUXILARY LOCATIONS.... \n");
 
 
759
    fprintf(logfile, "********************************* \n \n");
 
 
760
    #endif
 
 
761
 
 
 
762
    /* now go thro' each module calculating auxilary locations */
 
 
763
    for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++)
 
 
764
    {
 
 
765
        int ThisModuleIndex;    
 
 
766
        MODULE *thisModule = MainScene.sm_marray[moduleCounter]; 
 
 
767
 
 
 
768
         /* get a pointer to the next module, and it's index */
 
 
769
        assert(thisModule);
 
 
770
        ThisModuleIndex = thisModule->m_index;
 
 
771
        assert(ThisModuleIndex >= 0);
 
 
772
        assert(ThisModuleIndex < ModuleArraySize);
 
 
773
 
 
 
774
        #if logFarLocData
 
 
775
        fprintf(logfile, "********************************* \n");
 
 
776
        fprintf(logfile, "Module Index: %d \n", ThisModuleIndex);
 
 
777
        fprintf(logfile, "Module X range: %d %d \n", thisModule->m_minx, thisModule->m_maxx);
 
 
778
        fprintf(logfile, "Module Z range: %d %d \n \n", thisModule->m_minz, thisModule->m_maxz);
 
 
779
        #endif
 
 
780
 
 
 
781
        /* check for entry points into this module if there    aren't any,
 
 
782
        don't bother with auxilary locations */
 
 
783
 
 
 
784
        if(thisModule->m_aimodule)
 
 
785
            BuildFM_AuxilaryLocs(thisModule);
 
 
786
        /*
 
 
787
        else
 
 
788
        {    
 
 
789
            #if logFarLocData
 
 
790
            fprintf(logfile, "NO AUXILARY LOCS COMPUTED: NO EPS \n \n");
 
 
791
            #endif
 
 
792
        } 
 
 
793
        */ 
 
 
794
    }
 
 
795
 
 
 
796
    /* deallocate the temporary work spaces */
 
 
797
    if (auxLocsGrid)
 
 
798
        free(auxLocsGrid);
 
 
799
 
 
 
800
    #if logFarLocData
 
 
801
    fprintf(logfile, "************************************* \n");
 
 
802
    fprintf(logfile, "FINISHED ! \n");
 
 
803
    //fprintf(logfile, "NUM INFINITE MODULES/TERMINATORS: %d \n", numInfiniteModules);
 
 
804
    fprintf(logfile, "************************************* \n");
 
 
805
    fclose(logfile);
 
 
806
    #endif
 
 
807
 
 
 
808
    #if logFarLocPositions && 0 //this log will need to updated for the ai modules.
 
 
809
    logfile2 = fopen("D:/PATRICK/FARLOCS2.TXT","w");
 
 
810
    fprintf(logfile2, "MODULE EPs AND AUXILARY LOCATIONS \n");
 
 
811
    fprintf(logfile2, "LeveName: %s \n", AvP.LevelName);
 
 
812
    fprintf(logfile2, "************************* \n \n");
 
 
813
 
 
 
814
    for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++)
 
 
815
    {
 
 
816
        int i;
 
 
817
        fprintf(logfile2, "MODULE INDEX: %d \n",moduleCounter);
 
 
818
        fprintf(logfile2, "  EPs: \n");
 
 
819
 
 
 
820
        for(i=0; i < FALLP_EntryPoints[moduleCounter].numEntryPoints; i++)
 
 
821
        {
 
 
822
            VECTORCH posn = (FALLP_EntryPoints[moduleCounter].entryPointsList)[i].position;
 
 
823
            int index = (FALLP_EntryPoints[moduleCounter].entryPointsList)[i].donorIndex; 
 
 
824
            fprintf(logfile2, "  %d %d %d FROM %d \n", posn.vx, posn.vy, posn.vz, index);
 
 
825
        }
 
 
826
 
 
 
827
        fprintf(logfile2, "  AUX: \n");
 
 
828
 
 
 
829
        for(i=0; i < FALLP_AuxLocs[moduleCounter].numLocations; i++)
 
 
830
        {
 
 
831
            VECTORCH posn = (FALLP_AuxLocs[moduleCounter].locationsList)[i];
 
 
832
            fprintf(logfile2, "  %d %d %d \n", posn.vx, posn.vy, posn.vz);
 
 
833
        }
 
 
834
        fprintf(logfile2, "\n");
 
 
835
    }
 
 
836
    fprintf(logfile2, "************************* \n");
 
 
837
    fprintf(logfile2, "END \n ");
 
 
838
    fclose(logfile2);
 
 
839
    #endif
 
 
840
}
 
 
841
 
 
 
842
/*-----------------------Patrick 28/11/96---------------------------
 
 
843
This function deallocates the location lists for each module,
 
 
844
and must be called at some point before the environment re-load
 
 
845
-------------------------------------------------------------------*/
 
 
846
void KillFarModuleLocs()
 
 
847
{    
 
 
848
    /* don't do this for a net game */
 
 
849
    //in fact do do it in net game
 
 
850
    //if(AvP.Network != I_No_Network)    return;
 
 
851
 
 
 
852
    assert(ModuleArraySize);
 
 
853
    assert(AIModuleArraySize);
 
 
854
    assert(FALLP_EntryPoints);
 
 
855
    assert(FALLP_AuxLocs);
 
 
856
    assert(FL_TotalNumAuxLocs>0);
 
 
857
    assert(FL_AuxData);
 
 
858
 
 
 
859
    /* deallocate the base data area in one go, and re-init globals */
 
 
860
    if (FL_AuxData)
 
 
861
        free(FL_AuxData);
 
 
862
 
 
 
863
    FL_TotalNumAuxLocs = 0;
 
 
864
    FL_AuxData = NULL;
 
 
865
 
 
 
866
    /* deallocate the list headers, and re-init globals */
 
 
867
    if (FALLP_AuxLocs)
 
 
868
        free(FALLP_AuxLocs);
 
 
869
 
 
 
870
    FALLP_AuxLocs = NULL;
 
 
871
 
 
 
872
    if (FALLP_EntryPoints) 
 
 
873
    {
 
 
874
        int i = 0;
 
 
875
        for(; i < AIModuleArraySize; i++)
 
 
876
        {
 
 
877
            if(FALLP_EntryPoints[i].entryPointsList)
 
 
878
            {
 
 
879
                free(FALLP_EntryPoints[i].entryPointsList);
 
 
880
            }
 
 
881
        }
 
 
882
 
 
 
883
        free(FALLP_EntryPoints);
 
 
884
    }
 
 
885
 
 
 
886
    FALLP_EntryPoints = NULL;
 
 
887
}
 
 
888
 
 
 
889
/*-----------------------Patrick 20/12/96---------------------------
 
 
890
THE FOLLOWING ARE SOME GENERIC FUNCTIONS FOR ANALYSING MODULE
 
 
891
STATES. THEY MAY BE USED IN ANY SOURCE FILE.
 
 
892
-------------------------------------------------------------------*/
 
 
893
 
 
 
894
/*-----------------------Patrick 20/12/96---------------------------
 
 
895
This function takes a module and returns whether it is a door,
 
 
896
and if so, what kind of door it is from an alien perspective.
 
 
897
-------------------------------------------------------------------*/
 
 
898
MODULEDOORTYPE ModuleIsADoor(MODULE* target)
 
 
899
{
 
 
900
    if((target->m_sbptr) && (target->m_sbptr->type == I_BehaviourProximityDoor))
 
 
901
        return MDT_ProxDoor;
 
 
902
 
 
 
903
    if((target->m_sbptr) && (target->m_sbptr->type == I_BehaviourLiftDoor))    
 
 
904
        return MDT_LiftDoor;
 
 
905
 
 
 
906
    if((target->m_sbptr) && (target->m_sbptr->type == I_BehaviourSwitchDoor))    
 
 
907
        return MDT_SecurityDoor;
 
 
908
 
 
 
909
return MDT_NotADoor;
 
 
910
}
 
 
911
 
 
 
912
MODULEDOORTYPE AIModuleIsADoor(AIMODULE* target)
 
 
913
{
 
 
914
    /* A bit rough and ready at this point. */
 
 
915
    MODULE **renderModule = target->m_module_ptrs;
 
 
916
    assert(target->m_module_ptrs);
 
 
917
 
 
 
918
    while ((*renderModule) != NULL)
 
 
919
    {
 
 
920
        if((*renderModule)->m_sbptr)
 
 
921
        {
 
 
922
            switch((*renderModule)->m_sbptr->type)
 
 
923
            {
 
 
924
                case I_BehaviourProximityDoor:
 
 
925
                    return MDT_ProxDoor;
 
 
926
                case I_BehaviourLiftDoor:
 
 
927
                    return MDT_LiftDoor;
 
 
928
                case I_BehaviourSwitchDoor:
 
 
929
                    return MDT_SecurityDoor;
 
 
930
                default:
 
 
931
                break;
 
 
932
            }
 
 
933
        }
 
 
934
 
 
 
935
        renderModule++;
 
 
936
    }
 
 
937
 
 
 
938
return MDT_NotADoor;
 
 
939
}
 
 
940
/*-----------------------Patrick 20/12/96---------------------------
 
 
941
Returns a pointer to an entry point in thisModule from fromModule,
 
 
942
or 0 if there isn't one.
 
 
943
-------------------------------------------------------------------*/
 
 
944
 
 
 
945
FARENTRYPOINT *GetAIModuleEP(AIMODULE* thisModule, AIMODULE *fromModule)
 
 
946
{
 
 
947
    FARENTRYPOINT *thisEp = NULL;
 
 
948
    int tmIndex = fromModule->m_index;
 
 
949
    int numEps = FALLP_EntryPoints[thisModule->m_index].numEntryPoints;
 
 
950
    FARENTRYPOINT *epList = FALLP_EntryPoints[thisModule->m_index].entryPointsList;
 
 
951
 
 
 
952
    while((numEps > 0) && (thisEp == NULL))
 
 
953
    {
 
 
954
        if(epList->donorIndex == tmIndex)
 
 
955
            thisEp = epList;
 
 
956
    epList++;
 
 
957
    numEps--;
 
 
958
    }
 
 
959
 
 
 
960
return thisEp;
 
 
961
}