diff options
Diffstat (limited to 'src/botlib/be_ai_chat.c')
-rw-r--r-- | src/botlib/be_ai_chat.c | 3030 |
1 files changed, 0 insertions, 3030 deletions
diff --git a/src/botlib/be_ai_chat.c b/src/botlib/be_ai_chat.c deleted file mode 100644 index 98ca1c3d..00000000 --- a/src/botlib/be_ai_chat.c +++ /dev/null @@ -1,3030 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_chat.c - * - * desc: bot chat AI - * - * $Archive: /MissionPack/code/botlib/be_ai_chat.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_libvar.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_utils.h" -#include "l_log.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ea.h" -#include "be_ai_chat.h" - - -//escape character -#define ESCAPE_CHAR 0x01 //'_' -// -// "hi ", people, " ", 0, " entered the game" -//becomes: -// "hi _rpeople_ _v0_ entered the game" -// - -//match piece types -#define MT_VARIABLE 1 //variable match piece -#define MT_STRING 2 //string match piece -//reply chat key flags -#define RCKFL_AND 1 //key must be present -#define RCKFL_NOT 2 //key must be absent -#define RCKFL_NAME 4 //name of bot must be present -#define RCKFL_STRING 8 //key is a string -#define RCKFL_VARIABLES 16 //key is a match template -#define RCKFL_BOTNAMES 32 //key is a series of botnames -#define RCKFL_GENDERFEMALE 64 //bot must be female -#define RCKFL_GENDERMALE 128 //bot must be male -#define RCKFL_GENDERLESS 256 //bot must be genderless -//time to ignore a chat message after using it -#define CHATMESSAGE_RECENTTIME 20 - -//the actuall chat messages -typedef struct bot_chatmessage_s -{ - char *chatmessage; //chat message string - float time; //last time used - struct bot_chatmessage_s *next; //next chat message in a list -} bot_chatmessage_t; -//bot chat type with chat lines -typedef struct bot_chattype_s -{ - char name[MAX_CHATTYPE_NAME]; - int numchatmessages; - bot_chatmessage_t *firstchatmessage; - struct bot_chattype_s *next; -} bot_chattype_t; -//bot chat lines -typedef struct bot_chat_s -{ - bot_chattype_t *types; -} bot_chat_t; - -//random string -typedef struct bot_randomstring_s -{ - char *string; - struct bot_randomstring_s *next; -} bot_randomstring_t; -//list with random strings -typedef struct bot_randomlist_s -{ - char *string; - int numstrings; - bot_randomstring_t *firstrandomstring; - struct bot_randomlist_s *next; -} bot_randomlist_t; - -//synonym -typedef struct bot_synonym_s -{ - char *string; - float weight; - struct bot_synonym_s *next; -} bot_synonym_t; -//list with synonyms -typedef struct bot_synonymlist_s -{ - unsigned long int context; - float totalweight; - bot_synonym_t *firstsynonym; - struct bot_synonymlist_s *next; -} bot_synonymlist_t; - -//fixed match string -typedef struct bot_matchstring_s -{ - char *string; - struct bot_matchstring_s *next; -} bot_matchstring_t; - -//piece of a match template -typedef struct bot_matchpiece_s -{ - int type; - bot_matchstring_t *firststring; - int variable; - struct bot_matchpiece_s *next; -} bot_matchpiece_t; -//match template -typedef struct bot_matchtemplate_s -{ - unsigned long int context; - int type; - int subtype; - bot_matchpiece_t *first; - struct bot_matchtemplate_s *next; -} bot_matchtemplate_t; - -//reply chat key -typedef struct bot_replychatkey_s -{ - int flags; - char *string; - bot_matchpiece_t *match; - struct bot_replychatkey_s *next; -} bot_replychatkey_t; -//reply chat -typedef struct bot_replychat_s -{ - bot_replychatkey_t *keys; - float priority; - int numchatmessages; - bot_chatmessage_t *firstchatmessage; - struct bot_replychat_s *next; -} bot_replychat_t; - -//string list -typedef struct bot_stringlist_s -{ - char *string; - struct bot_stringlist_s *next; -} bot_stringlist_t; - -//chat state of a bot -typedef struct bot_chatstate_s -{ - int gender; //0=it, 1=female, 2=male - int client; //client number - char name[32]; //name of the bot - char chatmessage[MAX_MESSAGE_SIZE]; - int handle; - //the console messages visible to the bot - bot_consolemessage_t *firstmessage; //first message is the first typed message - bot_consolemessage_t *lastmessage; //last message is the last typed message, bottom of console - //number of console messages stored in the state - int numconsolemessages; - //the bot chat lines - bot_chat_t *chat; -} bot_chatstate_t; - -typedef struct { - bot_chat_t *chat; - char filename[MAX_QPATH]; - char chatname[MAX_QPATH]; -} bot_ichatdata_t; - -bot_ichatdata_t *ichatdata[MAX_CLIENTS]; - -bot_chatstate_t *botchatstates[MAX_CLIENTS+1]; -//console message heap -bot_consolemessage_t *consolemessageheap = NULL; -bot_consolemessage_t *freeconsolemessages = NULL; -//list with match strings -bot_matchtemplate_t *matchtemplates = NULL; -//list with synonyms -bot_synonymlist_t *synonyms = NULL; -//list with random strings -bot_randomlist_t *randomstrings = NULL; -//reply chats -bot_replychat_t *replychats = NULL; - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_chatstate_t *BotChatStateFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); - return NULL; - } //end if - if (!botchatstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); - return NULL; - } //end if - return botchatstates[handle]; -} //end of the function BotChatStateFromHandle -//=========================================================================== -// initialize the heap with unused console messages -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void InitConsoleMessageHeap(void) -{ - int i, max_messages; - - if (consolemessageheap) FreeMemory(consolemessageheap); - // - max_messages = (int) LibVarValue("max_messages", "1024"); - consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages * - sizeof(bot_consolemessage_t)); - consolemessageheap[0].prev = NULL; - consolemessageheap[0].next = &consolemessageheap[1]; - for (i = 1; i < max_messages-1; i++) - { - consolemessageheap[i].prev = &consolemessageheap[i - 1]; - consolemessageheap[i].next = &consolemessageheap[i + 1]; - } //end for - consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2]; - consolemessageheap[max_messages-1].next = NULL; - //pointer to the free console messages - freeconsolemessages = consolemessageheap; -} //end of the function InitConsoleMessageHeap -//=========================================================================== -// allocate one console message from the heap -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_consolemessage_t *AllocConsoleMessage(void) -{ - bot_consolemessage_t *message; - message = freeconsolemessages; - if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next; - if (freeconsolemessages) freeconsolemessages->prev = NULL; - return message; -} //end of the function AllocConsoleMessage -//=========================================================================== -// deallocate one console message from the heap -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeConsoleMessage(bot_consolemessage_t *message) -{ - if (freeconsolemessages) freeconsolemessages->prev = message; - message->prev = NULL; - message->next = freeconsolemessages; - freeconsolemessages = message; -} //end of the function FreeConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotRemoveConsoleMessage(int chatstate, int handle) -{ - bot_consolemessage_t *m, *nextm; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - for (m = cs->firstmessage; m; m = nextm) - { - nextm = m->next; - if (m->handle == handle) - { - if (m->next) m->next->prev = m->prev; - else cs->lastmessage = m->prev; - if (m->prev) m->prev->next = m->next; - else cs->firstmessage = m->next; - - FreeConsoleMessage(m); - cs->numconsolemessages--; - break; - } //end if - } //end for -} //end of the function BotRemoveConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotQueueConsoleMessage(int chatstate, int type, char *message) -{ - bot_consolemessage_t *m; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - m = AllocConsoleMessage(); - if (!m) - { - botimport.Print(PRT_ERROR, "empty console message heap\n"); - return; - } //end if - cs->handle++; - if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1; - m->handle = cs->handle; - m->time = AAS_Time(); - m->type = type; - strncpy(m->message, message, MAX_MESSAGE_SIZE); - m->next = NULL; - if (cs->lastmessage) - { - cs->lastmessage->next = m; - m->prev = cs->lastmessage; - cs->lastmessage = m; - } //end if - else - { - cs->lastmessage = m; - cs->firstmessage = m; - m->prev = NULL; - } //end if - cs->numconsolemessages++; -} //end of the function BotQueueConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - if (cs->firstmessage) - { - Com_Memcpy(cm, cs->firstmessage, sizeof(bot_consolemessage_t)); - cm->next = cm->prev = NULL; - return cm->handle; - } //end if - return 0; -} //end of the function BotConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNumConsoleMessages(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - return cs->numconsolemessages; -} //end of the function BotNumConsoleMessages -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int IsWhiteSpace(char c) -{ - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '(' || c == ')' - || c == '?' || c == ':' - || c == '\''|| c == '/' - || c == ',' || c == '.' - || c == '[' || c == ']' - || c == '-' || c == '_' - || c == '+' || c == '=') return qfalse; - return qtrue; -} //end of the function IsWhiteSpace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotRemoveTildes(char *message) -{ - int i; - - //remove all tildes from the chat message - for (i = 0; message[i]; i++) - { - if (message[i] == '~') - { - memmove(&message[i], &message[i+1], strlen(&message[i+1])+1); - } //end if - } //end for -} //end of the function BotRemoveTildes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void UnifyWhiteSpaces(char *string) -{ - char *ptr, *oldptr; - - for (ptr = oldptr = string; *ptr; oldptr = ptr) - { - while(*ptr && IsWhiteSpace(*ptr)) ptr++; - if (ptr > oldptr) - { - //if not at the start and not at the end of the string - //write only one space - if (oldptr > string && *ptr) *oldptr++ = ' '; - //remove all other white spaces - if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1); - } //end if - while(*ptr && !IsWhiteSpace(*ptr)) ptr++; - } //end while -} //end of the function UnifyWhiteSpaces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int StringContains(char *str1, char *str2, int casesensitive) -{ - int len, i, j, index; - - if (str1 == NULL || str2 == NULL) return -1; - - len = strlen(str1) - strlen(str2); - index = 0; - for (i = 0; i <= len; i++, str1++, index++) - { - for (j = 0; str2[j]; j++) - { - if (casesensitive) - { - if (str1[j] != str2[j]) break; - } //end if - else - { - if (toupper(str1[j]) != toupper(str2[j])) break; - } //end else - } //end for - if (!str2[j]) return index; - } //end for - return -1; -} //end of the function StringContains -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *StringContainsWord(char *str1, char *str2, int casesensitive) -{ - int len, i, j; - - len = strlen(str1) - strlen(str2); - for (i = 0; i <= len; i++, str1++) - { - //if not at the start of the string - if (i) - { - //skip to the start of the next word - while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++; - if (!*str1) break; - str1++; - } //end for - //compare the word - for (j = 0; str2[j]; j++) - { - if (casesensitive) - { - if (str1[j] != str2[j]) break; - } //end if - else - { - if (toupper(str1[j]) != toupper(str2[j])) break; - } //end else - } //end for - //if there was a word match - if (!str2[j]) - { - //if the first string has an end of word - if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1; - } //end if - } //end for - return NULL; -} //end of the function StringContainsWord -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void StringReplaceWords(char *string, char *synonym, char *replacement) -{ - char *str, *str2; - - //find the synonym in the string - str = StringContainsWord(string, synonym, qfalse); - //if the synonym occured in the string - while(str) - { - //if the synonym isn't part of the replacement which is already in the string - //usefull for abreviations - str2 = StringContainsWord(string, replacement, qfalse); - while(str2) - { - if (str2 <= str && str < str2 + strlen(replacement)) break; - str2 = StringContainsWord(str2+1, replacement, qfalse); - } //end while - if (!str2) - { - memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1); - //append the synonum replacement - Com_Memcpy(str, replacement, strlen(replacement)); - } //end if - //find the next synonym in the string - str = StringContainsWord(str+strlen(replacement), synonym, qfalse); - } //end if -} //end of the function StringReplaceWords -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpSynonymList(bot_synonymlist_t *synlist) -{ - FILE *fp; - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - fp = Log_FilePointer(); - if (!fp) return; - for (syn = synlist; syn; syn = syn->next) - { - fprintf(fp, "%ld : [", syn->context); - for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) - { - fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight); - if (synonym->next) fprintf(fp, ", "); - } //end for - fprintf(fp, "]\n"); - } //end for -} //end of the function BotDumpSynonymList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_synonymlist_t *BotLoadSynonyms(char *filename) -{ - int pass, size, contextlevel, numsynonyms; - unsigned long int context, contextstack[32]; - char *ptr = NULL; - source_t *source; - token_t token; - bot_synonymlist_t *synlist, *lastsyn, *syn; - bot_synonym_t *synonym, *lastsynonym; - - size = 0; - synlist = NULL; //make compiler happy - syn = NULL; //make compiler happy - synonym = NULL; //make compiler happy - //the synonyms are parsed in two phases - for (pass = 0; pass < 2; pass++) - { - // - if (pass && size) ptr = (char *) GetClearedHunkMemory(size); - // - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - context = 0; - contextlevel = 0; - synlist = NULL; //list synonyms - lastsyn = NULL; //last synonym in the list - // - while(PC_ReadToken(source, &token)) - { - if (token.type == TT_NUMBER) - { - context |= token.intvalue; - contextstack[contextlevel] = token.intvalue; - contextlevel++; - if (contextlevel >= 32) - { - SourceError(source, "more than 32 context levels"); - FreeSource(source); - return NULL; - } //end if - if (!PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - } //end if - else if (token.type == TT_PUNCTUATION) - { - if (!strcmp(token.string, "}")) - { - contextlevel--; - if (contextlevel < 0) - { - SourceError(source, "too many }"); - FreeSource(source); - return NULL; - } //end if - context &= ~contextstack[contextlevel]; - } //end if - else if (!strcmp(token.string, "[")) - { - size += sizeof(bot_synonymlist_t); - if (pass) - { - syn = (bot_synonymlist_t *) ptr; - ptr += sizeof(bot_synonymlist_t); - syn->context = context; - syn->firstsynonym = NULL; - syn->next = NULL; - if (lastsyn) lastsyn->next = syn; - else synlist = syn; - lastsyn = syn; - } //end if - numsynonyms = 0; - lastsynonym = NULL; - while(1) - { - size_t len; - if (!PC_ExpectTokenString(source, "(") || - !PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (strlen(token.string) <= 0) - { - SourceError(source, "empty string", token.string); - FreeSource(source); - return NULL; - } //end if - len = strlen(token.string) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_synonym_t) + len; - if (pass) - { - synonym = (bot_synonym_t *) ptr; - ptr += sizeof(bot_synonym_t); - synonym->string = ptr; - ptr += len; - strcpy(synonym->string, token.string); - // - if (lastsynonym) lastsynonym->next = synonym; - else syn->firstsynonym = synonym; - lastsynonym = synonym; - } //end if - numsynonyms++; - if (!PC_ExpectTokenString(source, ",") || - !PC_ExpectTokenType(source, TT_NUMBER, 0, &token) || - !PC_ExpectTokenString(source, ")")) - { - FreeSource(source); - return NULL; - } //end if - if (pass) - { - synonym->weight = token.floatvalue; - syn->totalweight += synonym->weight; - } //end if - if (PC_CheckTokenString(source, "]")) break; - if (!PC_ExpectTokenString(source, ",")) - { - FreeSource(source); - return NULL; - } //end if - } //end while - if (numsynonyms < 2) - { - SourceError(source, "synonym must have at least two entries\n"); - FreeSource(source); - return NULL; - } //end if - } //end else - else - { - SourceError(source, "unexpected %s", token.string); - FreeSource(source); - return NULL; - } //end if - } //end else if - } //end while - // - FreeSource(source); - // - if (contextlevel > 0) - { - SourceError(source, "missing }"); - return NULL; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // - //BotDumpSynonymList(synlist); - // - return synlist; -} //end of the function BotLoadSynonyms -//=========================================================================== -// replace all the synonyms in the string -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceSynonyms(char *string, unsigned long int context) -{ - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) - { - StringReplaceWords(string, synonym->string, syn->firstsynonym->string); - } //end for - } //end for -} //end of the function BotReplaceSynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceWeightedSynonyms(char *string, unsigned long int context) -{ - bot_synonymlist_t *syn; - bot_synonym_t *synonym, *replacement; - float weight, curweight; - - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - //choose a weighted random replacement synonym - weight = random() * syn->totalweight; - if (!weight) continue; - curweight = 0; - for (replacement = syn->firstsynonym; replacement; replacement = replacement->next) - { - curweight += replacement->weight; - if (weight < curweight) break; - } //end for - if (!replacement) continue; - //replace all synonyms with the replacement - for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) - { - if (synonym == replacement) continue; - StringReplaceWords(string, synonym->string, replacement->string); - } //end for - } //end for -} //end of the function BotReplaceWeightedSynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceReplySynonyms(char *string, unsigned long int context) -{ - char *str1, *str2, *replacement; - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - for (str1 = string; *str1; ) - { - //go to the start of the next word - while(*str1 && *str1 <= ' ') str1++; - if (!*str1) break; - // - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) - { - str2 = synonym->string; - //if the synonym is not at the front of the string continue - str2 = StringContainsWord(str1, synonym->string, qfalse); - if (!str2 || str2 != str1) continue; - // - replacement = syn->firstsynonym->string; - //if the replacement IS in front of the string continue - str2 = StringContainsWord(str1, replacement, qfalse); - if (str2 && str2 == str1) continue; - // - memmove(str1 + strlen(replacement), str1+strlen(synonym->string), - strlen(str1+strlen(synonym->string)) + 1); - //append the synonum replacement - Com_Memcpy(str1, replacement, strlen(replacement)); - // - break; - } //end for - //if a synonym has been replaced - if (synonym) break; - } //end for - //skip over this word - while(*str1 && *str1 > ' ') str1++; - if (!*str1) break; - } //end while -} //end of the function BotReplaceReplySynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadChatMessage(source_t *source, char *chatmessagestring) -{ - char *ptr; - token_t token; - - ptr = chatmessagestring; - *ptr = 0; - // - while(1) - { - if (!PC_ExpectAnyToken(source, &token)) return qfalse; - //fixed string - if (token.type == TT_STRING) - { - StripDoubleQuotes(token.string); - if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - strcat(ptr, token.string); - } //end else if - //variable string - else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) - { - if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR); - } //end if - //random string - else if (token.type == TT_NAME) - { - if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR); - } //end else if - else - { - SourceError(source, "unknown message component %s\n", token.string); - return qfalse; - } //end else - if (PC_CheckTokenString(source, ";")) break; - if (!PC_ExpectTokenString(source, ",")) return qfalse; - } //end while - // - return qtrue; -} //end of the function BotLoadChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpRandomStringList(bot_randomlist_t *randomlist) -{ - FILE *fp; - bot_randomlist_t *random; - bot_randomstring_t *rs; - - fp = Log_FilePointer(); - if (!fp) return; - for (random = randomlist; random; random = random->next) - { - fprintf(fp, "%s = {", random->string); - for (rs = random->firstrandomstring; rs; rs = rs->next) - { - fprintf(fp, "\"%s\"", rs->string); - if (rs->next) fprintf(fp, ", "); - else fprintf(fp, "}\n"); - } //end for - } //end for -} //end of the function BotDumpRandomStringList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_randomlist_t *BotLoadRandomStrings(char *filename) -{ - int pass, size; - char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_randomlist_t *randomlist, *lastrandom, *random; - bot_randomstring_t *randomstring; - -#ifdef DEBUG - int starttime = Sys_MilliSeconds(); -#endif //DEBUG - - size = 0; - randomlist = NULL; - random = NULL; - //the synonyms are parsed in two phases - for (pass = 0; pass < 2; pass++) - { - // - if (pass && size) ptr = (char *) GetClearedHunkMemory(size); - // - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - randomlist = NULL; //list - lastrandom = NULL; //last - // - while(PC_ReadToken(source, &token)) - { - size_t len; - if (token.type != TT_NAME) - { - SourceError(source, "unknown random %s", token.string); - FreeSource(source); - return NULL; - } //end if - len = strlen(token.string) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_randomlist_t) + len; - if (pass) - { - random = (bot_randomlist_t *) ptr; - ptr += sizeof(bot_randomlist_t); - random->string = ptr; - ptr += len; - strcpy(random->string, token.string); - random->firstrandomstring = NULL; - random->numstrings = 0; - // - if (lastrandom) lastrandom->next = random; - else randomlist = random; - lastrandom = random; - } //end if - if (!PC_ExpectTokenString(source, "=") || - !PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - while(!PC_CheckTokenString(source, "}")) - { - size_t len; - if (!BotLoadChatMessage(source, chatmessagestring)) - { - FreeSource(source); - return NULL; - } //end if - len = strlen(chatmessagestring) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_randomstring_t) + len; - if (pass) - { - randomstring = (bot_randomstring_t *) ptr; - ptr += sizeof(bot_randomstring_t); - randomstring->string = ptr; - ptr += len; - strcpy(randomstring->string, chatmessagestring); - // - random->numstrings++; - randomstring->next = random->firstrandomstring; - random->firstrandomstring = randomstring; - } //end if - } //end while - } //end while - //free the source after one pass - FreeSource(source); - } //end for - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime); - //BotDumpRandomStringList(randomlist); -#endif //DEBUG - // - return randomlist; -} //end of the function BotLoadRandomStrings -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *RandomString(char *name) -{ - bot_randomlist_t *random; - bot_randomstring_t *rs; - int i; - - for (random = randomstrings; random; random = random->next) - { - if (!strcmp(random->string, name)) - { - i = random() * random->numstrings; - for (rs = random->firstrandomstring; rs; rs = rs->next) - { - if (--i < 0) break; - } //end for - if (rs) - { - return rs->string; - } //end if - } //end for - } //end for - return NULL; -} //end of the function RandomString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpMatchTemplates(bot_matchtemplate_t *matches) -{ - FILE *fp; - bot_matchtemplate_t *mt; - bot_matchpiece_t *mp; - bot_matchstring_t *ms; - - fp = Log_FilePointer(); - if (!fp) return; - for (mt = matches; mt; mt = mt->next) - { - fprintf(fp, "{ " ); - for (mp = mt->first; mp; mp = mp->next) - { - if (mp->type == MT_STRING) - { - for (ms = mp->firststring; ms; ms = ms->next) - { - fprintf(fp, "\"%s\"", ms->string); - if (ms->next) fprintf(fp, "|"); - } //end for - } //end if - else if (mp->type == MT_VARIABLE) - { - fprintf(fp, "%d", mp->variable); - } //end else if - if (mp->next) fprintf(fp, ", "); - } //end for - fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype); - } //end for -} //end of the function BotDumpMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeMatchPieces(bot_matchpiece_t *matchpieces) -{ - bot_matchpiece_t *mp, *nextmp; - bot_matchstring_t *ms, *nextms; - - for (mp = matchpieces; mp; mp = nextmp) - { - nextmp = mp->next; - if (mp->type == MT_STRING) - { - for (ms = mp->firststring; ms; ms = nextms) - { - nextms = ms->next; - FreeMemory(ms); - } //end for - } //end if - FreeMemory(mp); - } //end for -} //end of the function BotFreeMatchPieces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken) -{ - int lastwasvariable, emptystring; - token_t token; - bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece; - bot_matchstring_t *matchstring, *lastmatchstring; - - firstpiece = NULL; - lastpiece = NULL; - // - lastwasvariable = qfalse; - // - while(PC_ReadToken(source, &token)) - { - if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) - { - if (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES) - { - SourceError(source, "can't have more than %d match variables\n", MAX_MATCHVARIABLES); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - if (lastwasvariable) - { - SourceError(source, "not allowed to have adjacent variables\n"); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - lastwasvariable = qtrue; - // - matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); - matchpiece->type = MT_VARIABLE; - matchpiece->variable = token.intvalue; - matchpiece->next = NULL; - if (lastpiece) lastpiece->next = matchpiece; - else firstpiece = matchpiece; - lastpiece = matchpiece; - } //end if - else if (token.type == TT_STRING) - { - // - matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); - matchpiece->firststring = NULL; - matchpiece->type = MT_STRING; - matchpiece->variable = 0; - matchpiece->next = NULL; - if (lastpiece) lastpiece->next = matchpiece; - else firstpiece = matchpiece; - lastpiece = matchpiece; - // - lastmatchstring = NULL; - emptystring = qfalse; - // - do - { - if (matchpiece->firststring) - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - } //end if - StripDoubleQuotes(token.string); - matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1); - matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t); - strcpy(matchstring->string, token.string); - if (!strlen(token.string)) emptystring = qtrue; - matchstring->next = NULL; - if (lastmatchstring) lastmatchstring->next = matchstring; - else matchpiece->firststring = matchstring; - lastmatchstring = matchstring; - } while(PC_CheckTokenString(source, "|")); - //if there was no empty string found - if (!emptystring) lastwasvariable = qfalse; - } //end if - else - { - SourceError(source, "invalid token %s\n", token.string); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end else - if (PC_CheckTokenString(source, endtoken)) break; - if (!PC_ExpectTokenString(source, ",")) - { - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - } //end while - return firstpiece; -} //end of the function BotLoadMatchPieces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeMatchTemplates(bot_matchtemplate_t *mt) -{ - bot_matchtemplate_t *nextmt; - - for (; mt; mt = nextmt) - { - nextmt = mt->next; - BotFreeMatchPieces(mt->first); - FreeMemory(mt); - } //end for -} //end of the function BotFreeMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile) -{ - source_t *source; - token_t token; - bot_matchtemplate_t *matchtemplate, *matches, *lastmatch; - unsigned long int context; - - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(matchfile); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile); - return NULL; - } //end if - // - matches = NULL; //list with matches - lastmatch = NULL; //last match in the list - - while(PC_ReadToken(source, &token)) - { - if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) - { - SourceError(source, "expected integer, found %s\n", token.string); - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - //the context - context = token.intvalue; - // - if (!PC_ExpectTokenString(source, "{")) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - // - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "}")) break; - // - PC_UnreadLastToken(source); - // - matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t)); - matchtemplate->context = context; - matchtemplate->next = NULL; - //add the match template to the list - if (lastmatch) lastmatch->next = matchtemplate; - else matches = matchtemplate; - lastmatch = matchtemplate; - //load the match template - matchtemplate->first = BotLoadMatchPieces(source, "="); - if (!matchtemplate->first) - { - BotFreeMatchTemplates(matches); - return NULL; - } //end if - //read the match type - if (!PC_ExpectTokenString(source, "(") || - !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - matchtemplate->type = token.intvalue; - //read the match subtype - if (!PC_ExpectTokenString(source, ",") || - !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - matchtemplate->subtype = token.intvalue; - //read trailing punctuations - if (!PC_ExpectTokenString(source, ")") || - !PC_ExpectTokenString(source, ";")) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - } //end while - } //end while - //free the source - FreeSource(source); - botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile); - // - //BotDumpMatchTemplates(matches); - // - return matches; -} //end of the function BotLoadMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match) -{ - int lastvariable, index; - char *strptr, *newstrptr; - bot_matchpiece_t *mp; - bot_matchstring_t *ms; - - //no last variable - lastvariable = -1; - //pointer to the string to compare the match string with - strptr = match->string; - //Log_Write("match: %s", strptr); - //compare the string with the current match string - for (mp = pieces; mp; mp = mp->next) - { - //if it is a piece of string - if (mp->type == MT_STRING) - { - newstrptr = NULL; - for (ms = mp->firststring; ms; ms = ms->next) - { - if (!strlen(ms->string)) - { - newstrptr = strptr; - break; - } //end if - //Log_Write("MT_STRING: %s", mp->string); - index = StringContains(strptr, ms->string, qfalse); - if (index >= 0) - { - newstrptr = strptr + index; - if (lastvariable >= 0) - { - match->variables[lastvariable].length = - (newstrptr - match->string) - match->variables[lastvariable].offset; - //newstrptr - match->variables[lastvariable].ptr; - lastvariable = -1; - break; - } //end if - else if (index == 0) - { - break; - } //end else - newstrptr = NULL; - } //end if - } //end for - if (!newstrptr) return qfalse; - strptr = newstrptr + strlen(ms->string); - } //end if - //if it is a variable piece of string - else if (mp->type == MT_VARIABLE) - { - //Log_Write("MT_VARIABLE"); - match->variables[mp->variable].offset = strptr - match->string; - lastvariable = mp->variable; - } //end else if - } //end for - //if a match was found - if (!mp && (lastvariable >= 0 || !strlen(strptr))) - { - //if the last piece was a variable string - if (lastvariable >= 0) - { - assert( match->variables[lastvariable].offset >= 0 ); // bk001204 - match->variables[lastvariable].length = - strlen(&match->string[ (int) match->variables[lastvariable].offset]); - } //end if - return qtrue; - } //end if - return qfalse; -} //end of the function StringsMatch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotFindMatch(char *str, bot_match_t *match, unsigned long int context) -{ - int i; - bot_matchtemplate_t *ms; - - strncpy(match->string, str, MAX_MESSAGE_SIZE); - //remove any trailing enters - while(strlen(match->string) && - match->string[strlen(match->string)-1] == '\n') - { - match->string[strlen(match->string)-1] = '\0'; - } //end while - //compare the string with all the match strings - for (ms = matchtemplates; ms; ms = ms->next) - { - if (!(ms->context & context)) continue; - //reset the match variable offsets - for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1; - // - if (StringsMatch(ms->first, match)) - { - match->type = ms->type; - match->subtype = ms->subtype; - return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function BotFindMatch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size) -{ - if (variable < 0 || variable >= MAX_MATCHVARIABLES) - { - botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n"); - strcpy(buf, ""); - return; - } //end if - - if (match->variables[variable].offset >= 0) - { - if (match->variables[variable].length < size) - size = match->variables[variable].length+1; - assert( match->variables[variable].offset >= 0 ); // bk001204 - strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1); - buf[size-1] = '\0'; - } //end if - else - { - strcpy(buf, ""); - } //end else - return; -} //end of the function BotMatchVariable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string) -{ - bot_stringlist_t *s; - - for (s = list; s; s = s->next) - { - if (!strcmp(s->string, string)) return s; - } //end for - return NULL; -} //end of the function BotFindStringInList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist) -{ - int i; - char *msgptr; - char temp[MAX_MESSAGE_SIZE]; - bot_stringlist_t *s; - - msgptr = message; - // - while(*msgptr) - { - if (*msgptr == ESCAPE_CHAR) - { - msgptr++; - switch(*msgptr) - { - case 'v': //variable - { - //step over the 'v' - msgptr++; - while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++; - //step over the trailing escape char - if (*msgptr) msgptr++; - break; - } //end case - case 'r': //random - { - //step over the 'r' - msgptr++; - for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) - { - temp[i] = *msgptr++; - } //end while - temp[i] = '\0'; - //step over the trailing escape char - if (*msgptr) msgptr++; - //find the random keyword - if (!RandomString(temp)) - { - if (!BotFindStringInList(stringlist, temp)) - { - Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp); - s = GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1); - s->string = (char *) s + sizeof(bot_stringlist_t); - strcpy(s->string, temp); - s->next = stringlist; - stringlist = s; - } //end if - } //end if - break; - } //end case - default: - { - botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message); - break; - } //end default - } //end switch - } //end if - else - { - msgptr++; - } //end else - } //end while - return stringlist; -} //end of the function BotCheckChatMessageIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckInitialChatIntegrety(bot_chat_t *chat) -{ - bot_chattype_t *t; - bot_chatmessage_t *cm; - bot_stringlist_t *stringlist, *s, *nexts; - - stringlist = NULL; - for (t = chat->types; t; t = t->next) - { - for (cm = t->firstchatmessage; cm; cm = cm->next) - { - stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); - } //end for - } //end for - for (s = stringlist; s; s = nexts) - { - nexts = s->next; - FreeMemory(s); - } //end for -} //end of the function BotCheckInitialChatIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckReplyChatIntegrety(bot_replychat_t *replychat) -{ - bot_replychat_t *rp; - bot_chatmessage_t *cm; - bot_stringlist_t *stringlist, *s, *nexts; - - stringlist = NULL; - for (rp = replychat; rp; rp = rp->next) - { - for (cm = rp->firstchatmessage; cm; cm = cm->next) - { - stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); - } //end for - } //end for - for (s = stringlist; s; s = nexts) - { - nexts = s->next; - FreeMemory(s); - } //end for -} //end of the function BotCheckReplyChatIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpReplyChat(bot_replychat_t *replychat) -{ - FILE *fp; - bot_replychat_t *rp; - bot_replychatkey_t *key; - bot_chatmessage_t *cm; - bot_matchpiece_t *mp; - - fp = Log_FilePointer(); - if (!fp) return; - fprintf(fp, "BotDumpReplyChat:\n"); - for (rp = replychat; rp; rp = rp->next) - { - fprintf(fp, "["); - for (key = rp->keys; key; key = key->next) - { - if (key->flags & RCKFL_AND) fprintf(fp, "&"); - else if (key->flags & RCKFL_NOT) fprintf(fp, "!"); - // - if (key->flags & RCKFL_NAME) fprintf(fp, "name"); - else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female"); - else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male"); - else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it"); - else if (key->flags & RCKFL_VARIABLES) - { - fprintf(fp, "("); - for (mp = key->match; mp; mp = mp->next) - { - if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string); - else fprintf(fp, "%d", mp->variable); - if (mp->next) fprintf(fp, ", "); - } //end for - fprintf(fp, ")"); - } //end if - else if (key->flags & RCKFL_STRING) - { - fprintf(fp, "\"%s\"", key->string); - } //end if - if (key->next) fprintf(fp, ", "); - else fprintf(fp, "] = %1.0f\n", rp->priority); - } //end for - fprintf(fp, "{\n"); - for (cm = rp->firstchatmessage; cm; cm = cm->next) - { - fprintf(fp, "\t\"%s\";\n", cm->chatmessage); - } //end for - fprintf(fp, "}\n"); - } //end for -} //end of the function BotDumpReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeReplyChat(bot_replychat_t *replychat) -{ - bot_replychat_t *rp, *nextrp; - bot_replychatkey_t *key, *nextkey; - bot_chatmessage_t *cm, *nextcm; - - for (rp = replychat; rp; rp = nextrp) - { - nextrp = rp->next; - for (key = rp->keys; key; key = nextkey) - { - nextkey = key->next; - if (key->match) BotFreeMatchPieces(key->match); - if (key->string) FreeMemory(key->string); - FreeMemory(key); - } //end for - for (cm = rp->firstchatmessage; cm; cm = nextcm) - { - nextcm = cm->next; - FreeMemory(cm); - } //end for - FreeMemory(rp); - } //end for -} //end of the function BotFreeReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys) -{ - int allprefixed, hasvariableskey, hasstringkey; - bot_matchpiece_t *m; - bot_matchstring_t *ms; - bot_replychatkey_t *key, *key2; - - // - allprefixed = qtrue; - hasvariableskey = hasstringkey = qfalse; - for (key = keys; key; key = key->next) - { - if (!(key->flags & (RCKFL_AND|RCKFL_NOT))) - { - allprefixed = qfalse; - if (key->flags & RCKFL_VARIABLES) - { - for (m = key->match; m; m = m->next) - { - if (m->type == MT_VARIABLE) hasvariableskey = qtrue; - } //end for - } //end if - else if (key->flags & RCKFL_STRING) - { - hasstringkey = qtrue; - } //end else if - } //end if - else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING)) - { - for (key2 = keys; key2; key2 = key2->next) - { - if (key2 == key) continue; - if (key2->flags & RCKFL_NOT) continue; - if (key2->flags & RCKFL_VARIABLES) - { - for (m = key2->match; m; m = m->next) - { - if (m->type == MT_STRING) - { - for (ms = m->firststring; ms; ms = ms->next) - { - if (StringContains(ms->string, key->string, qfalse) != -1) - { - break; - } //end if - } //end for - if (ms) break; - } //end if - else if (m->type == MT_VARIABLE) - { - break; - } //end if - } //end for - if (!m) - { - SourceWarning(source, "one of the match templates does not " - "leave space for the key %s with the & prefix", key->string); - } //end if - } //end if - } //end for - } //end else - if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING)) - { - for (key2 = keys; key2; key2 = key2->next) - { - if (key2 == key) continue; - if (key2->flags & RCKFL_NOT) continue; - if (key2->flags & RCKFL_STRING) - { - if (StringContains(key2->string, key->string, qfalse) != -1) - { - SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string); - } //end if - } //end if - else if (key2->flags & RCKFL_VARIABLES) - { - for (m = key2->match; m; m = m->next) - { - if (m->type == MT_STRING) - { - for (ms = m->firststring; ms; ms = ms->next) - { - if (StringContains(ms->string, key->string, qfalse) != -1) - { - SourceWarning(source, "the key %s with prefix ! is inside " - "the match template string %s", key->string, ms->string); - } //end if - } //end for - } //end if - } //end for - } //end else if - } //end for - } //end if - } //end for - if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix"); - if (hasvariableskey && hasstringkey) - { - SourceWarning(source, "variables from the match template(s) could be " - "invalid when outputting one of the chat messages"); - } //end if -} //end of the function BotCheckValidReplyChatKeySet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_replychat_t *BotLoadReplyChat(char *filename) -{ - char chatmessagestring[MAX_MESSAGE_SIZE]; - char namebuffer[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_chatmessage_t *chatmessage = NULL; - bot_replychat_t *replychat, *replychatlist; - bot_replychatkey_t *key; - - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - replychatlist = NULL; - // - while(PC_ReadToken(source, &token)) - { - if (strcmp(token.string, "[")) - { - SourceError(source, "expected [, found %s", token.string); - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - // - replychat = GetClearedHunkMemory(sizeof(bot_replychat_t)); - replychat->keys = NULL; - replychat->next = replychatlist; - replychatlist = replychat; - //read the keys, there must be at least one key - do - { - //allocate a key - key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t)); - key->flags = 0; - key->string = NULL; - key->match = NULL; - key->next = replychat->keys; - replychat->keys = key; - //check for MUST BE PRESENT and MUST BE ABSENT keys - if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND; - else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT; - //special keys - if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME; - else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE; - else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE; - else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS; - else if (PC_CheckTokenString(source, "(")) //match key - { - key->flags |= RCKFL_VARIABLES; - key->match = BotLoadMatchPieces(source, ")"); - if (!key->match) - { - BotFreeReplyChat(replychatlist); - return NULL; - } //end if - } //end else if - else if (PC_CheckTokenString(source, "<")) //bot names - { - key->flags |= RCKFL_BOTNAMES; - strcpy(namebuffer, ""); - do - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (strlen(namebuffer)) strcat(namebuffer, "\\"); - strcat(namebuffer, token.string); - } while(PC_CheckTokenString(source, ",")); - if (!PC_ExpectTokenString(source, ">")) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1); - strcpy(key->string, namebuffer); - } //end else if - else //normal string key - { - key->flags |= RCKFL_STRING; - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1); - strcpy(key->string, token.string); - } //end else - // - PC_CheckTokenString(source, ","); - } while(!PC_CheckTokenString(source, "]")); - // - BotCheckValidReplyChatKeySet(source, replychat->keys); - //read the = sign and the priority - if (!PC_ExpectTokenString(source, "=") || - !PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - replychat->priority = token.floatvalue; - //read the leading { - if (!PC_ExpectTokenString(source, "{")) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - replychat->numchatmessages = 0; - //while the trailing } is not found - while(!PC_CheckTokenString(source, "}")) - { - if (!BotLoadChatMessage(source, chatmessagestring)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1); - chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t); - strcpy(chatmessage->chatmessage, chatmessagestring); - chatmessage->time = -2*CHATMESSAGE_RECENTTIME; - chatmessage->next = replychat->firstchatmessage; - //add the chat message to the reply chat - replychat->firstchatmessage = chatmessage; - replychat->numchatmessages++; - } //end while - } //end while - FreeSource(source); - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // - //BotDumpReplyChat(replychatlist); - if (bot_developer) - { - BotCheckReplyChatIntegrety(replychatlist); - } //end if - // - if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n"); - // - return replychatlist; -} //end of the function BotLoadReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpInitialChat(bot_chat_t *chat) -{ - bot_chattype_t *t; - bot_chatmessage_t *m; - - Log_Write("{"); - for (t = chat->types; t; t = t->next) - { - Log_Write(" type \"%s\"", t->name); - Log_Write(" {"); - Log_Write(" numchatmessages = %d", t->numchatmessages); - for (m = t->firstchatmessage; m; m = m->next) - { - Log_Write(" \"%s\"", m->chatmessage); - } //end for - Log_Write(" }"); - } //end for - Log_Write("}"); -} //end of the function BotDumpInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) -{ - int pass, foundchat, indent, size; - char *ptr = NULL; - char chatmessagestring[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_chat_t *chat = NULL; - bot_chattype_t *chattype = NULL; - bot_chatmessage_t *chatmessage = NULL; -#ifdef DEBUG - int starttime; - - starttime = Sys_MilliSeconds(); -#endif //DEBUG - // - size = 0; - foundchat = qfalse; - //a bot chat is parsed in two phases - for (pass = 0; pass < 2; pass++) - { - //allocate memory - if (pass && size) ptr = (char *) GetClearedMemory(size); - //load the source file - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(chatfile); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile); - return NULL; - } //end if - //chat structure - if (pass) - { - chat = (bot_chat_t *) ptr; - ptr += sizeof(bot_chat_t); - } //end if - size = sizeof(bot_chat_t); - // - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "chat")) - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - //after the chat name we expect a opening brace - if (!PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - //if the chat name is found - if (!Q_stricmp(token.string, chatname)) - { - foundchat = qtrue; - //read the chat types - while(1) - { - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - return NULL; - } //end if - if (!strcmp(token.string, "}")) break; - if (strcmp(token.string, "type")) - { - SourceError(source, "expected type found %s\n", token.string); - FreeSource(source); - return NULL; - } //end if - //expect the chat type name - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) || - !PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (pass) - { - chattype = (bot_chattype_t *) ptr; - strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME); - chattype->firstchatmessage = NULL; - //add the chat type to the chat - chattype->next = chat->types; - chat->types = chattype; - // - ptr += sizeof(bot_chattype_t); - } //end if - size += sizeof(bot_chattype_t); - //read the chat messages - while(!PC_CheckTokenString(source, "}")) - { - size_t len; - if (!BotLoadChatMessage(source, chatmessagestring)) - { - FreeSource(source); - return NULL; - } //end if - len = strlen(chatmessagestring) + 1; - len = PAD(len, sizeof(long)); - if (pass) - { - chatmessage = (bot_chatmessage_t *) ptr; - chatmessage->time = -2*CHATMESSAGE_RECENTTIME; - //put the chat message in the list - chatmessage->next = chattype->firstchatmessage; - chattype->firstchatmessage = chatmessage; - //store the chat message - ptr += sizeof(bot_chatmessage_t); - chatmessage->chatmessage = ptr; - strcpy(chatmessage->chatmessage, chatmessagestring); - ptr += len; - //the number of chat messages increased - chattype->numchatmessages++; - } //end if - size += sizeof(bot_chatmessage_t) + len; - } //end if - } //end while - } //end if - else //skip the bot chat - { - indent = 1; - while(indent) - { - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - return NULL; - } //end if - if (!strcmp(token.string, "{")) indent++; - else if (!strcmp(token.string, "}")) indent--; - } //end while - } //end else - } //end if - else - { - SourceError(source, "unknown definition %s\n", token.string); - FreeSource(source); - return NULL; - } //end else - } //end while - //free the source - FreeSource(source); - //if the requested character is not found - if (!foundchat) - { - botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile); - return NULL; - } //end if - } //end for - // - botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile); - // - //BotDumpInitialChat(chat); - if (bot_developer) - { - BotCheckInitialChatIntegrety(chat); - } //end if -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime); -#endif //DEBUG - //character was read succesfully - return chat; -} //end of the function BotLoadInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeChatFile(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - if (cs->chat) FreeMemory(cs->chat); - cs->chat = NULL; -} //end of the function BotFreeChatFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadChatFile(int chatstate, char *chatfile, char *chatname) -{ - bot_chatstate_t *cs; - int n, avail = 0; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return BLERR_CANNOTLOADICHAT; - BotFreeChatFile(chatstate); - - if (!LibVarGetValue("bot_reloadcharacters")) - { - avail = -1; - for( n = 0; n < MAX_CLIENTS; n++ ) { - if( !ichatdata[n] ) { - if( avail == -1 ) { - avail = n; - } - continue; - } - if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) { - continue; - } - if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) { - continue; - } - cs->chat = ichatdata[n]->chat; - // botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile ); - return BLERR_NOERROR; - } - - if( avail == -1 ) { - botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile); - return BLERR_CANNOTLOADICHAT; - } - } - - cs->chat = BotLoadInitialChat(chatfile, chatname); - if (!cs->chat) - { - botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile); - return BLERR_CANNOTLOADICHAT; - } //end if - if (!LibVarGetValue("bot_reloadcharacters")) - { - ichatdata[avail] = GetClearedMemory( sizeof(bot_ichatdata_t) ); - ichatdata[avail]->chat = cs->chat; - Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) ); - Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) ); - } //end if - - return BLERR_NOERROR; -} //end of the function BotLoadChatFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext, - bot_match_t *match, unsigned long vcontext, int reply) -{ - int num, len, i, expansion; - char *outputbuf, *ptr, *msgptr; - char temp[MAX_MESSAGE_SIZE]; - - expansion = qfalse; - msgptr = message; - outputbuf = outmessage; - len = 0; - // - while(*msgptr) - { - if (*msgptr == ESCAPE_CHAR) - { - msgptr++; - switch(*msgptr) - { - case 'v': //variable - { - msgptr++; - num = 0; - while(*msgptr && *msgptr != ESCAPE_CHAR) - { - num = num * 10 + (*msgptr++) - '0'; - } //end while - //step over the trailing escape char - if (*msgptr) msgptr++; - if (num > MAX_MATCHVARIABLES) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num); - return qfalse; - } //end if - if (match->variables[num].offset >= 0) - { - assert( match->variables[num].offset >= 0 ); // bk001204 - ptr = &match->string[ (int) match->variables[num].offset]; - for (i = 0; i < match->variables[num].length; i++) - { - temp[i] = ptr[i]; - } //end for - temp[i] = 0; - //if it's a reply message - if (reply) - { - //replace the reply synonyms in the variables - BotReplaceReplySynonyms(temp, vcontext); - } //end if - else - { - //replace synonyms in the variable context - BotReplaceSynonyms(temp, vcontext); - } //end else - // - if (len + strlen(temp) >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message); - return qfalse; - } //end if - strcpy(&outputbuf[len], temp); - len += strlen(temp); - } //end if - break; - } //end case - case 'r': //random - { - msgptr++; - for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) - { - temp[i] = *msgptr++; - } //end while - temp[i] = '\0'; - //step over the trailing escape char - if (*msgptr) msgptr++; - //find the random keyword - ptr = RandomString(temp); - if (!ptr) - { - botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp); - return qfalse; - } //end if - if (len + strlen(ptr) >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); - return qfalse; - } //end if - strcpy(&outputbuf[len], ptr); - len += strlen(ptr); - expansion = qtrue; - break; - } //end case - default: - { - botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message); - break; - } //end default - } //end switch - } //end if - else - { - outputbuf[len++] = *msgptr++; - if (len >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); - break; - } //end if - } //end else - } //end while - outputbuf[len] = '\0'; - //replace synonyms weighted in the message context - BotReplaceWeightedSynonyms(outputbuf, mcontext); - //return true if a random was expanded - return expansion; -} //end of the function BotExpandChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext, - bot_match_t *match, unsigned long vcontext, int reply) -{ - int i; - char srcmessage[MAX_MESSAGE_SIZE]; - - strcpy(srcmessage, message); - for (i = 0; i < 10; i++) - { - if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply)) - { - break; - } //end if - strcpy(srcmessage, chatstate->chatmessage); - } //end for - if (i >= 10) - { - botimport.Print(PRT_WARNING, "too many expansions in chat message\n"); - botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage); - } //end if -} //end of the function BotConstructChatMessage -//=========================================================================== -// randomly chooses one of the chat message of the given type -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type) -{ - int n, numchatmessages; - float besttime; - bot_chattype_t *t; - bot_chatmessage_t *m, *bestchatmessage; - bot_chat_t *chat; - - chat = cs->chat; - for (t = chat->types; t; t = t->next) - { - if (!Q_stricmp(t->name, type)) - { - numchatmessages = 0; - for (m = t->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - numchatmessages++; - } //end if - //if all chat messages have been used recently - if (numchatmessages <= 0) - { - besttime = 0; - bestchatmessage = NULL; - for (m = t->firstchatmessage; m; m = m->next) - { - if (!besttime || m->time < besttime) - { - bestchatmessage = m; - besttime = m->time; - } //end if - } //end for - if (bestchatmessage) return bestchatmessage->chatmessage; - } //end if - else //choose a chat message randomly - { - n = random() * numchatmessages; - for (m = t->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - if (--n < 0) - { - m->time = AAS_Time() + CHATMESSAGE_RECENTTIME; - return m->chatmessage; - } //end if - } //end for - } //end else - return NULL; - } //end if - } //end for - return NULL; -} //end of the function BotChooseInitialChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNumInitialChats(int chatstate, char *type) -{ - bot_chatstate_t *cs; - bot_chattype_t *t; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - - for (t = cs->chat->types; t; t = t->next) - { - if (!Q_stricmp(t->name, type)) - { - if (LibVarGetValue("bot_testichat")) { - botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages); - botimport.Print(PRT_MESSAGE, "-------------------\n"); - } - return t->numchatmessages; - } //end if - } //end for - return 0; -} //end of the function BotNumInitialChats -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7) -{ - char *message; - int index; - bot_match_t match; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - //if no chat file is loaded - if (!cs->chat) return; - //choose a chat message randomly of the given type - message = BotChooseInitialChatMessage(cs, type); - //if there's no message of the given type - if (!message) - { -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type); -#endif //DEBUG - return; - } //end if - // - Com_Memset(&match, 0, sizeof(match)); - index = 0; - if( var0 ) { - strcat(match.string, var0); - match.variables[0].offset = index; - match.variables[0].length = strlen(var0); - index += strlen(var0); - } - if( var1 ) { - strcat(match.string, var1); - match.variables[1].offset = index; - match.variables[1].length = strlen(var1); - index += strlen(var1); - } - if( var2 ) { - strcat(match.string, var2); - match.variables[2].offset = index; - match.variables[2].length = strlen(var2); - index += strlen(var2); - } - if( var3 ) { - strcat(match.string, var3); - match.variables[3].offset = index; - match.variables[3].length = strlen(var3); - index += strlen(var3); - } - if( var4 ) { - strcat(match.string, var4); - match.variables[4].offset = index; - match.variables[4].length = strlen(var4); - index += strlen(var4); - } - if( var5 ) { - strcat(match.string, var5); - match.variables[5].offset = index; - match.variables[5].length = strlen(var5); - index += strlen(var5); - } - if( var6 ) { - strcat(match.string, var6); - match.variables[6].offset = index; - match.variables[6].length = strlen(var6); - index += strlen(var6); - } - if( var7 ) { - strcat(match.string, var7); - match.variables[7].offset = index; - match.variables[7].length = strlen(var7); - index += strlen(var7); - } - // - BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse); -} //end of the function BotInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotPrintReplyChatKeys(bot_replychat_t *replychat) -{ - bot_replychatkey_t *key; - bot_matchpiece_t *mp; - - botimport.Print(PRT_MESSAGE, "["); - for (key = replychat->keys; key; key = key->next) - { - if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&"); - else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!"); - // - if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name"); - else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female"); - else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male"); - else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it"); - else if (key->flags & RCKFL_VARIABLES) - { - botimport.Print(PRT_MESSAGE, "("); - for (mp = key->match; mp; mp = mp->next) - { - if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string); - else botimport.Print(PRT_MESSAGE, "%d", mp->variable); - if (mp->next) botimport.Print(PRT_MESSAGE, ", "); - } //end for - botimport.Print(PRT_MESSAGE, ")"); - } //end if - else if (key->flags & RCKFL_STRING) - { - botimport.Print(PRT_MESSAGE, "\"%s\"", key->string); - } //end if - if (key->next) botimport.Print(PRT_MESSAGE, ", "); - else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority); - } //end for - botimport.Print(PRT_MESSAGE, "{\n"); -} //end of the function BotPrintReplyChatKeys -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -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) -{ - bot_replychat_t *rchat, *bestrchat; - bot_replychatkey_t *key; - bot_chatmessage_t *m, *bestchatmessage; - bot_match_t match, bestmatch; - int bestpriority, num, found, res, numchatmessages, index; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return qfalse; - Com_Memset(&match, 0, sizeof(bot_match_t)); - strcpy(match.string, message); - bestpriority = -1; - bestchatmessage = NULL; - bestrchat = NULL; - //go through all the reply chats - for (rchat = replychats; rchat; rchat = rchat->next) - { - found = qfalse; - for (key = rchat->keys; key; key = key->next) - { - res = qfalse; - //get the match result - if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1); - else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1); - else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE); - else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE); - else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS); - else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match); - else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL); - //if the key must be present - if (key->flags & RCKFL_AND) - { - if (!res) - { - found = qfalse; - break; - } //end if - } //end else if - //if the key must be absent - else if (key->flags & RCKFL_NOT) - { - if (res) - { - found = qfalse; - break; - } //end if - } //end if - else if (res) - { - found = qtrue; - } //end else - } //end for - // - if (found) - { - if (rchat->priority > bestpriority) - { - numchatmessages = 0; - for (m = rchat->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - numchatmessages++; - } //end if - num = random() * numchatmessages; - for (m = rchat->firstchatmessage; m; m = m->next) - { - if (--num < 0) break; - if (m->time > AAS_Time()) continue; - } //end for - //if the reply chat has a message - if (m) - { - Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t)); - bestchatmessage = m; - bestrchat = rchat; - bestpriority = rchat->priority; - } //end if - } //end if - } //end if - } //end for - if (bestchatmessage) - { - index = strlen(bestmatch.string); - if( var0 ) { - strcat(bestmatch.string, var0); - bestmatch.variables[0].offset = index; - bestmatch.variables[0].length = strlen(var0); - index += strlen(var0); - } - if( var1 ) { - strcat(bestmatch.string, var1); - bestmatch.variables[1].offset = index; - bestmatch.variables[1].length = strlen(var1); - index += strlen(var1); - } - if( var2 ) { - strcat(bestmatch.string, var2); - bestmatch.variables[2].offset = index; - bestmatch.variables[2].length = strlen(var2); - index += strlen(var2); - } - if( var3 ) { - strcat(bestmatch.string, var3); - bestmatch.variables[3].offset = index; - bestmatch.variables[3].length = strlen(var3); - index += strlen(var3); - } - if( var4 ) { - strcat(bestmatch.string, var4); - bestmatch.variables[4].offset = index; - bestmatch.variables[4].length = strlen(var4); - index += strlen(var4); - } - if( var5 ) { - strcat(bestmatch.string, var5); - bestmatch.variables[5].offset = index; - bestmatch.variables[5].length = strlen(var5); - index += strlen(var5); - } - if( var6 ) { - strcat(bestmatch.string, var6); - bestmatch.variables[6].offset = index; - bestmatch.variables[6].length = strlen(var6); - index += strlen(var6); - } - if( var7 ) { - strcat(bestmatch.string, var7); - bestmatch.variables[7].offset = index; - bestmatch.variables[7].length = strlen(var7); - index += strlen(var7); - } - if (LibVarGetValue("bot_testrchat")) - { - for (m = bestrchat->firstchatmessage; m; m = m->next) - { - BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue); - BotRemoveTildes(cs->chatmessage); - botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); - } //end if - } //end if - else - { - bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME; - BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue); - } //end else - return qtrue; - } //end if - return qfalse; -} //end of the function BotReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotChatLength(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - return strlen(cs->chatmessage); -} //end of the function BotChatLength -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotEnterChat(int chatstate, int clientto, int sendto) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - if (strlen(cs->chatmessage)) - { - BotRemoveTildes(cs->chatmessage); - if (LibVarGetValue("bot_testichat")) { - botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); - } - else { - switch(sendto) { - case CHAT_TEAM: - EA_Command(cs->client, va("say_team %s", cs->chatmessage)); - break; - case CHAT_TELL: - EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage)); - break; - default: //CHAT_ALL - EA_Command(cs->client, va("say %s", cs->chatmessage)); - break; - } - } - //clear the chat message from the state - strcpy(cs->chatmessage, ""); - } //end if -} //end of the function BotEnterChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotGetChatMessage(int chatstate, char *buf, int size) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - BotRemoveTildes(cs->chatmessage); - strncpy(buf, cs->chatmessage, size-1); - buf[size-1] = '\0'; - //clear the chat message from the state - strcpy(cs->chatmessage, ""); -} //end of the function BotGetChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSetChatGender(int chatstate, int gender) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - switch(gender) - { - case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break; - case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break; - default: cs->gender = CHAT_GENDERLESS; break; - } //end switch -} //end of the function BotSetChatGender -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSetChatName(int chatstate, char *name, int client) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - cs->client = client; - Com_Memset(cs->name, 0, sizeof(cs->name)); - strncpy(cs->name, name, sizeof(cs->name)); - cs->name[sizeof(cs->name)-1] = '\0'; -} //end of the function BotSetChatName -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetChatAI(void) -{ - bot_replychat_t *rchat; - bot_chatmessage_t *m; - - for (rchat = replychats; rchat; rchat = rchat->next) - { - for (m = rchat->firstchatmessage; m; m = m->next) - { - m->time = 0; - } //end for - } //end for -} //end of the function BotResetChatAI -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -int BotAllocChatState(void) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (!botchatstates[i]) - { - botchatstates[i] = GetClearedMemory(sizeof(bot_chatstate_t)); - return i; - } //end if - } //end for - return 0; -} //end of the function BotAllocChatState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeChatState(int handle) -{ - bot_chatstate_t *cs; - bot_consolemessage_t m; - int h; - - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); - return; - } //end if - if (!botchatstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); - return; - } //end if - cs = botchatstates[handle]; - if (LibVarGetValue("bot_reloadcharacters")) - { - BotFreeChatFile(handle); - } //end if - //free all the console messages left in the chat state - for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m)) - { - //remove the console message - BotRemoveConsoleMessage(handle, h); - } //end for - FreeMemory(botchatstates[handle]); - botchatstates[handle] = NULL; -} //end of the function BotFreeChatState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSetupChatAI(void) -{ - char *file; - -#ifdef DEBUG - int starttime = Sys_MilliSeconds(); -#endif //DEBUG - - file = LibVarString("synfile", "syn.c"); - synonyms = BotLoadSynonyms(file); - file = LibVarString("rndfile", "rnd.c"); - randomstrings = BotLoadRandomStrings(file); - file = LibVarString("matchfile", "match.c"); - matchtemplates = BotLoadMatchTemplates(file); - // - if (!LibVarValue("nochat", "0")) - { - file = LibVarString("rchatfile", "rchat.c"); - replychats = BotLoadReplyChat(file); - } //end if - - InitConsoleMessageHeap(); - -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime); -#endif //DEBUG - return BLERR_NOERROR; -} //end of the function BotSetupChatAI -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownChatAI(void) -{ - int i; - - //free all remaining chat states - for(i = 0; i < MAX_CLIENTS; i++) - { - if (botchatstates[i]) - { - BotFreeChatState(i); - } //end if - } //end for - //free all cached chats - for(i = 0; i < MAX_CLIENTS; i++) - { - if (ichatdata[i]) - { - FreeMemory(ichatdata[i]->chat); - FreeMemory(ichatdata[i]); - ichatdata[i] = NULL; - } //end if - } //end for - if (consolemessageheap) FreeMemory(consolemessageheap); - consolemessageheap = NULL; - if (matchtemplates) BotFreeMatchTemplates(matchtemplates); - matchtemplates = NULL; - if (randomstrings) FreeMemory(randomstrings); - randomstrings = NULL; - if (synonyms) FreeMemory(synonyms); - synonyms = NULL; - if (replychats) BotFreeReplyChat(replychats); - replychats = NULL; -} //end of the function BotShutdownChatAI |