1 /*----------------Patrick 15/11/96-------------------
2  Source for NPC generator behavior
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 #include "bh_alien.h"
12 #include "bh_marin.h"
13 #include "pfarlocs.h"
14 #include "bh_gener.h"
15 #include "pvisible.h"
16 #include "pheromon.h"
17 #include "bh_far.h"
18 #include "pldghost.h"
19 
20 #include "load_shp.h"
21 #define UseLocalAssert Yes
22 #include "ourasert.h"
23 
24 #include "huddefs.h"
25 #include "showcmds.h"
26 
27 /* externs for this file */
28 extern int NormalFrameTime;
29 extern char *ModuleCurrVisArray;
30 
31 extern void CreateMarineDynamic(STRATEGYBLOCK* Generator,MARINE_NPC_WEAPONS weapon_for_marine);
32 
33 /* globals for this file */
34 HIVE_DATA NPCHive;
35 
36 //generator details that are initialised with in setup_generators in the rif load
37 HIVELEVELPARAMS LoadedHiveData;
38 static int TypeOfNPCGenerated;
39 
40 /* prototypes for this file */
41 static void ResetGeneratorTimer(GENERATOR_BLOCK *genBlock);
42 static void ResetHiveStateTime(void);
43 int NumNPCsFromThisGenerator(STRATEGYBLOCK* gen_sbptr);
44 
45 int SlackTotal;
46 int SlackSize;
47 int ShowSlack=0;
48 
49 int NearAliens;
50 int Alt_NearAliens;
51 int FarAliens;
52 int Alt_FarAliens;
53 int ShowHiveState=0;
54 
55 /* for testing */
56 #define logGenData	0
57 #if logGenData
58 FILE *logFile;
59 #endif
60 
61 
62 /*
63 Stuff for adjusting difficulty level according to player's performance
64 */
65 static void GeneratorBalance_Init();
66 static void GeneratorBalance_PerFrameMaintenance();
67 static int GeneratorBalance_GlobalLimit();
68 static int GeneratorBalance_LocalLimit(int normal_limit);
69 
70 BOOL UseGeneratorBalance = FALSE;
71 struct
72 {
73 
74 	int Timer;
75 
76 	int AIScore;
77 	int PlayerScore;
78 
79 	int PlayerValue;
80 
81 	int RateMultiplier;
82 	int MaxAIShift;
83 
84 	int Counter;
85 
86 	int MaxOwnSettingNpc;
87 }GeneratorBalance;
88 
ZapSlack(void)89 void ZapSlack(void) {
90 
91 	SlackTotal=0;
92 	SlackSize=0;
93 
94 }
95 
96 /*----------------Patrick 15/11/96-------------------
97  Initialise a generator.
98  ----------------------------------------------------*/
InitGenerator(void * bhdata,STRATEGYBLOCK * sbPtr)99 void InitGenerator(void *bhdata, STRATEGYBLOCK *sbPtr)
100 {
101 
102 	GENERATOR_BLOCK *toolsData = (GENERATOR_BLOCK *)bhdata;
103  	GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)AllocateMem(sizeof(GENERATOR_BLOCK));
104 	if (!genBlock)
105 	{
106 		memoryInitialisationFailure = 1;
107 		return;
108 	}
109 
110 	*genBlock=*toolsData;
111 
112  	genBlock->Timer = 0;
113 	genBlock->RateIncreaseTimer=60*ONE_FIXED;
114 	if(genBlock->GenerationRate<=0)
115 		genBlock->GenerationRate=1;
116 
117  	sbPtr->SBdataptr = (void *)genBlock;
118  	sbPtr->maintainVisibility = 0;
119  	sbPtr->containingModule = NULL;
120 
121 
122   	sbPtr->shapeIndex=0; //shape index not relevant when using hierarchical	models
123 
124 	if(UseGeneratorBalance && genBlock->use_own_max_npc)
125 	{
126 		GeneratorBalance.MaxOwnSettingNpc+=genBlock->MaxGenNPCs;
127 	}
128 }
129 
130 
131 /*----------------Patrick 22/1/97-------------------
132   Generator Behaviour function.
133  ----------------------------------------------------*/
GeneratorBehaviour(STRATEGYBLOCK * sbPtr)134 void GeneratorBehaviour(STRATEGYBLOCK *sbPtr)
135 {
136 	GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr;
137 	LOCALASSERT(genBlock);
138 
139 	/* don't do this for a net game */
140 //	textprint("GenBeh\n");
141 	if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return;
142 //	textprint("GenBeh ok\n");
143 
144 	/* if our number of generators/minute is not > 0, the generator system is
145 	effectively turned off... */
146 	if(!(NPCHive.generatorNPCsPerMinute>0)) return;
147 
148 	/*see whether this generator is active*/
149 	if(!genBlock->Active)return;
150 
151 	/*if generator is using its own rate values , check for rate increase */
152 	if(genBlock->use_own_rate_values)
153 	{
154 		genBlock->RateIncreaseTimer-=NormalFrameTime;
155 		if(genBlock->RateIncreaseTimer<0)
156 		{
157 			genBlock->RateIncreaseTimer=ONE_FIXED*60;
158 			genBlock->GenerationRate+=genBlock->GenerationRateIncrease;
159 			genBlock->GenerationRate=min(genBlock->GenerationRate,GENSPERMINUTE_MAX*100);
160 			genBlock->GenerationRate=max(genBlock->GenerationRate,GENSPERMINUTE_MIN*100);
161 		}
162 	}
163 
164 	/* check the timer */
165 	if(UseGeneratorBalance && AvP.Network != I_No_Network)
166 	{
167 		genBlock->Timer -= MUL_FIXED(NormalFrameTime,GeneratorBalance.RateMultiplier);
168 	}
169 	else
170 	{
171 		genBlock->Timer -= NormalFrameTime;
172 	}
173 	if(genBlock->Timer > 0) return;
174 
175 	/* reset the timer */
176 	ResetGeneratorTimer(genBlock);
177 
178 	/* at this point, we have reset the timer, and are set to
179 	generate a new npc: however, some things can still
180 	prevent this: eg if the module is visible, or there are too
181 	many generator npcs in the environment */
182 
183 	/* if generator is visible, do not create a new NPC */
184 	if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)])
185 	{
186 		#if logGenData
187 		{
188 			logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
189 			fprintf(logFile, "generator: I am visible \n \n");
190  			fclose(logFile);
191 		}
192 		#endif
193 		return;
194 	}
195 
196 	/*If in a network game , must also make sure the module isn't visible by other players*/
197 	if(AvP.Network!=I_No_Network)
198 	{
199 		/* go through the strategy blocks looking for players*/
200 		int sbIndex;
201 		for(sbIndex=0;sbIndex<NumActiveStBlocks;sbIndex++)
202 		{
203 			STRATEGYBLOCK *playerSbPtr = ActiveStBlockList[sbIndex];
204 			NETGHOSTDATABLOCK *ghostData;
205 			if(playerSbPtr->I_SBtype!=I_BehaviourNetGhost) continue;
206 			ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr;
207 
208 			if(ghostData->type==I_BehaviourAlienPlayer ||
209 			   ghostData->type==I_BehaviourMarinePlayer ||
210 			   ghostData->type==I_BehaviourPredatorPlayer)
211 			{
212 				/*this is another player*/
213 				if(playerSbPtr->containingModule)
214 				{
215 					if(IsModuleVisibleFromModule(playerSbPtr->containingModule,sbPtr->containingModule))
216 					{
217 						/*Another player can see this generator's module*/
218 						return;
219 					}
220 				}
221 			}
222 		}
223 	}
224 
225 	/* if there are too many NPCs in the module, do not create a new one */
226 	if(PherAi_Buf[(sbPtr->containingModule->m_aimodule->m_index)] >= MAX_GENERATORNPCSPERMODULE)
227 	{
228 		#if logGenData
229 		{
230 			logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
231 			fprintf(logFile, "generator: too many aliens in my module \n \n");
232  			fclose(logFile);
233 		}
234 		#endif
235 		return;
236 	}
237 	/* if there are too many npcs in the env, do not create a new one */
238 	if(UseGeneratorBalance && AvP.Network != I_No_Network)
239 	{
240 		if(genBlock->use_own_max_npc)
241 		{
242 			//check npcs from this generator
243 			if (NumNPCsFromThisGenerator(sbPtr) >= GeneratorBalance_LocalLimit(genBlock->MaxGenNPCs))
244 				return;
245 
246 		}
247 		else
248 		{
249 			//check global npc limit
250 			if (NumGeneratorNPCsInEnv() >= GeneratorBalance_GlobalLimit())
251 				return;
252 		}
253 	}
254 	else
255 	{
256 		if(genBlock->use_own_max_npc)
257 		{
258 			//check npcs from this generator
259 			if (NumNPCsFromThisGenerator(sbPtr) >= genBlock->MaxGenNPCs)
260 				return;
261 
262 		}
263 		else
264 		{
265 			//check global npc limit
266 			if (NumGeneratorNPCsInEnv() >= NPCHive.maxGeneratorNPCs)
267 				return;
268 		}
269 	}
270 	/* ok... create an NPC, then */
271 	GLOBALASSERT(genBlock->WeightingTotal);
272 	{
273 		int random=FastRandom()%genBlock->WeightingTotal;
274 		if(random<0) random=-random;
275 
276 		//pulse rifle marine
277 		if(random<genBlock->PulseMarine_Wt)
278 		{
279 			CreateMarineDynamic(sbPtr,MNPCW_PulseRifle);
280 			return;
281 		}
282 		random-=genBlock->PulseMarine_Wt;
283 
284 		//pistol marine
285 		if(random<genBlock->PistolMarine_Wt)
286 		{
287 			CreateMarineDynamic(sbPtr,MNPCW_PistolMarine);
288 			return;
289 		}
290 		random-=genBlock->PistolMarine_Wt;
291 
292 		//flamer marine
293 		if(random<genBlock->FlameMarine_Wt)
294 		{
295 			CreateMarineDynamic(sbPtr,MNPCW_Flamethrower);
296 			return;
297 		}
298 		random-=genBlock->FlameMarine_Wt;
299 
300 		//smartgun marine
301 		if(random<genBlock->SmartMarine_Wt)
302 		{
303 			CreateMarineDynamic(sbPtr,MNPCW_Smartgun);
304 			return;
305 		}
306 		random-=genBlock->SmartMarine_Wt;
307 
308 		//sadar marine
309 		if(random<genBlock->SadarMarine_Wt)
310 		{
311 			CreateMarineDynamic(sbPtr,MNPCW_SADAR);
312 			return;
313 		}
314 		random-=genBlock->SadarMarine_Wt;
315 
316 		//grenade marine
317 		if(random<genBlock->GrenadeMarine_Wt)
318 		{
319 			CreateMarineDynamic(sbPtr,MNPCW_GrenadeLauncher);
320 			return;
321 		}
322 		random-=genBlock->GrenadeMarine_Wt;
323 
324 
325 		//minigun marine
326 		if(random<genBlock->MinigunMarine_Wt)
327 		{
328 			CreateMarineDynamic(sbPtr,MNPCW_Minigun);
329 			return;
330 		}
331 		random-=genBlock->MinigunMarine_Wt;
332 
333 		//shotgun civilian
334 		if(random<genBlock->ShotgunCiv_Wt)
335 		{
336 			CreateMarineDynamic(sbPtr,MNPCW_MShotgun);
337 			return;
338 		}
339 		random-=genBlock->ShotgunCiv_Wt;
340 
341 		//pistol civilian
342 		if(random<genBlock->PistolCiv_Wt)
343 		{
344 			CreateMarineDynamic(sbPtr,MNPCW_MPistol);
345 			return;
346 		}
347 		random-=genBlock->PistolCiv_Wt;
348 
349 		//flamer civilian
350 		if(random<genBlock->FlameCiv_Wt)
351 		{
352 			CreateMarineDynamic(sbPtr,MNPCW_MFlamer);
353 			return;
354 		}
355 		random-=genBlock->FlameCiv_Wt;
356 
357 		//unarmed civilian
358 		if(random<genBlock->UnarmedCiv_Wt)
359 		{
360 			CreateMarineDynamic(sbPtr,MNPCW_MUnarmed);
361 			return;
362 		}
363 		random-=genBlock->UnarmedCiv_Wt;
364 
365 		//molotov civilian
366 		if(random<genBlock->MolotovCiv_Wt)
367 		{
368 			CreateMarineDynamic(sbPtr,MNPCW_MMolotov);
369 			return;
370 		}
371 		random-=genBlock->MolotovCiv_Wt;
372 
373 		//alien
374 		if(random<genBlock->Alien_Wt)
375 		{
376 			CreateAlienDynamic(sbPtr,AT_Standard);
377 			return;
378 		}
379 		random-=genBlock->Alien_Wt;
380 
381 		//predator alien
382 		if(random<genBlock->PredAlien_Wt)
383 		{
384 			CreateAlienDynamic(sbPtr,AT_Predalien);
385 			return;
386 		}
387 		random-=genBlock->PredAlien_Wt;
388 
389 		//praetorian
390 		if(random<genBlock->Praetorian_Wt)
391 		{
392 			CreateAlienDynamic(sbPtr,AT_Praetorian);
393 			return;
394 		}
395 		random-=genBlock->Praetorian_Wt;
396 
397 		GLOBALASSERT(0=="Failed to select generator badguy");
398 
399 	}
400 
401 }
402 
403 
404 /*----------------Patrick 21/1/97-------------------
405  Initialise the hive
406  ----------------------------------------------------*/
InitHive(void)407 void InitHive(void)
408 {
409 	extern int NumActiveStBlocks;
410 	extern STRATEGYBLOCK *ActiveStBlockList[];
411 	int sbIndex = 0;
412 	STRATEGYBLOCK *sbPtr;
413 
414 	GeneratorBalance_Init();
415 
416 	/* initialise the hive data */
417 	NPCHive.currentState = HS_Attack;
418 	NPCHive.numGenerators = 0;
419 
420 	NPCHive.hiveStateTimer = 0;
421 	NPCHive.genRateTimer = 0;
422 	NPCHive.maxGeneratorNPCs = 0;
423 	NPCHive.generatorNPCsPerMinute = 0;
424 	NPCHive.deltaGeneratorNPCsPerMinute = 0;
425 
426 	NPCHive.AliensCanBeGenerated = FALSE;
427 	NPCHive.PredAliensCanBeGenerated = FALSE;
428 	NPCHive.PraetoriansCanBeGenerated = FALSE;
429 
430 	SlackTotal=0;
431 	SlackSize=0;
432 
433 	NearAliens=0;
434 	Alt_NearAliens=0;
435 	FarAliens=0;
436 	Alt_FarAliens=0;
437 
438 	/* don't do any more for a net game */
439 	/* actually, do - Richard */
440 //	if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return;
441 //	if(AvP.Network != I_No_Network)	return;
442 
443 
444 
445 
446 	/* set the level parameters */
447 //	NPCHive.maxGeneratorNPCs = hiveLevelData[AvP.CurrentEnv].maxGeneratorNPCs;
448 //	NPCHive.generatorNPCsPerMinute = hiveLevelData[AvP.CurrentEnv].generatorNPCsPerMinute;
449 //	NPCHive.deltaGeneratorNPCsPerMinute = hiveLevelData[AvP.CurrentEnv].deltaGeneratorNPCsPerMinute;
450 //	NPCHive.genRateTimer = (ONE_FIXED*60);
451 //
452 //	/* validate these parameters */
453 //	if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX)
454 //		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX;
455 //	if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN)
456 //		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN;
457 //	if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX)
458 //		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX;
459 //	if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN)
460 //		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN;
461 //	if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX)
462 //		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX;
463 //	if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN)
464 //		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN;
465 //
466 //	/* init the hive timer */
467 //	ResetHiveStateTime();
468 
469 	/* Now in ActivateHive. */
470 
471 	/* Some futher generator initialisations: work out what modules the generators are
472 	in, and how many generators there are.
473 	*/
474 	sbIndex = 0;
475 	while(sbIndex < NumActiveStBlocks)
476 	{
477 		sbPtr = ActiveStBlockList[sbIndex++];
478 		if(sbPtr->I_SBtype == I_BehaviourGenerator)
479 		{
480    			GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr;
481 			sbPtr->containingModule = ModuleFromPosition(&genBlock->Position, (MODULE *)0);
482 			LOCALASSERT(sbPtr->containingModule);
483 			NPCHive.numGenerators++;
484 			/* init generator times to something quite small...
485 			so that we get some npcs in the env quickly */
486 			genBlock->Timer = ONE_FIXED;
487 
488 			//work out which types of alien can be generated on this level (for multiplayer)
489 			if(genBlock->Alien_Wt) NPCHive.AliensCanBeGenerated = TRUE;
490 			if(genBlock->PredAlien_Wt) NPCHive.PredAliensCanBeGenerated = TRUE;
491 			if(genBlock->Praetorian_Wt) NPCHive.PraetoriansCanBeGenerated = TRUE;
492 		}
493 	}
494 
495 	#if logGenData
496 	{
497 		logFile = fopen("D:/PATRICK/GENLOG.TXT","w");
498 		fprintf(logFile, "GENERATOR/HIVE DATA LOG \n \n");
499 		fprintf(logFile, "num Geners: %d \n",NPCHive.numGenerators);
500 		fprintf(logFile, "hive timer: %d \n",NPCHive.hiveStateTimer);
501 		fprintf(logFile, "max npcs: %d \n",NPCHive.maxGeneratorNPCs);
502 		fprintf(logFile, "npcs per min: %d \n",NPCHive.generatorNPCsPerMinute);
503 		fprintf(logFile, "change in npcs per min: %d \n \n",NPCHive.deltaGeneratorNPCsPerMinute);
504  		fclose(logFile);
505 	}
506 	#endif
507 
508 	ActivateHive();
509 
510 }
511 
ActivateHive(void)512 void ActivateHive(void) {
513 
514 	/* Placed in for Jules's level... CDF 1/12/97, Deadline day! */
515 
516 	NPCHive.maxGeneratorNPCs=LoadedHiveData.maxGeneratorNPCs;
517 	NPCHive.generatorNPCsPerMinute=LoadedHiveData.generatorNPCsPerMinute;
518 	NPCHive.deltaGeneratorNPCsPerMinute=LoadedHiveData.deltaGeneratorNPCsPerMinute;
519 	NPCHive.genRateTimer=60*ONE_FIXED;
520 
521 	/* validate these parameters */
522 	if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX)
523 		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX;
524 	if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN)
525 		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN;
526 	if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX)
527 		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX;
528 	if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN)
529 		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN;
530 	if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX)
531 		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX;
532 	if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN)
533 		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN;
534 
535 	/* init the hive timer */
536 	ResetHiveStateTime();
537 
538 }
539 
DeActivateHive(void)540 void DeActivateHive(void) {
541 
542 	NPCHive.genRateTimer = 0;
543 	NPCHive.maxGeneratorNPCs = 0;
544 	NPCHive.generatorNPCsPerMinute = 0;
545 	NPCHive.deltaGeneratorNPCsPerMinute = 0;
546 
547 	/* validate these parameters */
548 	if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX)
549 		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX;
550 	if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN)
551 		NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN;
552 	if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX)
553 		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX;
554 	if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN)
555 		NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN;
556 	if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX)
557 		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX;
558 	if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN)
559 		NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN;
560 
561 	/* init the hive timer */
562 	ResetHiveStateTime();
563 
564 }
565 
566 /*---------------------Patrick 21/1/97------------------------
567  Do hive management:
568  generator time is decreased at the start of an attack phase
569  ------------------------------------------------------------*/
DoHive(void)570 void DoHive(void)
571 {
572 	/* don't do this for a net game */
573 	if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return;
574 //	if(AvP.Network != I_No_Network)	return;
575 
576 	if(AvP.Network != I_No_Network)
577 	{
578 		GeneratorBalance_PerFrameMaintenance();
579 	}
580 
581 	NearAliens=Alt_NearAliens;
582 	Alt_NearAliens=0;
583 	FarAliens=Alt_FarAliens;
584 	Alt_FarAliens=0;
585 
586 	/* chack hive state timer */
587 	NPCHive.hiveStateTimer -= NormalFrameTime;
588 	if(NPCHive.hiveStateTimer <= 0)
589 	{
590 		/* state change */
591 		if(NPCHive.currentState == HS_Attack)
592 		{
593 			#if ULTRAVIOLENCE
594 			/* Hackery.  An experiment. CDF 2/12/97.  Ha. */
595 			NPCHive.currentState = HS_Attack;
596 			#else
597 			/* switch to regroup */
598 			NPCHive.currentState = HS_Regroup;
599 			#endif
600 		}
601 		else
602 		{
603 			/* switch to attack */
604 			#if ULTRAVIOLENCE
605 			#else
606 			LOCALASSERT(NPCHive.currentState == HS_Regroup);
607 			#endif
608 			NPCHive.currentState = HS_Attack;
609 		}
610 		ResetHiveStateTime();
611 	}
612 
613 	/* check gen rate timer */
614 	NPCHive.genRateTimer -= NormalFrameTime;
615 	if(NPCHive.genRateTimer <= 0)
616 	{
617 		/* increase frequency */
618 		NPCHive.generatorNPCsPerMinute += NPCHive.deltaGeneratorNPCsPerMinute;
619 		/* validate this value */
620 		if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX)
621 			NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX;
622 		if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN)
623 			NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN;
624 
625 		NPCHive.genRateTimer = (ONE_FIXED*60);
626 	}
627 
628 	/* Print hive state. */
629 
630 	if(NPCHive.currentState == HS_Attack) {
631 		if (ShowHiveState) {
632 			PrintDebuggingText("Hive Attacking %d...\n",NPCHive.hiveStateTimer);
633 		}
634 	} else {
635 		if (ShowHiveState) {
636 			PrintDebuggingText("Hive Retreating %d...\n",NPCHive.hiveStateTimer);
637 		}
638 	}
639 
640 	if (ShowHiveState) {
641 		PrintDebuggingText("Near Aliens = %d\nFar Aliens = %d\n",NearAliens,FarAliens);
642 	}
643 
644 	if ((SlackSize)&&(ShowSlack)) {
645 		int Slack;
646 
647 		Slack=(SlackTotal/SlackSize);
648 		PrintDebuggingText("Average Slack %d\n",Slack);
649 	}
650 }
651 
652 
653 /*----------------Patrick 22/1/97-------------------
654   Timer functions
655  ----------------------------------------------------*/
ResetGeneratorTimer(GENERATOR_BLOCK * genBlock)656 static void ResetGeneratorTimer(GENERATOR_BLOCK *genBlock)
657 {
658 	LOCALASSERT(genBlock);
659 
660 	/* shouldn't be doing this for a net game */
661 //	LOCALASSERT(AvP.Network == I_No_Network);
662 
663 	if(genBlock->use_own_rate_values)
664 	{
665 		LOCALASSERT(genBlock->GenerationRate);
666 		genBlock->Timer	= (60 * ONE_FIXED *100)/genBlock->GenerationRate;
667 	}
668 	else
669 	{
670 		/* if we get here, there must be at least one generator, and some kind of generator rate */
671 		LOCALASSERT(NPCHive.numGenerators>0);
672 		LOCALASSERT(NPCHive.generatorNPCsPerMinute>0);
673 
674 		/* set the timer */
675 		genBlock->Timer	= (((60 * ONE_FIXED)/(NPCHive.generatorNPCsPerMinute))*NPCHive.numGenerators);
676 	}
677 	/* randomise +- an eighth */
678 	{
679 		int baseTime = genBlock->Timer;
680 		genBlock->Timer = ((baseTime*7)/8) + (FastRandom()%(baseTime/4));
681 	}
682 	/* clamp */
683 	if(genBlock->Timer>GENERATORTIME_MAX) genBlock->Timer=GENERATORTIME_MAX;
684 	if(genBlock->Timer<GENERATORTIME_MIN) genBlock->Timer=GENERATORTIME_MIN;
685 
686 	#if logGenData
687 	{
688 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
689 		fprintf(logFile, "Reset Gen Timer \n");
690 		fprintf(logFile, "gen timer to: %d seconds \n \n",genBlock->Timer);
691  		fclose(logFile);
692 	}
693 	#endif
694 }
695 
ResetHiveStateTime(void)696 static void ResetHiveStateTime(void)
697 {
698 	int baseTime;
699 
700 	/* shouldn't be doing this for a net game */
701 //	LOCALASSERT(AvP.Network == I_No_Network);
702 
703 	/* set the timer, +- an eighth */
704 	baseTime = LoadedHiveData.hiveStateBaseTime;
705 	NPCHive.hiveStateTimer = ((baseTime*7)/8) + (FastRandom()%(baseTime/4));
706 
707 	#if logGenData
708 	{
709 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
710 		fprintf(logFile, "Reset Hive Timer \n");
711 		fprintf(logFile, "hive timer to: %d seconds \n \n",NPCHive.hiveStateTimer);
712  		fclose(logFile);
713 	}
714 	#endif
715 }
716 
717 
718 /* Patrick 11/8/97 ---------------------------------------------------
719    A couple of useful functions
720    -------------------------------------------------------------------*/
NumGeneratorNPCsInEnv(void)721 int NumGeneratorNPCsInEnv(void)
722 {
723 	extern int NumActiveStBlocks;
724 	extern STRATEGYBLOCK *ActiveStBlockList[];
725 	int sbIndex = 0;
726 	STRATEGYBLOCK *sbPtr;
727 	int numOfNPCs = 0;
728 
729 	while(sbIndex < NumActiveStBlocks)
730 	{
731 		sbPtr = ActiveStBlockList[sbIndex++];
732 		if((sbPtr->I_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine))
733 		{
734 			//All placed bad guys will have the last character of the sbname as 0
735 			//generated badguys shoud have a non-zero last character.
736 			if(sbPtr->SBname[SB_NAME_LENGTH-1])
737 			{
738 				numOfNPCs++;
739 			}
740 		}
741 	}
742 
743 	#if logGenData
744 	{
745 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
746 		fprintf(logFile, "current num gener npcs: %d \n \n",numOfNPCs);
747  		fclose(logFile);
748 	}
749 	#endif
750 	return numOfNPCs;
751 }
NumNPCsFromThisGenerator(STRATEGYBLOCK * gen_sbptr)752 int NumNPCsFromThisGenerator(STRATEGYBLOCK* gen_sbptr)
753 {
754 	extern int NumActiveStBlocks;
755 	extern STRATEGYBLOCK *ActiveStBlockList[];
756 	int sbIndex = 0;
757 	STRATEGYBLOCK *sbPtr;
758 	int numOfNPCs = 0;
759 
760 	while(sbIndex < NumActiveStBlocks)
761 	{
762 		sbPtr = ActiveStBlockList[sbIndex++];
763 		switch(sbPtr->I_SBtype)
764 		{
765 			case I_BehaviourAlien :
766 				{
767 					ALIEN_STATUS_BLOCK* status_block=(ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr;
768 					GLOBALASSERT(status_block);
769 
770 					if(status_block->generator_sbptr==gen_sbptr)
771 					{
772 						//this alien was produced by this generator
773 						numOfNPCs++;
774 					}
775 				}
776 				break;
777 
778 			case I_BehaviourMarine :
779 				{
780 					MARINE_STATUS_BLOCK* status_block=(MARINE_STATUS_BLOCK*)sbPtr->SBdataptr;
781 					GLOBALASSERT(status_block);
782 
783 					if(status_block->generator_sbptr==gen_sbptr)
784 					{
785 						//this marine was produced by this generator
786 						numOfNPCs++;
787 					}
788 				}
789 				break;
790 
791 			default: ; /* do nothing */
792 		}
793 
794 	}
795 
796 	return numOfNPCs;
797 }
798 
799 
NumGeneratorNPCsVisible(void)800 int NumGeneratorNPCsVisible(void)
801 {
802 	extern int NumActiveStBlocks;
803 	extern STRATEGYBLOCK *ActiveStBlockList[];
804 	int sbIndex = 0;
805 	STRATEGYBLOCK *sbPtr;
806 	int numOfVisNPCs = 0;
807 
808 	while(sbIndex < NumActiveStBlocks)
809 	{
810 		sbPtr = ActiveStBlockList[sbIndex++];
811 		if((sbPtr->I_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine))
812 		{
813 			if(sbPtr->SBdptr)numOfVisNPCs++;
814 		}
815 	}
816 	#if logGenData
817 	{
818 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
819 		fprintf(logFile, "current num visible npcs: %d \n \n",numOfVisNPCs);
820  		fclose(logFile);
821 	}
822 	#endif
823 	return numOfVisNPCs;
824 }
825 
ForceAGenerator_Shell(void)826 void ForceAGenerator_Shell(void) {
827 
828 	NewOnScreenMessage("FORCING...\n");
829 	ForceAGenerator();
830 }
831 
ForceAGenerator(void)832 void ForceAGenerator(void)
833 {
834 	extern int NumActiveStBlocks;
835 	extern STRATEGYBLOCK *ActiveStBlockList[];
836 	int sbIndex = 0;
837 	STRATEGYBLOCK *sbPtr;
838 	#if logGenData
839 	{
840 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
841 		fprintf(logFile, "forcing a generator... \n");
842  		fclose(logFile);
843 	}
844 	#endif
845 
846 	while(sbIndex < NumActiveStBlocks)
847 	{
848 		sbPtr = ActiveStBlockList[sbIndex++];
849 		if(sbPtr->I_SBtype == I_BehaviourGenerator)
850 		{
851 			GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr;
852 			LOCALASSERT(genBlock);
853 
854 			if(genBlock->Timer>0)
855 			{
856 				/* found a generator with timer>0, so set it to zero and return */
857 				genBlock->Timer = 0;
858 				#if logGenData
859 				{
860 					logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
861 					fprintf(logFile, "... forced generator ref %d \n \n",sbIndex);
862  					fclose(logFile);
863 				}
864 				#endif
865 				return;
866 			}
867 		}
868 	}
869 	#if logGenData
870 	{
871 		logFile = fopen("D:/PATRICK/GENLOG.TXT","a");
872 		fprintf(logFile, "... didn't find one to force \n \n");
873  		fclose(logFile);
874 	}
875 	#endif
876 
877 }
878 
879 
SetHiveParamaters(int enemytype,int max,int genpermin,int deltagenpermin,int time)880 void SetHiveParamaters(int enemytype,int max,int genpermin,int deltagenpermin,int time)
881 {
882 	LoadedHiveData.maxGeneratorNPCs=max;
883 	LoadedHiveData.generatorNPCsPerMinute=genpermin;
884 	LoadedHiveData.deltaGeneratorNPCsPerMinute=deltagenpermin;
885 	LoadedHiveData.hiveStateBaseTime=time;
886 
887 	TypeOfNPCGenerated=enemytype;
888 }
889 
890 
891 /*--------------------**
892 ** Loading and Saving **
893 **--------------------*/
894 #include "savegame.h"
895 typedef struct generator_save_block
896 {
897 	SAVE_BLOCK_STRATEGY_HEADER header;
898 
899 	int Timer;
900 	int Active;
901 
902 	int GenerationRate;		//scaled up by 100
903 	int RateIncreaseTimer;
904 }GENERATOR_SAVE_BLOCK;
905 
906 //defines for load/save macros
907 #define SAVELOAD_BLOCK block
908 #define SAVELOAD_BEHAV genBlock
909 
910 
LoadStrategy_Generator(SAVE_BLOCK_STRATEGY_HEADER * header)911 void LoadStrategy_Generator(SAVE_BLOCK_STRATEGY_HEADER* header)
912 {
913 	STRATEGYBLOCK* sbPtr;
914 	GENERATOR_BLOCK *genBlock;
915 	GENERATOR_SAVE_BLOCK* block = (GENERATOR_SAVE_BLOCK*) header;
916 
917 	//check the size of the save block
918 	if(header->size!=sizeof(*block)) return;
919 
920 	//find the existing strategy block
921 	sbPtr = FindSBWithName(header->SBname);
922 	if(!sbPtr) return;
923 
924 	//make sure the strategy found is of the right type
925 	if(sbPtr->I_SBtype != I_BehaviourGenerator) return;
926 
927 	genBlock = (GENERATOR_BLOCK*)sbPtr->SBdataptr;
928 
929 	//start copying stuff
930 
931 	COPYELEMENT_LOAD(Timer)
932 	COPYELEMENT_LOAD(Active)
933 	COPYELEMENT_LOAD(GenerationRate)
934 	COPYELEMENT_LOAD(RateIncreaseTimer)
935 
936 }
937 
SaveStrategy_Generator(STRATEGYBLOCK * sbPtr)938 void SaveStrategy_Generator(STRATEGYBLOCK* sbPtr)
939 {
940 	GENERATOR_SAVE_BLOCK *block;
941 	GENERATOR_BLOCK *genBlock;
942 	genBlock = (GENERATOR_BLOCK*)sbPtr->SBdataptr;
943 
944 
945 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
946 
947 	//start copying stuff
948 
949 	COPYELEMENT_SAVE(Timer)
950 	COPYELEMENT_SAVE(Active)
951 	COPYELEMENT_SAVE(GenerationRate)
952 	COPYELEMENT_SAVE(RateIncreaseTimer)
953 
954 }
955 
956 
957 /*----------------------------------**
958 ** And now the global hive settings **
959 **----------------------------------*/
960 
961 
962 typedef struct hive_save_block
963 {
964 	SAVE_BLOCK_HEADER header;
965 
966 	HIVE_STATE currentState;
967 	int hiveStateTimer;
968 	int genRateTimer;
969 	int generatorNPCsPerMinute;
970 
971 }HIVE_SAVE_BLOCK;
972 
973 #undef  SAVELOAD_BLOCK
974 #undef  SAVELOAD_BEHAV
975 //defines for load/save macros
976 #define SAVELOAD_BLOCK block
977 #define SAVELOAD_BEHAV (&NPCHive)
978 
LoadHiveSettings(SAVE_BLOCK_HEADER * header)979 void LoadHiveSettings(SAVE_BLOCK_HEADER* header)
980 {
981 	HIVE_SAVE_BLOCK* block = (HIVE_SAVE_BLOCK*) header;
982 
983 	//check the size of the save block
984 	if(header->size!=sizeof(*block)) return;
985 
986 	COPYELEMENT_LOAD(currentState)
987 	COPYELEMENT_LOAD(hiveStateTimer)
988 	COPYELEMENT_LOAD(genRateTimer)
989 	COPYELEMENT_LOAD(generatorNPCsPerMinute)
990 
991 }
992 
SaveHiveSettings()993 void SaveHiveSettings()
994 {
995 	HIVE_SAVE_BLOCK* block;
996 	GET_SAVE_BLOCK_POINTER(block);
997 
998 	//fill in the header
999 	block->header.type = SaveBlock_GlobalHive;
1000 	block->header.size = sizeof(*block);
1001 
1002 
1003 	COPYELEMENT_SAVE(currentState)
1004 	COPYELEMENT_SAVE(hiveStateTimer)
1005 	COPYELEMENT_SAVE(genRateTimer)
1006 	COPYELEMENT_SAVE(generatorNPCsPerMinute)
1007 }
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 int GeneratorBalance_PlayerScoreValue = 0;
1017 
1018 #define GENERATOR_BALANCE_DECAY  (ONE_FIXED * .01)
1019 #define GENERATOR_BALANCE_THRESHHOLD (100000)
1020 
GeneratorBalance_Init()1021 static void GeneratorBalance_Init()
1022 {
1023 	GeneratorBalance.PlayerValue = GeneratorBalance_PlayerScoreValue*100;
1024 
1025 	GeneratorBalance.Timer = 0;
1026 	GeneratorBalance.AIScore = 0;
1027 	GeneratorBalance.PlayerScore = 0;
1028 
1029 	GeneratorBalance.RateMultiplier = ONE_FIXED;
1030 	GeneratorBalance.MaxAIShift = 0;
1031 	GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2;
1032 
1033 	GeneratorBalance.MaxOwnSettingNpc = 0;
1034 
1035 }
1036 
GeneratorBalance_NotePlayerDeath()1037 void GeneratorBalance_NotePlayerDeath()
1038 {
1039 	if(!UseGeneratorBalance) return;
1040 
1041 	GeneratorBalance.PlayerScore += GeneratorBalance.PlayerValue;
1042 }
1043 
GeneratorBalance_NoteAIDeath()1044 void GeneratorBalance_NoteAIDeath()
1045 {
1046 	if(!UseGeneratorBalance) return;
1047 
1048 	GeneratorBalance.AIScore+=100;
1049 }
1050 
GeneratorBalance_PerFrameMaintenance()1051 static void GeneratorBalance_PerFrameMaintenance()
1052 {
1053 	if(GeneratorBalance.PlayerValue!=GeneratorBalance_PlayerScoreValue*100)
1054 	{
1055 		GeneratorBalance.PlayerValue=GeneratorBalance_PlayerScoreValue*100;
1056 		UseGeneratorBalance = (GeneratorBalance.PlayerValue>0);
1057 	}
1058 
1059 	if(!UseGeneratorBalance) return;
1060 
1061 
1062 //	PrintDebuggingText("\n\n\n\n\nAI : %d\n",GeneratorBalance.AIScore);
1063 //	PrintDebuggingText("Player : %d\n",GeneratorBalance.PlayerScore);
1064 //	PrintDebuggingText("Counter : %d\n",GeneratorBalance.Counter);
1065 	PrintDebuggingText("\n\n\nAi Limit Shift : %d\n",GeneratorBalance.MaxAIShift);
1066 
1067 
1068 	GeneratorBalance.Timer += NormalFrameTime;
1069 
1070 	if(GeneratorBalance.Timer > 10 * ONE_FIXED)
1071 	{
1072 		GeneratorBalance.Timer-= 10 * ONE_FIXED;
1073 
1074 		if(GeneratorBalance.PlayerScore>0 || GeneratorBalance.AIScore>0)
1075 		{
1076 
1077 			if(GeneratorBalance.PlayerScore>GeneratorBalance.AIScore)
1078 			{
1079 				//make things easier
1080 				int ratio = DIV_FIXED(GeneratorBalance.PlayerScore+GeneratorBalance.PlayerValue,GeneratorBalance.AIScore+GeneratorBalance.PlayerValue);
1081 
1082 /*
1083 				if(ratio > (ONE_FIXED*1.1))
1084 				{
1085 					GeneratorBalance.RateMultiplier = DIV_FIXED(GeneratorBalance.RateMultiplier,ONE_FIXED *1.1);
1086 				}
1087 */
1088 				{
1089 					int decrement = ratio - ONE_FIXED;
1090 					if(GeneratorBalance.MaxAIShift < 0)
1091 					{
1092 						decrement /= (-GeneratorBalance.MaxAIShift)+1;
1093 					}
1094 
1095 					GeneratorBalance.Counter-=decrement;
1096 					if(GeneratorBalance.Counter<0)
1097 					{
1098 						GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2;
1099 						GeneratorBalance.MaxAIShift--;
1100 						GeneratorBalance.PlayerScore = 	GeneratorBalance.AIScore;
1101 
1102 					}
1103 
1104 				}
1105 			}
1106 			else
1107 			{
1108 				//make things harder
1109 				int ratio = DIV_FIXED(GeneratorBalance.AIScore+GeneratorBalance.PlayerValue,GeneratorBalance.PlayerScore+GeneratorBalance.PlayerValue);
1110   /*
1111 				if(ratio > (ONE_FIXED*1.1))
1112 				{
1113 					GeneratorBalance.RateMultiplier = MUL_FIXED(GeneratorBalance.RateMultiplier,ONE_FIXED *1.1);
1114 				}
1115 */
1116 
1117 
1118 				{
1119 					int increment = ratio - ONE_FIXED;
1120 					if(GeneratorBalance.MaxAIShift > 0)
1121 					{
1122 						increment /= GeneratorBalance.MaxAIShift+1;
1123 					}
1124 
1125 					GeneratorBalance.Counter+=increment;
1126 					if(GeneratorBalance.Counter>GENERATOR_BALANCE_THRESHHOLD)
1127 					{
1128 						GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2;
1129 						GeneratorBalance.MaxAIShift++;
1130 						GeneratorBalance.AIScore = 	GeneratorBalance.PlayerScore;
1131 
1132 					}
1133 
1134 				}
1135 			}
1136 	   		GeneratorBalance.AIScore -= MUL_FIXED(GENERATOR_BALANCE_DECAY,GeneratorBalance.AIScore);
1137 			GeneratorBalance.PlayerScore -= MUL_FIXED(GENERATOR_BALANCE_DECAY,GeneratorBalance.PlayerScore);
1138 		}
1139 
1140 		if(GeneratorBalance.RateMultiplier > 4*ONE_FIXED) GeneratorBalance.RateMultiplier = 4*ONE_FIXED;
1141 		if(GeneratorBalance.RateMultiplier < ONE_FIXED/4) GeneratorBalance.RateMultiplier = ONE_FIXED/4;
1142 
1143 
1144 
1145 
1146 	}
1147 }
1148 
1149 
GeneratorBalance_GlobalLimit()1150 static int GeneratorBalance_GlobalLimit()
1151 {
1152 	int limit = NPCHive.maxGeneratorNPCs + GeneratorBalance.MaxAIShift;
1153 
1154 	if(limit < 2) limit = 2;
1155 	if(limit > NPCHive.maxGeneratorNPCs +4) limit = NPCHive.maxGeneratorNPCs +4;
1156 	return(limit);
1157 }
1158 
GeneratorBalance_LocalLimit(int normal_limit)1159 static int GeneratorBalance_LocalLimit(int normal_limit)
1160 {
1161 	if(GeneratorBalance.MaxAIShift == 0) return(normal_limit);
1162 
1163 	if(GeneratorBalance.MaxAIShift < 0)
1164 	{
1165 		int limit = GeneratorBalance.MaxOwnSettingNpc + GeneratorBalance.MaxAIShift;
1166 
1167 		if(limit < 2) limit = 2;
1168 
1169 		if(NumGeneratorNPCsInEnv() >= limit) return(0);
1170 		return(normal_limit);
1171 	}
1172 	else
1173 	{
1174 		int shift = min(GeneratorBalance.MaxAIShift,4);
1175 		int limit = GeneratorBalance.MaxOwnSettingNpc + shift;
1176 		int	alien_shortfall = limit - NumGeneratorNPCsInEnv();
1177 
1178 		return(normal_limit + min(alien_shortfall,shift));
1179 
1180 	}
1181 }
1182