1 /*------------------------Patrick 13/12/96-----------------------------
2 Source file for FAR AI alien module locations, as used by far alien
3 behaviours....
4 --------------------------------------------------------------------*/
5 #include "3dc.h"
6 #include "inline.h"
7 #include "module.h"
8 #include "stratdef.h"
9 #include "gamedef.h"
10 #include "bh_types.h"
11 #include "comp_shp.h"
12
13 #include "dynblock.h"
14 #include "dynamics.h"
15
16 #include "pheromon.h"
17 #include "bh_alien.h"
18 #include "bh_far.h"
19 #include "pfarlocs.h"
20
21 #define UseLocalAssert Yes
22 #include "ourasert.h"
23
24 /* prototypes for this file */
25 //static void BuildFM_EntryPoints(MODULE *thisModule);
26 //static void BuildFM_ASingleEP(MODULE *thisModule, MODULE *targetModule);
27
28 static void BuildFM_AuxilaryLocs(MODULE *thisModule);
29 static void GetFarLocHeight(FARVALIDATEDLOCATION *location, MODULE *thisModule);
30 static void FarLocVolumeTest(FARVALIDATEDLOCATION *location, MODULE *thisModule);
31 static int IsXZinPoly(VECTORCH* location, struct ColPolyTag *polygonData);
32 static void InitFarLocDataAreas(MODULE **moduleList, int numModules);
33
34 /* external global variables used in this file */
35 extern int ModuleArraySize;
36
37 /* prototypes for external functions */
38 int SetupPolygonAccessFromShapeIndex(int shapeIndex);
39 int SetupPointAccessFromShapeIndex(int shapeIndex);
40 VECTORCH* AccessNextPoint(void);
41 VECTORCH* AccessPointFromIndex(int index);
42 int *GetPolygonVertexIndices(void);
43
44 /* globals for this file */
45 FARENTRYPOINTSHEADER *FALLP_EntryPoints=(FARENTRYPOINTSHEADER*)0;
46 FARLOCATIONSHEADER *FALLP_AuxLocs = (FARLOCATIONSHEADER *)0;
47
48 int AIModuleArraySize=0;
49 AIMODULE *AIModuleArray=0;
50
51 /* static globals for this file */
52 static FARVALIDATEDLOCATION *auxLocsGrid;
53 static int numInfiniteModules = 0;
54
55 static int FL_TotalNumAuxLocs = 0;
56 static VECTORCH *FL_AuxData = (VECTORCH *)0;
57
58 /* a define for logging location data */
59 #define logFarLocData 0
60 #if logFarLocData
61 static FILE *logfile;
62 #endif
63
64 #define logFarLocPositions 0
65 #if logFarLocPositions
66 static FILE *logfile2;
67 #endif
68
69 /*----------------------Patrick 16/12/96------------------------
70 This function builds a list of entry points and auxilary
71 locations for each module.
72
73
74 NB this cannot be called until the module system has been
75 initialised for this environment.
76 ----------------------------------------------------------------*/
77
BuildFarModuleLocs(void)78 void BuildFarModuleLocs(void)
79 {
80 MODULE **moduleListPointer;
81 int moduleCounter;
82
83 /* don't do this for a net game */
84 //in fact do do it in net game
85 #if 0
86 if(AvP.Network != I_No_Network)
87 {
88 /* Make sure global data is zeroed, then return */
89 FALLP_AuxLocs = (FARLOCATIONSHEADER *)0;
90 FL_TotalNumAuxLocs = 0;
91 FL_AuxData = (VECTORCH *)0;
92 return;
93 }
94 #endif
95
96 LOCALASSERT(ModuleArraySize);
97
98 /* now get a pointer to the list of modules in this environment. */
99 {
100 extern SCENE Global_Scene;
101 extern SCENEMODULE **Global_ModulePtr;
102 SCENEMODULE *ScenePtr;
103
104 LOCALASSERT(Global_ModulePtr);
105
106 ScenePtr = Global_ModulePtr[Global_Scene];
107 moduleListPointer = ScenePtr->sm_marray;
108 }
109
110 #if logFarLocData
111 logfile = fopen("E:/3DC/FARLOCS.TXT","w");
112 fprintf(logfile, "MODULE FAR LOCATIONS DATA \n");
113 fprintf(logfile, "ENV: %s \n", Env_List[AvP.CurrentEnv]->main);
114 fprintf(logfile, "************************* \n");
115 fprintf(logfile, "number of modules: %d \n", ModuleArraySize);
116 fprintf(logfile, "grid size: %d \n", FAR_GRID_SIZE);
117 fprintf(logfile, "max locs stored per module: %d \n \n", FAR_MAX_LOCS);
118 fprintf(logfile, "alien box height: %d \n", FAR_BB_HEIGHT);
119 fprintf(logfile, "alien box width: %d \n", FAR_BB_WIDTH);
120 fprintf(logfile, "************************* \n \n");
121 #endif
122
123 /* initialise infinite module counter */
124 numInfiniteModules = 0;
125
126 /* allocate some temporary work spaces..*/
127 auxLocsGrid = (FARVALIDATEDLOCATION *)AllocateMem(FAR_GRID_SIZE*FAR_GRID_SIZE*sizeof(FARVALIDATEDLOCATION));
128 if(!auxLocsGrid)
129 {
130 memoryInitialisationFailure = 1;
131 return;
132 }
133
134 /* Initialise the entry point list and auxilary location list.
135 NB entry points are are pre-allocated, since they are evaluated in pairs.*/
136 InitFarLocDataAreas(moduleListPointer, ModuleArraySize);
137
138 #if logFarLocData
139 fprintf(logfile, "********************************* \n");
140 fprintf(logfile, "STARTING ENTRY POINTS.... \n");
141 fprintf(logfile, "********************************* \n \n");
142 #endif
143
144 /* Now go through the module list, and calculate entry points. This step should
145 be done before auxilary locations, to be absolutely sure everything works out */
146 #if 0
147 //set up in projload now
148 for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++)
149 {
150 MODULE *thisModule;
151 int ThisModuleIndex;
152
153 /* get a pointer to the next module, and it's index */
154 thisModule = moduleListPointer[moduleCounter];
155 LOCALASSERT(thisModule);
156 ThisModuleIndex = thisModule->m_index;
157 LOCALASSERT(ThisModuleIndex >= 0);
158 LOCALASSERT(ThisModuleIndex < ModuleArraySize);
159
160 #if logFarLocData
161 fprintf(logfile, "********************************* \n");
162 fprintf(logfile, "Module Index: %d %s\n", ThisModuleIndex,thisModule->name);
163 #endif
164
165 /* reject modules that are not physical */
166 if(ModuleIsPhysical(thisModule))
167 BuildFM_EntryPoints(thisModule);
168 else
169 {
170 numInfiniteModules++;
171 #if logFarLocData
172 fprintf(logfile, "NO EPS COMPUTED: NOT PHYSICAL\n \n");
173 #endif
174 }
175 }
176 #endif
177
178 #if logFarLocData
179 fprintf(logfile, "********************************* \n");
180 fprintf(logfile, "STARTING AUXILARY LOCATIONS.... \n");
181 fprintf(logfile, "********************************* \n \n");
182 #endif
183
184 /* now go thro' each module calculating auxilary locations */
185 for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++)
186 {
187 MODULE *thisModule;
188 int ThisModuleIndex;
189
190 /* get a pointer to the next module, and it's index */
191 thisModule = moduleListPointer[moduleCounter];
192 LOCALASSERT(thisModule);
193 ThisModuleIndex = thisModule->m_index;
194 LOCALASSERT(ThisModuleIndex >= 0);
195 LOCALASSERT(ThisModuleIndex < ModuleArraySize);
196
197 #if logFarLocData
198 fprintf(logfile, "********************************* \n");
199 fprintf(logfile, "Module Index: %d \n", ThisModuleIndex);
200 fprintf(logfile, "Module X range: %d %d \n", thisModule->m_minx, thisModule->m_maxx);
201 fprintf(logfile, "Module Z range: %d %d \n \n", thisModule->m_minz, thisModule->m_maxz);
202 #endif
203
204 /* check for entry points into this module if there aren't any,
205 don't bother with auxilary locations */
206
207 if(thisModule->m_aimodule)
208 BuildFM_AuxilaryLocs(thisModule);
209 /*
210 else
211 {
212 #if logFarLocData
213 fprintf(logfile, "NO AUXILARY LOCS COMPUTED: NO EPS \n \n");
214 #endif
215 }
216 */
217 }
218
219 /* deallocate the temporary work spaces */
220 if (auxLocsGrid) DeallocateMem(auxLocsGrid);
221
222 #if logFarLocData
223 fprintf(logfile, "************************************* \n");
224 fprintf(logfile, "FINISHED ! \n");
225 fprintf(logfile, "NUM INFINITE MODULES/TERMINATORS: %d \n", numInfiniteModules);
226 fprintf(logfile, "************************************* \n");
227 fclose(logfile);
228 #endif
229
230 #if logFarLocPositions && 0 //this log will need to updated for the ai modules.
231 logfile2 = fopen("D:/PATRICK/FARLOCS2.TXT","w");
232 fprintf(logfile2, "MODULE EPs AND AUXILARY LOCATIONS \n");
233 fprintf(logfile2, "ENV: %s \n", Env_List[AvP.CurrentEnv]->main);
234 fprintf(logfile2, "************************* \n \n");
235
236 for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++)
237 {
238 int i;
239 fprintf(logfile2, "MODULE INDEX: %d \n",moduleCounter);
240 fprintf(logfile2, " EPs: \n");
241 for(i=0;i<FALLP_EntryPoints[moduleCounter].numEntryPoints;i++)
242 {
243 VECTORCH posn;
244 int index;
245 posn = (FALLP_EntryPoints[moduleCounter].entryPointsList)[i].position;
246 index = (FALLP_EntryPoints[moduleCounter].entryPointsList)[i].donorIndex;
247 fprintf(logfile2, " %d %d %d FROM %d \n", posn.vx, posn.vy, posn.vz, index);
248 }
249 fprintf(logfile2, " AUX: \n");
250 for(i=0;i<FALLP_AuxLocs[moduleCounter].numLocations;i++)
251 {
252 VECTORCH posn;
253 posn = (FALLP_AuxLocs[moduleCounter].locationsList)[i];
254 fprintf(logfile2, " %d %d %d \n", posn.vx, posn.vy, posn.vz);
255 }
256 fprintf(logfile2, "\n");
257 }
258 fprintf(logfile2, "************************* \n");
259 fprintf(logfile2, "END \n ");
260 fclose(logfile2);
261 #endif
262 }
263
264 /* allocates and initialises primitive data areas */
InitFarLocDataAreas(MODULE ** moduleList,int numModules)265 static void InitFarLocDataAreas(MODULE **moduleList, int numModules)
266 {
267 int moduleCounter;
268
269 /* first, the lists of data headers */
270 LOCALASSERT(numModules>0);
271 FALLP_AuxLocs = (FARLOCATIONSHEADER *)AllocateMem(numModules*sizeof(FARLOCATIONSHEADER));
272 if(!FALLP_AuxLocs)
273 {
274 memoryInitialisationFailure = 1;
275 return;
276 }
277
278
279 FL_TotalNumAuxLocs = 0;
280 FL_AuxData = (VECTORCH *)0;
281
282 /* work out the number of adjacent modules/auxilary locations for each module,
283 and add them up */
284 for(moduleCounter=0;moduleCounter<numModules;moduleCounter++)
285 {
286 MODULE *thisModule;
287 int thisModuleIndex;
288
289 thisModule = moduleList[moduleCounter];
290 LOCALASSERT(thisModule);
291 thisModuleIndex = thisModule->m_index;
292 LOCALASSERT(thisModuleIndex >= 0);
293 LOCALASSERT(thisModuleIndex < ModuleArraySize);
294
295 if(ModuleIsPhysical(thisModule))
296 {
297 FL_TotalNumAuxLocs += FAR_MAX_LOCS;
298 }
299 }
300
301 /* allocate base data areas */
302 LOCALASSERT(FL_TotalNumAuxLocs>0);
303 FL_AuxData = AllocateMem(FL_TotalNumAuxLocs*sizeof(VECTORCH));;
304 if(!FL_AuxData)
305 {
306 memoryInitialisationFailure = 1;
307 return;
308 }
309
310 /* init header lists */
311 {
312 VECTORCH *auxDataPtr = FL_AuxData;
313
314 for(moduleCounter=0;moduleCounter<AIModuleArraySize;moduleCounter++)
315 {
316 AIMODULE* thisAIModule = &AIModuleArray[moduleCounter];
317 int thisModuleIndex = thisAIModule->m_index;
318 /* NB these pointers and indexes have been validated above */
319
320 FALLP_AuxLocs[thisModuleIndex].numLocations = 0;
321 FALLP_AuxLocs[thisModuleIndex].locationsList = (VECTORCH *)0;
322
323 {
324 MODULE** modulearray=thisAIModule->m_module_ptrs;
325 if(modulearray)
326 {
327 FALLP_AuxLocs[thisModuleIndex].locationsList = auxDataPtr;
328 while(*modulearray)
329 {
330 modulearray++;
331 auxDataPtr += FAR_MAX_LOCS;
332
333 }
334 }
335 }
336 }
337
338 /* we can now validate this process... */
339 LOCALASSERT(auxDataPtr==(FL_AuxData+FL_TotalNumAuxLocs));
340 }
341 }
342
343
344 /*-----------------------Patrick 28/11/96---------------------------
345 This function deallocates the location lists for each module,
346 and must be called at some point before the environment re-load
347 -------------------------------------------------------------------*/
KillFarModuleLocs(void)348 void KillFarModuleLocs(void)
349 {
350 /* don't do this for a net game */
351 //in fact do do it in net game
352 //if(AvP.Network != I_No_Network) return;
353
354 LOCALASSERT(ModuleArraySize);
355 LOCALASSERT(AIModuleArraySize);
356 LOCALASSERT(FALLP_EntryPoints);
357 LOCALASSERT(FALLP_AuxLocs);
358 LOCALASSERT(FL_TotalNumAuxLocs>0);
359 LOCALASSERT(FL_AuxData);
360
361 /* deallocate the base data area in one go, and re-init globals */
362 if (FL_AuxData) DeallocateMem(FL_AuxData);
363 FL_TotalNumAuxLocs = 0;
364 FL_AuxData = (VECTORCH *)0;
365
366 /* deallocate the list headers, and re-init globals */
367 if (FALLP_AuxLocs) DeallocateMem(FALLP_AuxLocs);
368 FALLP_AuxLocs = (FARLOCATIONSHEADER *)0;
369 if (FALLP_EntryPoints)
370 {
371 int i;
372 for(i=0;i<AIModuleArraySize;i++)
373 {
374 if(FALLP_EntryPoints[i].entryPointsList)
375 {
376 DeallocateMem(FALLP_EntryPoints[i].entryPointsList);
377 }
378 }
379 DeallocateMem(FALLP_EntryPoints);
380 }
381 FALLP_EntryPoints = (FARENTRYPOINTSHEADER *)0;
382 }
383
384
385
386 /*-----------------------Patrick 20/12/96---------------------------
387 THE FOLLOWING ARE SOME GENERIC FUNCTIONS FOR ANALYSING MODULE
388 STATES. THEY MAY BE USED IN ANY SOURCE FILE.
389 -------------------------------------------------------------------*/
390
391 /*-----------------------Patrick 20/12/96---------------------------
392 This function takes a module and returns whether it is a door,
393 and if so, what kind of door it is from an alien perspective.
394 -------------------------------------------------------------------*/
ModuleIsADoor(MODULE * target)395 MODULEDOORTYPE ModuleIsADoor(MODULE* target)
396 {
397 if((target->m_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourProximityDoor))
398 return MDT_ProxDoor;
399 if((target->m_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourLiftDoor))
400 return MDT_LiftDoor;
401 if((target->m_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourSwitchDoor))
402 return MDT_SecurityDoor;
403
404 return MDT_NotADoor;
405 }
406
AIModuleIsADoor(AIMODULE * target)407 MODULEDOORTYPE AIModuleIsADoor(AIMODULE* target)
408 {
409 /* A bit rough and ready at this point. */
410 int a;
411 MODULE **renderModule;
412
413 GLOBALASSERT(target->m_module_ptrs);
414
415 renderModule=target->m_module_ptrs;
416 a=0;
417
418 while ((*renderModule)!=NULL) {
419
420 if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourProximityDoor))
421 return MDT_ProxDoor;
422 if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourLiftDoor))
423 return MDT_LiftDoor;
424 if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourSwitchDoor))
425 return MDT_SecurityDoor;
426
427 GLOBALASSERT(a<300);
428
429 renderModule++;
430 a++;
431 }
432
433 return MDT_NotADoor;
434 }
435
436 /*-----------------------Patrick 20/12/96---------------------------
437 Returns TRUE if a module is a physical part of the environment,
438 ie is not infinite or a terminator, etc...
439 -------------------------------------------------------------------*/
ModuleIsPhysical(MODULE * target)440 int ModuleIsPhysical(MODULE* target)
441 {
442 if(target->m_flags & m_flag_infinite) return 0;
443 if(target->m_type == mtype_term) return 0;
444 return 1;
445 }
446
AIModuleIsPhysical(AIMODULE * target)447 int AIModuleIsPhysical(AIMODULE* target)
448 {
449 if (target==NULL) {
450 return(0);
451 }
452 GLOBALASSERT(target);
453 if(target->m_module_ptrs==NULL) return 0;
454 return 1;
455 }
456
457 /*-----------------------Patrick 20/12/96---------------------------
458 Takes 2 modules, and returns TRUE if the centre of the target module
459 is within the bounding box of the source;
460 -------------------------------------------------------------------*/
ModuleInModule(MODULE * source,MODULE * target)461 int ModuleInModule(MODULE* source, MODULE* target)
462 {
463
464 if(target->m_world.vx < (source->m_world.vx + source->m_minx)) return 0;
465 if(target->m_world.vx > (source->m_world.vx + source->m_maxx)) return 0;
466
467 if(target->m_world.vy < (source->m_world.vy + source->m_miny)) return 0;
468 if(target->m_world.vy > (source->m_world.vy + source->m_maxy)) return 0;
469
470 if(target->m_world.vz < (source->m_world.vz + source->m_minz)) return 0;
471 if(target->m_world.vz > (source->m_world.vz + source->m_maxz)) return 0;
472
473 return 1;
474 }
475
476 /*-----------------------Patrick 20/12/96---------------------------
477 Returns the number of entries in a given module's adjacency list
478 If there is no adjacency list, return 0.
479 -------------------------------------------------------------------*/
NumAdjacentModules(AIMODULE * target)480 int NumAdjacentModules(AIMODULE* target)
481 {
482 AIMODULE **AdjAIModulePtr;
483 int counter = 0;
484
485 AdjAIModulePtr = (target->m_link_ptrs);
486 if(AdjAIModulePtr)
487 {
488 while(*AdjAIModulePtr)
489 {
490 counter++;
491 AdjAIModulePtr++;
492 }
493 }
494 else return 0;
495
496 return counter;
497 }
498
499 /*-----------------------Patrick 20/12/96---------------------------
500 Returns a pointer to an entry point in thisModule from fromModule,
501 or 0 if there isn't one.
502 -------------------------------------------------------------------*/
GetModuleEP(MODULE * thisModule,MODULE * fromModule)503 FARENTRYPOINT *GetModuleEP(MODULE* thisModule, MODULE*fromModule)
504 {
505 int numEps;
506 FARENTRYPOINT *epList;
507 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
508 int tmIndex = fromModule->m_index;
509
510 numEps = FALLP_EntryPoints[thisModule->m_index].numEntryPoints;
511 epList = FALLP_EntryPoints[thisModule->m_index].entryPointsList;
512
513 while((numEps>0) && (thisEp == (FARENTRYPOINT *)0))
514 {
515 if(epList->donorIndex == tmIndex) thisEp = epList;
516 epList++;
517 numEps--;
518 }
519
520 return thisEp;
521 }
522
GetAIModuleEP(AIMODULE * thisModule,AIMODULE * fromModule)523 FARENTRYPOINT *GetAIModuleEP(AIMODULE* thisModule, AIMODULE*fromModule)
524 {
525 int numEps;
526 FARENTRYPOINT *epList;
527 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
528 int tmIndex = fromModule->m_index;
529
530 numEps = FALLP_EntryPoints[thisModule->m_index].numEntryPoints;
531 epList = FALLP_EntryPoints[thisModule->m_index].entryPointsList;
532
533 while((numEps>0) && (thisEp == (FARENTRYPOINT *)0))
534 {
535 if(epList->donorIndex == tmIndex) thisEp = epList;
536 epList++;
537 numEps--;
538 }
539
540 return thisEp;
541 }
542
543 /*-----------------------Patrick 20/12/96---------------------------
544 Returns 1 if the given point is in a given module, or 0 otherwise.
545 The point is in module LOCAL space.
546
547 NB the bizzare structure of this function produces optimum pentium
548 instructions... apparently.
549 -------------------------------------------------------------------*/
PointIsInModule(MODULE * thisModule,VECTORCH * thisPoint)550 int PointIsInModule(MODULE* thisModule, VECTORCH* thisPoint)
551 {
552 /*
553 Allow tolerance level on module boundaries equivavlent to that used by
554 ModuleFromPosition_WithToleranace.
555 THis may be a bad plan , but I think this function only really gets used
556 for the purposes of asserts.
557 */
558 if(thisPoint->vx <= thisModule->m_maxx + 50)
559 if(thisPoint->vx >= thisModule->m_minx - 50)
560 if(thisPoint->vy <= thisModule->m_maxy + 50)
561 if(thisPoint->vy >= thisModule->m_miny - 50)
562 if(thisPoint->vz <= thisModule->m_maxz + 50)
563 if(thisPoint->vz >= thisModule->m_minz - 50)
564 return 1;
565 return 0;
566 }
567
568
569
570
571
572 /*-----------------------Patrick 20/12/96---------------------------
573 LOCAL FUNCTIONS FOR MODULE ENTRY POINT SUPPORT
574 -------------------------------------------------------------------*/
575
576 /* a structure and globals for the entry point calculations */
577 typedef struct epbbextents
578 {
579 int maxX;
580 int minX;
581 int maxY;
582 int minY;
583 int maxZ;
584 int minZ;
585 } EPBBEXTENTS;
586
587 #if 0
588 static EPBBEXTENTS MI_Volume1;
589 static EPBBEXTENTS MI_Volume2;
590 static EPBBEXTENTS MI_Volume3;
591
592 static int GetModulesIntersection(MODULE *thisModule, MODULE *targetModule);
593 static int GetModulePointBox(MODULE *thisModule, EPBBEXTENTS *extents);
594 static void AddModuleEP(MODULE* thisModule, MODULE*fromModule, VECTORCH *posn);
595 #endif
596
597 /*-----------------------Patrick 16/12/96---------------------------
598 This Function checks if a module has any adjacent modules, and if
599 so calls BuildFM_ASingleEntryEp for each one.
600 -------------------------------------------------------------------*/
601 #if 0
602 static void BuildFM_EntryPoints(MODULE *thisModule)
603 {
604 int ThisModuleIndex;
605 MREF *AdjModuleRefPtr;
606
607 LOCALASSERT(thisModule);
608 ThisModuleIndex = thisModule->m_index;
609 LOCALASSERT(ThisModuleIndex >= 0);
610 LOCALASSERT(ThisModuleIndex < ModuleArraySize);
611
612 /* check that there is a list of adjacent modules */
613 if(!(NumAdjacentModules(thisModule)))
614 {
615 #if logFarLocData
616 fprintf(logfile, "No adjacent modules found for this module \n");
617 #endif
618 return;
619 }
620
621 AdjModuleRefPtr = thisModule->m_link_ptrs;
622
623 /* go through each adjacent module */
624 while(AdjModuleRefPtr->mref_ptr != 0)
625 {
626 BuildFM_ASingleEP(thisModule, ((MODULE* )AdjModuleRefPtr->mref_ptr));
627 AdjModuleRefPtr++;
628 }
629 }
630 #endif
631
632 /*-----------------------Patrick 16/12/96---------------------------
633 This Function builds a single entry point pair between two modules.
634 -------------------------------------------------------------------*/
635 #if 0
636 static void BuildFM_ASingleEP(MODULE *thisModule, MODULE *targetModule)
637 {
638 VECTORCH thisModuleEP;
639 VECTORCH targetModuleEP;
640 int numpts1, numpts2;
641
642 /* containment check */
643 if(ModuleInModule(thisModule, targetModule))
644 {
645 #if logFarLocData
646 fprintf(logfile, "Against module %d: containment failure \n",targetModule->m_index);
647 #endif
648 targetModule->m_flags |= m_flag_slipped_inside;
649 return;
650 }
651 if(ModuleInModule(targetModule, thisModule))
652 {
653 #if logFarLocData
654 fprintf(logfile, "Against module %d: containment failure \n",targetModule->m_index);
655 #endif
656 thisModule->m_flags |= m_flag_slipped_inside;
657 return;
658 }
659
660 /* check if entry point already exists... */
661 if(GetModuleEP(thisModule, targetModule) != (FARENTRYPOINT *)0)
662 {
663 #if logFarLocData
664 fprintf(logfile, "Against module %d: ep already exists \n",targetModule->m_index);
665 #endif
666 return;
667 }
668
669 /* at this stage we know that thisModule is physical....
670 but it's a good idea to check the target module */
671 if (!(ModuleIsPhysical(targetModule)))
672 {
673 #if logFarLocData
674 fprintf(logfile, "Against module %d: target is not physical \n",targetModule->m_index);
675 #endif
676 return;
677 }
678
679 /* so go ahead and find the entry point pair... */
680 #if logFarLocData
681 fprintf(logfile, "Calculating ep against module %d %s\n", targetModule->m_index,targetModule->name);
682 #endif
683
684 /* compute the bounding box intersection between the modules */
685 if(GetModulesIntersection(thisModule, targetModule) == 0)
686 {
687 #if logFarLocData
688 fprintf(logfile, "Against module %d: BBOX failure \n",targetModule->m_index);
689 #endif
690 return;
691 }
692
693 /* get the bounding boxes defined by each module's points inside the intersection volume */
694
695 numpts1 = GetModulePointBox(thisModule, &MI_Volume2);
696 numpts2 = GetModulePointBox(targetModule, &MI_Volume3);
697
698 if(numpts1<2 || numpts2<2)
699 {
700 int extentCentre;
701
702 #if logFarLocData
703 fprintf(logfile, "Against module %d: not enough points in intersection \n",targetModule->m_index);
704 #endif
705
706 /* Create one anyways. */
707
708 extentCentre=MI_Volume1.maxX + MI_Volume1.minX;
709 extentCentre>>=1;
710 thisModuleEP.vx = extentCentre;
711 targetModuleEP.vx = extentCentre;
712
713 extentCentre=MI_Volume1.maxY + MI_Volume1.minY;
714 extentCentre>>=1;
715 thisModuleEP.vy = extentCentre;
716 targetModuleEP.vy = extentCentre;
717
718 extentCentre=MI_Volume1.maxZ + MI_Volume1.minZ;
719 extentCentre>>=1;
720 thisModuleEP.vz = extentCentre;
721 targetModuleEP.vz = extentCentre;
722
723 if( ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxY - MI_Volume1.minY))&&
724 ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxZ - MI_Volume1.minZ)))
725 {
726 /* x is smallest */
727 if(thisModule->m_world.vx > targetModule->m_world.vx)
728 {
729 thisModuleEP.vx = MI_Volume2.maxX + EP_POSNDISP;
730 targetModuleEP.vx = MI_Volume3.minX - EP_POSNDISP;
731 }
732 else
733 {
734 thisModuleEP.vx = MI_Volume2.minX - EP_POSNDISP;
735 targetModuleEP.vx = MI_Volume3.maxX + EP_POSNDISP;
736 }
737 }
738 else if((MI_Volume1.maxZ - MI_Volume1.minZ) < (MI_Volume1.maxY - MI_Volume1.minY))
739 {
740 /* z is smallest */
741
742 if(thisModule->m_world.vz > targetModule->m_world.vz)
743 {
744 thisModuleEP.vz = MI_Volume2.maxZ + EP_POSNDISP;
745 targetModuleEP.vz = MI_Volume3.minZ - EP_POSNDISP;
746 }
747 else
748 {
749 thisModuleEP.vz = MI_Volume2.minZ - EP_POSNDISP;
750 targetModuleEP.vz = MI_Volume3.maxZ + EP_POSNDISP;
751 }
752 }
753 else
754 {
755 /* y is smallest */
756 if(thisModule->m_world.vy > targetModule->m_world.vy)
757 {
758 thisModuleEP.vy = MI_Volume2.maxY + EP_POSNDISP;
759 targetModuleEP.vy = MI_Volume3.minY - EP_POSNDISP;
760 }
761 else
762 {
763 thisModuleEP.vy = MI_Volume2.minY - EP_POSNDISP;
764 targetModuleEP.vy = MI_Volume3.maxY + EP_POSNDISP;
765 }
766 }
767 #if logFarLocData
768 fprintf(logfile, "Made one anyway.\n");
769 #endif
770
771 } else {
772
773 /* Test the point bounding boxes, just to make sure */
774 LOCALASSERT(MI_Volume2.maxX >= MI_Volume2.minX);
775 LOCALASSERT(MI_Volume2.maxY >= MI_Volume2.minY);
776 LOCALASSERT(MI_Volume2.maxZ >= MI_Volume2.minZ);
777 LOCALASSERT(MI_Volume3.maxX >= MI_Volume3.minX);
778 LOCALASSERT(MI_Volume3.maxY >= MI_Volume3.minY);
779 LOCALASSERT(MI_Volume3.maxZ >= MI_Volume3.minZ);
780
781 /* calculate ep's */
782 if( ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxY - MI_Volume1.minY))&&
783 ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxZ - MI_Volume1.minZ)))
784 {
785 /* x is smallest */
786 int extentCentre;
787
788 if(MI_Volume2.maxY < MI_Volume3.maxY) extentCentre = MI_Volume2.maxY;
789 else extentCentre = MI_Volume3.maxY;
790 if(MI_Volume2.minY > MI_Volume3.minY) extentCentre += MI_Volume2.minY;
791 else extentCentre += MI_Volume3.minY;
792 extentCentre /= 2;
793 thisModuleEP.vy = extentCentre;
794 targetModuleEP.vy = extentCentre;
795
796 if(MI_Volume2.maxZ < MI_Volume3.maxZ) extentCentre = MI_Volume2.maxZ;
797 else extentCentre = MI_Volume3.maxZ;
798 if(MI_Volume2.minZ > MI_Volume3.minZ) extentCentre += MI_Volume2.minZ;
799 else extentCentre += MI_Volume3.minZ;
800 extentCentre /= 2;
801 thisModuleEP.vz = extentCentre;
802 targetModuleEP.vz = extentCentre;
803
804 if(thisModule->m_world.vx > targetModule->m_world.vx)
805 {
806 thisModuleEP.vx = MI_Volume2.maxX + EP_POSNDISP;
807 targetModuleEP.vx = MI_Volume3.minX - EP_POSNDISP;
808 }
809 else
810 {
811 thisModuleEP.vx = MI_Volume2.minX - EP_POSNDISP;
812 targetModuleEP.vx = MI_Volume3.maxX + EP_POSNDISP;
813 }
814 }
815 else if((MI_Volume1.maxZ - MI_Volume1.minZ) < (MI_Volume1.maxY - MI_Volume1.minY))
816 {
817 /* z is smallest */
818 int extentCentre;
819
820 if(MI_Volume2.maxX < MI_Volume3.maxX) extentCentre = MI_Volume2.maxX;
821 else extentCentre = MI_Volume3.maxX;
822 if(MI_Volume2.minX > MI_Volume3.minX) extentCentre += MI_Volume2.minX;
823 else extentCentre += MI_Volume3.minX;
824 extentCentre /= 2;
825 thisModuleEP.vx = extentCentre;
826 targetModuleEP.vx = extentCentre;
827
828 if(MI_Volume2.maxY < MI_Volume3.maxY) extentCentre = MI_Volume2.maxY;
829 else extentCentre = MI_Volume3.maxY;
830 if(MI_Volume2.minY > MI_Volume3.minY) extentCentre += MI_Volume2.minY;
831 else extentCentre += MI_Volume3.minY;
832 extentCentre /= 2;
833 thisModuleEP.vy = extentCentre;
834 targetModuleEP.vy = extentCentre;
835
836 if(thisModule->m_world.vz > targetModule->m_world.vz)
837 {
838 thisModuleEP.vz = MI_Volume2.maxZ + EP_POSNDISP;
839 targetModuleEP.vz = MI_Volume3.minZ - EP_POSNDISP;
840 }
841 else
842 {
843 thisModuleEP.vz = MI_Volume2.minZ - EP_POSNDISP;
844 targetModuleEP.vz = MI_Volume3.maxZ + EP_POSNDISP;
845 }
846 }
847 else
848 {
849 /* y is smallest */
850 int extentCentre;
851
852 if(MI_Volume2.maxX < MI_Volume3.maxX) extentCentre = MI_Volume2.maxX;
853 else extentCentre = MI_Volume3.maxX;
854 if(MI_Volume2.minX > MI_Volume3.minX) extentCentre += MI_Volume2.minX;
855 else extentCentre += MI_Volume3.minX;
856 extentCentre /= 2;
857 thisModuleEP.vx = extentCentre;
858 targetModuleEP.vx = extentCentre;
859
860 if(MI_Volume2.maxZ < MI_Volume3.maxZ) extentCentre = MI_Volume2.maxZ;
861 else extentCentre = MI_Volume3.maxZ;
862 if(MI_Volume2.minZ > MI_Volume3.minZ) extentCentre += MI_Volume2.minZ;
863 else extentCentre += MI_Volume3.minZ;
864 extentCentre /= 2;
865 thisModuleEP.vz = extentCentre;
866 targetModuleEP.vz = extentCentre;
867
868 if(thisModule->m_world.vy > targetModule->m_world.vy)
869 {
870 thisModuleEP.vy = MI_Volume2.maxY + EP_POSNDISP;
871 targetModuleEP.vy = MI_Volume3.minY - EP_POSNDISP;
872 }
873 else
874 {
875 thisModuleEP.vy = MI_Volume2.minY - EP_POSNDISP;
876 targetModuleEP.vy = MI_Volume3.maxY + EP_POSNDISP;
877 }
878 }
879 }
880
881 /* convert back into local space */
882 thisModuleEP.vx -= thisModule->m_world.vx;
883 thisModuleEP.vy -= thisModule->m_world.vy;
884 thisModuleEP.vz -= thisModule->m_world.vz;
885 targetModuleEP.vx -= targetModule->m_world.vx;
886 targetModuleEP.vy -= targetModule->m_world.vy;
887 targetModuleEP.vz -= targetModule->m_world.vz;
888
889 /* now test to make sure the entry points are inside their respective modules.
890 (If not, don't add either) */
891 {
892 int inModule;
893 inModule = PointIsInModule(thisModule, &thisModuleEP);
894 if(!inModule)
895 {
896 #if logFarLocData
897 fprintf(logfile, "....can't add eps: MODULE %d, EP NOT IN MODULE SPACE \n", thisModule->m_index);
898 #endif
899 return;
900 }
901 inModule = PointIsInModule(targetModule, &targetModuleEP);
902 if(!inModule)
903 {
904 #if logFarLocData
905 fprintf(logfile, "....can't add eps: MODULE %d, EP NOT IN MODULE SPACE \n", targetModule->m_index);
906 #endif
907 return;
908 }
909 }
910
911 /* Finally, set up the entry points for this and target module */
912 AddModuleEP(thisModule, targetModule, &thisModuleEP);
913 AddModuleEP(targetModule, thisModule, &targetModuleEP);
914 #if logFarLocData
915 fprintf(logfile, "... entry points added \n");
916 #endif
917
918 }
919 #endif
920
921 /*-----------------------Patrick 28/2/96---------------------------
922 This function calculates the bounding box intersection volume
923 between 2 adjacent modules (in world space coords).
924
925 Returns 1 if the bounding box is valis, 0 if not.
926 ------------------------------------------------------------------*/
927 #if 0
928 static int GetModulesIntersection(MODULE *thisModule, MODULE *targetModule)
929 {
930 int thisExtent, targetExtent;
931
932 /* do x extents */
933 thisExtent = (thisModule->m_maxx + thisModule->m_world.vx + EPBB_XTRA);
934 targetExtent = (targetModule->m_maxx + targetModule->m_world.vx + EPBB_XTRA);
935 if(thisExtent < targetExtent) MI_Volume1.maxX = thisExtent;
936 else MI_Volume1.maxX = targetExtent;
937 thisExtent = (thisModule->m_minx + thisModule->m_world.vx - EPBB_XTRA);
938 targetExtent = (targetModule->m_minx + targetModule->m_world.vx - EPBB_XTRA);
939 if(thisExtent > targetExtent) MI_Volume1.minX = thisExtent;
940 else MI_Volume1.minX = targetExtent;
941 if(!(MI_Volume1.maxX > MI_Volume1.minX)) return 0;
942
943 /* do y extents */
944 thisExtent = (thisModule->m_maxy + thisModule->m_world.vy + EPBB_XTRA);
945 targetExtent = (targetModule->m_maxy + targetModule->m_world.vy + EPBB_XTRA);
946 if(thisExtent < targetExtent) MI_Volume1.maxY = thisExtent;
947 else MI_Volume1.maxY = targetExtent;
948 thisExtent = (thisModule->m_miny + thisModule->m_world.vy - EPBB_XTRA);
949 targetExtent = (targetModule->m_miny + targetModule->m_world.vy - EPBB_XTRA);
950 if(thisExtent > targetExtent) MI_Volume1.minY = thisExtent;
951 else MI_Volume1.minY = targetExtent;
952 if(!(MI_Volume1.maxY > MI_Volume1.minY)) return 0;
953
954 /* do z extents */
955 thisExtent = (thisModule->m_maxz + thisModule->m_world.vz + EPBB_XTRA);
956 targetExtent = (targetModule->m_maxz+ targetModule->m_world.vz + EPBB_XTRA);
957 if(thisExtent < targetExtent) MI_Volume1.maxZ = thisExtent;
958 else MI_Volume1.maxZ = targetExtent;
959 thisExtent = (thisModule->m_minz + thisModule->m_world.vz - EPBB_XTRA);
960 targetExtent = (targetModule->m_minz + targetModule->m_world.vz - EPBB_XTRA);
961 if(thisExtent > targetExtent) MI_Volume1.minZ = thisExtent;
962 else MI_Volume1.minZ = targetExtent;
963 if(!(MI_Volume1.maxZ > MI_Volume1.minZ)) return 0;
964
965 return 1;
966 }
967
968
969 /*-----------------------Patrick 28/2/97---------------------------
970 Generates a volume defined by the module's points inside the
971 mutual intersection volume (in world space)
972 -------------------------------------------------------------------*/
973 static int GetModulePointBox(MODULE *thisModule, EPBBEXTENTS *extents)
974 {
975 int numPtsFound = 0;
976 int pointCounter;
977
978 /* initialise the extents */
979 extents->minX = thisModule->m_maxx + thisModule->m_world.vx;
980 extents->maxX = thisModule->m_minx + thisModule->m_world.vx;
981 extents->minY = thisModule->m_maxy + thisModule->m_world.vy;
982 extents->maxY = thisModule->m_miny + thisModule->m_world.vy;
983 extents->minZ = thisModule->m_maxz + thisModule->m_world.vz;
984 extents->maxZ = thisModule->m_minz + thisModule->m_world.vz;
985
986 /* go through each point in the shape */
987 pointCounter = SetupPointAccessFromShapeIndex(thisModule->m_mapptr->MapShape);
988 while(pointCounter>0)
989 {
990 VECTORCH* thisPt = AccessNextPoint();
991 VECTORCH thisWorldPoint;
992
993 thisWorldPoint.vx = thisPt->vx + thisModule->m_world.vx;
994 thisWorldPoint.vy = thisPt->vy + thisModule->m_world.vy;
995 thisWorldPoint.vz = thisPt->vz + thisModule->m_world.vz;
996
997 if( (thisWorldPoint.vx >= MI_Volume1.minX)&&
998 (thisWorldPoint.vx <= MI_Volume1.maxX)&&
999 (thisWorldPoint.vy >= MI_Volume1.minY)&&
1000 (thisWorldPoint.vy <= MI_Volume1.maxY)&&
1001 (thisWorldPoint.vz >= MI_Volume1.minZ)&&
1002 (thisWorldPoint.vz <= MI_Volume1.maxZ))
1003 {
1004 numPtsFound++;
1005
1006 if(thisWorldPoint.vx > extents->maxX) extents->maxX = thisWorldPoint.vx;
1007 if(thisWorldPoint.vx < extents->minX) extents->minX = thisWorldPoint.vx;
1008 if(thisWorldPoint.vy > extents->maxY) extents->maxY = thisWorldPoint.vy;
1009 if(thisWorldPoint.vy < extents->minY) extents->minY = thisWorldPoint.vy;
1010 if(thisWorldPoint.vz > extents->maxZ) extents->maxZ = thisWorldPoint.vz;
1011 if(thisWorldPoint.vz < extents->minZ) extents->minZ = thisWorldPoint.vz;
1012 }
1013 pointCounter--;
1014 }
1015 return numPtsFound;
1016 }
1017
1018
1019
1020
1021
1022
1023 /*-----------------------Patrick 20/12/96---------------------------
1024 Adds an entry point to the list for this module,
1025 -------------------------------------------------------------------*/
1026 static void AddModuleEP(MODULE* thisModule, MODULE*fromModule, VECTORCH *posn)
1027 {
1028 FARENTRYPOINTSHEADER *epHeader = &FALLP_EntryPoints[thisModule->m_index];
1029 FARENTRYPOINT *epList = epHeader->entryPointsList;
1030
1031 if(epHeader->numEntryPoints==(NumAdjacentModules((AIMODULE*)thisModule)))
1032 {
1033 /* no room for any more eps. This may occur where two modules are not
1034 mutually linked as adjacent... specifically, the target is missing the
1035 link. This shouldn't really happen, and if it does it means there's an
1036 error in the visibility and/or adjacency links which requires attention.
1037 The effective result is that the linked module will get an ep from the
1038 unlinked module, but not the other way round....
1039 */
1040 #if logFarLocData
1041 fprintf(logfile, "....CAN'T ADD EP TO MODULE %d : NO EP SLOTS \n", thisModule->m_index);
1042 #endif
1043 return;
1044 }
1045
1046 LOCALASSERT(epHeader->numEntryPoints<(NumAdjacentModules(thisModule)));
1047
1048 epList[epHeader->numEntryPoints].position = *posn;
1049 epList[epHeader->numEntryPoints].donorIndex = fromModule->m_index;
1050
1051 (epHeader->numEntryPoints)++;
1052
1053 }
1054 #endif
1055
1056 /*-----------------------Patrick 20/12/96---------------------------
1057 LOCAL FUNCTIONS FOR AUXILARY MODULE LOCATION SUPPORT
1058 -------------------------------------------------------------------*/
1059
1060 /*--------------------- Patrick 26/11/96 --------------------------
1061 This function attempts to construct a series of valid
1062 auxilary locations inside the module (provided it has entry points)
1063 -----------------------------------------------------------------*/
BuildFM_AuxilaryLocs(MODULE * thisModule)1064 static void BuildFM_AuxilaryLocs(MODULE *thisModule)
1065 {
1066 int gridStartX, gridStartZ, gridExtentX, gridExtentZ, XIndex, ZIndex;
1067 int NumLocsValid = 0;
1068 int NumLocsHeightFailed = 0;
1069 int NumLocsVolFailed = 0;
1070 int ThisModuleIndex;
1071 AIMODULE* aimodule=thisModule->m_aimodule;
1072
1073 /* get the module index */
1074 LOCALASSERT(aimodule);
1075 ThisModuleIndex = aimodule->m_index;
1076 LOCALASSERT(ThisModuleIndex >= 0);
1077 LOCALASSERT(ThisModuleIndex < ModuleArraySize);
1078
1079 gridStartX = thisModule->m_minx + (FAR_BB_WIDTH>>1);
1080 gridStartZ = thisModule->m_minz + (FAR_BB_WIDTH>>1);
1081 gridExtentX = thisModule->m_maxx - thisModule->m_minx - FAR_BB_WIDTH;
1082 gridExtentZ = thisModule->m_maxz - thisModule->m_minz - FAR_BB_WIDTH;
1083
1084 if(gridExtentX<=0 || gridExtentZ<=0)
1085 {
1086 //module is too narrow for auxilary locations
1087 return;
1088 }
1089
1090 LOCALASSERT(gridStartX > thisModule->m_minx);
1091
1092 /* step through each grid (index) location */
1093 for(XIndex = FAR_GRID_SIZE; XIndex > 0; XIndex--)
1094 {
1095 for(ZIndex = FAR_GRID_SIZE; ZIndex > 0; ZIndex--)
1096 {
1097 int locationsIndex = (XIndex-1)*FAR_GRID_SIZE + (ZIndex-1);
1098
1099 auxLocsGrid[locationsIndex].position.vx = gridStartX + (gridExtentX*(XIndex-1))/(FAR_GRID_SIZE-1);
1100 auxLocsGrid[locationsIndex].position.vz = gridStartZ + (gridExtentZ*(ZIndex-1))/(FAR_GRID_SIZE-1);
1101 auxLocsGrid[locationsIndex].position.vy = 0;
1102 auxLocsGrid[locationsIndex].valid = 1; /* validated by default */
1103
1104 /* get the floor height for this location.
1105 If no valid height is found, the location is set to
1106 minx,minz,miny, ie. outside of the grid, and abandoned */
1107
1108 GetFarLocHeight(&auxLocsGrid[locationsIndex], thisModule);
1109
1110 /* if there's a valid floor height, check the volume around the location
1111 for impinging polygons. If volume is impinged, the location is set to
1112 minx,minz,miny, ie. outside of the grid, and abandoned */
1113 if(auxLocsGrid[locationsIndex].valid)
1114 {
1115 FarLocVolumeTest(&auxLocsGrid[locationsIndex], thisModule);
1116 if(auxLocsGrid[locationsIndex].valid)
1117 {
1118
1119 AddVector(&thisModule->m_world,&auxLocsGrid[locationsIndex].position);
1120 SubVector(&aimodule->m_world,&auxLocsGrid[locationsIndex].position);
1121 NumLocsValid++;
1122 }
1123 else NumLocsVolFailed++;
1124 }
1125 else NumLocsHeightFailed++;
1126 }
1127 }
1128
1129
1130 #if logFarLocData
1131 fprintf(logfile, "Num valid locs: %d \n", NumLocsValid);
1132 fprintf(logfile, "Num Height failed: %d \n", NumLocsHeightFailed);
1133 fprintf(logfile, "Num Vol failed: %d \n \n", NumLocsVolFailed);
1134 #endif
1135
1136 /* now have a full list of locations....
1137 Those that are zero are invalid: hopefully some have survived */
1138 LOCALASSERT((NumLocsHeightFailed+NumLocsVolFailed+NumLocsValid) == (FAR_GRID_SIZE*FAR_GRID_SIZE));
1139
1140 /* If there are any valid locations remaining, store them in the locations list */
1141 if(NumLocsValid > 0)
1142 {
1143 /* Build a final and definitive list of valid locations for the module:
1144 look at the number of valid locations. If there are more than the maximum
1145 number, take a reasonably distributed sample. Otherwise just put them all in.
1146
1147 NB this wil be a list of Local Space coordinates.
1148 */
1149
1150 if(NumLocsValid > FAR_MAX_LOCS)
1151 {
1152 VECTORCH *destinationPtr;
1153 int locationsIndex = 0;
1154
1155 int numTaken = 0;
1156 int numFound = 0;
1157 int nextToTake = 0;
1158
1159 /* fill out the header (space is preallocated) */
1160 destinationPtr = &FALLP_AuxLocs[ThisModuleIndex].locationsList[FALLP_AuxLocs[ThisModuleIndex].numLocations];
1161 FALLP_AuxLocs[ThisModuleIndex].numLocations += FAR_MAX_LOCS;
1162
1163 numTaken=0;
1164 nextToTake = NumLocsValid / FAR_MAX_LOCS;
1165
1166 while(numTaken<FAR_MAX_LOCS)
1167 {
1168 LOCALASSERT(nextToTake <= NumLocsValid);
1169 LOCALASSERT(locationsIndex < (FAR_GRID_SIZE*FAR_GRID_SIZE));
1170
1171 while(auxLocsGrid[locationsIndex].valid == 0) locationsIndex++;
1172 LOCALASSERT(locationsIndex < (FAR_GRID_SIZE*FAR_GRID_SIZE));
1173 numFound++;
1174 LOCALASSERT(numFound <= NumLocsValid);
1175
1176 if(numFound == nextToTake)
1177 {
1178 *destinationPtr++ = auxLocsGrid[locationsIndex].position;
1179 numTaken++;
1180 /* calc index of the next one to take */
1181 nextToTake = ((numTaken + 1) * NumLocsValid) / FAR_MAX_LOCS;
1182 }
1183 /* move to next location */
1184 locationsIndex++;
1185 }
1186
1187 }
1188 else
1189 {
1190 VECTORCH *destinationPtr;
1191 int locationsIndex;
1192 int checkCount = 0;
1193
1194 /* fill out the header (space is preallocated) */
1195 destinationPtr = &FALLP_AuxLocs[ThisModuleIndex].locationsList[FALLP_AuxLocs[ThisModuleIndex].numLocations];
1196 FALLP_AuxLocs[ThisModuleIndex].numLocations += NumLocsValid;
1197
1198 /* fill up the list with what we've got */
1199 locationsIndex = (FAR_GRID_SIZE*FAR_GRID_SIZE) - 1;
1200 do
1201 {
1202 if(auxLocsGrid[locationsIndex].valid)
1203 {
1204 /* found a valid location: copy it into the list */
1205 *(destinationPtr++) = auxLocsGrid[locationsIndex].position;
1206 checkCount++;
1207 }
1208 }
1209 while(locationsIndex--);
1210
1211 LOCALASSERT(checkCount == NumLocsValid);
1212
1213 }
1214 #if logFarLocData
1215 {
1216 /* log the final list */
1217 VECTORCH *tmpPtr;
1218 int tmpCounter;
1219 fprintf(logfile, "Locations list: \n");
1220
1221 tmpCounter = FALLP_AuxLocs[ThisModuleIndex].numLocations;
1222 tmpPtr = FALLP_AuxLocs[ThisModuleIndex].locationsList;
1223
1224 while(tmpCounter > 0)
1225 {
1226 fprintf(logfile, "%d %d %d \n", tmpPtr->vx, tmpPtr->vz, tmpPtr->vy);
1227 tmpPtr++;
1228 tmpCounter--;
1229 }
1230
1231 fprintf(logfile,"\n");
1232
1233 }
1234 #endif
1235 }
1236 else
1237 {
1238 /* No valid locations */
1239 #if logFarLocData
1240 {
1241 /* log an error */
1242 fprintf(logfile,"All auxilary locations FAILED \n");
1243 }
1244 #endif
1245 }
1246 }
1247
1248 /*----------------------Patrick 1/12/96--------------------------
1249 Given an x/z position for the shape, this function returns a
1250 height value, by examining upwards facing polygons....
1251 To validate the height, there must also be a downwards facing
1252 polgon above the upwards facing polygon (so that we know that
1253 the location iiiiis inside the shape): if there is no up &
1254 down polygon, the location is invalidated, and an error code
1255 returned (either no up poly, no down poly, no up-or-down poly)
1256 ----------------------------------------------------------------*/
GetFarLocHeight(FARVALIDATEDLOCATION * location,MODULE * thisModule)1257 static void GetFarLocHeight(FARVALIDATEDLOCATION *location, MODULE *thisModule)
1258 {
1259 int polyCounter;
1260 int heightOfUpPoly = thisModule->m_maxy; /* init to lowest module extent */
1261 int heightOfDownPoly = thisModule->m_miny; /* init to heighest module extent */
1262 int upPolyFound = 0;
1263 int downPolyFound = 0;
1264 int XZcontainment;
1265
1266 struct ColPolyTag polygonData;
1267
1268 polyCounter = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape);
1269
1270 /* loop through the item list, then ... */
1271 while(polyCounter>0)
1272 {
1273 AccessNextPolygon();
1274 GetPolygonVertices(&polygonData);
1275 GetPolygonNormal(&polygonData);
1276
1277 /* first test if poly is vertical */
1278 if((polygonData.PolyNormal.vy > FAR_MIN_INCLINE)||(polygonData.PolyNormal.vy < -FAR_MIN_INCLINE))
1279 {
1280 XZcontainment = IsXZinPoly(&(location->position), &polygonData);
1281 if(XZcontainment)
1282 {
1283 if(polygonData.PolyNormal.vy > 0) /* downwards facing */
1284 {
1285 downPolyFound++;
1286 {
1287 /* find height of this poly: height of lowest vertex */
1288 int tmpHeight = polygonData.PolyPoint[0].vy;
1289
1290 if(polygonData.PolyPoint[1].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[1].vy;
1291 if(polygonData.PolyPoint[2].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy;
1292 if(polygonData.NumberOfVertices == 4)
1293 {
1294 if(polygonData.PolyPoint[3].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy;
1295 }
1296
1297 /* record height of lowest downward facing poly */
1298 if(tmpHeight > heightOfDownPoly) heightOfDownPoly = tmpHeight;
1299 }
1300 }
1301 else /* upwards facing */
1302 {
1303 upPolyFound++;
1304 {
1305 /* find height of this poly: height of highest vertex */
1306 int tmpHeight = polygonData.PolyPoint[0].vy;
1307
1308 if(polygonData.PolyPoint[1].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[1].vy;
1309 if(polygonData.PolyPoint[2].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy;
1310 if(polygonData.NumberOfVertices == 4)
1311 {
1312 if(polygonData.PolyPoint[3].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy;
1313 }
1314
1315 /* record height of heighest upward facing poly */
1316 if(tmpHeight < heightOfUpPoly) heightOfUpPoly = tmpHeight;
1317 }
1318 }
1319 }
1320 }
1321 polyCounter--;
1322 }
1323 /* if up & down polys exist check their heights:
1324 if there is not enough clearance bewteen the lowest down poly and the heighest up poly,
1325 invalidate the location.*/
1326 if((upPolyFound!=0) && (downPolyFound!=0))
1327 {
1328 int minclearance = FAR_BB_HEIGHT;
1329 if(thisModule->m_flags & MODULEFLAG_AIRDUCT) minclearance>>=1;
1330 if((heightOfUpPoly-heightOfDownPoly)>=minclearance)
1331 {
1332 //position the aux location slightly above the polygon
1333 location->position.vy = heightOfUpPoly-10;
1334 }
1335 else location->valid = 0;
1336 }
1337 else location->valid = 0;
1338 }
1339
1340
1341 /*------------------ Patrick 3/12/96 ----------------------
1342 This function determines whether an x/z position lies
1343 within the x/z projection of a polygon.
1344
1345 NB is not entirely accurate for concave polygons.
1346 ---------------------------------------------------------*/
IsXZinPoly(VECTORCH * location,struct ColPolyTag * polygonData)1347 static int IsXZinPoly(VECTORCH* location, struct ColPolyTag *polygonData)
1348 {
1349 int x = location->vx;
1350 int z = location->vz;
1351 int xa,za,xb,zb;
1352 int intersections = 0;
1353 int intersectMinz, intersectMaxz;
1354 int linesToTest;
1355 int nextLine;
1356
1357 linesToTest = polygonData->NumberOfVertices;
1358
1359 if(linesToTest == 3)
1360 {
1361 xa = polygonData->PolyPoint[2].vx;
1362 za = polygonData->PolyPoint[2].vz;
1363 }
1364 else
1365 {
1366 LOCALASSERT(linesToTest == 4);
1367 xa = polygonData->PolyPoint[3].vx;
1368 za = polygonData->PolyPoint[3].vz;
1369 }
1370
1371 nextLine = 0;
1372
1373 while(nextLine < linesToTest)
1374 {
1375 /* copy last first point to next last point (?) */
1376 xb = xa;
1377 zb = za;
1378
1379 /* get next first point */
1380 xa = polygonData->PolyPoint[nextLine].vx;
1381 za = polygonData->PolyPoint[nextLine].vz;
1382
1383 if(((x>=xb) && (x<=xa)) || ((x<xb) && (x>=xa)))
1384 {
1385 /* intesection ! */
1386 intersections++;
1387 if(!(intersections<4)) return 0;
1388
1389 {
1390 int zPosn;
1391
1392 if(xb==xa)
1393 zPosn = za;
1394 else
1395 zPosn = zb + WideMulNarrowDiv((za-zb),(x-xb),(xa-xb));
1396
1397 if(intersections == 1)
1398 intersectMinz = intersectMaxz = zPosn;
1399 else
1400 {
1401 if(zPosn < intersectMinz) intersectMinz = zPosn;
1402 else if(zPosn > intersectMaxz) intersectMaxz = zPosn;
1403 }
1404 }
1405 }
1406 nextLine++;
1407 }
1408
1409 if(intersections == 0) return 0;
1410 if(intersections == 1)
1411 return (z == intersectMinz);
1412 else
1413 return ((z >= intersectMinz)&&(z <= intersectMaxz));
1414
1415 }
1416
1417
1418 /*--------------------Patrick 4/12/96--------------------
1419 This function checks a potential location for impinging
1420 downward or sideways facing polygons (ie ceiling or floor).
1421 This is done using a bounding box containment test. If
1422 the test fails, it invalidates the location.
1423 -------------------------------------------------------*/
1424
1425 static int farbbox_maxx;
1426 static int farbbox_minx;
1427 static int farbbox_maxy;
1428 static int farbbox_miny;
1429 static int farbbox_maxz;
1430 static int farbbox_minz;
1431 static struct ColPolyTag farbbox_polygonData;
1432
1433 static int FarBoxContainsPolygon();
1434
FarLocVolumeTest(FARVALIDATEDLOCATION * location,MODULE * thisModule)1435 static void FarLocVolumeTest(FARVALIDATEDLOCATION *location, MODULE *thisModule)
1436 {
1437 int polyCounter;
1438 int containmentFailure = 0;
1439
1440 LOCALASSERT(location->valid);
1441
1442 /* the location is provided as an x,y,z:
1443 the x and z indicate the centre, and the y indicates the bottom.
1444 translate these into bounding box extents.... */
1445
1446 /* 10/7/97: this test has been modified: the bbox is moved up slightly, and any
1447 impinging ploygon invalidates the location */
1448
1449 farbbox_maxx = location->position.vx + (FAR_BB_WIDTH>>1);
1450 farbbox_minx = location->position.vx - (FAR_BB_WIDTH>>1);
1451 farbbox_maxz = location->position.vz + (FAR_BB_WIDTH>>1);
1452 farbbox_minz = location->position.vz - (FAR_BB_WIDTH>>1);
1453 farbbox_maxy = location->position.vy - 10;
1454
1455 /* patrick 4/7/97: a little adittion for airducts: npc should be crouched in them */
1456 if(thisModule->m_flags & MODULEFLAG_AIRDUCT)
1457 farbbox_miny = location->position.vy - (FAR_BB_HEIGHT>>1) - 10;
1458 else
1459 farbbox_miny = location->position.vy - FAR_BB_HEIGHT - 10;
1460
1461 /* now just run through the polygons in the shape. If a polygon is
1462 inside (actually, not definitely outside) the bbox, invalidate the location */
1463 polyCounter = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape);
1464 while((polyCounter>0)&&(!containmentFailure))
1465 {
1466 AccessNextPolygon();
1467 GetPolygonVertices(&farbbox_polygonData);
1468 containmentFailure = FarBoxContainsPolygon();
1469 polyCounter--;
1470 }
1471 /* so, if there has been a containmentFailure, invalidate the location */
1472 if(containmentFailure) location->valid = 0;
1473 }
1474
1475 /*--------------------Patrick 5/12/96----------------------------------
1476 This does a bounding box extent test for a polygon.
1477 NB returns false if the poly definitely isn't in the bbox, and returns
1478 true if the poly is in the bbox, and for unresolved cases.
1479 ----------------------------------------------------------------------*/
FarBoxContainsPolygon()1480 static int FarBoxContainsPolygon()
1481 {
1482 if(farbbox_polygonData.NumberOfVertices == 3)
1483 {
1484 if( (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&&
1485 (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&&
1486 (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny)) return 0;
1487
1488 if( (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&&
1489 (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&&
1490 (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx)) return 0;
1491
1492 if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&&
1493 (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&&
1494 (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz)) return 0;
1495
1496 if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&&
1497 (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&&
1498 (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz)) return 0;
1499
1500 if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&&
1501 (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&&
1502 (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx)) return 0;
1503
1504 if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&&
1505 (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&&
1506 (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy)) return 0;
1507 }
1508 else
1509 {
1510 if( (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&&
1511 (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&&
1512 (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny)&&
1513 (farbbox_polygonData.PolyPoint[3].vy<=farbbox_miny)) return 0;
1514
1515 if( (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&&
1516 (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&&
1517 (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx)&&
1518 (farbbox_polygonData.PolyPoint[3].vx<=farbbox_minx)) return 0;
1519
1520 if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&&
1521 (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&&
1522 (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz)&&
1523 (farbbox_polygonData.PolyPoint[3].vz<=farbbox_minz)) return 0;
1524
1525 if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&&
1526 (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&&
1527 (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz)&&
1528 (farbbox_polygonData.PolyPoint[3].vz>=farbbox_maxz)) return 0;
1529
1530 if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&&
1531 (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&&
1532 (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx)&&
1533 (farbbox_polygonData.PolyPoint[3].vx>=farbbox_maxx)) return 0;
1534
1535 if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&&
1536 (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&&
1537 (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy)&&
1538 (farbbox_polygonData.PolyPoint[3].vy>=farbbox_maxy)) return 0;
1539 }
1540 return 1;
1541 }
1542
1543