1 /*-----------------------Patrick 12/11/96--------------------------
2   Source for AVP Pheromone system
3   -----------------------------------------------------------------*/
4 #include "3dc.h"
5 #include "inline.h"
6 #include "module.h"
7 #include "stratdef.h"
8 #include "gamedef.h"
9 #include "bh_types.h"
10 
11 #define UseLocalAssert Yes
12 #include "ourasert.h"
13 
14 #include "pheromon.h"
15 #include "pfarlocs.h"
16 #include "pvisible.h"
17 #include "bh_alien.h"
18 #include "bh_far.h"
19 #include "bh_gener.h"
20 #include "showcmds.h"
21 #include "pldghost.h"
22 
23 #if 1
24 static unsigned int *Pher_Player1;
25 static unsigned int *Pher_Player2;
26 static unsigned char *Pher_Ai1;
27 #else
28 #define	MaxModules	300
29 static unsigned int Pher_Player1[MaxModules];
30 static unsigned int Pher_Player2[MaxModules];
31 static unsigned char Pher_Ai1[MaxModules];
32 #endif
33 
34 /* these pointers indicate the current read from and write to
35 buffers for the player and ai pheromone systems */
36 unsigned int *PherPl_ReadBuf;
37 unsigned int *PherPl_WriteBuf;
38 unsigned char *PherAi_Buf;
39 
40 #if SUPER_PHEROMONE_SYSTEM
41 static unsigned int *Pher_Aliens1;
42 static unsigned int *Pher_Aliens2;
43 
44 unsigned int *PherAls_ReadBuf;
45 unsigned int *PherAls_WriteBuf;
46 
47 unsigned int AlienPheromoneScale;
48 
49 /* Marine pheromones: a pathfinding system only. */
50 static unsigned int *Pher_Marines1;
51 static unsigned int *Pher_Marines2;
52 
53 unsigned int *PherMars_ReadBuf;
54 unsigned int *PherMars_WriteBuf;
55 
56 #endif
57 
58 /* This global is used to store	the current player phermone intensity */
59 unsigned int PlayerSmell = 3;
60 MODULE *playerPherModule = (MODULE *)0;
61 
62 /* external globals */
63 extern int AIModuleArraySize;
64 
65 /* this define enables diagnostic text 'dump' for pheromone system */
66 #define logPheromoneDiagnostics 0
67 
68 #if logPheromoneDiagnostics
69 static void LogPlayerPherValues(void);
70 static void LogModuleAdjacencies(void);
71 int printModAdj = 1;
72 #endif
73 
74 /*----------------------Patrick 12/11/96---------------------------
75 Initialises pheromone systems
76 -------------------------------------------------------------------*/
InitPheromoneSystem(void)77 void InitPheromoneSystem(void)
78 {
79 	int i;
80 
81 	#if 1
82 	/* allocate	the pheromone buffers */
83 	Pher_Player1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
84 	if(!Pher_Player1)
85 	{
86 		memoryInitialisationFailure = 1;
87 		return;
88 	}
89 	Pher_Player2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
90 	if(!Pher_Player2)
91 	{
92 		memoryInitialisationFailure = 1;
93 		return;
94 	}
95 	Pher_Ai1 = (unsigned char *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned char));
96 	if(!Pher_Ai1)
97 	{
98 		memoryInitialisationFailure = 1;
99 		return;
100 	}
101 	#endif
102 
103 	#if SUPER_PHEROMONE_SYSTEM
104 	Pher_Aliens1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
105 	if(!Pher_Aliens1)
106 	{
107 		memoryInitialisationFailure = 1;
108 		return;
109 	}
110 
111 	Pher_Aliens2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
112 	if(!Pher_Aliens2)
113 	{
114 		memoryInitialisationFailure = 1;
115 		return;
116 	}
117 
118 	Pher_Marines1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
119 	if(!Pher_Marines1)
120 	{
121 		memoryInitialisationFailure = 1;
122 		return;
123 	}
124 
125 	Pher_Marines2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int));
126 	if(!Pher_Marines2)
127 	{
128 		memoryInitialisationFailure = 1;
129 		return;
130 	}
131 	#endif
132 
133 	/* init the player phermone system */
134 	for(i=0;i<AIModuleArraySize;i++)
135 	{
136 		Pher_Player1[i] = 1;
137 		Pher_Player2[i] = 1;
138 	}
139 	PherPl_ReadBuf = &Pher_Player1[0];
140 	PherPl_WriteBuf = &Pher_Player2[0];
141 	PlayerSmell = 3;
142 	playerPherModule = (MODULE *)0;
143 
144 	/* init the ai pheromone system */
145 	for(i=0;i<AIModuleArraySize;i++)
146 	{
147 		Pher_Ai1[i] = 0;
148 	}
149 	PherAi_Buf = &Pher_Ai1[0];
150 
151 	#if SUPER_PHEROMONE_SYSTEM
152 
153 	for(i=0;i<AIModuleArraySize;i++)
154 	{
155 		Pher_Aliens1[i] = 0;
156 		Pher_Aliens2[i] = 0;
157 	}
158 	PherAls_ReadBuf = &Pher_Aliens1[0];
159 	PherAls_WriteBuf = &Pher_Aliens2[0];
160 
161 	AlienPheromoneScale=1;
162 
163 	for(i=0;i<AIModuleArraySize;i++)
164 	{
165 		Pher_Marines1[i] = 0;
166 		Pher_Marines2[i] = 0;
167 	}
168 	PherMars_ReadBuf = &Pher_Marines1[0];
169 	PherMars_WriteBuf = &Pher_Marines2[0];
170 
171 	#endif
172 
173 	#if logPheromoneDiagnostics
174 	printModAdj = 1;
175 	#endif
176 
177 }
178 
179 /*----------------------Patrick 14/3/96---------------------------
180 End of level clean up for pheromone system
181 -------------------------------------------------------------------*/
CleanUpPheromoneSystem(void)182 void CleanUpPheromoneSystem(void)
183 {
184 	#if 1
185 	if (Pher_Player1 != NULL) {
186 		DeallocateMem(Pher_Player1);
187 		Pher_Player1 = NULL;
188 	}
189 	if (Pher_Player2 != NULL) {
190 		DeallocateMem(Pher_Player2);
191 		Pher_Player2 = NULL;
192 	}
193 	if (Pher_Ai1 != NULL) {
194 		DeallocateMem(Pher_Ai1);
195 		Pher_Ai1 = NULL;
196 	}
197 	PherPl_ReadBuf = NULL;
198 	PherPl_WriteBuf = NULL;
199 	PherAi_Buf = NULL;
200 	#endif
201 
202 	#if SUPER_PHEROMONE_SYSTEM
203 	if (Pher_Aliens1 != NULL) {
204 		DeallocateMem(Pher_Aliens1);
205 		Pher_Aliens1 = NULL;
206 	}
207 	if (Pher_Aliens2 != NULL) {
208 		DeallocateMem(Pher_Aliens2);
209 		Pher_Aliens2 = NULL;
210 	}
211 	if (Pher_Marines1 != NULL) {
212 		DeallocateMem(Pher_Marines1);
213 		Pher_Marines1 = NULL;
214 	}
215 	if (Pher_Marines2 != NULL) {
216 		DeallocateMem(Pher_Marines2);
217 		Pher_Marines2 = NULL;
218 	}
219 	PherAls_ReadBuf = NULL;
220 	PherAls_WriteBuf = NULL;
221 	PherMars_ReadBuf = NULL;
222 	PherMars_WriteBuf = NULL;
223 	#endif
224 }
225 
226 
AIModuleAdmitsPheromones(AIMODULE * targetModule)227 int AIModuleAdmitsPheromones(AIMODULE *targetModule) {
228 
229 	/* Check state. */
230 
231 	MODULEDOORTYPE doorStatus;
232 
233 	doorStatus = (AIModuleIsADoor(targetModule));
234 
235 	switch(doorStatus)
236 	{
237 		case(MDT_ProxDoor):
238 		{
239 			/* Go thru UNLOCKED proxdoors... */
240 			MODULE *renderModule;
241 			PROXDOOR_BEHAV_BLOCK *pdbblk;
242 
243 			renderModule=*(targetModule->m_module_ptrs);
244 			pdbblk=((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr);
245 
246 			if (pdbblk->lockable_door) {
247 				if (pdbblk->door_locked) {
248 					return(0);
249 				} else {
250 					return(1);
251 				}
252 			} else {
253 				if (pdbblk->door_locked) {
254 					return(0);
255 				} else {
256 					return(1);
257 				}
258 			}
259 		}
260 
261 		case(MDT_LiftDoor):
262 		{
263  			GLOBALASSERT(targetModule->m_module_ptrs);
264  			GLOBALASSERT(*(targetModule->m_module_ptrs));
265  			if(GetState((*(targetModule->m_module_ptrs))->m_sbptr)) {
266 				/* Open. */
267  				return (1);
268 			} else {
269 				/* Closed. */
270 				return (0);
271 			}
272 			break;
273 		}
274 
275 		case(MDT_SecurityDoor):
276 		{
277  			GLOBALASSERT(targetModule->m_module_ptrs);
278  			GLOBALASSERT(*(targetModule->m_module_ptrs));
279  			if(GetState((*(targetModule->m_module_ptrs))->m_sbptr)) {
280 				/* Open. */
281  				return (1);
282 			} else {
283 				/* Closed. */
284 				return (0);
285 			}
286 			break;
287 		}
288 
289 		default:
290 		{
291 			LOCALASSERT(doorStatus==MDT_NotADoor);
292 			return(1);
293 		}
294 
295 	}
296 
297 }
298 
299 #if SUPER_PHEROMONE_SYSTEM
AddMarinePheromones(AIMODULE * targetModule)300 void AddMarinePheromones(AIMODULE *targetModule) {
301 
302 	int ThisModuleIndex;
303 
304 	ThisModuleIndex = targetModule->m_index;
305 
306 	PherAls_WriteBuf[ThisModuleIndex] += 3;
307 
308 }
309 
MaintainMarineTargetZone(AIMODULE * targetModule)310 void MaintainMarineTargetZone(AIMODULE *targetModule) {
311 
312 	int ThisModuleIndex;
313 
314 	ThisModuleIndex = targetModule->m_index;
315 
316 	PherMars_WriteBuf[ThisModuleIndex] += 3;
317 
318 }
319 
320 #endif
321 
322 /*----------------------Patrick 12/11/96---------------------------
323 Updates the player pheromone system:
324 this is used by the NPC far behaviour for hunting the player.
325 -------------------------------------------------------------------*/
PlayerPheromoneSystem(void)326 void PlayerPheromoneSystem(void)
327 {
328 	int moduleCounter;
329 	AIMODULE *ModuleListPointer;
330 	AIMODULE *ThisModulePtr;
331 	int ThisModuleIndex;
332 	AIMODULE **AdjModuleRefPtr;
333 	int AdjModuleIndex;
334 
335 
336 	#if logPheromoneDiagnostics
337 		if(printModAdj)
338 		{
339 			printModAdj = 0;
340 			LogModuleAdjacencies();
341 		}
342 	#endif
343 
344 
345 	/* get a pointer to the global array of pointers to the modules
346 	in the environment (interfaces'r'us).
347 	First check if  Global_ModulePtr is set. If not we're buggered,
348 	so leave everything as it is and try again next frame*/
349 	{
350 		extern AIMODULE *AIModuleArray;
351 
352 		ModuleListPointer = AIModuleArray;
353 	}
354 
355 
356 	/* go through each module in the environment  */
357 	for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++)
358 	{
359 
360 		/* get a pointer to the next current module */
361 		ThisModulePtr = &(ModuleListPointer[moduleCounter]);
362 		LOCALASSERT(ThisModulePtr);
363 
364 		/* get it's index */
365 		ThisModuleIndex = ThisModulePtr->m_index;
366 
367 		LOCALASSERT(ThisModuleIndex >= 0);
368 		LOCALASSERT(ThisModuleIndex < AIModuleArraySize);
369 
370 
371 		/* !!!!!!!!!!!!!!!!!!!!!
372 		check for closed non-traversable door module here if detected, do not update its smell.
373 
374 		Actually, no: allow smell to pass thro' non-openable doors. Otherwise AIs that can open
375 		doors will choose not to
376 		!!!!!!!!!!!!!!!!!!!!!!!!*/
377 
378 		/* CDF 4/12/97: Actually, yes.  AIs CAN'T open security doors, fool! */
379 
380 		/* check for universal module: don't want to update this! */
381 		if(AIModuleIsPhysical(ThisModulePtr))
382 		{
383 
384 			if (AIModuleAdmitsPheromones(ThisModulePtr)) {
385 				/* get a pointer to the list of physically adjacent modules
386 				and traverse them */
387 
388 				AdjModuleRefPtr = ThisModulePtr->m_link_ptrs;
389 
390 				if(AdjModuleRefPtr)	/* check that there is a list of adjacent modules */
391 				{
392 					while(*AdjModuleRefPtr != 0)
393 					{
394 						/* get the index */
395 						AdjModuleIndex = (*AdjModuleRefPtr)->m_index;
396 
397 						/* if adjacent module's previous smell is greater than
398 						the current module's new smell (so far), then update
399 						the current module's newq smell */
400 						if(PherPl_ReadBuf[AdjModuleIndex] > PherPl_WriteBuf[ThisModuleIndex])
401 							PherPl_WriteBuf[ThisModuleIndex] = (PherPl_ReadBuf[AdjModuleIndex] - 1);
402 
403 						#if SUPER_PHEROMONE_SYSTEM
404 						if(PherAls_ReadBuf[AdjModuleIndex] > PherAls_WriteBuf[ThisModuleIndex]) {
405 							PherAls_WriteBuf[ThisModuleIndex] = (PherAls_ReadBuf[AdjModuleIndex] - 1);
406 						}
407 
408 						if (CheckAdjacencyValidity((*AdjModuleRefPtr),ThisModulePtr,0)) {
409 							if(PherMars_ReadBuf[AdjModuleIndex] > PherMars_WriteBuf[ThisModuleIndex]) {
410 								PherMars_WriteBuf[ThisModuleIndex] = (PherMars_ReadBuf[AdjModuleIndex] - 1);
411 							}
412 						}
413 						#endif
414 
415 						/* next adjacent module reference pointer */
416 						AdjModuleRefPtr++;
417 					}
418 				}
419 			}
420 			#if SUPER_PHEROMONE_SYSTEM
421 			/* Decay pheromones. */
422 			if (PherAls_WriteBuf[ThisModuleIndex]>0) {
423 				PherAls_WriteBuf[ThisModuleIndex]--;
424 			}
425 
426 			if (PherMars_WriteBuf[ThisModuleIndex]>0) {
427 				PherMars_WriteBuf[ThisModuleIndex]--;
428 			}
429 			#endif
430 		}
431 	}
432 
433 	/*If in a network game add pheromon's for other players*/
434 	if(AvP.Network!=I_No_Network && AvP.NetworkAIServer)
435 	{
436 		/* go through the strategy blocks looking for players*/
437 		int sbIndex;
438 		for(sbIndex=0;sbIndex<NumActiveStBlocks;sbIndex++)
439 		{
440 			STRATEGYBLOCK *playerSbPtr = ActiveStBlockList[sbIndex];
441 			NETGHOSTDATABLOCK *ghostData;
442 			if(playerSbPtr->I_SBtype!=I_BehaviourNetGhost) continue;
443 			ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr;
444 
445 			if(ghostData->type==I_BehaviourMarinePlayer ||
446 			   ghostData->type==I_BehaviourPredatorPlayer)
447 			{
448 				/*this is another player*/
449 				if(playerSbPtr->containingModule)
450 				{
451 		   			PherPl_WriteBuf[playerSbPtr->containingModule->m_aimodule->m_index] = PlayerSmell;
452 					AddMarinePheromones(playerSbPtr->containingModule->m_aimodule);
453 				}
454 			}
455 		}
456 	}
457 
458 	/* That completed, find which module the player is in, set it's smell to the
459 	current player smell value, and update the player smell for the next frame */
460 	{
461 		extern DISPLAYBLOCK* Player;
462 		VECTORCH playerPosition = Player->ObWorld;
463 		PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
464 
465 		playerPherModule = (ModuleFromPosition(&playerPosition, playerPherModule));
466 		if(playerPherModule)
467 		{
468    			//the player must be alive to leave pheromones
469 			//(mainly relevant in coop games)
470    			if(playerStatusPtr->IsAlive)
471 			{
472    				PherPl_WriteBuf[playerPherModule->m_aimodule->m_index] = PlayerSmell;
473 
474 				if(playerPherModule->name)
475 				{
476 					if (ShowDebuggingText.Module)
477 					{
478 						ReleasePrintDebuggingText("Player Module: %d '%s'\n", playerPherModule->m_index,playerPherModule->name);
479 						ReleasePrintDebuggingText("Player Module Coords: %d %d %d\n",playerPherModule->m_world.vx,playerPherModule->m_world.vy,playerPherModule->m_world.vz);
480 					}
481 					#if SUPER_PHEROMONE_SYSTEM
482 					AlienPheromoneScale+=3;
483 					if (AlienPheromoneScale==0) AlienPheromoneScale=1;
484 					{
485 						unsigned int prop=DIV_FIXED(PherAls_WriteBuf[playerPherModule->m_aimodule->m_index],AlienPheromoneScale);
486 						textprint("Alien readable pheromones in Player Module: %d\n",prop);
487 					}
488 					/* No scale for 'marine' pheromones, the player will never see it. */
489 					#endif
490 				}
491 			}
492 		}
493 	}
494 
495 	PlayerSmell++;
496 
497 	#if SUPER_PHEROMONE_SYSTEM
498 	/* Note that marines should add pheromones at the AI level... */
499 	{
500 		unsigned int *tempBufPointer = PherAls_ReadBuf;
501 		PherAls_ReadBuf = PherAls_WriteBuf;
502 		PherAls_WriteBuf= tempBufPointer;
503   	}
504 	/* As should the pathfinding system. */
505 	{
506 		unsigned int *tempBufPointer = PherMars_ReadBuf;
507 		PherMars_ReadBuf = PherMars_WriteBuf;
508 		PherMars_WriteBuf= tempBufPointer;
509   	}
510 	#endif
511 
512 	/* swap the read and write buffers:
513 	   behaviours access most recent data thro' the read buffer */
514 	{
515 		unsigned int *tempBufPointer = PherPl_ReadBuf;
516 		PherPl_ReadBuf = PherPl_WriteBuf;
517 		PherPl_WriteBuf	= tempBufPointer;
518   	}
519 
520 	#if logPheromoneDiagnostics
521 	LogPlayerPherValues();
522 	#endif
523 
524 
525 }
526 
527 
528 /*----------------------Patrick 14/11/96---------------------------
529 Ai Pheromone system.
530 
531 This system just keeps track of how many aliens are in each module,
532 and is calculated from scratch at the start of each frame.
533 Also, the numactivealiens bit of the hive data block is calculated
534 for this frame.
535 -------------------------------------------------------------------*/
AiPheromoneSystem(void)536 void AiPheromoneSystem(void)
537 {
538 	extern int NumActiveStBlocks;
539 	extern STRATEGYBLOCK *ActiveStBlockList[];
540 
541 	int sbIndex = 0;
542 	STRATEGYBLOCK *sbPtr;
543 	int i;
544 
545 	/* first, zero the buffer, and hive counter */
546 	for(i=0;i<AIModuleArraySize;i++) PherAi_Buf[i] = 0;
547 
548 	/* next, have a look at the sb list */
549 	while(sbIndex < NumActiveStBlocks)
550 	{
551 		sbPtr = ActiveStBlockList[sbIndex++];
552 		if((sbPtr->I_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine))
553 		{
554 			if(sbPtr->containingModule)
555 			{
556 				PherAi_Buf[(sbPtr->containingModule->m_aimodule->m_index)]++;
557 			}
558 		}
559 	}
560 }
561 
562 
563 
564 #if logPheromoneDiagnostics
565 
566 	/* write out a list of module ajacencies */
567 
LogModuleAdjacencies(void)568 static void LogModuleAdjacencies(void)
569 {
570 	extern SCENE Global_Scene;
571 	extern SCENEMODULE **Global_ModulePtr;
572 
573 	GLOBALASSERT(0);
574 
575 	/* This function does not use AI modules yet! */
576 
577 	FILE *logFile;
578 	int i;
579 	SCENEMODULE *ScenePtr;
580 	MODULE **ModuleListPointer;
581 	MODULE *ThisModulePtr;
582 	int ThisModuleIndex;
583 	MREF *AdjModuleRefPtr;
584 	int AdjModuleIndex;
585 
586 	LOCALASSERT(Global_ModulePtr != 0);
587 
588 	ScenePtr = Global_ModulePtr[Global_Scene];
589 	ModuleListPointer = ScenePtr->sm_marray;
590 
591 	logFile = fopen("D:/PATRICK/MODADJ.TXT","w");
592 
593 	if(logFile)
594 	{
595 
596 		LOCALASSERT(ModuleArraySize);
597 
598 		for(i = 0; i < ModuleArraySize; i++)
599 		{
600 			ThisModulePtr = ModuleListPointer[i];
601 			LOCALASSERT(ThisModulePtr);
602 
603 			/* get it's index */
604 			ThisModuleIndex = ThisModulePtr->m_index;
605 
606 			LOCALASSERT(ThisModuleIndex >= 0);
607 			LOCALASSERT(ThisModuleIndex < ModuleArraySize);
608 
609 			fprintf(logFile, "Module %d Adjoing modules: ", ThisModuleIndex);
610 
611 			/* get a pointer to the list of physically adjacent modules
612 			and traverse them */
613 			AdjModuleRefPtr = ThisModulePtr->m_link_ptrs;
614 			if(AdjModuleRefPtr == 0)
615 			{
616 				fprintf(logFile, " None/n");
617 			}
618 			else
619 			{
620 				while(AdjModuleRefPtr->mref_ptr != 0)
621 				{
622 					/* get the index */
623 					AdjModuleIndex = (AdjModuleRefPtr->mref_ptr)->m_index;
624 
625 					fprintf(logFile, " %d,", AdjModuleIndex);
626 
627 					/* next adjacent module reference pointer */
628 					AdjModuleRefPtr++;
629 				}
630 
631 				fprintf(logFile, "\n");
632 			}
633 
634 		}
635 
636 		fclose(logFile);
637 
638 
639 	}
640 
641 	/* also, initialise pheromone value file */
642 
643 	logFile = fopen("D:/PATRICK/MODPPHER.TXT","w");
644 
645 	if(logFile)
646 	{
647 		fprintf(logFile, "PLAYER PHEROMONE VALUES \n");
648 		fclose(logFile);
649 	}
650 
651 
652 }
653 
654 
655 /* Log the player pheromone values */
LogPlayerPherValues(void)656 static void LogPlayerPherValues(void)
657 {
658 	FILE *logFile;
659 	int i;
660 
661 	logFile = fopen("D:/PATRICK/MODPPHER.TXT","a");
662 	if (!logFile) return;
663 
664 	fprintf(logFile, "\n ***************************** \n");
665 
666 	for(i=0;i<AIModuleArraySize;i++)
667 	{
668 		if(i%7 == 0) fprintf(logFile, "\n");
669 		fprintf(logFile, "%5d", PherPl_ReadBuf[i]);
670 	}
671 
672 	fclose(logFile);
673 }
674 
675 #endif
676