📄 be_ai_chat.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Foobar; 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 "../game/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 "../game/botlib.h"
#include "../game/be_aas.h"
#include "be_aas_funcs.h"
#include "be_interface.h"
#include "../game/be_ea.h"
#include "../game/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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -