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