2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
/*****************************************************************************
28
* $Archive: /MissionPack/code/botlib/be_ai_chat.c $
30
*****************************************************************************/
32
#include "../qcommon/q_shared.h"
36
#include "l_precomp.h"
43
#include "be_aas_funcs.h"
44
#include "be_interface.h"
46
#include "be_ai_chat.h"
50
#define ESCAPE_CHAR 0x01 //'_'
52
// "hi ", people, " ", 0, " entered the game"
54
// "hi _rpeople_ _v0_ entered the game"
58
#define MT_VARIABLE 1 //variable match piece
59
#define MT_STRING 2 //string match piece
60
//reply chat key flags
61
#define RCKFL_AND 1 //key must be present
62
#define RCKFL_NOT 2 //key must be absent
63
#define RCKFL_NAME 4 //name of bot must be present
64
#define RCKFL_STRING 8 //key is a string
65
#define RCKFL_VARIABLES 16 //key is a match template
66
#define RCKFL_BOTNAMES 32 //key is a series of botnames
67
#define RCKFL_GENDERFEMALE 64 //bot must be female
68
#define RCKFL_GENDERMALE 128 //bot must be male
69
#define RCKFL_GENDERLESS 256 //bot must be genderless
70
//time to ignore a chat message after using it
71
#define CHATMESSAGE_RECENTTIME 20
73
//the actuall chat messages
74
typedef struct bot_chatmessage_s
76
char *chatmessage; //chat message string
77
float time; //last time used
78
struct bot_chatmessage_s *next; //next chat message in a list
80
//bot chat type with chat lines
81
typedef struct bot_chattype_s
83
char name[MAX_CHATTYPE_NAME];
85
bot_chatmessage_t *firstchatmessage;
86
struct bot_chattype_s *next;
89
typedef struct bot_chat_s
91
bot_chattype_t *types;
95
typedef struct bot_randomstring_s
98
struct bot_randomstring_s *next;
100
//list with random strings
101
typedef struct bot_randomlist_s
105
bot_randomstring_t *firstrandomstring;
106
struct bot_randomlist_s *next;
110
typedef struct bot_synonym_s
114
struct bot_synonym_s *next;
117
typedef struct bot_synonymlist_s
119
unsigned long int context;
121
bot_synonym_t *firstsynonym;
122
struct bot_synonymlist_s *next;
126
typedef struct bot_matchstring_s
129
struct bot_matchstring_s *next;
132
//piece of a match template
133
typedef struct bot_matchpiece_s
136
bot_matchstring_t *firststring;
138
struct bot_matchpiece_s *next;
141
typedef struct bot_matchtemplate_s
143
unsigned long int context;
146
bot_matchpiece_t *first;
147
struct bot_matchtemplate_s *next;
148
} bot_matchtemplate_t;
151
typedef struct bot_replychatkey_s
155
bot_matchpiece_t *match;
156
struct bot_replychatkey_s *next;
157
} bot_replychatkey_t;
159
typedef struct bot_replychat_s
161
bot_replychatkey_t *keys;
164
bot_chatmessage_t *firstchatmessage;
165
struct bot_replychat_s *next;
169
typedef struct bot_stringlist_s
172
struct bot_stringlist_s *next;
175
//chat state of a bot
176
typedef struct bot_chatstate_s
178
int gender; //0=it, 1=female, 2=male
179
int client; //client number
180
char name[32]; //name of the bot
181
char chatmessage[MAX_MESSAGE_SIZE];
183
//the console messages visible to the bot
184
bot_consolemessage_t *firstmessage; //first message is the first typed message
185
bot_consolemessage_t *lastmessage; //last message is the last typed message, bottom of console
186
//number of console messages stored in the state
187
int numconsolemessages;
194
char filename[MAX_QPATH];
195
char chatname[MAX_QPATH];
198
bot_ichatdata_t *ichatdata[MAX_CLIENTS];
200
bot_chatstate_t *botchatstates[MAX_CLIENTS+1];
201
//console message heap
202
bot_consolemessage_t *consolemessageheap = NULL;
203
bot_consolemessage_t *freeconsolemessages = NULL;
204
//list with match strings
205
bot_matchtemplate_t *matchtemplates = NULL;
207
bot_synonymlist_t *synonyms = NULL;
208
//list with random strings
209
bot_randomlist_t *randomstrings = NULL;
211
bot_replychat_t *replychats = NULL;
213
//========================================================================
217
// Changes Globals: -
218
//========================================================================
219
bot_chatstate_t *BotChatStateFromHandle(int handle)
221
if (handle <= 0 || handle > MAX_CLIENTS)
223
botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
226
if (!botchatstates[handle])
228
botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
231
return botchatstates[handle];
232
} //end of the function BotChatStateFromHandle
233
//===========================================================================
234
// initialize the heap with unused console messages
238
// Changes Globals: -
239
//===========================================================================
240
void InitConsoleMessageHeap(void)
244
if (consolemessageheap) FreeMemory(consolemessageheap);
246
max_messages = (int) LibVarValue("max_messages", "1024");
247
consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages *
248
sizeof(bot_consolemessage_t));
249
consolemessageheap[0].prev = NULL;
250
consolemessageheap[0].next = &consolemessageheap[1];
251
for (i = 1; i < max_messages-1; i++)
253
consolemessageheap[i].prev = &consolemessageheap[i - 1];
254
consolemessageheap[i].next = &consolemessageheap[i + 1];
256
consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2];
257
consolemessageheap[max_messages-1].next = NULL;
258
//pointer to the free console messages
259
freeconsolemessages = consolemessageheap;
260
} //end of the function InitConsoleMessageHeap
261
//===========================================================================
262
// allocate one console message from the heap
266
// Changes Globals: -
267
//===========================================================================
268
bot_consolemessage_t *AllocConsoleMessage(void)
270
bot_consolemessage_t *message;
271
message = freeconsolemessages;
272
if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next;
273
if (freeconsolemessages) freeconsolemessages->prev = NULL;
275
} //end of the function AllocConsoleMessage
276
//===========================================================================
277
// deallocate one console message from the heap
281
// Changes Globals: -
282
//===========================================================================
283
void FreeConsoleMessage(bot_consolemessage_t *message)
285
if (freeconsolemessages) freeconsolemessages->prev = message;
286
message->prev = NULL;
287
message->next = freeconsolemessages;
288
freeconsolemessages = message;
289
} //end of the function FreeConsoleMessage
290
//===========================================================================
294
// Changes Globals: -
295
//===========================================================================
296
void BotRemoveConsoleMessage(int chatstate, int handle)
298
bot_consolemessage_t *m, *nextm;
301
cs = BotChatStateFromHandle(chatstate);
304
for (m = cs->firstmessage; m; m = nextm)
307
if (m->handle == handle)
309
if (m->next) m->next->prev = m->prev;
310
else cs->lastmessage = m->prev;
311
if (m->prev) m->prev->next = m->next;
312
else cs->firstmessage = m->next;
314
FreeConsoleMessage(m);
315
cs->numconsolemessages--;
319
} //end of the function BotRemoveConsoleMessage
320
//===========================================================================
324
// Changes Globals: -
325
//===========================================================================
326
void BotQueueConsoleMessage(int chatstate, int type, char *message)
328
bot_consolemessage_t *m;
331
cs = BotChatStateFromHandle(chatstate);
334
m = AllocConsoleMessage();
337
botimport.Print(PRT_ERROR, "empty console message heap\n");
341
if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1;
342
m->handle = cs->handle;
343
m->time = AAS_Time();
345
strncpy(m->message, message, MAX_MESSAGE_SIZE);
349
cs->lastmessage->next = m;
350
m->prev = cs->lastmessage;
356
cs->firstmessage = m;
359
cs->numconsolemessages++;
360
} //end of the function BotQueueConsoleMessage
361
//===========================================================================
365
// Changes Globals: -
366
//===========================================================================
367
int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm)
371
cs = BotChatStateFromHandle(chatstate);
373
if (cs->firstmessage)
375
Com_Memcpy(cm, cs->firstmessage, sizeof(bot_consolemessage_t));
376
cm->next = cm->prev = NULL;
380
} //end of the function BotConsoleMessage
381
//===========================================================================
385
// Changes Globals: -
386
//===========================================================================
387
int BotNumConsoleMessages(int chatstate)
391
cs = BotChatStateFromHandle(chatstate);
393
return cs->numconsolemessages;
394
} //end of the function BotNumConsoleMessages
395
//===========================================================================
399
// Changes Globals: -
400
//===========================================================================
401
int IsWhiteSpace(char c)
403
if ((c >= 'a' && c <= 'z')
404
|| (c >= 'A' && c <= 'Z')
405
|| (c >= '0' && c <= '9')
406
|| c == '(' || c == ')'
407
|| c == '?' || c == ':'
408
|| c == '\''|| c == '/'
409
|| c == ',' || c == '.'
410
|| c == '[' || c == ']'
411
|| c == '-' || c == '_'
412
|| c == '+' || c == '=') return qfalse;
414
} //end of the function IsWhiteSpace
415
//===========================================================================
419
// Changes Globals: -
420
//===========================================================================
421
void BotRemoveTildes(char *message)
425
//remove all tildes from the chat message
426
for (i = 0; message[i]; i++)
428
if (message[i] == '~')
430
memmove(&message[i], &message[i+1], strlen(&message[i+1])+1);
433
} //end of the function BotRemoveTildes
434
//===========================================================================
438
// Changes Globals: -
439
//===========================================================================
440
void UnifyWhiteSpaces(char *string)
444
for (ptr = oldptr = string; *ptr; oldptr = ptr)
446
while(*ptr && IsWhiteSpace(*ptr)) ptr++;
449
//if not at the start and not at the end of the string
450
//write only one space
451
if (oldptr > string && *ptr) *oldptr++ = ' ';
452
//remove all other white spaces
453
if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1);
455
while(*ptr && !IsWhiteSpace(*ptr)) ptr++;
457
} //end of the function UnifyWhiteSpaces
458
//===========================================================================
462
// Changes Globals: -
463
//===========================================================================
464
int StringContains(char *str1, char *str2, int casesensitive)
466
int len, i, j, index;
468
if (str1 == NULL || str2 == NULL) return -1;
470
len = strlen(str1) - strlen(str2);
472
for (i = 0; i <= len; i++, str1++, index++)
474
for (j = 0; str2[j]; j++)
478
if (str1[j] != str2[j]) break;
482
if (toupper(str1[j]) != toupper(str2[j])) break;
485
if (!str2[j]) return index;
488
} //end of the function StringContains
489
//===========================================================================
493
// Changes Globals: -
494
//===========================================================================
495
char *StringContainsWord(char *str1, char *str2, int casesensitive)
499
len = strlen(str1) - strlen(str2);
500
for (i = 0; i <= len; i++, str1++)
502
//if not at the start of the string
505
//skip to the start of the next word
506
while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++;
511
for (j = 0; str2[j]; j++)
515
if (str1[j] != str2[j]) break;
519
if (toupper(str1[j]) != toupper(str2[j])) break;
522
//if there was a word match
525
//if the first string has an end of word
526
if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1;
530
} //end of the function StringContainsWord
531
//===========================================================================
535
// Changes Globals: -
536
//===========================================================================
537
void StringReplaceWords(char *string, char *synonym, char *replacement)
541
//find the synonym in the string
542
str = StringContainsWord(string, synonym, qfalse);
543
//if the synonym occured in the string
546
//if the synonym isn't part of the replacement which is already in the string
547
//usefull for abreviations
548
str2 = StringContainsWord(string, replacement, qfalse);
551
if (str2 <= str && str < str2 + strlen(replacement)) break;
552
str2 = StringContainsWord(str2+1, replacement, qfalse);
556
memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1);
557
//append the synonum replacement
558
Com_Memcpy(str, replacement, strlen(replacement));
560
//find the next synonym in the string
561
str = StringContainsWord(str+strlen(replacement), synonym, qfalse);
563
} //end of the function StringReplaceWords
564
//===========================================================================
568
// Changes Globals: -
569
//===========================================================================
570
void BotDumpSynonymList(bot_synonymlist_t *synlist)
573
bot_synonymlist_t *syn;
574
bot_synonym_t *synonym;
576
fp = Log_FilePointer();
578
for (syn = synlist; syn; syn = syn->next)
580
fprintf(fp, "%ld : [", syn->context);
581
for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
583
fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight);
584
if (synonym->next) fprintf(fp, ", ");
588
} //end of the function BotDumpSynonymList
589
//===========================================================================
593
// Changes Globals: -
594
//===========================================================================
595
bot_synonymlist_t *BotLoadSynonyms(char *filename)
597
int pass, size, contextlevel, numsynonyms;
598
unsigned long int context, contextstack[32];
602
bot_synonymlist_t *synlist, *lastsyn, *syn;
603
bot_synonym_t *synonym, *lastsynonym;
606
synlist = NULL; //make compiler happy
607
syn = NULL; //make compiler happy
608
synonym = NULL; //make compiler happy
609
//the synonyms are parsed in two phases
610
for (pass = 0; pass < 2; pass++)
613
if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
615
PC_SetBaseFolder(BOTFILESBASEFOLDER);
616
source = LoadSourceFile(filename);
619
botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
625
synlist = NULL; //list synonyms
626
lastsyn = NULL; //last synonym in the list
628
while(PC_ReadToken(source, &token))
630
if (token.type == TT_NUMBER)
632
context |= token.intvalue;
633
contextstack[contextlevel] = token.intvalue;
635
if (contextlevel >= 32)
637
SourceError(source, "more than 32 context levels");
641
if (!PC_ExpectTokenString(source, "{"))
647
else if (token.type == TT_PUNCTUATION)
649
if (!strcmp(token.string, "}"))
652
if (contextlevel < 0)
654
SourceError(source, "too many }");
658
context &= ~contextstack[contextlevel];
660
else if (!strcmp(token.string, "["))
662
size += sizeof(bot_synonymlist_t);
665
syn = (bot_synonymlist_t *) ptr;
666
ptr += sizeof(bot_synonymlist_t);
667
syn->context = context;
668
syn->firstsynonym = NULL;
670
if (lastsyn) lastsyn->next = syn;
679
if (!PC_ExpectTokenString(source, "(") ||
680
!PC_ExpectTokenType(source, TT_STRING, 0, &token))
685
StripDoubleQuotes(token.string);
686
if (strlen(token.string) <= 0)
688
SourceError(source, "empty string", token.string);
692
len = strlen(token.string) + 1;
693
len = PAD(len, sizeof(long));
694
size += sizeof(bot_synonym_t) + len;
697
synonym = (bot_synonym_t *) ptr;
698
ptr += sizeof(bot_synonym_t);
699
synonym->string = ptr;
701
strcpy(synonym->string, token.string);
703
if (lastsynonym) lastsynonym->next = synonym;
704
else syn->firstsynonym = synonym;
705
lastsynonym = synonym;
708
if (!PC_ExpectTokenString(source, ",") ||
709
!PC_ExpectTokenType(source, TT_NUMBER, 0, &token) ||
710
!PC_ExpectTokenString(source, ")"))
717
synonym->weight = token.floatvalue;
718
syn->totalweight += synonym->weight;
720
if (PC_CheckTokenString(source, "]")) break;
721
if (!PC_ExpectTokenString(source, ","))
729
SourceError(source, "synonym must have at least two entries\n");
736
SourceError(source, "unexpected %s", token.string);
745
if (contextlevel > 0)
747
SourceError(source, "missing }");
751
botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
753
//BotDumpSynonymList(synlist);
756
} //end of the function BotLoadSynonyms
757
//===========================================================================
758
// replace all the synonyms in the string
762
// Changes Globals: -
763
//===========================================================================
764
void BotReplaceSynonyms(char *string, unsigned long int context)
766
bot_synonymlist_t *syn;
767
bot_synonym_t *synonym;
769
for (syn = synonyms; syn; syn = syn->next)
771
if (!(syn->context & context)) continue;
772
for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
774
StringReplaceWords(string, synonym->string, syn->firstsynonym->string);
777
} //end of the function BotReplaceSynonyms
778
//===========================================================================
782
// Changes Globals: -
783
//===========================================================================
784
void BotReplaceWeightedSynonyms(char *string, unsigned long int context)
786
bot_synonymlist_t *syn;
787
bot_synonym_t *synonym, *replacement;
788
float weight, curweight;
790
for (syn = synonyms; syn; syn = syn->next)
792
if (!(syn->context & context)) continue;
793
//choose a weighted random replacement synonym
794
weight = random() * syn->totalweight;
795
if (!weight) continue;
797
for (replacement = syn->firstsynonym; replacement; replacement = replacement->next)
799
curweight += replacement->weight;
800
if (weight < curweight) break;
802
if (!replacement) continue;
803
//replace all synonyms with the replacement
804
for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
806
if (synonym == replacement) continue;
807
StringReplaceWords(string, synonym->string, replacement->string);
810
} //end of the function BotReplaceWeightedSynonyms
811
//===========================================================================
815
// Changes Globals: -
816
//===========================================================================
817
void BotReplaceReplySynonyms(char *string, unsigned long int context)
819
char *str1, *str2, *replacement;
820
bot_synonymlist_t *syn;
821
bot_synonym_t *synonym;
823
for (str1 = string; *str1; )
825
//go to the start of the next word
826
while(*str1 && *str1 <= ' ') str1++;
829
for (syn = synonyms; syn; syn = syn->next)
831
if (!(syn->context & context)) continue;
832
for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
834
str2 = synonym->string;
835
//if the synonym is not at the front of the string continue
836
str2 = StringContainsWord(str1, synonym->string, qfalse);
837
if (!str2 || str2 != str1) continue;
839
replacement = syn->firstsynonym->string;
840
//if the replacement IS in front of the string continue
841
str2 = StringContainsWord(str1, replacement, qfalse);
842
if (str2 && str2 == str1) continue;
844
memmove(str1 + strlen(replacement), str1+strlen(synonym->string),
845
strlen(str1+strlen(synonym->string)) + 1);
846
//append the synonum replacement
847
Com_Memcpy(str1, replacement, strlen(replacement));
851
//if a synonym has been replaced
854
//skip over this word
855
while(*str1 && *str1 > ' ') str1++;
858
} //end of the function BotReplaceReplySynonyms
859
//===========================================================================
863
// Changes Globals: -
864
//===========================================================================
865
int BotLoadChatMessage(source_t *source, char *chatmessagestring)
870
ptr = chatmessagestring;
875
if (!PC_ExpectAnyToken(source, &token)) return qfalse;
877
if (token.type == TT_STRING)
879
StripDoubleQuotes(token.string);
880
if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE)
882
SourceError(source, "chat message too long\n");
885
strcat(ptr, token.string);
888
else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
890
if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
892
SourceError(source, "chat message too long\n");
895
sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR);
898
else if (token.type == TT_NAME)
900
if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
902
SourceError(source, "chat message too long\n");
905
sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR);
909
SourceError(source, "unknown message component %s\n", token.string);
912
if (PC_CheckTokenString(source, ";")) break;
913
if (!PC_ExpectTokenString(source, ",")) return qfalse;
917
} //end of the function BotLoadChatMessage
918
//===========================================================================
922
// Changes Globals: -
923
//===========================================================================
924
void BotDumpRandomStringList(bot_randomlist_t *randomlist)
927
bot_randomlist_t *random;
928
bot_randomstring_t *rs;
930
fp = Log_FilePointer();
932
for (random = randomlist; random; random = random->next)
934
fprintf(fp, "%s = {", random->string);
935
for (rs = random->firstrandomstring; rs; rs = rs->next)
937
fprintf(fp, "\"%s\"", rs->string);
938
if (rs->next) fprintf(fp, ", ");
939
else fprintf(fp, "}\n");
942
} //end of the function BotDumpRandomStringList
943
//===========================================================================
947
// Changes Globals: -
948
//===========================================================================
949
bot_randomlist_t *BotLoadRandomStrings(char *filename)
952
char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE];
955
bot_randomlist_t *randomlist, *lastrandom, *random;
956
bot_randomstring_t *randomstring;
959
int starttime = Sys_MilliSeconds();
965
//the synonyms are parsed in two phases
966
for (pass = 0; pass < 2; pass++)
969
if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
971
PC_SetBaseFolder(BOTFILESBASEFOLDER);
972
source = LoadSourceFile(filename);
975
botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
979
randomlist = NULL; //list
980
lastrandom = NULL; //last
982
while(PC_ReadToken(source, &token))
985
if (token.type != TT_NAME)
987
SourceError(source, "unknown random %s", token.string);
991
len = strlen(token.string) + 1;
992
len = PAD(len, sizeof(long));
993
size += sizeof(bot_randomlist_t) + len;
996
random = (bot_randomlist_t *) ptr;
997
ptr += sizeof(bot_randomlist_t);
998
random->string = ptr;
1000
strcpy(random->string, token.string);
1001
random->firstrandomstring = NULL;
1002
random->numstrings = 0;
1004
if (lastrandom) lastrandom->next = random;
1005
else randomlist = random;
1006
lastrandom = random;
1008
if (!PC_ExpectTokenString(source, "=") ||
1009
!PC_ExpectTokenString(source, "{"))
1014
while(!PC_CheckTokenString(source, "}"))
1017
if (!BotLoadChatMessage(source, chatmessagestring))
1022
len = strlen(chatmessagestring) + 1;
1023
len = PAD(len, sizeof(long));
1024
size += sizeof(bot_randomstring_t) + len;
1027
randomstring = (bot_randomstring_t *) ptr;
1028
ptr += sizeof(bot_randomstring_t);
1029
randomstring->string = ptr;
1031
strcpy(randomstring->string, chatmessagestring);
1033
random->numstrings++;
1034
randomstring->next = random->firstrandomstring;
1035
random->firstrandomstring = randomstring;
1039
//free the source after one pass
1042
botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
1045
botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime);
1046
//BotDumpRandomStringList(randomlist);
1050
} //end of the function BotLoadRandomStrings
1051
//===========================================================================
1055
// Changes Globals: -
1056
//===========================================================================
1057
char *RandomString(char *name)
1059
bot_randomlist_t *random;
1060
bot_randomstring_t *rs;
1063
for (random = randomstrings; random; random = random->next)
1065
if (!strcmp(random->string, name))
1067
i = random() * random->numstrings;
1068
for (rs = random->firstrandomstring; rs; rs = rs->next)
1079
} //end of the function RandomString
1080
//===========================================================================
1084
// Changes Globals: -
1085
//===========================================================================
1086
void BotDumpMatchTemplates(bot_matchtemplate_t *matches)
1089
bot_matchtemplate_t *mt;
1090
bot_matchpiece_t *mp;
1091
bot_matchstring_t *ms;
1093
fp = Log_FilePointer();
1095
for (mt = matches; mt; mt = mt->next)
1098
for (mp = mt->first; mp; mp = mp->next)
1100
if (mp->type == MT_STRING)
1102
for (ms = mp->firststring; ms; ms = ms->next)
1104
fprintf(fp, "\"%s\"", ms->string);
1105
if (ms->next) fprintf(fp, "|");
1108
else if (mp->type == MT_VARIABLE)
1110
fprintf(fp, "%d", mp->variable);
1112
if (mp->next) fprintf(fp, ", ");
1114
fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype);
1116
} //end of the function BotDumpMatchTemplates
1117
//===========================================================================
1121
// Changes Globals: -
1122
//===========================================================================
1123
void BotFreeMatchPieces(bot_matchpiece_t *matchpieces)
1125
bot_matchpiece_t *mp, *nextmp;
1126
bot_matchstring_t *ms, *nextms;
1128
for (mp = matchpieces; mp; mp = nextmp)
1131
if (mp->type == MT_STRING)
1133
for (ms = mp->firststring; ms; ms = nextms)
1141
} //end of the function BotFreeMatchPieces
1142
//===========================================================================
1146
// Changes Globals: -
1147
//===========================================================================
1148
bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken)
1150
int lastwasvariable, emptystring;
1152
bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece;
1153
bot_matchstring_t *matchstring, *lastmatchstring;
1158
lastwasvariable = qfalse;
1160
while(PC_ReadToken(source, &token))
1162
if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
1164
if (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES)
1166
SourceError(source, "can't have more than %d match variables\n", MAX_MATCHVARIABLES);
1168
BotFreeMatchPieces(firstpiece);
1171
if (lastwasvariable)
1173
SourceError(source, "not allowed to have adjacent variables\n");
1175
BotFreeMatchPieces(firstpiece);
1178
lastwasvariable = qtrue;
1180
matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
1181
matchpiece->type = MT_VARIABLE;
1182
matchpiece->variable = token.intvalue;
1183
matchpiece->next = NULL;
1184
if (lastpiece) lastpiece->next = matchpiece;
1185
else firstpiece = matchpiece;
1186
lastpiece = matchpiece;
1188
else if (token.type == TT_STRING)
1191
matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
1192
matchpiece->firststring = NULL;
1193
matchpiece->type = MT_STRING;
1194
matchpiece->variable = 0;
1195
matchpiece->next = NULL;
1196
if (lastpiece) lastpiece->next = matchpiece;
1197
else firstpiece = matchpiece;
1198
lastpiece = matchpiece;
1200
lastmatchstring = NULL;
1201
emptystring = qfalse;
1205
if (matchpiece->firststring)
1207
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
1210
BotFreeMatchPieces(firstpiece);
1214
StripDoubleQuotes(token.string);
1215
matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1);
1216
matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t);
1217
strcpy(matchstring->string, token.string);
1218
if (!strlen(token.string)) emptystring = qtrue;
1219
matchstring->next = NULL;
1220
if (lastmatchstring) lastmatchstring->next = matchstring;
1221
else matchpiece->firststring = matchstring;
1222
lastmatchstring = matchstring;
1223
} while(PC_CheckTokenString(source, "|"));
1224
//if there was no empty string found
1225
if (!emptystring) lastwasvariable = qfalse;
1229
SourceError(source, "invalid token %s\n", token.string);
1231
BotFreeMatchPieces(firstpiece);
1234
if (PC_CheckTokenString(source, endtoken)) break;
1235
if (!PC_ExpectTokenString(source, ","))
1238
BotFreeMatchPieces(firstpiece);
1243
} //end of the function BotLoadMatchPieces
1244
//===========================================================================
1248
// Changes Globals: -
1249
//===========================================================================
1250
void BotFreeMatchTemplates(bot_matchtemplate_t *mt)
1252
bot_matchtemplate_t *nextmt;
1254
for (; mt; mt = nextmt)
1257
BotFreeMatchPieces(mt->first);
1260
} //end of the function BotFreeMatchTemplates
1261
//===========================================================================
1265
// Changes Globals: -
1266
//===========================================================================
1267
bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile)
1271
bot_matchtemplate_t *matchtemplate, *matches, *lastmatch;
1272
unsigned long int context;
1274
PC_SetBaseFolder(BOTFILESBASEFOLDER);
1275
source = LoadSourceFile(matchfile);
1278
botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile);
1282
matches = NULL; //list with matches
1283
lastmatch = NULL; //last match in the list
1285
while(PC_ReadToken(source, &token))
1287
if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))
1289
SourceError(source, "expected integer, found %s\n", token.string);
1290
BotFreeMatchTemplates(matches);
1295
context = token.intvalue;
1297
if (!PC_ExpectTokenString(source, "{"))
1299
BotFreeMatchTemplates(matches);
1304
while(PC_ReadToken(source, &token))
1306
if (!strcmp(token.string, "}")) break;
1308
PC_UnreadLastToken(source);
1310
matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t));
1311
matchtemplate->context = context;
1312
matchtemplate->next = NULL;
1313
//add the match template to the list
1314
if (lastmatch) lastmatch->next = matchtemplate;
1315
else matches = matchtemplate;
1316
lastmatch = matchtemplate;
1317
//load the match template
1318
matchtemplate->first = BotLoadMatchPieces(source, "=");
1319
if (!matchtemplate->first)
1321
BotFreeMatchTemplates(matches);
1324
//read the match type
1325
if (!PC_ExpectTokenString(source, "(") ||
1326
!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
1328
BotFreeMatchTemplates(matches);
1332
matchtemplate->type = token.intvalue;
1333
//read the match subtype
1334
if (!PC_ExpectTokenString(source, ",") ||
1335
!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
1337
BotFreeMatchTemplates(matches);
1341
matchtemplate->subtype = token.intvalue;
1342
//read trailing punctuations
1343
if (!PC_ExpectTokenString(source, ")") ||
1344
!PC_ExpectTokenString(source, ";"))
1346
BotFreeMatchTemplates(matches);
1354
botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile);
1356
//BotDumpMatchTemplates(matches);
1359
} //end of the function BotLoadMatchTemplates
1360
//===========================================================================
1364
// Changes Globals: -
1365
//===========================================================================
1366
int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match)
1368
int lastvariable, index;
1369
char *strptr, *newstrptr;
1370
bot_matchpiece_t *mp;
1371
bot_matchstring_t *ms;
1375
//pointer to the string to compare the match string with
1376
strptr = match->string;
1377
//Log_Write("match: %s", strptr);
1378
//compare the string with the current match string
1379
for (mp = pieces; mp; mp = mp->next)
1381
//if it is a piece of string
1382
if (mp->type == MT_STRING)
1385
for (ms = mp->firststring; ms; ms = ms->next)
1387
if (!strlen(ms->string))
1392
//Log_Write("MT_STRING: %s", mp->string);
1393
index = StringContains(strptr, ms->string, qfalse);
1396
newstrptr = strptr + index;
1397
if (lastvariable >= 0)
1399
match->variables[lastvariable].length =
1400
(newstrptr - match->string) - match->variables[lastvariable].offset;
1401
//newstrptr - match->variables[lastvariable].ptr;
1405
else if (index == 0)
1412
if (!newstrptr) return qfalse;
1413
strptr = newstrptr + strlen(ms->string);
1415
//if it is a variable piece of string
1416
else if (mp->type == MT_VARIABLE)
1418
//Log_Write("MT_VARIABLE");
1419
match->variables[mp->variable].offset = strptr - match->string;
1420
lastvariable = mp->variable;
1423
//if a match was found
1424
if (!mp && (lastvariable >= 0 || !strlen(strptr)))
1426
//if the last piece was a variable string
1427
if (lastvariable >= 0)
1429
assert( match->variables[lastvariable].offset >= 0 ); // bk001204
1430
match->variables[lastvariable].length =
1431
strlen(&match->string[ (int) match->variables[lastvariable].offset]);
1436
} //end of the function StringsMatch
1437
//===========================================================================
1441
// Changes Globals: -
1442
//===========================================================================
1443
int BotFindMatch(char *str, bot_match_t *match, unsigned long int context)
1446
bot_matchtemplate_t *ms;
1448
strncpy(match->string, str, MAX_MESSAGE_SIZE);
1449
//remove any trailing enters
1450
while(strlen(match->string) &&
1451
match->string[strlen(match->string)-1] == '\n')
1453
match->string[strlen(match->string)-1] = '\0';
1455
//compare the string with all the match strings
1456
for (ms = matchtemplates; ms; ms = ms->next)
1458
if (!(ms->context & context)) continue;
1459
//reset the match variable offsets
1460
for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1;
1462
if (StringsMatch(ms->first, match))
1464
match->type = ms->type;
1465
match->subtype = ms->subtype;
1470
} //end of the function BotFindMatch
1471
//===========================================================================
1475
// Changes Globals: -
1476
//===========================================================================
1477
void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size)
1479
if (variable < 0 || variable >= MAX_MATCHVARIABLES)
1481
botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n");
1486
if (match->variables[variable].offset >= 0)
1488
if (match->variables[variable].length < size)
1489
size = match->variables[variable].length+1;
1490
assert( match->variables[variable].offset >= 0 ); // bk001204
1491
strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1);
1499
} //end of the function BotMatchVariable
1500
//===========================================================================
1504
// Changes Globals: -
1505
//===========================================================================
1506
bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string)
1508
bot_stringlist_t *s;
1510
for (s = list; s; s = s->next)
1512
if (!strcmp(s->string, string)) return s;
1515
} //end of the function BotFindStringInList
1516
//===========================================================================
1520
// Changes Globals: -
1521
//===========================================================================
1522
bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist)
1526
char temp[MAX_MESSAGE_SIZE];
1527
bot_stringlist_t *s;
1533
if (*msgptr == ESCAPE_CHAR)
1538
case 'v': //variable
1542
while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++;
1543
//step over the trailing escape char
1544
if (*msgptr) msgptr++;
1551
for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
1553
temp[i] = *msgptr++;
1556
//step over the trailing escape char
1557
if (*msgptr) msgptr++;
1558
//find the random keyword
1559
if (!RandomString(temp))
1561
if (!BotFindStringInList(stringlist, temp))
1563
Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp);
1564
s = GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1);
1565
s->string = (char *) s + sizeof(bot_stringlist_t);
1566
strcpy(s->string, temp);
1567
s->next = stringlist;
1575
botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message);
1586
} //end of the function BotCheckChatMessageIntegrety
1587
//===========================================================================
1591
// Changes Globals: -
1592
//===========================================================================
1593
void BotCheckInitialChatIntegrety(bot_chat_t *chat)
1596
bot_chatmessage_t *cm;
1597
bot_stringlist_t *stringlist, *s, *nexts;
1600
for (t = chat->types; t; t = t->next)
1602
for (cm = t->firstchatmessage; cm; cm = cm->next)
1604
stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
1607
for (s = stringlist; s; s = nexts)
1612
} //end of the function BotCheckInitialChatIntegrety
1613
//===========================================================================
1617
// Changes Globals: -
1618
//===========================================================================
1619
void BotCheckReplyChatIntegrety(bot_replychat_t *replychat)
1621
bot_replychat_t *rp;
1622
bot_chatmessage_t *cm;
1623
bot_stringlist_t *stringlist, *s, *nexts;
1626
for (rp = replychat; rp; rp = rp->next)
1628
for (cm = rp->firstchatmessage; cm; cm = cm->next)
1630
stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
1633
for (s = stringlist; s; s = nexts)
1638
} //end of the function BotCheckReplyChatIntegrety
1639
//===========================================================================
1643
// Changes Globals: -
1644
//===========================================================================
1645
void BotDumpReplyChat(bot_replychat_t *replychat)
1648
bot_replychat_t *rp;
1649
bot_replychatkey_t *key;
1650
bot_chatmessage_t *cm;
1651
bot_matchpiece_t *mp;
1653
fp = Log_FilePointer();
1655
fprintf(fp, "BotDumpReplyChat:\n");
1656
for (rp = replychat; rp; rp = rp->next)
1659
for (key = rp->keys; key; key = key->next)
1661
if (key->flags & RCKFL_AND) fprintf(fp, "&");
1662
else if (key->flags & RCKFL_NOT) fprintf(fp, "!");
1664
if (key->flags & RCKFL_NAME) fprintf(fp, "name");
1665
else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female");
1666
else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male");
1667
else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it");
1668
else if (key->flags & RCKFL_VARIABLES)
1671
for (mp = key->match; mp; mp = mp->next)
1673
if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string);
1674
else fprintf(fp, "%d", mp->variable);
1675
if (mp->next) fprintf(fp, ", ");
1679
else if (key->flags & RCKFL_STRING)
1681
fprintf(fp, "\"%s\"", key->string);
1683
if (key->next) fprintf(fp, ", ");
1684
else fprintf(fp, "] = %1.0f\n", rp->priority);
1687
for (cm = rp->firstchatmessage; cm; cm = cm->next)
1689
fprintf(fp, "\t\"%s\";\n", cm->chatmessage);
1693
} //end of the function BotDumpReplyChat
1694
//===========================================================================
1698
// Changes Globals: -
1699
//===========================================================================
1700
void BotFreeReplyChat(bot_replychat_t *replychat)
1702
bot_replychat_t *rp, *nextrp;
1703
bot_replychatkey_t *key, *nextkey;
1704
bot_chatmessage_t *cm, *nextcm;
1706
for (rp = replychat; rp; rp = nextrp)
1709
for (key = rp->keys; key; key = nextkey)
1711
nextkey = key->next;
1712
if (key->match) BotFreeMatchPieces(key->match);
1713
if (key->string) FreeMemory(key->string);
1716
for (cm = rp->firstchatmessage; cm; cm = nextcm)
1723
} //end of the function BotFreeReplyChat
1724
//===========================================================================
1728
// Changes Globals: -
1729
//===========================================================================
1730
void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys)
1732
int allprefixed, hasvariableskey, hasstringkey;
1733
bot_matchpiece_t *m;
1734
bot_matchstring_t *ms;
1735
bot_replychatkey_t *key, *key2;
1738
allprefixed = qtrue;
1739
hasvariableskey = hasstringkey = qfalse;
1740
for (key = keys; key; key = key->next)
1742
if (!(key->flags & (RCKFL_AND|RCKFL_NOT)))
1744
allprefixed = qfalse;
1745
if (key->flags & RCKFL_VARIABLES)
1747
for (m = key->match; m; m = m->next)
1749
if (m->type == MT_VARIABLE) hasvariableskey = qtrue;
1752
else if (key->flags & RCKFL_STRING)
1754
hasstringkey = qtrue;
1757
else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING))
1759
for (key2 = keys; key2; key2 = key2->next)
1761
if (key2 == key) continue;
1762
if (key2->flags & RCKFL_NOT) continue;
1763
if (key2->flags & RCKFL_VARIABLES)
1765
for (m = key2->match; m; m = m->next)
1767
if (m->type == MT_STRING)
1769
for (ms = m->firststring; ms; ms = ms->next)
1771
if (StringContains(ms->string, key->string, qfalse) != -1)
1778
else if (m->type == MT_VARIABLE)
1785
SourceWarning(source, "one of the match templates does not "
1786
"leave space for the key %s with the & prefix", key->string);
1791
if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING))
1793
for (key2 = keys; key2; key2 = key2->next)
1795
if (key2 == key) continue;
1796
if (key2->flags & RCKFL_NOT) continue;
1797
if (key2->flags & RCKFL_STRING)
1799
if (StringContains(key2->string, key->string, qfalse) != -1)
1801
SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string);
1804
else if (key2->flags & RCKFL_VARIABLES)
1806
for (m = key2->match; m; m = m->next)
1808
if (m->type == MT_STRING)
1810
for (ms = m->firststring; ms; ms = ms->next)
1812
if (StringContains(ms->string, key->string, qfalse) != -1)
1814
SourceWarning(source, "the key %s with prefix ! is inside "
1815
"the match template string %s", key->string, ms->string);
1824
if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix");
1825
if (hasvariableskey && hasstringkey)
1827
SourceWarning(source, "variables from the match template(s) could be "
1828
"invalid when outputting one of the chat messages");
1830
} //end of the function BotCheckValidReplyChatKeySet
1831
//===========================================================================
1835
// Changes Globals: -
1836
//===========================================================================
1837
bot_replychat_t *BotLoadReplyChat(char *filename)
1839
char chatmessagestring[MAX_MESSAGE_SIZE];
1840
char namebuffer[MAX_MESSAGE_SIZE];
1843
bot_chatmessage_t *chatmessage = NULL;
1844
bot_replychat_t *replychat, *replychatlist;
1845
bot_replychatkey_t *key;
1847
PC_SetBaseFolder(BOTFILESBASEFOLDER);
1848
source = LoadSourceFile(filename);
1851
botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
1855
replychatlist = NULL;
1857
while(PC_ReadToken(source, &token))
1859
if (strcmp(token.string, "["))
1861
SourceError(source, "expected [, found %s", token.string);
1862
BotFreeReplyChat(replychatlist);
1867
replychat = GetClearedHunkMemory(sizeof(bot_replychat_t));
1868
replychat->keys = NULL;
1869
replychat->next = replychatlist;
1870
replychatlist = replychat;
1871
//read the keys, there must be at least one key
1875
key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t));
1879
key->next = replychat->keys;
1880
replychat->keys = key;
1881
//check for MUST BE PRESENT and MUST BE ABSENT keys
1882
if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND;
1883
else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT;
1885
if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME;
1886
else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE;
1887
else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE;
1888
else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS;
1889
else if (PC_CheckTokenString(source, "(")) //match key
1891
key->flags |= RCKFL_VARIABLES;
1892
key->match = BotLoadMatchPieces(source, ")");
1895
BotFreeReplyChat(replychatlist);
1899
else if (PC_CheckTokenString(source, "<")) //bot names
1901
key->flags |= RCKFL_BOTNAMES;
1902
strcpy(namebuffer, "");
1905
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
1907
BotFreeReplyChat(replychatlist);
1911
StripDoubleQuotes(token.string);
1912
if (strlen(namebuffer)) strcat(namebuffer, "\\");
1913
strcat(namebuffer, token.string);
1914
} while(PC_CheckTokenString(source, ","));
1915
if (!PC_ExpectTokenString(source, ">"))
1917
BotFreeReplyChat(replychatlist);
1921
key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1);
1922
strcpy(key->string, namebuffer);
1924
else //normal string key
1926
key->flags |= RCKFL_STRING;
1927
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
1929
BotFreeReplyChat(replychatlist);
1933
StripDoubleQuotes(token.string);
1934
key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1);
1935
strcpy(key->string, token.string);
1938
PC_CheckTokenString(source, ",");
1939
} while(!PC_CheckTokenString(source, "]"));
1941
BotCheckValidReplyChatKeySet(source, replychat->keys);
1942
//read the = sign and the priority
1943
if (!PC_ExpectTokenString(source, "=") ||
1944
!PC_ExpectTokenType(source, TT_NUMBER, 0, &token))
1946
BotFreeReplyChat(replychatlist);
1950
replychat->priority = token.floatvalue;
1951
//read the leading {
1952
if (!PC_ExpectTokenString(source, "{"))
1954
BotFreeReplyChat(replychatlist);
1958
replychat->numchatmessages = 0;
1959
//while the trailing } is not found
1960
while(!PC_CheckTokenString(source, "}"))
1962
if (!BotLoadChatMessage(source, chatmessagestring))
1964
BotFreeReplyChat(replychatlist);
1968
chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1);
1969
chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t);
1970
strcpy(chatmessage->chatmessage, chatmessagestring);
1971
chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
1972
chatmessage->next = replychat->firstchatmessage;
1973
//add the chat message to the reply chat
1974
replychat->firstchatmessage = chatmessage;
1975
replychat->numchatmessages++;
1979
botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
1981
//BotDumpReplyChat(replychatlist);
1984
BotCheckReplyChatIntegrety(replychatlist);
1987
if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n");
1989
return replychatlist;
1990
} //end of the function BotLoadReplyChat
1991
//===========================================================================
1995
// Changes Globals: -
1996
//===========================================================================
1997
void BotDumpInitialChat(bot_chat_t *chat)
2000
bot_chatmessage_t *m;
2003
for (t = chat->types; t; t = t->next)
2005
Log_Write(" type \"%s\"", t->name);
2007
Log_Write(" numchatmessages = %d", t->numchatmessages);
2008
for (m = t->firstchatmessage; m; m = m->next)
2010
Log_Write(" \"%s\"", m->chatmessage);
2015
} //end of the function BotDumpInitialChat
2016
//===========================================================================
2020
// Changes Globals: -
2021
//===========================================================================
2022
bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname)
2024
int pass, foundchat, indent, size;
2026
char chatmessagestring[MAX_MESSAGE_SIZE];
2029
bot_chat_t *chat = NULL;
2030
bot_chattype_t *chattype = NULL;
2031
bot_chatmessage_t *chatmessage = NULL;
2035
starttime = Sys_MilliSeconds();
2040
//a bot chat is parsed in two phases
2041
for (pass = 0; pass < 2; pass++)
2044
if (pass && size) ptr = (char *) GetClearedMemory(size);
2045
//load the source file
2046
PC_SetBaseFolder(BOTFILESBASEFOLDER);
2047
source = LoadSourceFile(chatfile);
2050
botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile);
2056
chat = (bot_chat_t *) ptr;
2057
ptr += sizeof(bot_chat_t);
2059
size = sizeof(bot_chat_t);
2061
while(PC_ReadToken(source, &token))
2063
if (!strcmp(token.string, "chat"))
2065
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
2070
StripDoubleQuotes(token.string);
2071
//after the chat name we expect a opening brace
2072
if (!PC_ExpectTokenString(source, "{"))
2077
//if the chat name is found
2078
if (!Q_stricmp(token.string, chatname))
2081
//read the chat types
2084
if (!PC_ExpectAnyToken(source, &token))
2089
if (!strcmp(token.string, "}")) break;
2090
if (strcmp(token.string, "type"))
2092
SourceError(source, "expected type found %s\n", token.string);
2096
//expect the chat type name
2097
if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) ||
2098
!PC_ExpectTokenString(source, "{"))
2103
StripDoubleQuotes(token.string);
2106
chattype = (bot_chattype_t *) ptr;
2107
strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME);
2108
chattype->firstchatmessage = NULL;
2109
//add the chat type to the chat
2110
chattype->next = chat->types;
2111
chat->types = chattype;
2113
ptr += sizeof(bot_chattype_t);
2115
size += sizeof(bot_chattype_t);
2116
//read the chat messages
2117
while(!PC_CheckTokenString(source, "}"))
2120
if (!BotLoadChatMessage(source, chatmessagestring))
2125
len = strlen(chatmessagestring) + 1;
2126
len = PAD(len, sizeof(long));
2129
chatmessage = (bot_chatmessage_t *) ptr;
2130
chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
2131
//put the chat message in the list
2132
chatmessage->next = chattype->firstchatmessage;
2133
chattype->firstchatmessage = chatmessage;
2134
//store the chat message
2135
ptr += sizeof(bot_chatmessage_t);
2136
chatmessage->chatmessage = ptr;
2137
strcpy(chatmessage->chatmessage, chatmessagestring);
2139
//the number of chat messages increased
2140
chattype->numchatmessages++;
2142
size += sizeof(bot_chatmessage_t) + len;
2146
else //skip the bot chat
2151
if (!PC_ExpectAnyToken(source, &token))
2156
if (!strcmp(token.string, "{")) indent++;
2157
else if (!strcmp(token.string, "}")) indent--;
2163
SourceError(source, "unknown definition %s\n", token.string);
2170
//if the requested character is not found
2173
botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile);
2178
botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile);
2180
//BotDumpInitialChat(chat);
2183
BotCheckInitialChatIntegrety(chat);
2186
botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime);
2188
//character was read succesfully
2190
} //end of the function BotLoadInitialChat
2191
//===========================================================================
2195
// Changes Globals: -
2196
//===========================================================================
2197
void BotFreeChatFile(int chatstate)
2199
bot_chatstate_t *cs;
2201
cs = BotChatStateFromHandle(chatstate);
2203
if (cs->chat) FreeMemory(cs->chat);
2205
} //end of the function BotFreeChatFile
2206
//===========================================================================
2210
// Changes Globals: -
2211
//===========================================================================
2212
int BotLoadChatFile(int chatstate, char *chatfile, char *chatname)
2214
bot_chatstate_t *cs;
2217
cs = BotChatStateFromHandle(chatstate);
2218
if (!cs) return BLERR_CANNOTLOADICHAT;
2219
BotFreeChatFile(chatstate);
2221
if (!LibVarGetValue("bot_reloadcharacters"))
2224
for( n = 0; n < MAX_CLIENTS; n++ ) {
2225
if( !ichatdata[n] ) {
2231
if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) {
2234
if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) {
2237
cs->chat = ichatdata[n]->chat;
2238
// botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile );
2239
return BLERR_NOERROR;
2243
botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile);
2244
return BLERR_CANNOTLOADICHAT;
2248
cs->chat = BotLoadInitialChat(chatfile, chatname);
2251
botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile);
2252
return BLERR_CANNOTLOADICHAT;
2254
if (!LibVarGetValue("bot_reloadcharacters"))
2256
ichatdata[avail] = GetClearedMemory( sizeof(bot_ichatdata_t) );
2257
ichatdata[avail]->chat = cs->chat;
2258
Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) );
2259
Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) );
2262
return BLERR_NOERROR;
2263
} //end of the function BotLoadChatFile
2264
//===========================================================================
2268
// Changes Globals: -
2269
//===========================================================================
2270
int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext,
2271
bot_match_t *match, unsigned long vcontext, int reply)
2273
int num, len, i, expansion;
2274
char *outputbuf, *ptr, *msgptr;
2275
char temp[MAX_MESSAGE_SIZE];
2279
outputbuf = outmessage;
2284
if (*msgptr == ESCAPE_CHAR)
2289
case 'v': //variable
2293
while(*msgptr && *msgptr != ESCAPE_CHAR)
2295
num = num * 10 + (*msgptr++) - '0';
2297
//step over the trailing escape char
2298
if (*msgptr) msgptr++;
2299
if (num > MAX_MATCHVARIABLES)
2301
botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num);
2304
if (match->variables[num].offset >= 0)
2306
assert( match->variables[num].offset >= 0 ); // bk001204
2307
ptr = &match->string[ (int) match->variables[num].offset];
2308
for (i = 0; i < match->variables[num].length; i++)
2313
//if it's a reply message
2316
//replace the reply synonyms in the variables
2317
BotReplaceReplySynonyms(temp, vcontext);
2321
//replace synonyms in the variable context
2322
BotReplaceSynonyms(temp, vcontext);
2325
if (len + strlen(temp) >= MAX_MESSAGE_SIZE)
2327
botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message);
2330
strcpy(&outputbuf[len], temp);
2331
len += strlen(temp);
2338
for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
2340
temp[i] = *msgptr++;
2343
//step over the trailing escape char
2344
if (*msgptr) msgptr++;
2345
//find the random keyword
2346
ptr = RandomString(temp);
2349
botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp);
2352
if (len + strlen(ptr) >= MAX_MESSAGE_SIZE)
2354
botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
2357
strcpy(&outputbuf[len], ptr);
2364
botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message);
2371
outputbuf[len++] = *msgptr++;
2372
if (len >= MAX_MESSAGE_SIZE)
2374
botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
2379
outputbuf[len] = '\0';
2380
//replace synonyms weighted in the message context
2381
BotReplaceWeightedSynonyms(outputbuf, mcontext);
2382
//return true if a random was expanded
2384
} //end of the function BotExpandChatMessage
2385
//===========================================================================
2389
// Changes Globals: -
2390
//===========================================================================
2391
void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext,
2392
bot_match_t *match, unsigned long vcontext, int reply)
2395
char srcmessage[MAX_MESSAGE_SIZE];
2397
strcpy(srcmessage, message);
2398
for (i = 0; i < 10; i++)
2400
if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply))
2404
strcpy(srcmessage, chatstate->chatmessage);
2408
botimport.Print(PRT_WARNING, "too many expansions in chat message\n");
2409
botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage);
2411
} //end of the function BotConstructChatMessage
2412
//===========================================================================
2413
// randomly chooses one of the chat message of the given type
2417
// Changes Globals: -
2418
//===========================================================================
2419
char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type)
2421
int n, numchatmessages;
2424
bot_chatmessage_t *m, *bestchatmessage;
2428
for (t = chat->types; t; t = t->next)
2430
if (!Q_stricmp(t->name, type))
2432
numchatmessages = 0;
2433
for (m = t->firstchatmessage; m; m = m->next)
2435
if (m->time > AAS_Time()) continue;
2438
//if all chat messages have been used recently
2439
if (numchatmessages <= 0)
2442
bestchatmessage = NULL;
2443
for (m = t->firstchatmessage; m; m = m->next)
2445
if (!besttime || m->time < besttime)
2447
bestchatmessage = m;
2451
if (bestchatmessage) return bestchatmessage->chatmessage;
2453
else //choose a chat message randomly
2455
n = random() * numchatmessages;
2456
for (m = t->firstchatmessage; m; m = m->next)
2458
if (m->time > AAS_Time()) continue;
2461
m->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
2462
return m->chatmessage;
2470
} //end of the function BotChooseInitialChatMessage
2471
//===========================================================================
2475
// Changes Globals: -
2476
//===========================================================================
2477
int BotNumInitialChats(int chatstate, char *type)
2479
bot_chatstate_t *cs;
2482
cs = BotChatStateFromHandle(chatstate);
2485
for (t = cs->chat->types; t; t = t->next)
2487
if (!Q_stricmp(t->name, type))
2489
if (LibVarGetValue("bot_testichat")) {
2490
botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages);
2491
botimport.Print(PRT_MESSAGE, "-------------------\n");
2493
return t->numchatmessages;
2497
} //end of the function BotNumInitialChats
2498
//===========================================================================
2502
// Changes Globals: -
2503
//===========================================================================
2504
void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
2509
bot_chatstate_t *cs;
2511
cs = BotChatStateFromHandle(chatstate);
2513
//if no chat file is loaded
2514
if (!cs->chat) return;
2515
//choose a chat message randomly of the given type
2516
message = BotChooseInitialChatMessage(cs, type);
2517
//if there's no message of the given type
2521
botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type);
2526
Com_Memset(&match, 0, sizeof(match));
2529
strcat(match.string, var0);
2530
match.variables[0].offset = index;
2531
match.variables[0].length = strlen(var0);
2532
index += strlen(var0);
2535
strcat(match.string, var1);
2536
match.variables[1].offset = index;
2537
match.variables[1].length = strlen(var1);
2538
index += strlen(var1);
2541
strcat(match.string, var2);
2542
match.variables[2].offset = index;
2543
match.variables[2].length = strlen(var2);
2544
index += strlen(var2);
2547
strcat(match.string, var3);
2548
match.variables[3].offset = index;
2549
match.variables[3].length = strlen(var3);
2550
index += strlen(var3);
2553
strcat(match.string, var4);
2554
match.variables[4].offset = index;
2555
match.variables[4].length = strlen(var4);
2556
index += strlen(var4);
2559
strcat(match.string, var5);
2560
match.variables[5].offset = index;
2561
match.variables[5].length = strlen(var5);
2562
index += strlen(var5);
2565
strcat(match.string, var6);
2566
match.variables[6].offset = index;
2567
match.variables[6].length = strlen(var6);
2568
index += strlen(var6);
2571
strcat(match.string, var7);
2572
match.variables[7].offset = index;
2573
match.variables[7].length = strlen(var7);
2574
index += strlen(var7);
2577
BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse);
2578
} //end of the function BotInitialChat
2579
//===========================================================================
2583
// Changes Globals: -
2584
//===========================================================================
2585
void BotPrintReplyChatKeys(bot_replychat_t *replychat)
2587
bot_replychatkey_t *key;
2588
bot_matchpiece_t *mp;
2590
botimport.Print(PRT_MESSAGE, "[");
2591
for (key = replychat->keys; key; key = key->next)
2593
if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&");
2594
else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!");
2596
if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name");
2597
else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female");
2598
else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male");
2599
else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it");
2600
else if (key->flags & RCKFL_VARIABLES)
2602
botimport.Print(PRT_MESSAGE, "(");
2603
for (mp = key->match; mp; mp = mp->next)
2605
if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string);
2606
else botimport.Print(PRT_MESSAGE, "%d", mp->variable);
2607
if (mp->next) botimport.Print(PRT_MESSAGE, ", ");
2609
botimport.Print(PRT_MESSAGE, ")");
2611
else if (key->flags & RCKFL_STRING)
2613
botimport.Print(PRT_MESSAGE, "\"%s\"", key->string);
2615
if (key->next) botimport.Print(PRT_MESSAGE, ", ");
2616
else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority);
2618
botimport.Print(PRT_MESSAGE, "{\n");
2619
} //end of the function BotPrintReplyChatKeys
2620
//===========================================================================
2624
// Changes Globals: -
2625
//===========================================================================
2626
int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
2628
bot_replychat_t *rchat, *bestrchat;
2629
bot_replychatkey_t *key;
2630
bot_chatmessage_t *m, *bestchatmessage;
2631
bot_match_t match, bestmatch;
2632
int bestpriority, num, found, res, numchatmessages, index;
2633
bot_chatstate_t *cs;
2635
cs = BotChatStateFromHandle(chatstate);
2636
if (!cs) return qfalse;
2637
Com_Memset(&match, 0, sizeof(bot_match_t));
2638
strcpy(match.string, message);
2640
bestchatmessage = NULL;
2642
//go through all the reply chats
2643
for (rchat = replychats; rchat; rchat = rchat->next)
2646
for (key = rchat->keys; key; key = key->next)
2649
//get the match result
2650
if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1);
2651
else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1);
2652
else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE);
2653
else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE);
2654
else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS);
2655
else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match);
2656
else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL);
2657
//if the key must be present
2658
if (key->flags & RCKFL_AND)
2666
//if the key must be absent
2667
else if (key->flags & RCKFL_NOT)
2683
if (rchat->priority > bestpriority)
2685
numchatmessages = 0;
2686
for (m = rchat->firstchatmessage; m; m = m->next)
2688
if (m->time > AAS_Time()) continue;
2691
num = random() * numchatmessages;
2692
for (m = rchat->firstchatmessage; m; m = m->next)
2694
if (--num < 0) break;
2695
if (m->time > AAS_Time()) continue;
2697
//if the reply chat has a message
2700
Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t));
2701
bestchatmessage = m;
2703
bestpriority = rchat->priority;
2708
if (bestchatmessage)
2710
index = strlen(bestmatch.string);
2712
strcat(bestmatch.string, var0);
2713
bestmatch.variables[0].offset = index;
2714
bestmatch.variables[0].length = strlen(var0);
2715
index += strlen(var0);
2718
strcat(bestmatch.string, var1);
2719
bestmatch.variables[1].offset = index;
2720
bestmatch.variables[1].length = strlen(var1);
2721
index += strlen(var1);
2724
strcat(bestmatch.string, var2);
2725
bestmatch.variables[2].offset = index;
2726
bestmatch.variables[2].length = strlen(var2);
2727
index += strlen(var2);
2730
strcat(bestmatch.string, var3);
2731
bestmatch.variables[3].offset = index;
2732
bestmatch.variables[3].length = strlen(var3);
2733
index += strlen(var3);
2736
strcat(bestmatch.string, var4);
2737
bestmatch.variables[4].offset = index;
2738
bestmatch.variables[4].length = strlen(var4);
2739
index += strlen(var4);
2742
strcat(bestmatch.string, var5);
2743
bestmatch.variables[5].offset = index;
2744
bestmatch.variables[5].length = strlen(var5);
2745
index += strlen(var5);
2748
strcat(bestmatch.string, var6);
2749
bestmatch.variables[6].offset = index;
2750
bestmatch.variables[6].length = strlen(var6);
2751
index += strlen(var6);
2754
strcat(bestmatch.string, var7);
2755
bestmatch.variables[7].offset = index;
2756
bestmatch.variables[7].length = strlen(var7);
2757
index += strlen(var7);
2759
if (LibVarGetValue("bot_testrchat"))
2761
for (m = bestrchat->firstchatmessage; m; m = m->next)
2763
BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
2764
BotRemoveTildes(cs->chatmessage);
2765
botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
2770
bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
2771
BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
2776
} //end of the function BotReplyChat
2777
//===========================================================================
2781
// Changes Globals: -
2782
//===========================================================================
2783
int BotChatLength(int chatstate)
2785
bot_chatstate_t *cs;
2787
cs = BotChatStateFromHandle(chatstate);
2789
return strlen(cs->chatmessage);
2790
} //end of the function BotChatLength
2791
//===========================================================================
2795
// Changes Globals: -
2796
//===========================================================================
2797
void BotEnterChat(int chatstate, int clientto, int sendto)
2799
bot_chatstate_t *cs;
2801
cs = BotChatStateFromHandle(chatstate);
2804
if (strlen(cs->chatmessage))
2806
BotRemoveTildes(cs->chatmessage);
2807
if (LibVarGetValue("bot_testichat")) {
2808
botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
2813
EA_Command(cs->client, va("say_team %s", cs->chatmessage));
2816
EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage));
2819
EA_Command(cs->client, va("say %s", cs->chatmessage));
2823
//clear the chat message from the state
2824
strcpy(cs->chatmessage, "");
2826
} //end of the function BotEnterChat
2827
//===========================================================================
2831
// Changes Globals: -
2832
//===========================================================================
2833
void BotGetChatMessage(int chatstate, char *buf, int size)
2835
bot_chatstate_t *cs;
2837
cs = BotChatStateFromHandle(chatstate);
2840
BotRemoveTildes(cs->chatmessage);
2841
strncpy(buf, cs->chatmessage, size-1);
2843
//clear the chat message from the state
2844
strcpy(cs->chatmessage, "");
2845
} //end of the function BotGetChatMessage
2846
//===========================================================================
2850
// Changes Globals: -
2851
//===========================================================================
2852
void BotSetChatGender(int chatstate, int gender)
2854
bot_chatstate_t *cs;
2856
cs = BotChatStateFromHandle(chatstate);
2860
case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break;
2861
case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break;
2862
default: cs->gender = CHAT_GENDERLESS; break;
2864
} //end of the function BotSetChatGender
2865
//===========================================================================
2869
// Changes Globals: -
2870
//===========================================================================
2871
void BotSetChatName(int chatstate, char *name, int client)
2873
bot_chatstate_t *cs;
2875
cs = BotChatStateFromHandle(chatstate);
2877
cs->client = client;
2878
Com_Memset(cs->name, 0, sizeof(cs->name));
2879
strncpy(cs->name, name, sizeof(cs->name));
2880
cs->name[sizeof(cs->name)-1] = '\0';
2881
} //end of the function BotSetChatName
2882
//===========================================================================
2886
// Changes Globals: -
2887
//===========================================================================
2888
void BotResetChatAI(void)
2890
bot_replychat_t *rchat;
2891
bot_chatmessage_t *m;
2893
for (rchat = replychats; rchat; rchat = rchat->next)
2895
for (m = rchat->firstchatmessage; m; m = m->next)
2900
} //end of the function BotResetChatAI
2901
//========================================================================
2905
// Changes Globals: -
2906
//========================================================================
2907
int BotAllocChatState(void)
2911
for (i = 1; i <= MAX_CLIENTS; i++)
2913
if (!botchatstates[i])
2915
botchatstates[i] = GetClearedMemory(sizeof(bot_chatstate_t));
2920
} //end of the function BotAllocChatState
2921
//========================================================================
2925
// Changes Globals: -
2926
//========================================================================
2927
void BotFreeChatState(int handle)
2929
bot_chatstate_t *cs;
2930
bot_consolemessage_t m;
2933
if (handle <= 0 || handle > MAX_CLIENTS)
2935
botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
2938
if (!botchatstates[handle])
2940
botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
2943
cs = botchatstates[handle];
2944
if (LibVarGetValue("bot_reloadcharacters"))
2946
BotFreeChatFile(handle);
2948
//free all the console messages left in the chat state
2949
for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m))
2951
//remove the console message
2952
BotRemoveConsoleMessage(handle, h);
2954
FreeMemory(botchatstates[handle]);
2955
botchatstates[handle] = NULL;
2956
} //end of the function BotFreeChatState
2957
//===========================================================================
2961
// Changes Globals: -
2962
//===========================================================================
2963
int BotSetupChatAI(void)
2968
int starttime = Sys_MilliSeconds();
2971
file = LibVarString("synfile", "syn.c");
2972
synonyms = BotLoadSynonyms(file);
2973
file = LibVarString("rndfile", "rnd.c");
2974
randomstrings = BotLoadRandomStrings(file);
2975
file = LibVarString("matchfile", "match.c");
2976
matchtemplates = BotLoadMatchTemplates(file);
2978
if (!LibVarValue("nochat", "0"))
2980
file = LibVarString("rchatfile", "rchat.c");
2981
replychats = BotLoadReplyChat(file);
2984
InitConsoleMessageHeap();
2987
botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime);
2989
return BLERR_NOERROR;
2990
} //end of the function BotSetupChatAI
2991
//===========================================================================
2995
// Changes Globals: -
2996
//===========================================================================
2997
void BotShutdownChatAI(void)
3001
//free all remaining chat states
3002
for(i = 0; i < MAX_CLIENTS; i++)
3004
if (botchatstates[i])
3006
BotFreeChatState(i);
3009
//free all cached chats
3010
for(i = 0; i < MAX_CLIENTS; i++)
3014
FreeMemory(ichatdata[i]->chat);
3015
FreeMemory(ichatdata[i]);
3016
ichatdata[i] = NULL;
3019
if (consolemessageheap) FreeMemory(consolemessageheap);
3020
consolemessageheap = NULL;
3021
if (matchtemplates) BotFreeMatchTemplates(matchtemplates);
3022
matchtemplates = NULL;
3023
if (randomstrings) FreeMemory(randomstrings);
3024
randomstrings = NULL;
3025
if (synonyms) FreeMemory(synonyms);
3027
if (replychats) BotFreeReplyChat(replychats);
3029
} //end of the function BotShutdownChatAI