PageRenderTime 147ms CodeModel.GetById 61ms app.highlight 48ms RepoModel.GetById 32ms app.codeStats 0ms

/codemp/game/ai_util.c

https://github.com/Stoiss/jaMME
C | 867 lines | 699 code | 160 blank | 8 comment | 231 complexity | c5e89b7d154d7013ba9e8029c954e1b3 MD5 | raw file
  1#include "g_local.h"
  2#include "qcommon/q_shared.h"
  3#include "botlib/botlib.h"
  4#include "ai_main.h"
  5
  6#ifdef BOT_ZMALLOC
  7#define MAX_BALLOC 8192
  8
  9void *BAllocList[MAX_BALLOC];
 10#endif
 11
 12char gBotChatBuffer[MAX_CLIENTS][MAX_CHAT_BUFFER_SIZE];
 13
 14void *B_TempAlloc(int size)
 15{
 16	return BG_TempAlloc(size);
 17}
 18
 19void B_TempFree(int size)
 20{
 21	BG_TempFree(size);
 22}
 23
 24
 25void *B_Alloc(int size)
 26{
 27#ifdef BOT_ZMALLOC
 28	void *ptr = NULL;
 29	int i = 0;
 30
 31#ifdef BOTMEMTRACK
 32	int free = 0;
 33	int used = 0;
 34
 35	while (i < MAX_BALLOC)
 36	{
 37		if (!BAllocList[i])
 38		{
 39			free++;
 40		}
 41		else
 42		{
 43			used++;
 44		}
 45
 46		i++;
 47	}
 48
 49	G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
 50
 51	i = 0;
 52#endif
 53
 54	ptr = trap_BotGetMemoryGame(size);
 55
 56	while (i < MAX_BALLOC)
 57	{
 58		if (!BAllocList[i])
 59		{
 60			BAllocList[i] = ptr;
 61			break;
 62		}
 63		i++;
 64	}
 65
 66	if (i == MAX_BALLOC)
 67	{
 68		//If this happens we'll have to rely on this chunk being freed manually with B_Free, which it hopefully will be
 69#ifdef DEBUG
 70		G_Printf("WARNING: MAXIMUM B_ALLOC ALLOCATIONS EXCEEDED\n");
 71#endif
 72	}
 73
 74	return ptr;
 75#else
 76
 77	return BG_Alloc(size);
 78
 79#endif
 80}
 81
 82void B_Free(void *ptr)
 83{
 84#ifdef BOT_ZMALLOC
 85	int i = 0;
 86
 87#ifdef BOTMEMTRACK
 88	int free = 0;
 89	int used = 0;
 90
 91	while (i < MAX_BALLOC)
 92	{
 93		if (!BAllocList[i])
 94		{
 95			free++;
 96		}
 97		else
 98		{
 99			used++;
100		}
101
102		i++;
103	}
104
105	G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
106
107	i = 0;
108#endif
109
110	while (i < MAX_BALLOC)
111	{
112		if (BAllocList[i] == ptr)
113		{
114			BAllocList[i] = NULL;
115			break;
116		}
117
118		i++;
119	}
120
121	if (i == MAX_BALLOC)
122	{
123		//Likely because the limit was exceeded and we're now freeing the chunk manually as we hoped would happen
124#ifdef DEBUG
125		G_Printf("WARNING: Freeing allocation which is not in the allocation structure\n");
126#endif
127	}
128
129	trap_BotFreeMemoryGame(ptr);
130#endif
131}
132
133void B_InitAlloc(void)
134{
135#ifdef BOT_ZMALLOC
136	memset(BAllocList, 0, sizeof(BAllocList));
137#endif
138
139	memset(gWPArray, 0, sizeof(gWPArray));
140}
141
142void B_CleanupAlloc(void)
143{
144#ifdef BOT_ZMALLOC
145	int i = 0;
146
147	while (i < MAX_BALLOC)
148	{
149		if (BAllocList[i])
150		{
151			trap_BotFreeMemoryGame(BAllocList[i]);
152			BAllocList[i] = NULL;
153		}
154
155		i++;
156	}
157#endif
158}
159
160int GetValueGroup(char *buf, char *group, char *outbuf)
161{
162	char *place, *placesecond;
163	int iplace;
164	int failure;
165	int i;
166	int startpoint, startletter;
167	int subg = 0;
168
169	i = 0;
170
171	iplace = 0;
172
173	place = strstr(buf, group);
174
175	if (!place)
176	{
177		return 0;
178	}
179
180	startpoint = place - buf + strlen(group) + 1;
181	startletter = (place - buf) - 1;
182
183	failure = 0;
184
185	while (buf[startpoint+1] != '{' || buf[startletter] != '\n')
186	{
187		placesecond = strstr(place+1, group);
188
189		if (placesecond)
190		{
191			startpoint += (placesecond - place);
192			startletter += (placesecond - place);
193			place = placesecond;
194		}
195		else
196		{
197			failure = 1;
198			break;
199		}
200	}
201
202	if (failure)
203	{
204		return 0;
205	}
206
207	//we have found the proper group name if we made it here, so find the opening brace and read into the outbuf
208	//until hitting the end brace
209
210	while (buf[startpoint] != '{')
211	{
212		startpoint++;
213	}
214
215	startpoint++;
216
217	while (buf[startpoint] != '}' || subg)
218	{
219		if (buf[startpoint] == '{')
220		{
221			subg++;
222		}
223		else if (buf[startpoint] == '}')
224		{
225			subg--;
226		}
227		outbuf[i] = buf[startpoint];
228		i++;
229		startpoint++;
230	}
231	outbuf[i] = '\0';
232
233	return 1;
234}
235
236int GetPairedValue(char *buf, char *key, char *outbuf)
237{
238	char *place, *placesecond;
239	int startpoint, startletter;
240	int i, found;
241
242	if (!buf || !key || !outbuf)
243	{
244		return 0;
245	}
246
247	i = 0;
248
249	while (buf[i] && buf[i] != '\0')
250	{
251		if (buf[i] == '/')
252		{
253			if (buf[i+1] && buf[i+1] != '\0' && buf[i+1] == '/')
254			{
255				while (buf[i] != '\n')
256				{
257					buf[i] = '/';
258					i++;
259				}
260			}
261		}
262		i++;
263	}
264
265	place = strstr(buf, key);
266
267	if (!place)
268	{
269		return 0;
270	}
271	//tab == 9
272	startpoint = place - buf + strlen(key);
273	startletter = (place - buf) - 1;
274
275	found = 0;
276
277	while (!found)
278	{
279		if (startletter == 0 || !buf[startletter] || buf[startletter] == '\0' || buf[startletter] == 9 || buf[startletter] == ' ' || buf[startletter] == '\n')
280		{
281			if (buf[startpoint] == '\0' || buf[startpoint] == 9 || buf[startpoint] == ' ' || buf[startpoint] == '\n')
282			{
283				found = 1;
284				break;
285			}
286		}
287
288		placesecond = strstr(place+1, key);
289
290		if (placesecond)
291		{
292			startpoint += placesecond - place;
293			startletter += placesecond - place;
294			place = placesecond;
295		}
296		else
297		{
298			place = NULL;
299			break;
300		}
301
302	}
303
304	if (!found || !place || !buf[startpoint] || buf[startpoint] == '\0')
305	{
306		return 0;
307	}
308
309	while (buf[startpoint] == ' ' || buf[startpoint] == 9 || buf[startpoint] == '\n')
310	{
311		startpoint++;
312	}
313
314	i = 0;
315
316	while (buf[startpoint] && buf[startpoint] != '\0' && buf[startpoint] != '\n')
317	{
318		outbuf[i] = buf[startpoint];
319		i++;
320		startpoint++;
321	}
322
323	outbuf[i] = '\0';
324
325	return 1;
326}
327
328int BotDoChat(bot_state_t *bs, char *section, int always)
329{
330	char *chatgroup;
331	int rVal;
332	int inc_1;
333	int inc_2;
334	int inc_n;
335	int lines;
336	int checkedline;
337	int getthisline;
338	gentity_t *cobject;
339
340	if (!bs->canChat)
341	{
342		return 0;
343	}
344
345	if (bs->doChat)
346	{ //already have a chat scheduled
347		return 0;
348	}
349
350	if (trap_Cvar_VariableIntegerValue("se_language"))
351	{ //no chatting unless English.
352		return 0;
353	}
354
355	if (Q_irand(1, 10) > bs->chatFrequency && !always)
356	{
357		return 0;
358	}
359
360	bs->chatTeam = 0;
361
362	chatgroup = (char *)B_TempAlloc(MAX_CHAT_BUFFER_SIZE);
363
364	rVal = GetValueGroup(gBotChatBuffer[bs->client], section, chatgroup);
365
366	if (!rVal) //the bot has no group defined for the specified chat event
367	{
368		B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
369		return 0;
370	}
371
372	inc_1 = 0;
373	inc_2 = 2;
374
375	while (chatgroup[inc_2] && chatgroup[inc_2] != '\0')
376	{
377		if (chatgroup[inc_2] != 13 && chatgroup[inc_2] != 9)
378		{
379			chatgroup[inc_1] = chatgroup[inc_2];
380			inc_1++;
381		}
382		inc_2++;
383	}
384	chatgroup[inc_1] = '\0';
385
386	inc_1 = 0;
387
388	lines = 0;
389
390	while (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
391	{
392		if (chatgroup[inc_1] == '\n')
393		{
394			lines++;
395		}
396		inc_1++;
397	}
398
399	if (!lines)
400	{
401		B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
402		return 0;
403	}
404
405	getthisline = Q_irand(0, (lines+1));
406
407	if (getthisline < 1)
408	{
409		getthisline = 1;
410	}
411	if (getthisline > lines)
412	{
413		getthisline = lines;
414	}
415
416	checkedline = 1;
417
418	inc_1 = 0;
419
420	while (checkedline != getthisline)
421	{
422		if (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
423		{
424			if (chatgroup[inc_1] == '\n')
425			{
426				inc_1++;
427				checkedline++;
428			}
429		}
430
431		if (checkedline == getthisline)
432		{
433			break;
434		}
435
436		inc_1++;
437	}
438
439	//we're at the starting position of the desired line here
440	inc_2 = 0;
441
442	while (chatgroup[inc_1] != '\n')
443	{
444		chatgroup[inc_2] = chatgroup[inc_1];
445		inc_2++;
446		inc_1++;
447	}
448	chatgroup[inc_2] = '\0';
449
450	//trap_EA_Say(bs->client, chatgroup);
451	inc_1 = 0;
452	inc_2 = 0;
453
454	if (strlen(chatgroup) > MAX_CHAT_LINE_SIZE)
455	{
456		B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
457		return 0;
458	}
459
460	while (chatgroup[inc_1])
461	{
462		if (chatgroup[inc_1] == '%' && chatgroup[inc_1+1] != '%')
463		{
464			inc_1++;
465
466			if (chatgroup[inc_1] == 's' && bs->chatObject)
467			{
468				cobject = bs->chatObject;
469			}
470			else if (chatgroup[inc_1] == 'a' && bs->chatAltObject)
471			{
472				cobject = bs->chatAltObject;
473			}
474			else
475			{
476				cobject = NULL;
477			}
478
479			if (cobject && cobject->client)
480			{
481				inc_n = 0;
482
483				while (cobject->client->pers.netname[inc_n])
484				{
485					bs->currentChat[inc_2] = cobject->client->pers.netname[inc_n];
486					inc_2++;
487					inc_n++;
488				}
489				inc_2--; //to make up for the auto-increment below
490			}
491		}
492		else
493		{
494			bs->currentChat[inc_2] = chatgroup[inc_1];
495		}
496		inc_2++;
497		inc_1++;
498	}
499	bs->currentChat[inc_2] = '\0';
500
501	if (strcmp(section, "GeneralGreetings") == 0)
502	{
503		bs->doChat = 2;
504	}
505	else
506	{
507		bs->doChat = 1;
508	}
509	bs->chatTime_stored = (strlen(bs->currentChat)*45)+Q_irand(1300, 1500);
510	bs->chatTime = level.time + bs->chatTime_stored;
511
512	B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
513
514	return 1;
515}
516
517void ParseEmotionalAttachments(bot_state_t *bs, char *buf)
518{
519	int i = 0;
520	int i_c = 0;
521	char tbuf[16];
522
523	while (buf[i] && buf[i] != '}')
524	{
525		while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
526		{
527			i++;
528		}
529
530		if (buf[i] && buf[i] != '}')
531		{
532			i_c = 0;
533			while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
534			{
535				bs->loved[bs->lovednum].name[i_c] = buf[i];
536				i_c++;
537				i++;
538			}
539			bs->loved[bs->lovednum].name[i_c] = '\0';
540
541			while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
542			{
543				i++;
544			}
545
546			i_c = 0;
547
548			while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
549			{
550				tbuf[i_c] = buf[i];
551				i_c++;
552				i++;
553			}
554			tbuf[i_c] = '\0';
555
556			bs->loved[bs->lovednum].level = atoi(tbuf);
557
558			bs->lovednum++;
559		}
560		else
561		{
562			break;
563		}
564
565		if (bs->lovednum >= MAX_LOVED_ONES)
566		{
567			return;
568		}
569
570		i++;
571	}
572}
573
574int ReadChatGroups(bot_state_t *bs, char *buf)
575{
576	char *cgroupbegin;
577	int cgbplace;
578	int i;
579
580	cgroupbegin = strstr(buf, "BEGIN_CHAT_GROUPS");
581
582	if (!cgroupbegin)
583	{
584		return 0;
585	}
586
587	if (strlen(cgroupbegin) >= MAX_CHAT_BUFFER_SIZE)
588	{
589		G_Printf(S_COLOR_RED "Error: Personality chat section exceeds max size\n");
590		return 0;
591	}
592
593	cgbplace = cgroupbegin - buf+1;
594
595	while (buf[cgbplace] != '\n')
596	{
597		cgbplace++;
598	}
599
600	i = 0;
601
602	while (buf[cgbplace] && buf[cgbplace] != '\0')
603	{
604		gBotChatBuffer[bs->client][i] = buf[cgbplace];
605		i++;
606		cgbplace++;
607	}
608
609	gBotChatBuffer[bs->client][i] = '\0';
610
611	return 1;
612}
613
614void BotUtilizePersonality(bot_state_t *bs)
615{
616	fileHandle_t f;
617	int len, rlen;
618	int failed;
619	int i;
620	//char buf[131072];
621	char *buf = (char *)B_TempAlloc(131072);
622	char *readbuf, *group;
623
624	len = trap_FS_FOpenFile(bs->settings.personalityfile, &f, FS_READ);
625
626	failed = 0;
627
628	if (!f)
629	{
630		G_Printf(S_COLOR_RED "Error: Specified personality not found\n");
631		B_TempFree(131072); //buf
632		return;
633	}
634
635	if (len >= 131072)
636	{
637		G_Printf(S_COLOR_RED "Personality file exceeds maximum length\n");
638		B_TempFree(131072); //buf
639		return;
640	}
641
642	trap_FS_Read(buf, len, f);
643
644	rlen = len;
645
646	while (len < 131072)
647	{ //kill all characters after the file length, since sometimes FS_Read doesn't do that entirely (or so it seems)
648		buf[len] = '\0';
649		len++;
650	}
651
652	len = rlen;
653
654	readbuf = (char *)B_TempAlloc(1024);
655	group = (char *)B_TempAlloc(65536);
656
657	if (!GetValueGroup(buf, "GeneralBotInfo", group))
658	{
659		G_Printf(S_COLOR_RED "Personality file contains no GeneralBotInfo group\n");
660		failed = 1; //set failed so we know to set everything to default values
661	}
662
663	if (!failed && GetPairedValue(group, "reflex", readbuf))
664	{
665		bs->skills.reflex = atoi(readbuf);
666	}
667	else
668	{
669		bs->skills.reflex = 100; //default
670	}
671
672	if (!failed && GetPairedValue(group, "accuracy", readbuf))
673	{
674		bs->skills.accuracy = atof(readbuf);
675	}
676	else
677	{
678		bs->skills.accuracy = 10; //default
679	}
680
681	if (!failed && GetPairedValue(group, "turnspeed", readbuf))
682	{
683		bs->skills.turnspeed = atof(readbuf);
684	}
685	else
686	{
687		bs->skills.turnspeed = 0.01f; //default
688	}
689
690	if (!failed && GetPairedValue(group, "turnspeed_combat", readbuf))
691	{
692		bs->skills.turnspeed_combat = atof(readbuf);
693	}
694	else
695	{
696		bs->skills.turnspeed_combat = 0.05f; //default
697	}
698
699	if (!failed && GetPairedValue(group, "maxturn", readbuf))
700	{
701		bs->skills.maxturn = atof(readbuf);
702	}
703	else
704	{
705		bs->skills.maxturn = 360; //default
706	}
707
708	if (!failed && GetPairedValue(group, "perfectaim", readbuf))
709	{
710		bs->skills.perfectaim = atoi(readbuf);
711	}
712	else
713	{
714		bs->skills.perfectaim = 0; //default
715	}
716
717	if (!failed && GetPairedValue(group, "chatability", readbuf))
718	{
719		bs->canChat = atoi(readbuf);
720	}
721	else
722	{
723		bs->canChat = 0; //default
724	}
725
726	if (!failed && GetPairedValue(group, "chatfrequency", readbuf))
727	{
728		bs->chatFrequency = atoi(readbuf);
729	}
730	else
731	{
732		bs->chatFrequency = 5; //default
733	}
734
735	if (!failed && GetPairedValue(group, "hatelevel", readbuf))
736	{
737		bs->loved_death_thresh = atoi(readbuf);
738	}
739	else
740	{
741		bs->loved_death_thresh = 3; //default
742	}
743
744	if (!failed && GetPairedValue(group, "camper", readbuf))
745	{
746		bs->isCamper = atoi(readbuf);
747	}
748	else
749	{
750		bs->isCamper = 0; //default
751	}
752
753	if (!failed && GetPairedValue(group, "saberspecialist", readbuf))
754	{
755		bs->saberSpecialist = atoi(readbuf);
756	}
757	else
758	{
759		bs->saberSpecialist = 0; //default
760	}
761
762	if (!failed && GetPairedValue(group, "forceinfo", readbuf))
763	{
764		Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", readbuf);
765	}
766	else
767	{
768		Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", DEFAULT_FORCEPOWERS);
769	}
770
771	i = 0;
772
773	while (i < MAX_CHAT_BUFFER_SIZE)
774	{ //clear out the chat buffer for this bot
775		gBotChatBuffer[bs->client][i] = '\0';
776		i++;
777	}
778
779	if (bs->canChat)
780	{
781		if (!ReadChatGroups(bs, buf))
782		{
783			bs->canChat = 0;
784		}
785	}
786
787	if (GetValueGroup(buf, "BotWeaponWeights", group))
788	{
789		if (GetPairedValue(group, "WP_STUN_BATON", readbuf))
790		{
791			bs->botWeaponWeights[WP_STUN_BATON] = atoi(readbuf);
792			bs->botWeaponWeights[WP_MELEE] = bs->botWeaponWeights[WP_STUN_BATON];
793		}
794
795		if (GetPairedValue(group, "WP_SABER", readbuf))
796		{
797			bs->botWeaponWeights[WP_SABER] = atoi(readbuf);
798		}
799
800		if (GetPairedValue(group, "WP_BRYAR_PISTOL", readbuf))
801		{
802			bs->botWeaponWeights[WP_BRYAR_PISTOL] = atoi(readbuf);
803		}
804
805		if (GetPairedValue(group, "WP_BLASTER", readbuf))
806		{
807			bs->botWeaponWeights[WP_BLASTER] = atoi(readbuf);
808		}
809
810		if (GetPairedValue(group, "WP_DISRUPTOR", readbuf))
811		{
812			bs->botWeaponWeights[WP_DISRUPTOR] = atoi(readbuf);
813		}
814
815		if (GetPairedValue(group, "WP_BOWCASTER", readbuf))
816		{
817			bs->botWeaponWeights[WP_BOWCASTER] = atoi(readbuf);
818		}
819
820		if (GetPairedValue(group, "WP_REPEATER", readbuf))
821		{
822			bs->botWeaponWeights[WP_REPEATER] = atoi(readbuf);
823		}
824
825		if (GetPairedValue(group, "WP_DEMP2", readbuf))
826		{
827			bs->botWeaponWeights[WP_DEMP2] = atoi(readbuf);
828		}
829
830		if (GetPairedValue(group, "WP_FLECHETTE", readbuf))
831		{
832			bs->botWeaponWeights[WP_FLECHETTE] = atoi(readbuf);
833		}
834
835		if (GetPairedValue(group, "WP_ROCKET_LAUNCHER", readbuf))
836		{
837			bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = atoi(readbuf);
838		}
839
840		if (GetPairedValue(group, "WP_THERMAL", readbuf))
841		{
842			bs->botWeaponWeights[WP_THERMAL] = atoi(readbuf);
843		}
844
845		if (GetPairedValue(group, "WP_TRIP_MINE", readbuf))
846		{
847			bs->botWeaponWeights[WP_TRIP_MINE] = atoi(readbuf);
848		}
849
850		if (GetPairedValue(group, "WP_DET_PACK", readbuf))
851		{
852			bs->botWeaponWeights[WP_DET_PACK] = atoi(readbuf);
853		}
854	}
855
856	bs->lovednum = 0;
857
858	if (GetValueGroup(buf, "EmotionalAttachments", group))
859	{
860		ParseEmotionalAttachments(bs, group);
861	}
862
863	B_TempFree(131072); //buf
864	B_TempFree(1024); //readbuf
865	B_TempFree(65536); //group
866	trap_FS_FCloseFile(f);
867}