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