~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/botlib/be_ai_chat.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
7
Quake III Arena source code is free software; you can redistribute it
 
8
and/or modify it under the terms of the GNU General Public License as
 
9
published by the Free Software Foundation; either version 2 of the License,
 
10
or (at your option) any later version.
 
11
 
 
12
Quake III Arena source code is distributed in the hope that it will be
 
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
GNU General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with Quake III Arena source code; if not, write to the Free Software
 
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
===========================================================================
 
21
*/
 
22
 
 
23
/*****************************************************************************
 
24
 * name:                be_ai_chat.c
 
25
 *
 
26
 * desc:                bot chat AI
 
27
 *
 
28
 * $Archive: /MissionPack/code/botlib/be_ai_chat.c $
 
29
 *
 
30
 *****************************************************************************/
 
31
 
 
32
#include "../qcommon/q_shared.h"
 
33
#include "l_memory.h"
 
34
#include "l_libvar.h"
 
35
#include "l_script.h"
 
36
#include "l_precomp.h"
 
37
#include "l_struct.h"
 
38
#include "l_utils.h"
 
39
#include "l_log.h"
 
40
#include "aasfile.h"
 
41
#include "botlib.h"
 
42
#include "be_aas.h"
 
43
#include "be_aas_funcs.h"
 
44
#include "be_interface.h"
 
45
#include "be_ea.h"
 
46
#include "be_ai_chat.h"
 
47
 
 
48
 
 
49
//escape character
 
50
#define ESCAPE_CHAR                             0x01    //'_'
 
51
//
 
52
// "hi ", people, " ", 0, " entered the game"
 
53
//becomes:
 
54
// "hi _rpeople_ _v0_ entered the game"
 
55
//
 
56
 
 
57
//match piece types
 
58
#define MT_VARIABLE                                     1               //variable match piece
 
59
#define MT_STRING                                       2               //string match piece
 
60
//reply chat key flags
 
61
#define RCKFL_AND                                       1               //key must be present
 
62
#define RCKFL_NOT                                       2               //key must be absent
 
63
#define RCKFL_NAME                                      4               //name of bot must be present
 
64
#define RCKFL_STRING                            8               //key is a string
 
65
#define RCKFL_VARIABLES                         16              //key is a match template
 
66
#define RCKFL_BOTNAMES                          32              //key is a series of botnames
 
67
#define RCKFL_GENDERFEMALE                      64              //bot must be female
 
68
#define RCKFL_GENDERMALE                        128             //bot must be male
 
69
#define RCKFL_GENDERLESS                        256             //bot must be genderless
 
70
//time to ignore a chat message after using it
 
71
#define CHATMESSAGE_RECENTTIME  20
 
72
 
 
73
//the actuall chat messages
 
74
typedef struct bot_chatmessage_s
 
75
{
 
76
        char *chatmessage;                                      //chat message string
 
77
        float time;                                                     //last time used
 
78
        struct bot_chatmessage_s *next;         //next chat message in a list
 
79
} bot_chatmessage_t;
 
80
//bot chat type with chat lines
 
81
typedef struct bot_chattype_s
 
82
{
 
83
        char name[MAX_CHATTYPE_NAME];
 
84
        int numchatmessages;
 
85
        bot_chatmessage_t *firstchatmessage;
 
86
        struct bot_chattype_s *next;
 
87
} bot_chattype_t;
 
88
//bot chat lines
 
89
typedef struct bot_chat_s
 
90
{
 
91
        bot_chattype_t *types;
 
92
} bot_chat_t;
 
93
 
 
94
//random string
 
95
typedef struct bot_randomstring_s
 
96
{
 
97
        char *string;
 
98
        struct bot_randomstring_s *next;
 
99
} bot_randomstring_t;
 
100
//list with random strings
 
101
typedef struct bot_randomlist_s
 
102
{
 
103
        char *string;
 
104
        int numstrings;
 
105
        bot_randomstring_t *firstrandomstring;
 
106
        struct bot_randomlist_s *next;
 
107
} bot_randomlist_t;
 
108
 
 
109
//synonym
 
110
typedef struct bot_synonym_s
 
111
{
 
112
        char *string;
 
113
        float weight;
 
114
        struct bot_synonym_s *next;
 
115
} bot_synonym_t;
 
116
//list with synonyms
 
117
typedef struct bot_synonymlist_s
 
118
{
 
119
        unsigned long int context;
 
120
        float totalweight;
 
121
        bot_synonym_t *firstsynonym;
 
122
        struct bot_synonymlist_s *next;
 
123
} bot_synonymlist_t;
 
124
 
 
125
//fixed match string
 
126
typedef struct bot_matchstring_s
 
127
{
 
128
        char *string;
 
129
        struct bot_matchstring_s *next;
 
130
} bot_matchstring_t;
 
131
 
 
132
//piece of a match template
 
133
typedef struct bot_matchpiece_s
 
134
{
 
135
        int type;
 
136
        bot_matchstring_t *firststring;
 
137
        int variable;
 
138
        struct bot_matchpiece_s *next;
 
139
} bot_matchpiece_t;
 
140
//match template
 
141
typedef struct bot_matchtemplate_s
 
142
{
 
143
        unsigned long int context;
 
144
        int type;
 
145
        int subtype;
 
146
        bot_matchpiece_t *first;
 
147
        struct bot_matchtemplate_s *next;
 
148
} bot_matchtemplate_t;
 
149
 
 
150
//reply chat key
 
151
typedef struct bot_replychatkey_s
 
152
{
 
153
        int flags;
 
154
        char *string;
 
155
        bot_matchpiece_t *match;
 
156
        struct bot_replychatkey_s *next;
 
157
} bot_replychatkey_t;
 
158
//reply chat
 
159
typedef struct bot_replychat_s
 
160
{
 
161
        bot_replychatkey_t *keys;
 
162
        float priority;
 
163
        int numchatmessages;
 
164
        bot_chatmessage_t *firstchatmessage;
 
165
        struct bot_replychat_s *next;
 
166
} bot_replychat_t;
 
167
 
 
168
//string list
 
169
typedef struct bot_stringlist_s
 
170
{
 
171
        char *string;
 
172
        struct bot_stringlist_s *next;
 
173
} bot_stringlist_t;
 
174
 
 
175
//chat state of a bot
 
176
typedef struct bot_chatstate_s
 
177
{
 
178
        int gender;                                                                                     //0=it, 1=female, 2=male
 
179
        int client;                                                                                     //client number
 
180
        char name[32];                                                                          //name of the bot
 
181
        char chatmessage[MAX_MESSAGE_SIZE];
 
182
        int handle;
 
183
        //the console messages visible to the bot
 
184
        bot_consolemessage_t *firstmessage;                     //first message is the first typed message
 
185
        bot_consolemessage_t *lastmessage;                      //last message is the last typed message, bottom of console
 
186
        //number of console messages stored in the state
 
187
        int numconsolemessages;
 
188
        //the bot chat lines
 
189
        bot_chat_t *chat;
 
190
} bot_chatstate_t;
 
191
 
 
192
typedef struct {
 
193
        bot_chat_t      *chat;
 
194
        char            filename[MAX_QPATH];
 
195
        char            chatname[MAX_QPATH];
 
196
} bot_ichatdata_t;
 
197
 
 
198
bot_ichatdata_t *ichatdata[MAX_CLIENTS];
 
199
 
 
200
bot_chatstate_t *botchatstates[MAX_CLIENTS+1];
 
201
//console message heap
 
202
bot_consolemessage_t *consolemessageheap = NULL;
 
203
bot_consolemessage_t *freeconsolemessages = NULL;
 
204
//list with match strings
 
205
bot_matchtemplate_t *matchtemplates = NULL;
 
206
//list with synonyms
 
207
bot_synonymlist_t *synonyms = NULL;
 
208
//list with random strings
 
209
bot_randomlist_t *randomstrings = NULL;
 
210
//reply chats
 
211
bot_replychat_t *replychats = NULL;
 
212
 
 
213
//========================================================================
 
214
//
 
215
// Parameter:                           -
 
216
// Returns:                                     -
 
217
// Changes Globals:             -
 
218
//========================================================================
 
219
bot_chatstate_t *BotChatStateFromHandle(int handle)
 
220
{
 
221
        if (handle <= 0 || handle > MAX_CLIENTS)
 
222
        {
 
223
                botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
 
224
                return NULL;
 
225
        } //end if
 
226
        if (!botchatstates[handle])
 
227
        {
 
228
                botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
 
229
                return NULL;
 
230
        } //end if
 
231
        return botchatstates[handle];
 
232
} //end of the function BotChatStateFromHandle
 
233
//===========================================================================
 
234
// initialize the heap with unused console messages
 
235
//
 
236
// Parameter:                           -
 
237
// Returns:                                     -
 
238
// Changes Globals:             -
 
239
//===========================================================================
 
240
void InitConsoleMessageHeap(void)
 
241
{
 
242
        int i, max_messages;
 
243
 
 
244
        if (consolemessageheap) FreeMemory(consolemessageheap);
 
245
        //
 
246
        max_messages = (int) LibVarValue("max_messages", "1024");
 
247
        consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages *
 
248
                                                                                                sizeof(bot_consolemessage_t));
 
249
        consolemessageheap[0].prev = NULL;
 
250
        consolemessageheap[0].next = &consolemessageheap[1];
 
251
        for (i = 1; i < max_messages-1; i++)
 
252
        {
 
253
                consolemessageheap[i].prev = &consolemessageheap[i - 1];
 
254
                consolemessageheap[i].next = &consolemessageheap[i + 1];
 
255
        } //end for
 
256
        consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2];
 
257
        consolemessageheap[max_messages-1].next = NULL;
 
258
        //pointer to the free console messages
 
259
        freeconsolemessages = consolemessageheap;
 
260
} //end of the function InitConsoleMessageHeap
 
261
//===========================================================================
 
262
// allocate one console message from the heap
 
263
//
 
264
// Parameter:                           -
 
265
// Returns:                                     -
 
266
// Changes Globals:             -
 
267
//===========================================================================
 
268
bot_consolemessage_t *AllocConsoleMessage(void)
 
269
{
 
270
        bot_consolemessage_t *message;
 
271
        message = freeconsolemessages;
 
272
        if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next;
 
273
        if (freeconsolemessages) freeconsolemessages->prev = NULL;
 
274
        return message;
 
275
} //end of the function AllocConsoleMessage
 
276
//===========================================================================
 
277
// deallocate one console message from the heap
 
278
//
 
279
// Parameter:                           -
 
280
// Returns:                                     -
 
281
// Changes Globals:             -
 
282
//===========================================================================
 
283
void FreeConsoleMessage(bot_consolemessage_t *message)
 
284
{
 
285
        if (freeconsolemessages) freeconsolemessages->prev = message;
 
286
        message->prev = NULL;
 
287
        message->next = freeconsolemessages;
 
288
        freeconsolemessages = message;
 
289
} //end of the function FreeConsoleMessage
 
290
//===========================================================================
 
291
//
 
292
// Parameter:                           -
 
293
// Returns:                                     -
 
294
// Changes Globals:             -
 
295
//===========================================================================
 
296
void BotRemoveConsoleMessage(int chatstate, int handle)
 
297
{
 
298
        bot_consolemessage_t *m, *nextm;
 
299
        bot_chatstate_t *cs;
 
300
 
 
301
        cs = BotChatStateFromHandle(chatstate);
 
302
        if (!cs) return;
 
303
 
 
304
        for (m = cs->firstmessage; m; m = nextm)
 
305
        {
 
306
                nextm = m->next;
 
307
                if (m->handle == handle)
 
308
                {
 
309
                        if (m->next) m->next->prev = m->prev;
 
310
                        else cs->lastmessage = m->prev;
 
311
                        if (m->prev) m->prev->next = m->next;
 
312
                        else cs->firstmessage = m->next;
 
313
 
 
314
                        FreeConsoleMessage(m);
 
315
                        cs->numconsolemessages--;
 
316
                        break;
 
317
                } //end if
 
318
        } //end for
 
319
} //end of the function BotRemoveConsoleMessage
 
320
//===========================================================================
 
321
//
 
322
// Parameter:                           -
 
323
// Returns:                                     -
 
324
// Changes Globals:             -
 
325
//===========================================================================
 
326
void BotQueueConsoleMessage(int chatstate, int type, char *message)
 
327
{
 
328
        bot_consolemessage_t *m;
 
329
        bot_chatstate_t *cs;
 
330
 
 
331
        cs = BotChatStateFromHandle(chatstate);
 
332
        if (!cs) return;
 
333
 
 
334
        m = AllocConsoleMessage();
 
335
        if (!m)
 
336
        {
 
337
                botimport.Print(PRT_ERROR, "empty console message heap\n");
 
338
                return;
 
339
        } //end if
 
340
        cs->handle++;
 
341
        if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1;
 
342
        m->handle = cs->handle;
 
343
        m->time = AAS_Time();
 
344
        m->type = type;
 
345
        strncpy(m->message, message, MAX_MESSAGE_SIZE);
 
346
        m->next = NULL;
 
347
        if (cs->lastmessage)
 
348
        {
 
349
                cs->lastmessage->next = m;
 
350
                m->prev = cs->lastmessage;
 
351
                cs->lastmessage = m;
 
352
        } //end if
 
353
        else
 
354
        {
 
355
                cs->lastmessage = m;
 
356
                cs->firstmessage = m;
 
357
                m->prev = NULL;
 
358
        } //end if
 
359
        cs->numconsolemessages++;
 
360
} //end of the function BotQueueConsoleMessage
 
361
//===========================================================================
 
362
//
 
363
// Parameter:                           -
 
364
// Returns:                                     -
 
365
// Changes Globals:             -
 
366
//===========================================================================
 
367
int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm)
 
368
{
 
369
        bot_chatstate_t *cs;
 
370
 
 
371
        cs = BotChatStateFromHandle(chatstate);
 
372
        if (!cs) return 0;
 
373
        if (cs->firstmessage)
 
374
        {
 
375
                Com_Memcpy(cm, cs->firstmessage, sizeof(bot_consolemessage_t));
 
376
                cm->next = cm->prev = NULL;
 
377
                return cm->handle;
 
378
        } //end if
 
379
        return 0;
 
380
} //end of the function BotConsoleMessage
 
381
//===========================================================================
 
382
//
 
383
// Parameter:                           -
 
384
// Returns:                                     -
 
385
// Changes Globals:             -
 
386
//===========================================================================
 
387
int BotNumConsoleMessages(int chatstate)
 
388
{
 
389
        bot_chatstate_t *cs;
 
390
 
 
391
        cs = BotChatStateFromHandle(chatstate);
 
392
        if (!cs) return 0;
 
393
        return cs->numconsolemessages;
 
394
} //end of the function BotNumConsoleMessages
 
395
//===========================================================================
 
396
//
 
397
// Parameter:                           -
 
398
// Returns:                                     -
 
399
// Changes Globals:             -
 
400
//===========================================================================
 
401
int IsWhiteSpace(char c)
 
402
{
 
403
        if ((c >= 'a' && c <= 'z')
 
404
                || (c >= 'A' && c <= 'Z')
 
405
                || (c >= '0' && c <= '9')
 
406
                || c == '(' || c == ')'
 
407
                || c == '?' || c == ':'
 
408
                || c == '\''|| c == '/'
 
409
                || c == ',' || c == '.'
 
410
                || c == '['     || c == ']'
 
411
                || c == '-' || c == '_'
 
412
                || c == '+' || c == '=') return qfalse;
 
413
        return qtrue;
 
414
} //end of the function IsWhiteSpace
 
415
//===========================================================================
 
416
//
 
417
// Parameter:                   -
 
418
// Returns:                             -
 
419
// Changes Globals:             -
 
420
//===========================================================================
 
421
void BotRemoveTildes(char *message)
 
422
{
 
423
        int i;
 
424
 
 
425
        //remove all tildes from the chat message
 
426
        for (i = 0; message[i]; i++)
 
427
        {
 
428
                if (message[i] == '~')
 
429
                {
 
430
                        memmove(&message[i], &message[i+1], strlen(&message[i+1])+1);
 
431
                } //end if
 
432
        } //end for
 
433
} //end of the function BotRemoveTildes
 
434
//===========================================================================
 
435
//
 
436
// Parameter:                           -
 
437
// Returns:                                     -
 
438
// Changes Globals:             -
 
439
//===========================================================================
 
440
void UnifyWhiteSpaces(char *string)
 
441
{
 
442
        char *ptr, *oldptr;
 
443
 
 
444
        for (ptr = oldptr = string; *ptr; oldptr = ptr)
 
445
        {
 
446
                while(*ptr && IsWhiteSpace(*ptr)) ptr++;
 
447
                if (ptr > oldptr)
 
448
                {
 
449
                        //if not at the start and not at the end of the string
 
450
                        //write only one space
 
451
                        if (oldptr > string && *ptr) *oldptr++ = ' ';
 
452
                        //remove all other white spaces
 
453
                        if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1);
 
454
                } //end if
 
455
                while(*ptr && !IsWhiteSpace(*ptr)) ptr++;
 
456
        } //end while
 
457
} //end of the function UnifyWhiteSpaces
 
458
//===========================================================================
 
459
//
 
460
// Parameter:                           -
 
461
// Returns:                                     -
 
462
// Changes Globals:             -
 
463
//===========================================================================
 
464
int StringContains(char *str1, char *str2, int casesensitive)
 
465
{
 
466
        int len, i, j, index;
 
467
 
 
468
        if (str1 == NULL || str2 == NULL) return -1;
 
469
 
 
470
        len = strlen(str1) - strlen(str2);
 
471
        index = 0;
 
472
        for (i = 0; i <= len; i++, str1++, index++)
 
473
        {
 
474
                for (j = 0; str2[j]; j++)
 
475
                {
 
476
                        if (casesensitive)
 
477
                        {
 
478
                                if (str1[j] != str2[j]) break;
 
479
                        } //end if
 
480
                        else
 
481
                        {
 
482
                                if (toupper(str1[j]) != toupper(str2[j])) break;
 
483
                        } //end else
 
484
                } //end for
 
485
                if (!str2[j]) return index;
 
486
        } //end for
 
487
        return -1;
 
488
} //end of the function StringContains
 
489
//===========================================================================
 
490
//
 
491
// Parameter:                           -
 
492
// Returns:                                     -
 
493
// Changes Globals:             -
 
494
//===========================================================================
 
495
char *StringContainsWord(char *str1, char *str2, int casesensitive)
 
496
{
 
497
        int len, i, j;
 
498
 
 
499
        len = strlen(str1) - strlen(str2);
 
500
        for (i = 0; i <= len; i++, str1++)
 
501
        {
 
502
                //if not at the start of the string
 
503
                if (i)
 
504
                {
 
505
                        //skip to the start of the next word
 
506
                        while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++;
 
507
                        if (!*str1) break;
 
508
                        str1++;
 
509
                } //end for
 
510
                //compare the word
 
511
                for (j = 0; str2[j]; j++)
 
512
                {
 
513
                        if (casesensitive)
 
514
                        {
 
515
                                if (str1[j] != str2[j]) break;
 
516
                        } //end if
 
517
                        else
 
518
                        {
 
519
                                if (toupper(str1[j]) != toupper(str2[j])) break;
 
520
                        } //end else
 
521
                } //end for
 
522
                //if there was a word match
 
523
                if (!str2[j])
 
524
                {
 
525
                        //if the first string has an end of word
 
526
                        if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1;
 
527
                } //end if
 
528
        } //end for
 
529
        return NULL;
 
530
} //end of the function StringContainsWord
 
531
//===========================================================================
 
532
//
 
533
// Parameter:                           -
 
534
// Returns:                                     -
 
535
// Changes Globals:             -
 
536
//===========================================================================
 
537
void StringReplaceWords(char *string, char *synonym, char *replacement)
 
538
{
 
539
        char *str, *str2;
 
540
 
 
541
        //find the synonym in the string
 
542
        str = StringContainsWord(string, synonym, qfalse);
 
543
        //if the synonym occured in the string
 
544
        while(str)
 
545
        {
 
546
                //if the synonym isn't part of the replacement which is already in the string
 
547
                //usefull for abreviations
 
548
                str2 = StringContainsWord(string, replacement, qfalse);
 
549
                while(str2)
 
550
                {
 
551
                        if (str2 <= str && str < str2 + strlen(replacement)) break;
 
552
                        str2 = StringContainsWord(str2+1, replacement, qfalse);
 
553
                } //end while
 
554
                if (!str2)
 
555
                {
 
556
                        memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1);
 
557
                        //append the synonum replacement
 
558
                        Com_Memcpy(str, replacement, strlen(replacement));
 
559
                } //end if
 
560
                //find the next synonym in the string
 
561
                str = StringContainsWord(str+strlen(replacement), synonym, qfalse);
 
562
        } //end if
 
563
} //end of the function StringReplaceWords
 
564
//===========================================================================
 
565
//
 
566
// Parameter:                           -
 
567
// Returns:                                     -
 
568
// Changes Globals:             -
 
569
//===========================================================================
 
570
void BotDumpSynonymList(bot_synonymlist_t *synlist)
 
571
{
 
572
        FILE *fp;
 
573
        bot_synonymlist_t *syn;
 
574
        bot_synonym_t *synonym;
 
575
 
 
576
        fp = Log_FilePointer();
 
577
        if (!fp) return;
 
578
        for (syn = synlist; syn; syn = syn->next)
 
579
        {
 
580
                fprintf(fp, "%ld : [", syn->context);
 
581
                for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
 
582
                {
 
583
                        fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight);
 
584
                        if (synonym->next) fprintf(fp, ", ");
 
585
                } //end for
 
586
                fprintf(fp, "]\n");
 
587
        } //end for
 
588
} //end of the function BotDumpSynonymList
 
589
//===========================================================================
 
590
//
 
591
// Parameter:                           -
 
592
// Returns:                                     -
 
593
// Changes Globals:             -
 
594
//===========================================================================
 
595
bot_synonymlist_t *BotLoadSynonyms(char *filename)
 
596
{
 
597
        int pass, size, contextlevel, numsynonyms;
 
598
        unsigned long int context, contextstack[32];
 
599
        char *ptr = NULL;
 
600
        source_t *source;
 
601
        token_t token;
 
602
        bot_synonymlist_t *synlist, *lastsyn, *syn;
 
603
        bot_synonym_t *synonym, *lastsynonym;
 
604
 
 
605
        size = 0;
 
606
        synlist = NULL; //make compiler happy
 
607
        syn = NULL; //make compiler happy
 
608
        synonym = NULL; //make compiler happy
 
609
        //the synonyms are parsed in two phases
 
610
        for (pass = 0; pass < 2; pass++)
 
611
        {
 
612
                //
 
613
                if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
 
614
                //
 
615
                PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
616
                source = LoadSourceFile(filename);
 
617
                if (!source)
 
618
                {
 
619
                        botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
 
620
                        return NULL;
 
621
                } //end if
 
622
                //
 
623
                context = 0;
 
624
                contextlevel = 0;
 
625
                synlist = NULL; //list synonyms
 
626
                lastsyn = NULL; //last synonym in the list
 
627
                //
 
628
                while(PC_ReadToken(source, &token))
 
629
                {
 
630
                        if (token.type == TT_NUMBER)
 
631
                        {
 
632
                                context |= token.intvalue;
 
633
                                contextstack[contextlevel] = token.intvalue;
 
634
                                contextlevel++;
 
635
                                if (contextlevel >= 32)
 
636
                                {
 
637
                                        SourceError(source, "more than 32 context levels");
 
638
                                        FreeSource(source);
 
639
                                        return NULL;
 
640
                                } //end if
 
641
                                if (!PC_ExpectTokenString(source, "{"))
 
642
                                {
 
643
                                        FreeSource(source);
 
644
                                        return NULL;
 
645
                                } //end if
 
646
                        } //end if
 
647
                        else if (token.type == TT_PUNCTUATION)
 
648
                        {
 
649
                                if (!strcmp(token.string, "}"))
 
650
                                {
 
651
                                        contextlevel--;
 
652
                                        if (contextlevel < 0)
 
653
                                        {
 
654
                                                SourceError(source, "too many }");
 
655
                                                FreeSource(source);
 
656
                                                return NULL;
 
657
                                        } //end if
 
658
                                        context &= ~contextstack[contextlevel];
 
659
                                } //end if
 
660
                                else if (!strcmp(token.string, "["))
 
661
                                {
 
662
                                        size += sizeof(bot_synonymlist_t);
 
663
                                        if (pass)
 
664
                                        {
 
665
                                                syn = (bot_synonymlist_t *) ptr;
 
666
                                                ptr += sizeof(bot_synonymlist_t);
 
667
                                                syn->context = context;
 
668
                                                syn->firstsynonym = NULL;
 
669
                                                syn->next = NULL;
 
670
                                                if (lastsyn) lastsyn->next = syn;
 
671
                                                else synlist = syn;
 
672
                                                lastsyn = syn;
 
673
                                        } //end if
 
674
                                        numsynonyms = 0;
 
675
                                        lastsynonym = NULL;
 
676
                                        while(1)
 
677
                                        {
 
678
                                                size_t len;
 
679
                                                if (!PC_ExpectTokenString(source, "(") ||
 
680
                                                        !PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
681
                                                {
 
682
                                                        FreeSource(source);
 
683
                                                        return NULL;
 
684
                                                } //end if
 
685
                                                StripDoubleQuotes(token.string);
 
686
                                                if (strlen(token.string) <= 0)
 
687
                                                {
 
688
                                                        SourceError(source, "empty string", token.string);
 
689
                                                        FreeSource(source);
 
690
                                                        return NULL;
 
691
                                                } //end if
 
692
                                                len = strlen(token.string) + 1;
 
693
                                                len = PAD(len, sizeof(long));
 
694
                                                size += sizeof(bot_synonym_t) + len;
 
695
                                                if (pass)
 
696
                                                {
 
697
                                                        synonym = (bot_synonym_t *) ptr;
 
698
                                                        ptr += sizeof(bot_synonym_t);
 
699
                                                        synonym->string = ptr;
 
700
                                                        ptr += len;
 
701
                                                        strcpy(synonym->string, token.string);
 
702
                                                        //
 
703
                                                        if (lastsynonym) lastsynonym->next = synonym;
 
704
                                                        else syn->firstsynonym = synonym;
 
705
                                                        lastsynonym = synonym;
 
706
                                                } //end if
 
707
                                                numsynonyms++;
 
708
                                                if (!PC_ExpectTokenString(source, ",") ||
 
709
                                                        !PC_ExpectTokenType(source, TT_NUMBER, 0, &token) ||
 
710
                                                        !PC_ExpectTokenString(source, ")"))
 
711
                                                {
 
712
                                                        FreeSource(source);
 
713
                                                        return NULL;
 
714
                                                } //end if
 
715
                                                if (pass)
 
716
                                                {
 
717
                                                        synonym->weight = token.floatvalue;
 
718
                                                        syn->totalweight += synonym->weight;
 
719
                                                } //end if
 
720
                                                if (PC_CheckTokenString(source, "]")) break;
 
721
                                                if (!PC_ExpectTokenString(source, ","))
 
722
                                                {
 
723
                                                        FreeSource(source);
 
724
                                                        return NULL;
 
725
                                                } //end if
 
726
                                        } //end while
 
727
                                        if (numsynonyms < 2)
 
728
                                        {
 
729
                                                SourceError(source, "synonym must have at least two entries\n");
 
730
                                                FreeSource(source);
 
731
                                                return NULL;
 
732
                                        } //end if
 
733
                                } //end else
 
734
                                else
 
735
                                {
 
736
                                        SourceError(source, "unexpected %s", token.string);
 
737
                                        FreeSource(source);
 
738
                                        return NULL;
 
739
                                } //end if
 
740
                        } //end else if
 
741
                } //end while
 
742
                //
 
743
                FreeSource(source);
 
744
                //
 
745
                if (contextlevel > 0)
 
746
                {
 
747
                        SourceError(source, "missing }");
 
748
                        return NULL;
 
749
                } //end if
 
750
        } //end for
 
751
        botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
 
752
        //
 
753
        //BotDumpSynonymList(synlist);
 
754
        //
 
755
        return synlist;
 
756
} //end of the function BotLoadSynonyms
 
757
//===========================================================================
 
758
// replace all the synonyms in the string
 
759
//
 
760
// Parameter:                           -
 
761
// Returns:                                     -
 
762
// Changes Globals:             -
 
763
//===========================================================================
 
764
void BotReplaceSynonyms(char *string, unsigned long int context)
 
765
{
 
766
        bot_synonymlist_t *syn;
 
767
        bot_synonym_t *synonym;
 
768
 
 
769
        for (syn = synonyms; syn; syn = syn->next)
 
770
        {
 
771
                if (!(syn->context & context)) continue;
 
772
                for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
 
773
                {
 
774
                        StringReplaceWords(string, synonym->string, syn->firstsynonym->string);
 
775
                } //end for
 
776
        } //end for
 
777
} //end of the function BotReplaceSynonyms
 
778
//===========================================================================
 
779
//
 
780
// Parameter:                           -
 
781
// Returns:                                     -
 
782
// Changes Globals:             -
 
783
//===========================================================================
 
784
void BotReplaceWeightedSynonyms(char *string, unsigned long int context)
 
785
{
 
786
        bot_synonymlist_t *syn;
 
787
        bot_synonym_t *synonym, *replacement;
 
788
        float weight, curweight;
 
789
 
 
790
        for (syn = synonyms; syn; syn = syn->next)
 
791
        {
 
792
                if (!(syn->context & context)) continue;
 
793
                //choose a weighted random replacement synonym
 
794
                weight = random() * syn->totalweight;
 
795
                if (!weight) continue;
 
796
                curweight = 0;
 
797
                for (replacement = syn->firstsynonym; replacement; replacement = replacement->next)
 
798
                {
 
799
                        curweight += replacement->weight;
 
800
                        if (weight < curweight) break;
 
801
                } //end for
 
802
                if (!replacement) continue;
 
803
                //replace all synonyms with the replacement
 
804
                for (synonym = syn->firstsynonym; synonym; synonym = synonym->next)
 
805
                {
 
806
                        if (synonym == replacement) continue;
 
807
                        StringReplaceWords(string, synonym->string, replacement->string);
 
808
                } //end for
 
809
        } //end for
 
810
} //end of the function BotReplaceWeightedSynonyms
 
811
//===========================================================================
 
812
//
 
813
// Parameter:                           -
 
814
// Returns:                                     -
 
815
// Changes Globals:             -
 
816
//===========================================================================
 
817
void BotReplaceReplySynonyms(char *string, unsigned long int context)
 
818
{
 
819
        char *str1, *str2, *replacement;
 
820
        bot_synonymlist_t *syn;
 
821
        bot_synonym_t *synonym;
 
822
 
 
823
        for (str1 = string; *str1; )
 
824
        {
 
825
                //go to the start of the next word
 
826
                while(*str1 && *str1 <= ' ') str1++;
 
827
                if (!*str1) break;
 
828
                //
 
829
                for (syn = synonyms; syn; syn = syn->next)
 
830
                {
 
831
                        if (!(syn->context & context)) continue;
 
832
                        for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next)
 
833
                        {
 
834
                                str2 = synonym->string;
 
835
                                //if the synonym is not at the front of the string continue
 
836
                                str2 = StringContainsWord(str1, synonym->string, qfalse);
 
837
                                if (!str2 || str2 != str1) continue;
 
838
                                //
 
839
                                replacement = syn->firstsynonym->string;
 
840
                                //if the replacement IS in front of the string continue
 
841
                                str2 = StringContainsWord(str1, replacement, qfalse);
 
842
                                if (str2 && str2 == str1) continue;
 
843
                                //
 
844
                                memmove(str1 + strlen(replacement), str1+strlen(synonym->string),
 
845
                                                        strlen(str1+strlen(synonym->string)) + 1);
 
846
                                //append the synonum replacement
 
847
                                Com_Memcpy(str1, replacement, strlen(replacement));
 
848
                                //
 
849
                                break;
 
850
                        } //end for
 
851
                        //if a synonym has been replaced
 
852
                        if (synonym) break;
 
853
                } //end for
 
854
                //skip over this word
 
855
                while(*str1 && *str1 > ' ') str1++;
 
856
                if (!*str1) break;
 
857
        } //end while
 
858
} //end of the function BotReplaceReplySynonyms
 
859
//===========================================================================
 
860
//
 
861
// Parameter:                   -
 
862
// Returns:                             -
 
863
// Changes Globals:             -
 
864
//===========================================================================
 
865
int BotLoadChatMessage(source_t *source, char *chatmessagestring)
 
866
{
 
867
        char *ptr;
 
868
        token_t token;
 
869
 
 
870
        ptr = chatmessagestring;
 
871
        *ptr = 0;
 
872
        //
 
873
        while(1)
 
874
        {
 
875
                if (!PC_ExpectAnyToken(source, &token)) return qfalse;
 
876
                //fixed string
 
877
                if (token.type == TT_STRING)
 
878
                {
 
879
                        StripDoubleQuotes(token.string);
 
880
                        if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE)
 
881
                        {
 
882
                                SourceError(source, "chat message too long\n");
 
883
                                return qfalse;
 
884
                        } //end if
 
885
                        strcat(ptr, token.string);
 
886
                } //end else if
 
887
                //variable string
 
888
                else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
 
889
                {
 
890
                        if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
 
891
                        {
 
892
                                SourceError(source, "chat message too long\n");
 
893
                                return qfalse;
 
894
                        } //end if
 
895
                        sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR);
 
896
                } //end if
 
897
                //random string
 
898
                else if (token.type == TT_NAME)
 
899
                {
 
900
                        if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE)
 
901
                        {
 
902
                                SourceError(source, "chat message too long\n");
 
903
                                return qfalse;
 
904
                        } //end if
 
905
                        sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR);
 
906
                } //end else if
 
907
                else
 
908
                {
 
909
                        SourceError(source, "unknown message component %s\n", token.string);
 
910
                        return qfalse;
 
911
                } //end else
 
912
                if (PC_CheckTokenString(source, ";")) break;
 
913
                if (!PC_ExpectTokenString(source, ",")) return qfalse;
 
914
        } //end while
 
915
        //
 
916
        return qtrue;
 
917
} //end of the function BotLoadChatMessage
 
918
//===========================================================================
 
919
//
 
920
// Parameter:                           -
 
921
// Returns:                                     -
 
922
// Changes Globals:             -
 
923
//===========================================================================
 
924
void BotDumpRandomStringList(bot_randomlist_t *randomlist)
 
925
{
 
926
        FILE *fp;
 
927
        bot_randomlist_t *random;
 
928
        bot_randomstring_t *rs;
 
929
 
 
930
        fp = Log_FilePointer();
 
931
        if (!fp) return;
 
932
        for (random = randomlist; random; random = random->next)
 
933
        {
 
934
                fprintf(fp, "%s = {", random->string);
 
935
                for (rs = random->firstrandomstring; rs; rs = rs->next)
 
936
                {
 
937
                        fprintf(fp, "\"%s\"", rs->string);
 
938
                        if (rs->next) fprintf(fp, ", ");
 
939
                        else fprintf(fp, "}\n");
 
940
                } //end for
 
941
        } //end for
 
942
} //end of the function BotDumpRandomStringList
 
943
//===========================================================================
 
944
//
 
945
// Parameter:                           -
 
946
// Returns:                                     -
 
947
// Changes Globals:             -
 
948
//===========================================================================
 
949
bot_randomlist_t *BotLoadRandomStrings(char *filename)
 
950
{
 
951
        int pass, size;
 
952
        char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE];
 
953
        source_t *source;
 
954
        token_t token;
 
955
        bot_randomlist_t *randomlist, *lastrandom, *random;
 
956
        bot_randomstring_t *randomstring;
 
957
 
 
958
#ifdef DEBUG
 
959
        int starttime = Sys_MilliSeconds();
 
960
#endif //DEBUG
 
961
 
 
962
        size = 0;
 
963
        randomlist = NULL;
 
964
        random = NULL;
 
965
        //the synonyms are parsed in two phases
 
966
        for (pass = 0; pass < 2; pass++)
 
967
        {
 
968
                //
 
969
                if (pass && size) ptr = (char *) GetClearedHunkMemory(size);
 
970
                //
 
971
                PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
972
                source = LoadSourceFile(filename);
 
973
                if (!source)
 
974
                {
 
975
                        botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
 
976
                        return NULL;
 
977
                } //end if
 
978
                //
 
979
                randomlist = NULL; //list
 
980
                lastrandom = NULL; //last
 
981
                //
 
982
                while(PC_ReadToken(source, &token))
 
983
                {
 
984
                        size_t len;
 
985
                        if (token.type != TT_NAME)
 
986
                        {
 
987
                                SourceError(source, "unknown random %s", token.string);
 
988
                                FreeSource(source);
 
989
                                return NULL;
 
990
                        } //end if
 
991
                        len = strlen(token.string) + 1;
 
992
                        len = PAD(len, sizeof(long));
 
993
                        size += sizeof(bot_randomlist_t) + len;
 
994
                        if (pass)
 
995
                        {
 
996
                                random = (bot_randomlist_t *) ptr;
 
997
                                ptr += sizeof(bot_randomlist_t);
 
998
                                random->string = ptr;
 
999
                                ptr += len;
 
1000
                                strcpy(random->string, token.string);
 
1001
                                random->firstrandomstring = NULL;
 
1002
                                random->numstrings = 0;
 
1003
                                //
 
1004
                                if (lastrandom) lastrandom->next = random;
 
1005
                                else randomlist = random;
 
1006
                                lastrandom = random;
 
1007
                        } //end if
 
1008
                        if (!PC_ExpectTokenString(source, "=") ||
 
1009
                                !PC_ExpectTokenString(source, "{"))
 
1010
                        {
 
1011
                                FreeSource(source);
 
1012
                                return NULL;
 
1013
                        } //end if
 
1014
                        while(!PC_CheckTokenString(source, "}"))
 
1015
                        {
 
1016
                                size_t len;
 
1017
                                if (!BotLoadChatMessage(source, chatmessagestring))
 
1018
                                {
 
1019
                                        FreeSource(source);
 
1020
                                        return NULL;
 
1021
                                } //end if
 
1022
                                len = strlen(chatmessagestring) + 1;
 
1023
                                len = PAD(len, sizeof(long));
 
1024
                                size += sizeof(bot_randomstring_t) + len;
 
1025
                                if (pass)
 
1026
                                {
 
1027
                                        randomstring = (bot_randomstring_t *) ptr;
 
1028
                                        ptr += sizeof(bot_randomstring_t);
 
1029
                                        randomstring->string = ptr;
 
1030
                                        ptr += len;
 
1031
                                        strcpy(randomstring->string, chatmessagestring);
 
1032
                                        //
 
1033
                                        random->numstrings++;
 
1034
                                        randomstring->next = random->firstrandomstring;
 
1035
                                        random->firstrandomstring = randomstring;
 
1036
                                } //end if
 
1037
                        } //end while
 
1038
                } //end while
 
1039
                //free the source after one pass
 
1040
                FreeSource(source);
 
1041
        } //end for
 
1042
        botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
 
1043
        //
 
1044
#ifdef DEBUG
 
1045
        botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime);
 
1046
        //BotDumpRandomStringList(randomlist);
 
1047
#endif //DEBUG
 
1048
        //
 
1049
        return randomlist;
 
1050
} //end of the function BotLoadRandomStrings
 
1051
//===========================================================================
 
1052
//
 
1053
// Parameter:                           -
 
1054
// Returns:                                     -
 
1055
// Changes Globals:             -
 
1056
//===========================================================================
 
1057
char *RandomString(char *name)
 
1058
{
 
1059
        bot_randomlist_t *random;
 
1060
        bot_randomstring_t *rs;
 
1061
        int i;
 
1062
 
 
1063
        for (random = randomstrings; random; random = random->next)
 
1064
        {
 
1065
                if (!strcmp(random->string, name))
 
1066
                {
 
1067
                        i = random() * random->numstrings;
 
1068
                        for (rs = random->firstrandomstring; rs; rs = rs->next)
 
1069
                        {
 
1070
                                if (--i < 0) break;
 
1071
                        } //end for
 
1072
                        if (rs)
 
1073
                        {
 
1074
                                return rs->string;
 
1075
                        } //end if
 
1076
                } //end for
 
1077
        } //end for
 
1078
        return NULL;
 
1079
} //end of the function RandomString
 
1080
//===========================================================================
 
1081
//
 
1082
// Parameter:                           -
 
1083
// Returns:                                     -
 
1084
// Changes Globals:             -
 
1085
//===========================================================================
 
1086
void BotDumpMatchTemplates(bot_matchtemplate_t *matches)
 
1087
{
 
1088
        FILE *fp;
 
1089
        bot_matchtemplate_t *mt;
 
1090
        bot_matchpiece_t *mp;
 
1091
        bot_matchstring_t *ms;
 
1092
 
 
1093
        fp = Log_FilePointer();
 
1094
        if (!fp) return;
 
1095
        for (mt = matches; mt; mt = mt->next)
 
1096
        {
 
1097
                fprintf(fp, "{ " );
 
1098
                for (mp = mt->first; mp; mp = mp->next)
 
1099
                {
 
1100
                        if (mp->type == MT_STRING)
 
1101
                        {
 
1102
                                for (ms = mp->firststring; ms; ms = ms->next)
 
1103
                                {
 
1104
                                        fprintf(fp, "\"%s\"", ms->string);
 
1105
                                        if (ms->next) fprintf(fp, "|");
 
1106
                                } //end for
 
1107
                        } //end if
 
1108
                        else if (mp->type == MT_VARIABLE)
 
1109
                        {
 
1110
                                fprintf(fp, "%d", mp->variable);
 
1111
                        } //end else if
 
1112
                        if (mp->next) fprintf(fp, ", ");
 
1113
                } //end for
 
1114
                fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype);
 
1115
        } //end for
 
1116
} //end of the function BotDumpMatchTemplates
 
1117
//===========================================================================
 
1118
//
 
1119
// Parameter:                           -
 
1120
// Returns:                                     -
 
1121
// Changes Globals:             -
 
1122
//===========================================================================
 
1123
void BotFreeMatchPieces(bot_matchpiece_t *matchpieces)
 
1124
{
 
1125
        bot_matchpiece_t *mp, *nextmp;
 
1126
        bot_matchstring_t *ms, *nextms;
 
1127
 
 
1128
        for (mp = matchpieces; mp; mp = nextmp)
 
1129
        {
 
1130
                nextmp = mp->next;
 
1131
                if (mp->type == MT_STRING)
 
1132
                {
 
1133
                        for (ms = mp->firststring; ms; ms = nextms)
 
1134
                        {
 
1135
                                nextms = ms->next;
 
1136
                                FreeMemory(ms);
 
1137
                        } //end for
 
1138
                } //end if
 
1139
                FreeMemory(mp);
 
1140
        } //end for
 
1141
} //end of the function BotFreeMatchPieces
 
1142
//===========================================================================
 
1143
//
 
1144
// Parameter:                           -
 
1145
// Returns:                                     -
 
1146
// Changes Globals:             -
 
1147
//===========================================================================
 
1148
bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken)
 
1149
{
 
1150
        int lastwasvariable, emptystring;
 
1151
        token_t token;
 
1152
        bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece;
 
1153
        bot_matchstring_t *matchstring, *lastmatchstring;
 
1154
 
 
1155
        firstpiece = NULL;
 
1156
        lastpiece = NULL;
 
1157
        //
 
1158
        lastwasvariable = qfalse;
 
1159
        //
 
1160
        while(PC_ReadToken(source, &token))
 
1161
        {
 
1162
                if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER))
 
1163
                {
 
1164
                        if (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES)
 
1165
                        {
 
1166
                                SourceError(source, "can't have more than %d match variables\n", MAX_MATCHVARIABLES);
 
1167
                                FreeSource(source);
 
1168
                                BotFreeMatchPieces(firstpiece);
 
1169
                                return NULL;
 
1170
                        } //end if
 
1171
                        if (lastwasvariable)
 
1172
                        {
 
1173
                                SourceError(source, "not allowed to have adjacent variables\n");
 
1174
                                FreeSource(source);
 
1175
                                BotFreeMatchPieces(firstpiece);
 
1176
                                return NULL;
 
1177
                        } //end if
 
1178
                        lastwasvariable = qtrue;
 
1179
                        //
 
1180
                        matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
 
1181
                        matchpiece->type = MT_VARIABLE;
 
1182
                        matchpiece->variable = token.intvalue;
 
1183
                        matchpiece->next = NULL;
 
1184
                        if (lastpiece) lastpiece->next = matchpiece;
 
1185
                        else firstpiece = matchpiece;
 
1186
                        lastpiece = matchpiece;
 
1187
                } //end if
 
1188
                else if (token.type == TT_STRING)
 
1189
                {
 
1190
                        //
 
1191
                        matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t));
 
1192
                        matchpiece->firststring = NULL;
 
1193
                        matchpiece->type = MT_STRING;
 
1194
                        matchpiece->variable = 0;
 
1195
                        matchpiece->next = NULL;
 
1196
                        if (lastpiece) lastpiece->next = matchpiece;
 
1197
                        else firstpiece = matchpiece;
 
1198
                        lastpiece = matchpiece;
 
1199
                        //
 
1200
                        lastmatchstring = NULL;
 
1201
                        emptystring = qfalse;
 
1202
                        //
 
1203
                        do
 
1204
                        {
 
1205
                                if (matchpiece->firststring)
 
1206
                                {
 
1207
                                        if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
1208
                                        {
 
1209
                                                FreeSource(source);
 
1210
                                                BotFreeMatchPieces(firstpiece);
 
1211
                                                return NULL;
 
1212
                                        } //end if
 
1213
                                } //end if
 
1214
                                StripDoubleQuotes(token.string);
 
1215
                                matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1);
 
1216
                                matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t);
 
1217
                                strcpy(matchstring->string, token.string);
 
1218
                                if (!strlen(token.string)) emptystring = qtrue;
 
1219
                                matchstring->next = NULL;
 
1220
                                if (lastmatchstring) lastmatchstring->next = matchstring;
 
1221
                                else matchpiece->firststring = matchstring;
 
1222
                                lastmatchstring = matchstring;
 
1223
                        } while(PC_CheckTokenString(source, "|"));
 
1224
                        //if there was no empty string found
 
1225
                        if (!emptystring) lastwasvariable = qfalse;
 
1226
                } //end if
 
1227
                else
 
1228
                {
 
1229
                        SourceError(source, "invalid token %s\n", token.string);
 
1230
                        FreeSource(source);
 
1231
                        BotFreeMatchPieces(firstpiece);
 
1232
                        return NULL;
 
1233
                } //end else
 
1234
                if (PC_CheckTokenString(source, endtoken)) break;
 
1235
                if (!PC_ExpectTokenString(source, ","))
 
1236
                {
 
1237
                        FreeSource(source);
 
1238
                        BotFreeMatchPieces(firstpiece);
 
1239
                        return NULL;
 
1240
                } //end if
 
1241
        } //end while
 
1242
        return firstpiece;
 
1243
} //end of the function BotLoadMatchPieces
 
1244
//===========================================================================
 
1245
//
 
1246
// Parameter:                           -
 
1247
// Returns:                                     -
 
1248
// Changes Globals:             -
 
1249
//===========================================================================
 
1250
void BotFreeMatchTemplates(bot_matchtemplate_t *mt)
 
1251
{
 
1252
        bot_matchtemplate_t *nextmt;
 
1253
 
 
1254
        for (; mt; mt = nextmt)
 
1255
        {
 
1256
                nextmt = mt->next;
 
1257
                BotFreeMatchPieces(mt->first);
 
1258
                FreeMemory(mt);
 
1259
        } //end for
 
1260
} //end of the function BotFreeMatchTemplates
 
1261
//===========================================================================
 
1262
//
 
1263
// Parameter:                           -
 
1264
// Returns:                                     -
 
1265
// Changes Globals:             -
 
1266
//===========================================================================
 
1267
bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile)
 
1268
{
 
1269
        source_t *source;
 
1270
        token_t token;
 
1271
        bot_matchtemplate_t *matchtemplate, *matches, *lastmatch;
 
1272
        unsigned long int context;
 
1273
 
 
1274
        PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
1275
        source = LoadSourceFile(matchfile);
 
1276
        if (!source)
 
1277
        {
 
1278
                botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile);
 
1279
                return NULL;
 
1280
        } //end if
 
1281
        //
 
1282
        matches = NULL; //list with matches
 
1283
        lastmatch = NULL; //last match in the list
 
1284
 
 
1285
        while(PC_ReadToken(source, &token))
 
1286
        {
 
1287
                if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))
 
1288
                {
 
1289
                        SourceError(source, "expected integer, found %s\n", token.string);
 
1290
                        BotFreeMatchTemplates(matches);
 
1291
                        FreeSource(source);
 
1292
                        return NULL;
 
1293
                } //end if
 
1294
                //the context
 
1295
                context = token.intvalue;
 
1296
                //
 
1297
                if (!PC_ExpectTokenString(source, "{"))
 
1298
                {
 
1299
                        BotFreeMatchTemplates(matches);
 
1300
                        FreeSource(source);
 
1301
                        return NULL;
 
1302
                } //end if
 
1303
                //
 
1304
                while(PC_ReadToken(source, &token))
 
1305
                {
 
1306
                        if (!strcmp(token.string, "}")) break;
 
1307
                        //
 
1308
                        PC_UnreadLastToken(source);
 
1309
                        //
 
1310
                        matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t));
 
1311
                        matchtemplate->context = context;
 
1312
                        matchtemplate->next = NULL;
 
1313
                        //add the match template to the list
 
1314
                        if (lastmatch) lastmatch->next = matchtemplate;
 
1315
                        else matches = matchtemplate;
 
1316
                        lastmatch = matchtemplate;
 
1317
                        //load the match template
 
1318
                        matchtemplate->first = BotLoadMatchPieces(source, "=");
 
1319
                        if (!matchtemplate->first)
 
1320
                        {
 
1321
                                BotFreeMatchTemplates(matches);
 
1322
                                return NULL;
 
1323
                        } //end if
 
1324
                        //read the match type
 
1325
                        if (!PC_ExpectTokenString(source, "(") ||
 
1326
                                !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
 
1327
                        {
 
1328
                                BotFreeMatchTemplates(matches);
 
1329
                                FreeSource(source);
 
1330
                                return NULL;
 
1331
                        } //end if
 
1332
                        matchtemplate->type = token.intvalue;
 
1333
                        //read the match subtype
 
1334
                        if (!PC_ExpectTokenString(source, ",") ||
 
1335
                                !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
 
1336
                        {
 
1337
                                BotFreeMatchTemplates(matches);
 
1338
                                FreeSource(source);
 
1339
                                return NULL;
 
1340
                        } //end if
 
1341
                        matchtemplate->subtype = token.intvalue;
 
1342
                        //read trailing punctuations
 
1343
                        if (!PC_ExpectTokenString(source, ")") ||
 
1344
                                !PC_ExpectTokenString(source, ";"))
 
1345
                        {
 
1346
                                BotFreeMatchTemplates(matches);
 
1347
                                FreeSource(source);
 
1348
                                return NULL;
 
1349
                        } //end if
 
1350
                } //end while
 
1351
        } //end while
 
1352
        //free the source
 
1353
        FreeSource(source);
 
1354
        botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile);
 
1355
        //
 
1356
        //BotDumpMatchTemplates(matches);
 
1357
        //
 
1358
        return matches;
 
1359
} //end of the function BotLoadMatchTemplates
 
1360
//===========================================================================
 
1361
//
 
1362
// Parameter:                           -
 
1363
// Returns:                                     -
 
1364
// Changes Globals:             -
 
1365
//===========================================================================
 
1366
int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match)
 
1367
{
 
1368
        int lastvariable, index;
 
1369
        char *strptr, *newstrptr;
 
1370
        bot_matchpiece_t *mp;
 
1371
        bot_matchstring_t *ms;
 
1372
 
 
1373
        //no last variable
 
1374
        lastvariable = -1;
 
1375
        //pointer to the string to compare the match string with
 
1376
        strptr = match->string;
 
1377
        //Log_Write("match: %s", strptr);
 
1378
        //compare the string with the current match string
 
1379
        for (mp = pieces; mp; mp = mp->next)
 
1380
        {
 
1381
                //if it is a piece of string
 
1382
                if (mp->type == MT_STRING)
 
1383
                {
 
1384
                        newstrptr = NULL;
 
1385
                        for (ms = mp->firststring; ms; ms = ms->next)
 
1386
                        {
 
1387
                                if (!strlen(ms->string))
 
1388
                                {
 
1389
                                        newstrptr = strptr;
 
1390
                                        break;
 
1391
                                } //end if
 
1392
                                //Log_Write("MT_STRING: %s", mp->string);
 
1393
                                index = StringContains(strptr, ms->string, qfalse);
 
1394
                                if (index >= 0)
 
1395
                                {
 
1396
                                        newstrptr = strptr + index;
 
1397
                                        if (lastvariable >= 0)
 
1398
                                        {
 
1399
                                                match->variables[lastvariable].length =
 
1400
                                                                (newstrptr - match->string) - match->variables[lastvariable].offset;
 
1401
                                                                //newstrptr - match->variables[lastvariable].ptr;
 
1402
                                                lastvariable = -1;
 
1403
                                                break;
 
1404
                                        } //end if
 
1405
                                        else if (index == 0)
 
1406
                                        {
 
1407
                                                break;
 
1408
                                        } //end else
 
1409
                                        newstrptr = NULL;
 
1410
                                } //end if
 
1411
                        } //end for
 
1412
                        if (!newstrptr) return qfalse;
 
1413
                        strptr = newstrptr + strlen(ms->string);
 
1414
                } //end if
 
1415
                //if it is a variable piece of string
 
1416
                else if (mp->type == MT_VARIABLE)
 
1417
                {
 
1418
                        //Log_Write("MT_VARIABLE");
 
1419
                        match->variables[mp->variable].offset = strptr - match->string;
 
1420
                        lastvariable = mp->variable;
 
1421
                } //end else if
 
1422
        } //end for
 
1423
        //if a match was found
 
1424
        if (!mp && (lastvariable >= 0 || !strlen(strptr)))
 
1425
        {
 
1426
                //if the last piece was a variable string
 
1427
                if (lastvariable >= 0)
 
1428
                {
 
1429
                        assert( match->variables[lastvariable].offset >= 0 ); // bk001204
 
1430
                        match->variables[lastvariable].length =
 
1431
                                strlen(&match->string[ (int) match->variables[lastvariable].offset]);
 
1432
                } //end if
 
1433
                return qtrue;
 
1434
        } //end if
 
1435
        return qfalse;
 
1436
} //end of the function StringsMatch
 
1437
//===========================================================================
 
1438
//
 
1439
// Parameter:                           -
 
1440
// Returns:                                     -
 
1441
// Changes Globals:             -
 
1442
//===========================================================================
 
1443
int BotFindMatch(char *str, bot_match_t *match, unsigned long int context)
 
1444
{
 
1445
        int i;
 
1446
        bot_matchtemplate_t *ms;
 
1447
 
 
1448
        strncpy(match->string, str, MAX_MESSAGE_SIZE);
 
1449
        //remove any trailing enters
 
1450
        while(strlen(match->string) &&
 
1451
                        match->string[strlen(match->string)-1] == '\n')
 
1452
        {
 
1453
                match->string[strlen(match->string)-1] = '\0';
 
1454
        } //end while
 
1455
        //compare the string with all the match strings
 
1456
        for (ms = matchtemplates; ms; ms = ms->next)
 
1457
        {
 
1458
                if (!(ms->context & context)) continue;
 
1459
                //reset the match variable offsets
 
1460
                for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1;
 
1461
                //
 
1462
                if (StringsMatch(ms->first, match))
 
1463
                {
 
1464
                        match->type = ms->type;
 
1465
                        match->subtype = ms->subtype;
 
1466
                        return qtrue;
 
1467
                } //end if
 
1468
        } //end for
 
1469
        return qfalse;
 
1470
} //end of the function BotFindMatch
 
1471
//===========================================================================
 
1472
//
 
1473
// Parameter:                           -
 
1474
// Returns:                                     -
 
1475
// Changes Globals:             -
 
1476
//===========================================================================
 
1477
void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size)
 
1478
{
 
1479
        if (variable < 0 || variable >= MAX_MATCHVARIABLES)
 
1480
        {
 
1481
                botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n");
 
1482
                strcpy(buf, "");
 
1483
                return;
 
1484
        } //end if
 
1485
 
 
1486
        if (match->variables[variable].offset >= 0)
 
1487
        {
 
1488
                if (match->variables[variable].length < size)
 
1489
                        size = match->variables[variable].length+1;
 
1490
                assert( match->variables[variable].offset >= 0 ); // bk001204
 
1491
                strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1);
 
1492
                buf[size-1] = '\0';
 
1493
        } //end if
 
1494
        else
 
1495
        {
 
1496
                strcpy(buf, "");
 
1497
        } //end else
 
1498
        return;
 
1499
} //end of the function BotMatchVariable
 
1500
//===========================================================================
 
1501
//
 
1502
// Parameter:                           -
 
1503
// Returns:                                     -
 
1504
// Changes Globals:             -
 
1505
//===========================================================================
 
1506
bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string)
 
1507
{
 
1508
        bot_stringlist_t *s;
 
1509
 
 
1510
        for (s = list; s; s = s->next)
 
1511
        {
 
1512
                if (!strcmp(s->string, string)) return s;
 
1513
        } //end for
 
1514
        return NULL;
 
1515
} //end of the function BotFindStringInList
 
1516
//===========================================================================
 
1517
//
 
1518
// Parameter:                           -
 
1519
// Returns:                                     -
 
1520
// Changes Globals:             -
 
1521
//===========================================================================
 
1522
bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist)
 
1523
{
 
1524
        int i;
 
1525
        char *msgptr;
 
1526
        char temp[MAX_MESSAGE_SIZE];
 
1527
        bot_stringlist_t *s;
 
1528
 
 
1529
        msgptr = message;
 
1530
        //
 
1531
        while(*msgptr)
 
1532
        {
 
1533
                if (*msgptr == ESCAPE_CHAR)
 
1534
                {
 
1535
                        msgptr++;
 
1536
                        switch(*msgptr)
 
1537
                        {
 
1538
                                case 'v': //variable
 
1539
                                {
 
1540
                                        //step over the 'v'
 
1541
                                        msgptr++;
 
1542
                                        while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++;
 
1543
                                        //step over the trailing escape char
 
1544
                                        if (*msgptr) msgptr++;
 
1545
                                        break;
 
1546
                                } //end case
 
1547
                                case 'r': //random
 
1548
                                {
 
1549
                                        //step over the 'r'
 
1550
                                        msgptr++;
 
1551
                                        for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
 
1552
                                        {
 
1553
                                                temp[i] = *msgptr++;
 
1554
                                        } //end while
 
1555
                                        temp[i] = '\0';
 
1556
                                        //step over the trailing escape char
 
1557
                                        if (*msgptr) msgptr++;
 
1558
                                        //find the random keyword
 
1559
                                        if (!RandomString(temp))
 
1560
                                        {
 
1561
                                                if (!BotFindStringInList(stringlist, temp))
 
1562
                                                {
 
1563
                                                        Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp);
 
1564
                                                        s = GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1);
 
1565
                                                        s->string = (char *) s + sizeof(bot_stringlist_t);
 
1566
                                                        strcpy(s->string, temp);
 
1567
                                                        s->next = stringlist;
 
1568
                                                        stringlist = s;
 
1569
                                                } //end if
 
1570
                                        } //end if
 
1571
                                        break;
 
1572
                                } //end case
 
1573
                                default:
 
1574
                                {
 
1575
                                        botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message);
 
1576
                                        break;
 
1577
                                } //end default
 
1578
                        } //end switch
 
1579
                } //end if
 
1580
                else
 
1581
                {
 
1582
                        msgptr++;
 
1583
                } //end else
 
1584
        } //end while
 
1585
        return stringlist;
 
1586
} //end of the function BotCheckChatMessageIntegrety
 
1587
//===========================================================================
 
1588
//
 
1589
// Parameter:                           -
 
1590
// Returns:                                     -
 
1591
// Changes Globals:             -
 
1592
//===========================================================================
 
1593
void BotCheckInitialChatIntegrety(bot_chat_t *chat)
 
1594
{
 
1595
        bot_chattype_t *t;
 
1596
        bot_chatmessage_t *cm;
 
1597
        bot_stringlist_t *stringlist, *s, *nexts;
 
1598
 
 
1599
        stringlist = NULL;
 
1600
        for (t = chat->types; t; t = t->next)
 
1601
        {
 
1602
                for (cm = t->firstchatmessage; cm; cm = cm->next)
 
1603
                {
 
1604
                        stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
 
1605
                } //end for
 
1606
        } //end for
 
1607
        for (s = stringlist; s; s = nexts)
 
1608
        {
 
1609
                nexts = s->next;
 
1610
                FreeMemory(s);
 
1611
        } //end for
 
1612
} //end of the function BotCheckInitialChatIntegrety
 
1613
//===========================================================================
 
1614
//
 
1615
// Parameter:                           -
 
1616
// Returns:                                     -
 
1617
// Changes Globals:             -
 
1618
//===========================================================================
 
1619
void BotCheckReplyChatIntegrety(bot_replychat_t *replychat)
 
1620
{
 
1621
        bot_replychat_t *rp;
 
1622
        bot_chatmessage_t *cm;
 
1623
        bot_stringlist_t *stringlist, *s, *nexts;
 
1624
 
 
1625
        stringlist = NULL;
 
1626
        for (rp = replychat; rp; rp = rp->next)
 
1627
        {
 
1628
                for (cm = rp->firstchatmessage; cm; cm = cm->next)
 
1629
                {
 
1630
                        stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist);
 
1631
                } //end for
 
1632
        } //end for
 
1633
        for (s = stringlist; s; s = nexts)
 
1634
        {
 
1635
                nexts = s->next;
 
1636
                FreeMemory(s);
 
1637
        } //end for
 
1638
} //end of the function BotCheckReplyChatIntegrety
 
1639
//===========================================================================
 
1640
//
 
1641
// Parameter:                           -
 
1642
// Returns:                                     -
 
1643
// Changes Globals:             -
 
1644
//===========================================================================
 
1645
void BotDumpReplyChat(bot_replychat_t *replychat)
 
1646
{
 
1647
        FILE *fp;
 
1648
        bot_replychat_t *rp;
 
1649
        bot_replychatkey_t *key;
 
1650
        bot_chatmessage_t *cm;
 
1651
        bot_matchpiece_t *mp;
 
1652
 
 
1653
        fp = Log_FilePointer();
 
1654
        if (!fp) return;
 
1655
        fprintf(fp, "BotDumpReplyChat:\n");
 
1656
        for (rp = replychat; rp; rp = rp->next)
 
1657
        {
 
1658
                fprintf(fp, "[");
 
1659
                for (key = rp->keys; key; key = key->next)
 
1660
                {
 
1661
                        if (key->flags & RCKFL_AND) fprintf(fp, "&");
 
1662
                        else if (key->flags & RCKFL_NOT) fprintf(fp, "!");
 
1663
                        //
 
1664
                        if (key->flags & RCKFL_NAME) fprintf(fp, "name");
 
1665
                        else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female");
 
1666
                        else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male");
 
1667
                        else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it");
 
1668
                        else if (key->flags & RCKFL_VARIABLES)
 
1669
                        {
 
1670
                                fprintf(fp, "(");
 
1671
                                for (mp = key->match; mp; mp = mp->next)
 
1672
                                {
 
1673
                                        if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string);
 
1674
                                        else fprintf(fp, "%d", mp->variable);
 
1675
                                        if (mp->next) fprintf(fp, ", ");
 
1676
                                } //end for
 
1677
                                fprintf(fp, ")");
 
1678
                        } //end if
 
1679
                        else if (key->flags & RCKFL_STRING)
 
1680
                        {
 
1681
                                fprintf(fp, "\"%s\"", key->string);
 
1682
                        } //end if
 
1683
                        if (key->next) fprintf(fp, ", ");
 
1684
                        else fprintf(fp, "] = %1.0f\n", rp->priority);
 
1685
                } //end for
 
1686
                fprintf(fp, "{\n");
 
1687
                for (cm = rp->firstchatmessage; cm; cm = cm->next)
 
1688
                {
 
1689
                        fprintf(fp, "\t\"%s\";\n", cm->chatmessage);
 
1690
                } //end for
 
1691
                fprintf(fp, "}\n");
 
1692
        } //end for
 
1693
} //end of the function BotDumpReplyChat
 
1694
//===========================================================================
 
1695
//
 
1696
// Parameter:                           -
 
1697
// Returns:                                     -
 
1698
// Changes Globals:             -
 
1699
//===========================================================================
 
1700
void BotFreeReplyChat(bot_replychat_t *replychat)
 
1701
{
 
1702
        bot_replychat_t *rp, *nextrp;
 
1703
        bot_replychatkey_t *key, *nextkey;
 
1704
        bot_chatmessage_t *cm, *nextcm;
 
1705
 
 
1706
        for (rp = replychat; rp; rp = nextrp)
 
1707
        {
 
1708
                nextrp = rp->next;
 
1709
                for (key = rp->keys; key; key = nextkey)
 
1710
                {
 
1711
                        nextkey = key->next;
 
1712
                        if (key->match) BotFreeMatchPieces(key->match);
 
1713
                        if (key->string) FreeMemory(key->string);
 
1714
                        FreeMemory(key);
 
1715
                } //end for
 
1716
                for (cm = rp->firstchatmessage; cm; cm = nextcm)
 
1717
                {
 
1718
                        nextcm = cm->next;
 
1719
                        FreeMemory(cm);
 
1720
                } //end for
 
1721
                FreeMemory(rp);
 
1722
        } //end for
 
1723
} //end of the function BotFreeReplyChat
 
1724
//===========================================================================
 
1725
//
 
1726
// Parameter:                   -
 
1727
// Returns:                             -
 
1728
// Changes Globals:             -
 
1729
//===========================================================================
 
1730
void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys)
 
1731
{
 
1732
        int allprefixed, hasvariableskey, hasstringkey;
 
1733
        bot_matchpiece_t *m;
 
1734
        bot_matchstring_t *ms;
 
1735
        bot_replychatkey_t *key, *key2;
 
1736
 
 
1737
        //
 
1738
        allprefixed = qtrue;
 
1739
        hasvariableskey = hasstringkey = qfalse;
 
1740
        for (key = keys; key; key = key->next)
 
1741
        {
 
1742
                if (!(key->flags & (RCKFL_AND|RCKFL_NOT)))
 
1743
                {
 
1744
                        allprefixed = qfalse;
 
1745
                        if (key->flags & RCKFL_VARIABLES)
 
1746
                        {
 
1747
                                for (m = key->match; m; m = m->next)
 
1748
                                {
 
1749
                                        if (m->type == MT_VARIABLE) hasvariableskey = qtrue;
 
1750
                                } //end for
 
1751
                        } //end if
 
1752
                        else if (key->flags & RCKFL_STRING)
 
1753
                        {
 
1754
                                hasstringkey = qtrue;
 
1755
                        } //end else if
 
1756
                } //end if
 
1757
                else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING))
 
1758
                {
 
1759
                        for (key2 = keys; key2; key2 = key2->next)
 
1760
                        {
 
1761
                                if (key2 == key) continue;
 
1762
                                if (key2->flags & RCKFL_NOT) continue;
 
1763
                                if (key2->flags & RCKFL_VARIABLES)
 
1764
                                {
 
1765
                                        for (m = key2->match; m; m = m->next)
 
1766
                                        {
 
1767
                                                if (m->type == MT_STRING)
 
1768
                                                {
 
1769
                                                        for (ms = m->firststring; ms; ms = ms->next)
 
1770
                                                        {
 
1771
                                                                if (StringContains(ms->string, key->string, qfalse) != -1)
 
1772
                                                                {
 
1773
                                                                        break;
 
1774
                                                                } //end if
 
1775
                                                        } //end for
 
1776
                                                        if (ms) break;
 
1777
                                                } //end if
 
1778
                                                else if (m->type == MT_VARIABLE)
 
1779
                                                {
 
1780
                                                        break;
 
1781
                                                } //end if
 
1782
                                        } //end for
 
1783
                                        if (!m)
 
1784
                                        {
 
1785
                                                SourceWarning(source, "one of the match templates does not "
 
1786
                                                                                "leave space for the key %s with the & prefix", key->string);
 
1787
                                        } //end if
 
1788
                                } //end if
 
1789
                        } //end for
 
1790
                } //end else
 
1791
                if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING))
 
1792
                {
 
1793
                        for (key2 = keys; key2; key2 = key2->next)
 
1794
                        {
 
1795
                                if (key2 == key) continue;
 
1796
                                if (key2->flags & RCKFL_NOT) continue;
 
1797
                                if (key2->flags & RCKFL_STRING)
 
1798
                                {
 
1799
                                        if (StringContains(key2->string, key->string, qfalse) != -1)
 
1800
                                        {
 
1801
                                                SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string);
 
1802
                                        } //end if
 
1803
                                } //end if
 
1804
                                else if (key2->flags & RCKFL_VARIABLES)
 
1805
                                {
 
1806
                                        for (m = key2->match; m; m = m->next)
 
1807
                                        {
 
1808
                                                if (m->type == MT_STRING)
 
1809
                                                {
 
1810
                                                        for (ms = m->firststring; ms; ms = ms->next)
 
1811
                                                        {
 
1812
                                                                if (StringContains(ms->string, key->string, qfalse) != -1)
 
1813
                                                                {
 
1814
                                                                        SourceWarning(source, "the key %s with prefix ! is inside "
 
1815
                                                                                                "the match template string %s", key->string, ms->string);
 
1816
                                                                } //end if
 
1817
                                                        } //end for
 
1818
                                                } //end if
 
1819
                                        } //end for
 
1820
                                } //end else if
 
1821
                        } //end for
 
1822
                } //end if
 
1823
        } //end for
 
1824
        if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix");
 
1825
        if (hasvariableskey && hasstringkey)
 
1826
        {
 
1827
                SourceWarning(source, "variables from the match template(s) could be "
 
1828
                                                                "invalid when outputting one of the chat messages");
 
1829
        } //end if
 
1830
} //end of the function BotCheckValidReplyChatKeySet
 
1831
//===========================================================================
 
1832
//
 
1833
// Parameter:                   -
 
1834
// Returns:                             -
 
1835
// Changes Globals:             -
 
1836
//===========================================================================
 
1837
bot_replychat_t *BotLoadReplyChat(char *filename)
 
1838
{
 
1839
        char chatmessagestring[MAX_MESSAGE_SIZE];
 
1840
        char namebuffer[MAX_MESSAGE_SIZE];
 
1841
        source_t *source;
 
1842
        token_t token;
 
1843
        bot_chatmessage_t *chatmessage = NULL;
 
1844
        bot_replychat_t *replychat, *replychatlist;
 
1845
        bot_replychatkey_t *key;
 
1846
 
 
1847
        PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
1848
        source = LoadSourceFile(filename);
 
1849
        if (!source)
 
1850
        {
 
1851
                botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
 
1852
                return NULL;
 
1853
        } //end if
 
1854
        //
 
1855
        replychatlist = NULL;
 
1856
        //
 
1857
        while(PC_ReadToken(source, &token))
 
1858
        {
 
1859
                if (strcmp(token.string, "["))
 
1860
                {
 
1861
                        SourceError(source, "expected [, found %s", token.string);
 
1862
                        BotFreeReplyChat(replychatlist);
 
1863
                        FreeSource(source);
 
1864
                        return NULL;
 
1865
                } //end if
 
1866
                //
 
1867
                replychat = GetClearedHunkMemory(sizeof(bot_replychat_t));
 
1868
                replychat->keys = NULL;
 
1869
                replychat->next = replychatlist;
 
1870
                replychatlist = replychat;
 
1871
                //read the keys, there must be at least one key
 
1872
                do
 
1873
                {
 
1874
                        //allocate a key
 
1875
                        key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t));
 
1876
                        key->flags = 0;
 
1877
                        key->string = NULL;
 
1878
                        key->match = NULL;
 
1879
                        key->next = replychat->keys;
 
1880
                        replychat->keys = key;
 
1881
                        //check for MUST BE PRESENT and MUST BE ABSENT keys
 
1882
                        if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND;
 
1883
                        else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT;
 
1884
                        //special keys
 
1885
                        if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME;
 
1886
                        else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE;
 
1887
                        else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE;
 
1888
                        else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS;
 
1889
                        else if (PC_CheckTokenString(source, "(")) //match key
 
1890
                        {
 
1891
                                key->flags |= RCKFL_VARIABLES;
 
1892
                                key->match = BotLoadMatchPieces(source, ")");
 
1893
                                if (!key->match)
 
1894
                                {
 
1895
                                        BotFreeReplyChat(replychatlist);
 
1896
                                        return NULL;
 
1897
                                } //end if
 
1898
                        } //end else if
 
1899
                        else if (PC_CheckTokenString(source, "<")) //bot names
 
1900
                        {
 
1901
                                key->flags |= RCKFL_BOTNAMES;
 
1902
                                strcpy(namebuffer, "");
 
1903
                                do
 
1904
                                {
 
1905
                                        if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
1906
                                        {
 
1907
                                                BotFreeReplyChat(replychatlist);
 
1908
                                                FreeSource(source);
 
1909
                                                return NULL;
 
1910
                                        } //end if
 
1911
                                        StripDoubleQuotes(token.string);
 
1912
                                        if (strlen(namebuffer)) strcat(namebuffer, "\\");
 
1913
                                        strcat(namebuffer, token.string);
 
1914
                                } while(PC_CheckTokenString(source, ","));
 
1915
                                if (!PC_ExpectTokenString(source, ">"))
 
1916
                                {
 
1917
                                        BotFreeReplyChat(replychatlist);
 
1918
                                        FreeSource(source);
 
1919
                                        return NULL;
 
1920
                                } //end if
 
1921
                                key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1);
 
1922
                                strcpy(key->string, namebuffer);
 
1923
                        } //end else if
 
1924
                        else //normal string key
 
1925
                        {
 
1926
                                key->flags |= RCKFL_STRING;
 
1927
                                if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
1928
                                {
 
1929
                                        BotFreeReplyChat(replychatlist);
 
1930
                                        FreeSource(source);
 
1931
                                        return NULL;
 
1932
                                } //end if
 
1933
                                StripDoubleQuotes(token.string);
 
1934
                                key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1);
 
1935
                                strcpy(key->string, token.string);
 
1936
                        } //end else
 
1937
                        //
 
1938
                        PC_CheckTokenString(source, ",");
 
1939
                } while(!PC_CheckTokenString(source, "]"));
 
1940
                //
 
1941
                BotCheckValidReplyChatKeySet(source, replychat->keys);
 
1942
                //read the = sign and the priority
 
1943
                if (!PC_ExpectTokenString(source, "=") ||
 
1944
                        !PC_ExpectTokenType(source, TT_NUMBER, 0, &token))
 
1945
                {
 
1946
                        BotFreeReplyChat(replychatlist);
 
1947
                        FreeSource(source);
 
1948
                        return NULL;
 
1949
                } //end if
 
1950
                replychat->priority = token.floatvalue;
 
1951
                //read the leading {
 
1952
                if (!PC_ExpectTokenString(source, "{"))
 
1953
                {
 
1954
                        BotFreeReplyChat(replychatlist);
 
1955
                        FreeSource(source);
 
1956
                        return NULL;
 
1957
                } //end if
 
1958
                replychat->numchatmessages = 0;
 
1959
                //while the trailing } is not found
 
1960
                while(!PC_CheckTokenString(source, "}"))
 
1961
                {
 
1962
                        if (!BotLoadChatMessage(source, chatmessagestring))
 
1963
                        {
 
1964
                                BotFreeReplyChat(replychatlist);
 
1965
                                FreeSource(source);
 
1966
                                return NULL;
 
1967
                        } //end if
 
1968
                        chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1);
 
1969
                        chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t);
 
1970
                        strcpy(chatmessage->chatmessage, chatmessagestring);
 
1971
                        chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
 
1972
                        chatmessage->next = replychat->firstchatmessage;
 
1973
                        //add the chat message to the reply chat
 
1974
                        replychat->firstchatmessage = chatmessage;
 
1975
                        replychat->numchatmessages++;
 
1976
                } //end while
 
1977
        } //end while
 
1978
        FreeSource(source);
 
1979
        botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
 
1980
        //
 
1981
        //BotDumpReplyChat(replychatlist);
 
1982
        if (bot_developer)
 
1983
        {
 
1984
                BotCheckReplyChatIntegrety(replychatlist);
 
1985
        } //end if
 
1986
        //
 
1987
        if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n");
 
1988
        //
 
1989
        return replychatlist;
 
1990
} //end of the function BotLoadReplyChat
 
1991
//===========================================================================
 
1992
//
 
1993
// Parameter:                           -
 
1994
// Returns:                                     -
 
1995
// Changes Globals:             -
 
1996
//===========================================================================
 
1997
void BotDumpInitialChat(bot_chat_t *chat)
 
1998
{
 
1999
        bot_chattype_t *t;
 
2000
        bot_chatmessage_t *m;
 
2001
 
 
2002
        Log_Write("{");
 
2003
        for (t = chat->types; t; t = t->next)
 
2004
        {
 
2005
                Log_Write(" type \"%s\"", t->name);
 
2006
                Log_Write(" {");
 
2007
                Log_Write("  numchatmessages = %d", t->numchatmessages);
 
2008
                for (m = t->firstchatmessage; m; m = m->next)
 
2009
                {
 
2010
                        Log_Write("  \"%s\"", m->chatmessage);
 
2011
                } //end for
 
2012
                Log_Write(" }");
 
2013
        } //end for
 
2014
        Log_Write("}");
 
2015
} //end of the function BotDumpInitialChat
 
2016
//===========================================================================
 
2017
//
 
2018
// Parameter:                           -
 
2019
// Returns:                                     -
 
2020
// Changes Globals:             -
 
2021
//===========================================================================
 
2022
bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname)
 
2023
{
 
2024
        int pass, foundchat, indent, size;
 
2025
        char *ptr = NULL;
 
2026
        char chatmessagestring[MAX_MESSAGE_SIZE];
 
2027
        source_t *source;
 
2028
        token_t token;
 
2029
        bot_chat_t *chat = NULL;
 
2030
        bot_chattype_t *chattype = NULL;
 
2031
        bot_chatmessage_t *chatmessage = NULL;
 
2032
#ifdef DEBUG
 
2033
        int starttime;
 
2034
 
 
2035
        starttime = Sys_MilliSeconds();
 
2036
#endif //DEBUG
 
2037
        //
 
2038
        size = 0;
 
2039
        foundchat = qfalse;
 
2040
        //a bot chat is parsed in two phases
 
2041
        for (pass = 0; pass < 2; pass++)
 
2042
        {
 
2043
                //allocate memory
 
2044
                if (pass && size) ptr = (char *) GetClearedMemory(size);
 
2045
                //load the source file
 
2046
                PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
2047
                source = LoadSourceFile(chatfile);
 
2048
                if (!source)
 
2049
                {
 
2050
                        botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile);
 
2051
                        return NULL;
 
2052
                } //end if
 
2053
                //chat structure
 
2054
                if (pass)
 
2055
                {
 
2056
                        chat = (bot_chat_t *) ptr;
 
2057
                        ptr += sizeof(bot_chat_t);
 
2058
                } //end if
 
2059
                size = sizeof(bot_chat_t);
 
2060
                //
 
2061
                while(PC_ReadToken(source, &token))
 
2062
                {
 
2063
                        if (!strcmp(token.string, "chat"))
 
2064
                        {
 
2065
                                if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
2066
                                {
 
2067
                                        FreeSource(source);
 
2068
                                        return NULL;
 
2069
                                } //end if
 
2070
                                StripDoubleQuotes(token.string);
 
2071
                                //after the chat name we expect a opening brace
 
2072
                                if (!PC_ExpectTokenString(source, "{"))
 
2073
                                {
 
2074
                                        FreeSource(source);
 
2075
                                        return NULL;
 
2076
                                } //end if
 
2077
                                //if the chat name is found
 
2078
                                if (!Q_stricmp(token.string, chatname))
 
2079
                                {
 
2080
                                        foundchat = qtrue;
 
2081
                                        //read the chat types
 
2082
                                        while(1)
 
2083
                                        {
 
2084
                                                if (!PC_ExpectAnyToken(source, &token))
 
2085
                                                {
 
2086
                                                        FreeSource(source);
 
2087
                                                        return NULL;
 
2088
                                                } //end if
 
2089
                                                if (!strcmp(token.string, "}")) break;
 
2090
                                                if (strcmp(token.string, "type"))
 
2091
                                                {
 
2092
                                                        SourceError(source, "expected type found %s\n", token.string);
 
2093
                                                        FreeSource(source);
 
2094
                                                        return NULL;
 
2095
                                                } //end if
 
2096
                                                //expect the chat type name
 
2097
                                                if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) ||
 
2098
                                                        !PC_ExpectTokenString(source, "{"))
 
2099
                                                {
 
2100
                                                        FreeSource(source);
 
2101
                                                        return NULL;
 
2102
                                                } //end if
 
2103
                                                StripDoubleQuotes(token.string);
 
2104
                                                if (pass)
 
2105
                                                {
 
2106
                                                        chattype = (bot_chattype_t *) ptr;
 
2107
                                                        strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME);
 
2108
                                                        chattype->firstchatmessage = NULL;
 
2109
                                                        //add the chat type to the chat
 
2110
                                                        chattype->next = chat->types;
 
2111
                                                        chat->types = chattype;
 
2112
                                                        //
 
2113
                                                        ptr += sizeof(bot_chattype_t);
 
2114
                                                } //end if
 
2115
                                                size += sizeof(bot_chattype_t);
 
2116
                                                //read the chat messages
 
2117
                                                while(!PC_CheckTokenString(source, "}"))
 
2118
                                                {
 
2119
                                                        size_t len;
 
2120
                                                        if (!BotLoadChatMessage(source, chatmessagestring))
 
2121
                                                        {
 
2122
                                                                FreeSource(source);
 
2123
                                                                return NULL;
 
2124
                                                        } //end if
 
2125
                                                        len = strlen(chatmessagestring) + 1;
 
2126
                                                        len = PAD(len, sizeof(long));
 
2127
                                                        if (pass)
 
2128
                                                        {
 
2129
                                                                chatmessage = (bot_chatmessage_t *) ptr;
 
2130
                                                                chatmessage->time = -2*CHATMESSAGE_RECENTTIME;
 
2131
                                                                //put the chat message in the list
 
2132
                                                                chatmessage->next = chattype->firstchatmessage;
 
2133
                                                                chattype->firstchatmessage = chatmessage;
 
2134
                                                                //store the chat message
 
2135
                                                                ptr += sizeof(bot_chatmessage_t);
 
2136
                                                                chatmessage->chatmessage = ptr;
 
2137
                                                                strcpy(chatmessage->chatmessage, chatmessagestring);
 
2138
                                                                ptr += len;
 
2139
                                                                //the number of chat messages increased
 
2140
                                                                chattype->numchatmessages++;
 
2141
                                                        } //end if
 
2142
                                                        size += sizeof(bot_chatmessage_t) + len;
 
2143
                                                } //end if
 
2144
                                        } //end while
 
2145
                                } //end if
 
2146
                                else //skip the bot chat
 
2147
                                {
 
2148
                                        indent = 1;
 
2149
                                        while(indent)
 
2150
                                        {
 
2151
                                                if (!PC_ExpectAnyToken(source, &token))
 
2152
                                                {
 
2153
                                                        FreeSource(source);
 
2154
                                                        return NULL;
 
2155
                                                } //end if
 
2156
                                                if (!strcmp(token.string, "{")) indent++;
 
2157
                                                else if (!strcmp(token.string, "}")) indent--;
 
2158
                                        } //end while
 
2159
                                } //end else
 
2160
                        } //end if
 
2161
                        else
 
2162
                        {
 
2163
                                SourceError(source, "unknown definition %s\n", token.string);
 
2164
                                FreeSource(source);
 
2165
                                return NULL;
 
2166
                        } //end else
 
2167
                } //end while
 
2168
                //free the source
 
2169
                FreeSource(source);
 
2170
                //if the requested character is not found
 
2171
                if (!foundchat)
 
2172
                {
 
2173
                        botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile);
 
2174
                        return NULL;
 
2175
                } //end if
 
2176
        } //end for
 
2177
        //
 
2178
        botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile);
 
2179
        //
 
2180
        //BotDumpInitialChat(chat);
 
2181
        if (bot_developer)
 
2182
        {
 
2183
                BotCheckInitialChatIntegrety(chat);
 
2184
        } //end if
 
2185
#ifdef DEBUG
 
2186
        botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime);
 
2187
#endif //DEBUG
 
2188
        //character was read succesfully
 
2189
        return chat;
 
2190
} //end of the function BotLoadInitialChat
 
2191
//===========================================================================
 
2192
//
 
2193
// Parameter:                   -
 
2194
// Returns:                             -
 
2195
// Changes Globals:             -
 
2196
//===========================================================================
 
2197
void BotFreeChatFile(int chatstate)
 
2198
{
 
2199
        bot_chatstate_t *cs;
 
2200
 
 
2201
        cs = BotChatStateFromHandle(chatstate);
 
2202
        if (!cs) return;
 
2203
        if (cs->chat) FreeMemory(cs->chat);
 
2204
        cs->chat = NULL;
 
2205
} //end of the function BotFreeChatFile
 
2206
//===========================================================================
 
2207
//
 
2208
// Parameter:                           -
 
2209
// Returns:                                     -
 
2210
// Changes Globals:             -
 
2211
//===========================================================================
 
2212
int BotLoadChatFile(int chatstate, char *chatfile, char *chatname)
 
2213
{
 
2214
        bot_chatstate_t *cs;
 
2215
        int n, avail = 0;
 
2216
 
 
2217
        cs = BotChatStateFromHandle(chatstate);
 
2218
        if (!cs) return BLERR_CANNOTLOADICHAT;
 
2219
        BotFreeChatFile(chatstate);
 
2220
 
 
2221
        if (!LibVarGetValue("bot_reloadcharacters"))
 
2222
        {
 
2223
                avail = -1;
 
2224
                for( n = 0; n < MAX_CLIENTS; n++ ) {
 
2225
                        if( !ichatdata[n] ) {
 
2226
                                if( avail == -1 ) {
 
2227
                                        avail = n;
 
2228
                                }
 
2229
                                continue;
 
2230
                        }
 
2231
                        if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) { 
 
2232
                                continue;
 
2233
                        }
 
2234
                        if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) { 
 
2235
                                continue;
 
2236
                        }
 
2237
                        cs->chat = ichatdata[n]->chat;
 
2238
                //              botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile );
 
2239
                        return BLERR_NOERROR;
 
2240
                }
 
2241
 
 
2242
                if( avail == -1 ) {
 
2243
                        botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile);
 
2244
                        return BLERR_CANNOTLOADICHAT;
 
2245
                }
 
2246
        }
 
2247
 
 
2248
        cs->chat = BotLoadInitialChat(chatfile, chatname);
 
2249
        if (!cs->chat)
 
2250
        {
 
2251
                botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile);
 
2252
                return BLERR_CANNOTLOADICHAT;
 
2253
        } //end if
 
2254
        if (!LibVarGetValue("bot_reloadcharacters"))
 
2255
        {
 
2256
                ichatdata[avail] = GetClearedMemory( sizeof(bot_ichatdata_t) );
 
2257
                ichatdata[avail]->chat = cs->chat;
 
2258
                Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) );
 
2259
                Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) );
 
2260
        } //end if
 
2261
 
 
2262
        return BLERR_NOERROR;
 
2263
} //end of the function BotLoadChatFile
 
2264
//===========================================================================
 
2265
//
 
2266
// Parameter:                   -
 
2267
// Returns:                             -
 
2268
// Changes Globals:             -
 
2269
//===========================================================================
 
2270
int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext,
 
2271
                                                         bot_match_t *match, unsigned long vcontext, int reply)
 
2272
{
 
2273
        int num, len, i, expansion;
 
2274
        char *outputbuf, *ptr, *msgptr;
 
2275
        char temp[MAX_MESSAGE_SIZE];
 
2276
 
 
2277
        expansion = qfalse;
 
2278
        msgptr = message;
 
2279
        outputbuf = outmessage;
 
2280
        len = 0;
 
2281
        //
 
2282
        while(*msgptr)
 
2283
        {
 
2284
                if (*msgptr == ESCAPE_CHAR)
 
2285
                {
 
2286
                        msgptr++;
 
2287
                        switch(*msgptr)
 
2288
                        {
 
2289
                                case 'v': //variable
 
2290
                                {
 
2291
                                        msgptr++;
 
2292
                                        num = 0;
 
2293
                                        while(*msgptr && *msgptr != ESCAPE_CHAR)
 
2294
                                        {
 
2295
                                                num = num * 10 + (*msgptr++) - '0';
 
2296
                                        } //end while
 
2297
                                        //step over the trailing escape char
 
2298
                                        if (*msgptr) msgptr++;
 
2299
                                        if (num > MAX_MATCHVARIABLES)
 
2300
                                        {
 
2301
                                                botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num);
 
2302
                                                return qfalse;
 
2303
                                        } //end if
 
2304
                                        if (match->variables[num].offset >= 0)
 
2305
                                        {
 
2306
                                                assert( match->variables[num].offset >= 0 ); // bk001204
 
2307
                                                ptr = &match->string[ (int) match->variables[num].offset];
 
2308
                                                for (i = 0; i < match->variables[num].length; i++)
 
2309
                                                {
 
2310
                                                        temp[i] = ptr[i];
 
2311
                                                } //end for
 
2312
                                                temp[i] = 0;
 
2313
                                                //if it's a reply message
 
2314
                                                if (reply)
 
2315
                                                {
 
2316
                                                        //replace the reply synonyms in the variables
 
2317
                                                        BotReplaceReplySynonyms(temp, vcontext);
 
2318
                                                } //end if
 
2319
                                                else 
 
2320
                                                {
 
2321
                                                        //replace synonyms in the variable context
 
2322
                                                        BotReplaceSynonyms(temp, vcontext);
 
2323
                                                } //end else
 
2324
                                                //
 
2325
                                                if (len + strlen(temp) >= MAX_MESSAGE_SIZE)
 
2326
                                                {
 
2327
                                                        botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message);
 
2328
                                                        return qfalse;
 
2329
                                                } //end if
 
2330
                                                strcpy(&outputbuf[len], temp);
 
2331
                                                len += strlen(temp);
 
2332
                                        } //end if
 
2333
                                        break;
 
2334
                                } //end case
 
2335
                                case 'r': //random
 
2336
                                {
 
2337
                                        msgptr++;
 
2338
                                        for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++)
 
2339
                                        {
 
2340
                                                temp[i] = *msgptr++;
 
2341
                                        } //end while
 
2342
                                        temp[i] = '\0';
 
2343
                                        //step over the trailing escape char
 
2344
                                        if (*msgptr) msgptr++;
 
2345
                                        //find the random keyword
 
2346
                                        ptr = RandomString(temp);
 
2347
                                        if (!ptr)
 
2348
                                        {
 
2349
                                                botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp);
 
2350
                                                return qfalse;
 
2351
                                        } //end if
 
2352
                                        if (len + strlen(ptr) >= MAX_MESSAGE_SIZE)
 
2353
                                        {
 
2354
                                                botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
 
2355
                                                return qfalse;
 
2356
                                        } //end if
 
2357
                                        strcpy(&outputbuf[len], ptr);
 
2358
                                        len += strlen(ptr);
 
2359
                                        expansion = qtrue;
 
2360
                                        break;
 
2361
                                } //end case
 
2362
                                default:
 
2363
                                {
 
2364
                                        botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message);
 
2365
                                        break;
 
2366
                                } //end default
 
2367
                        } //end switch
 
2368
                } //end if
 
2369
                else
 
2370
                {
 
2371
                        outputbuf[len++] = *msgptr++;
 
2372
                        if (len >= MAX_MESSAGE_SIZE)
 
2373
                        {
 
2374
                                botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message);
 
2375
                                break;
 
2376
                        } //end if
 
2377
                } //end else
 
2378
        } //end while
 
2379
        outputbuf[len] = '\0';
 
2380
        //replace synonyms weighted in the message context
 
2381
        BotReplaceWeightedSynonyms(outputbuf, mcontext);
 
2382
        //return true if a random was expanded
 
2383
        return expansion;
 
2384
} //end of the function BotExpandChatMessage
 
2385
//===========================================================================
 
2386
//
 
2387
// Parameter:                   -
 
2388
// Returns:                             -
 
2389
// Changes Globals:             -
 
2390
//===========================================================================
 
2391
void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext,
 
2392
                                                         bot_match_t *match, unsigned long vcontext, int reply)
 
2393
{
 
2394
        int i;
 
2395
        char srcmessage[MAX_MESSAGE_SIZE];
 
2396
 
 
2397
        strcpy(srcmessage, message);
 
2398
        for (i = 0; i < 10; i++)
 
2399
        {
 
2400
                if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply))
 
2401
                {
 
2402
                        break;
 
2403
                } //end if
 
2404
                strcpy(srcmessage, chatstate->chatmessage);
 
2405
        } //end for
 
2406
        if (i >= 10)
 
2407
        {
 
2408
                botimport.Print(PRT_WARNING, "too many expansions in chat message\n");
 
2409
                botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage);
 
2410
        } //end if
 
2411
} //end of the function BotConstructChatMessage
 
2412
//===========================================================================
 
2413
// randomly chooses one of the chat message of the given type
 
2414
//
 
2415
// Parameter:                           -
 
2416
// Returns:                                     -
 
2417
// Changes Globals:             -
 
2418
//===========================================================================
 
2419
char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type)
 
2420
{
 
2421
        int n, numchatmessages;
 
2422
        float besttime;
 
2423
        bot_chattype_t *t;
 
2424
        bot_chatmessage_t *m, *bestchatmessage;
 
2425
        bot_chat_t *chat;
 
2426
 
 
2427
        chat = cs->chat;
 
2428
        for (t = chat->types; t; t = t->next)
 
2429
        {
 
2430
                if (!Q_stricmp(t->name, type))
 
2431
                {
 
2432
                        numchatmessages = 0;
 
2433
                        for (m = t->firstchatmessage; m; m = m->next)
 
2434
                        {
 
2435
                                if (m->time > AAS_Time()) continue;
 
2436
                                numchatmessages++;
 
2437
                        } //end if
 
2438
                        //if all chat messages have been used recently
 
2439
                        if (numchatmessages <= 0)
 
2440
                        {
 
2441
                                besttime = 0;
 
2442
                                bestchatmessage = NULL;
 
2443
                                for (m = t->firstchatmessage; m; m = m->next)
 
2444
                                {
 
2445
                                        if (!besttime || m->time < besttime)
 
2446
                                        {
 
2447
                                                bestchatmessage = m;
 
2448
                                                besttime = m->time;
 
2449
                                        } //end if
 
2450
                                } //end for
 
2451
                                if (bestchatmessage) return bestchatmessage->chatmessage;
 
2452
                        } //end if
 
2453
                        else //choose a chat message randomly
 
2454
                        {
 
2455
                                n = random() * numchatmessages;
 
2456
                                for (m = t->firstchatmessage; m; m = m->next)
 
2457
                                {
 
2458
                                        if (m->time > AAS_Time()) continue;
 
2459
                                        if (--n < 0)
 
2460
                                        {
 
2461
                                                m->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
 
2462
                                                return m->chatmessage;
 
2463
                                        } //end if
 
2464
                                } //end for
 
2465
                        } //end else
 
2466
                        return NULL;
 
2467
                } //end if
 
2468
        } //end for
 
2469
        return NULL;
 
2470
} //end of the function BotChooseInitialChatMessage
 
2471
//===========================================================================
 
2472
//
 
2473
// Parameter:                           -
 
2474
// Returns:                                     -
 
2475
// Changes Globals:             -
 
2476
//===========================================================================
 
2477
int BotNumInitialChats(int chatstate, char *type)
 
2478
{
 
2479
        bot_chatstate_t *cs;
 
2480
        bot_chattype_t *t;
 
2481
 
 
2482
        cs = BotChatStateFromHandle(chatstate);
 
2483
        if (!cs) return 0;
 
2484
 
 
2485
        for (t = cs->chat->types; t; t = t->next)
 
2486
        {
 
2487
                if (!Q_stricmp(t->name, type))
 
2488
                {
 
2489
                        if (LibVarGetValue("bot_testichat")) {
 
2490
                                botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages);
 
2491
                                botimport.Print(PRT_MESSAGE, "-------------------\n");
 
2492
                        }
 
2493
                        return t->numchatmessages;
 
2494
                } //end if
 
2495
        } //end for
 
2496
        return 0;
 
2497
} //end of the function BotNumInitialChats
 
2498
//===========================================================================
 
2499
//
 
2500
// Parameter:                           -
 
2501
// Returns:                                     -
 
2502
// Changes Globals:             -
 
2503
//===========================================================================
 
2504
void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
 
2505
{
 
2506
        char *message;
 
2507
        int index;
 
2508
        bot_match_t match;
 
2509
        bot_chatstate_t *cs;
 
2510
 
 
2511
        cs = BotChatStateFromHandle(chatstate);
 
2512
        if (!cs) return;
 
2513
        //if no chat file is loaded
 
2514
        if (!cs->chat) return;
 
2515
        //choose a chat message randomly of the given type
 
2516
        message = BotChooseInitialChatMessage(cs, type);
 
2517
        //if there's no message of the given type
 
2518
        if (!message)
 
2519
        {
 
2520
#ifdef DEBUG
 
2521
                botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type);
 
2522
#endif //DEBUG
 
2523
                return;
 
2524
        } //end if
 
2525
        //
 
2526
        Com_Memset(&match, 0, sizeof(match));
 
2527
        index = 0;
 
2528
        if( var0 ) {
 
2529
                strcat(match.string, var0);
 
2530
                match.variables[0].offset = index;
 
2531
                match.variables[0].length = strlen(var0);
 
2532
                index += strlen(var0);
 
2533
        }
 
2534
        if( var1 ) {
 
2535
                strcat(match.string, var1);
 
2536
                match.variables[1].offset = index;
 
2537
                match.variables[1].length = strlen(var1);
 
2538
                index += strlen(var1);
 
2539
        }
 
2540
        if( var2 ) {
 
2541
                strcat(match.string, var2);
 
2542
                match.variables[2].offset = index;
 
2543
                match.variables[2].length = strlen(var2);
 
2544
                index += strlen(var2);
 
2545
        }
 
2546
        if( var3 ) {
 
2547
                strcat(match.string, var3);
 
2548
                match.variables[3].offset = index;
 
2549
                match.variables[3].length = strlen(var3);
 
2550
                index += strlen(var3);
 
2551
        }
 
2552
        if( var4 ) {
 
2553
                strcat(match.string, var4);
 
2554
                match.variables[4].offset = index;
 
2555
                match.variables[4].length = strlen(var4);
 
2556
                index += strlen(var4);
 
2557
        }
 
2558
        if( var5 ) {
 
2559
                strcat(match.string, var5);
 
2560
                match.variables[5].offset = index;
 
2561
                match.variables[5].length = strlen(var5);
 
2562
                index += strlen(var5);
 
2563
        }
 
2564
        if( var6 ) {
 
2565
                strcat(match.string, var6);
 
2566
                match.variables[6].offset = index;
 
2567
                match.variables[6].length = strlen(var6);
 
2568
                index += strlen(var6);
 
2569
        }
 
2570
        if( var7 ) {
 
2571
                strcat(match.string, var7);
 
2572
                match.variables[7].offset = index;
 
2573
                match.variables[7].length = strlen(var7);
 
2574
                index += strlen(var7);
 
2575
        }
 
2576
        //
 
2577
        BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse);
 
2578
} //end of the function BotInitialChat
 
2579
//===========================================================================
 
2580
//
 
2581
// Parameter:                           -
 
2582
// Returns:                                     -
 
2583
// Changes Globals:             -
 
2584
//===========================================================================
 
2585
void BotPrintReplyChatKeys(bot_replychat_t *replychat)
 
2586
{
 
2587
        bot_replychatkey_t *key;
 
2588
        bot_matchpiece_t *mp;
 
2589
 
 
2590
        botimport.Print(PRT_MESSAGE, "[");
 
2591
        for (key = replychat->keys; key; key = key->next)
 
2592
        {
 
2593
                if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&");
 
2594
                else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!");
 
2595
                //
 
2596
                if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name");
 
2597
                else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female");
 
2598
                else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male");
 
2599
                else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it");
 
2600
                else if (key->flags & RCKFL_VARIABLES)
 
2601
                {
 
2602
                        botimport.Print(PRT_MESSAGE, "(");
 
2603
                        for (mp = key->match; mp; mp = mp->next)
 
2604
                        {
 
2605
                                if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string);
 
2606
                                else botimport.Print(PRT_MESSAGE, "%d", mp->variable);
 
2607
                                if (mp->next) botimport.Print(PRT_MESSAGE, ", ");
 
2608
                        } //end for
 
2609
                        botimport.Print(PRT_MESSAGE, ")");
 
2610
                } //end if
 
2611
                else if (key->flags & RCKFL_STRING)
 
2612
                {
 
2613
                        botimport.Print(PRT_MESSAGE, "\"%s\"", key->string);
 
2614
                } //end if
 
2615
                if (key->next) botimport.Print(PRT_MESSAGE, ", ");
 
2616
                else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority);
 
2617
        } //end for
 
2618
        botimport.Print(PRT_MESSAGE, "{\n");
 
2619
} //end of the function BotPrintReplyChatKeys
 
2620
//===========================================================================
 
2621
//
 
2622
// Parameter:                           -
 
2623
// Returns:                                     -
 
2624
// Changes Globals:             -
 
2625
//===========================================================================
 
2626
int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7)
 
2627
{
 
2628
        bot_replychat_t *rchat, *bestrchat;
 
2629
        bot_replychatkey_t *key;
 
2630
        bot_chatmessage_t *m, *bestchatmessage;
 
2631
        bot_match_t match, bestmatch;
 
2632
        int bestpriority, num, found, res, numchatmessages, index;
 
2633
        bot_chatstate_t *cs;
 
2634
 
 
2635
        cs = BotChatStateFromHandle(chatstate);
 
2636
        if (!cs) return qfalse;
 
2637
        Com_Memset(&match, 0, sizeof(bot_match_t));
 
2638
        strcpy(match.string, message);
 
2639
        bestpriority = -1;
 
2640
        bestchatmessage = NULL;
 
2641
        bestrchat = NULL;
 
2642
        //go through all the reply chats
 
2643
        for (rchat = replychats; rchat; rchat = rchat->next)
 
2644
        {
 
2645
                found = qfalse;
 
2646
                for (key = rchat->keys; key; key = key->next)
 
2647
                {
 
2648
                        res = qfalse;
 
2649
                        //get the match result
 
2650
                        if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1);
 
2651
                        else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1);
 
2652
                        else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE);
 
2653
                        else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE);
 
2654
                        else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS);
 
2655
                        else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match);
 
2656
                        else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL);
 
2657
                        //if the key must be present
 
2658
                        if (key->flags & RCKFL_AND)
 
2659
                        {
 
2660
                                if (!res)
 
2661
                                {
 
2662
                                        found = qfalse;
 
2663
                                        break;
 
2664
                                } //end if
 
2665
                        } //end else if
 
2666
                        //if the key must be absent
 
2667
                        else if (key->flags & RCKFL_NOT)
 
2668
                        {
 
2669
                                if (res)
 
2670
                                {
 
2671
                                        found = qfalse;
 
2672
                                        break;
 
2673
                                } //end if
 
2674
                        } //end if
 
2675
                        else if (res)
 
2676
                        {
 
2677
                                found = qtrue;
 
2678
                        } //end else
 
2679
                } //end for
 
2680
                //
 
2681
                if (found)
 
2682
                {
 
2683
                        if (rchat->priority > bestpriority)
 
2684
                        {
 
2685
                                numchatmessages = 0;
 
2686
                                for (m = rchat->firstchatmessage; m; m = m->next)
 
2687
                                {
 
2688
                                        if (m->time > AAS_Time()) continue;
 
2689
                                        numchatmessages++;
 
2690
                                } //end if
 
2691
                                num = random() * numchatmessages;
 
2692
                                for (m = rchat->firstchatmessage; m; m = m->next)
 
2693
                                {
 
2694
                                        if (--num < 0) break;
 
2695
                                        if (m->time > AAS_Time()) continue;
 
2696
                                } //end for
 
2697
                                //if the reply chat has a message
 
2698
                                if (m)
 
2699
                                {
 
2700
                                        Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t));
 
2701
                                        bestchatmessage = m;
 
2702
                                        bestrchat = rchat;
 
2703
                                        bestpriority = rchat->priority;
 
2704
                                } //end if
 
2705
                        } //end if
 
2706
                } //end if
 
2707
        } //end for
 
2708
        if (bestchatmessage)
 
2709
        {
 
2710
                index = strlen(bestmatch.string);
 
2711
                if( var0 ) {
 
2712
                        strcat(bestmatch.string, var0);
 
2713
                        bestmatch.variables[0].offset = index;
 
2714
                        bestmatch.variables[0].length = strlen(var0);
 
2715
                        index += strlen(var0);
 
2716
                }
 
2717
                if( var1 ) {
 
2718
                        strcat(bestmatch.string, var1);
 
2719
                        bestmatch.variables[1].offset = index;
 
2720
                        bestmatch.variables[1].length = strlen(var1);
 
2721
                        index += strlen(var1);
 
2722
                }
 
2723
                if( var2 ) {
 
2724
                        strcat(bestmatch.string, var2);
 
2725
                        bestmatch.variables[2].offset = index;
 
2726
                        bestmatch.variables[2].length = strlen(var2);
 
2727
                        index += strlen(var2);
 
2728
                }
 
2729
                if( var3 ) {
 
2730
                        strcat(bestmatch.string, var3);
 
2731
                        bestmatch.variables[3].offset = index;
 
2732
                        bestmatch.variables[3].length = strlen(var3);
 
2733
                        index += strlen(var3);
 
2734
                }
 
2735
                if( var4 ) {
 
2736
                        strcat(bestmatch.string, var4);
 
2737
                        bestmatch.variables[4].offset = index;
 
2738
                        bestmatch.variables[4].length = strlen(var4);
 
2739
                        index += strlen(var4);
 
2740
                }
 
2741
                if( var5 ) {
 
2742
                        strcat(bestmatch.string, var5);
 
2743
                        bestmatch.variables[5].offset = index;
 
2744
                        bestmatch.variables[5].length = strlen(var5);
 
2745
                        index += strlen(var5);
 
2746
                }
 
2747
                if( var6 ) {
 
2748
                        strcat(bestmatch.string, var6);
 
2749
                        bestmatch.variables[6].offset = index;
 
2750
                        bestmatch.variables[6].length = strlen(var6);
 
2751
                        index += strlen(var6);
 
2752
                }
 
2753
                if( var7 ) {
 
2754
                        strcat(bestmatch.string, var7);
 
2755
                        bestmatch.variables[7].offset = index;
 
2756
                        bestmatch.variables[7].length = strlen(var7);
 
2757
                        index += strlen(var7);
 
2758
                }
 
2759
                if (LibVarGetValue("bot_testrchat"))
 
2760
                {
 
2761
                        for (m = bestrchat->firstchatmessage; m; m = m->next)
 
2762
                        {
 
2763
                                BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
 
2764
                                BotRemoveTildes(cs->chatmessage);
 
2765
                                botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
 
2766
                        } //end if
 
2767
                } //end if
 
2768
                else
 
2769
                {
 
2770
                        bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME;
 
2771
                        BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue);
 
2772
                } //end else
 
2773
                return qtrue;
 
2774
        } //end if
 
2775
        return qfalse;
 
2776
} //end of the function BotReplyChat
 
2777
//===========================================================================
 
2778
//
 
2779
// Parameter:                           -
 
2780
// Returns:                                     -
 
2781
// Changes Globals:             -
 
2782
//===========================================================================
 
2783
int BotChatLength(int chatstate)
 
2784
{
 
2785
        bot_chatstate_t *cs;
 
2786
 
 
2787
        cs = BotChatStateFromHandle(chatstate);
 
2788
        if (!cs) return 0;
 
2789
        return strlen(cs->chatmessage);
 
2790
} //end of the function BotChatLength
 
2791
//===========================================================================
 
2792
//
 
2793
// Parameter:                   -
 
2794
// Returns:                             -
 
2795
// Changes Globals:             -
 
2796
//===========================================================================
 
2797
void BotEnterChat(int chatstate, int clientto, int sendto)
 
2798
{
 
2799
        bot_chatstate_t *cs;
 
2800
 
 
2801
        cs = BotChatStateFromHandle(chatstate);
 
2802
        if (!cs) return;
 
2803
 
 
2804
        if (strlen(cs->chatmessage))
 
2805
        {
 
2806
                BotRemoveTildes(cs->chatmessage);
 
2807
                if (LibVarGetValue("bot_testichat")) {
 
2808
                        botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage);
 
2809
                }
 
2810
                else {
 
2811
                        switch(sendto) {
 
2812
                                case CHAT_TEAM:
 
2813
                                        EA_Command(cs->client, va("say_team %s", cs->chatmessage));
 
2814
                                        break;
 
2815
                                case CHAT_TELL:
 
2816
                                        EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage));
 
2817
                                        break;
 
2818
                                default: //CHAT_ALL
 
2819
                                        EA_Command(cs->client, va("say %s", cs->chatmessage));
 
2820
                                        break;
 
2821
                        }
 
2822
                }
 
2823
                //clear the chat message from the state
 
2824
                strcpy(cs->chatmessage, "");
 
2825
        } //end if
 
2826
} //end of the function BotEnterChat
 
2827
//===========================================================================
 
2828
//
 
2829
// Parameter:                   -
 
2830
// Returns:                             -
 
2831
// Changes Globals:             -
 
2832
//===========================================================================
 
2833
void BotGetChatMessage(int chatstate, char *buf, int size)
 
2834
{
 
2835
        bot_chatstate_t *cs;
 
2836
 
 
2837
        cs = BotChatStateFromHandle(chatstate);
 
2838
        if (!cs) return;
 
2839
 
 
2840
        BotRemoveTildes(cs->chatmessage);
 
2841
        strncpy(buf, cs->chatmessage, size-1);
 
2842
        buf[size-1] = '\0';
 
2843
        //clear the chat message from the state
 
2844
        strcpy(cs->chatmessage, "");
 
2845
} //end of the function BotGetChatMessage
 
2846
//===========================================================================
 
2847
//
 
2848
// Parameter:                   -
 
2849
// Returns:                             -
 
2850
// Changes Globals:             -
 
2851
//===========================================================================
 
2852
void BotSetChatGender(int chatstate, int gender)
 
2853
{
 
2854
        bot_chatstate_t *cs;
 
2855
 
 
2856
        cs = BotChatStateFromHandle(chatstate);
 
2857
        if (!cs) return;
 
2858
        switch(gender)
 
2859
        {
 
2860
                case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break;
 
2861
                case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break;
 
2862
                default: cs->gender = CHAT_GENDERLESS; break;
 
2863
        } //end switch
 
2864
} //end of the function BotSetChatGender
 
2865
//===========================================================================
 
2866
//
 
2867
// Parameter:                           -
 
2868
// Returns:                                     -
 
2869
// Changes Globals:             -
 
2870
//===========================================================================
 
2871
void BotSetChatName(int chatstate, char *name, int client)
 
2872
{
 
2873
        bot_chatstate_t *cs;
 
2874
 
 
2875
        cs = BotChatStateFromHandle(chatstate);
 
2876
        if (!cs) return;
 
2877
        cs->client = client;
 
2878
        Com_Memset(cs->name, 0, sizeof(cs->name));
 
2879
        strncpy(cs->name, name, sizeof(cs->name));
 
2880
        cs->name[sizeof(cs->name)-1] = '\0';
 
2881
} //end of the function BotSetChatName
 
2882
//===========================================================================
 
2883
//
 
2884
// Parameter:                           -
 
2885
// Returns:                                     -
 
2886
// Changes Globals:             -
 
2887
//===========================================================================
 
2888
void BotResetChatAI(void)
 
2889
{
 
2890
        bot_replychat_t *rchat;
 
2891
        bot_chatmessage_t *m;
 
2892
 
 
2893
        for (rchat = replychats; rchat; rchat = rchat->next)
 
2894
        {
 
2895
                for (m = rchat->firstchatmessage; m; m = m->next)
 
2896
                {
 
2897
                        m->time = 0;
 
2898
                } //end for
 
2899
        } //end for
 
2900
} //end of the function BotResetChatAI
 
2901
//========================================================================
 
2902
//
 
2903
// Parameter:                           -
 
2904
// Returns:                                     -
 
2905
// Changes Globals:             -
 
2906
//========================================================================
 
2907
int BotAllocChatState(void)
 
2908
{
 
2909
        int i;
 
2910
 
 
2911
        for (i = 1; i <= MAX_CLIENTS; i++)
 
2912
        {
 
2913
                if (!botchatstates[i])
 
2914
                {
 
2915
                        botchatstates[i] = GetClearedMemory(sizeof(bot_chatstate_t));
 
2916
                        return i;
 
2917
                } //end if
 
2918
        } //end for
 
2919
        return 0;
 
2920
} //end of the function BotAllocChatState
 
2921
//========================================================================
 
2922
//
 
2923
// Parameter:                           -
 
2924
// Returns:                                     -
 
2925
// Changes Globals:             -
 
2926
//========================================================================
 
2927
void BotFreeChatState(int handle)
 
2928
{
 
2929
        bot_chatstate_t *cs;
 
2930
        bot_consolemessage_t m;
 
2931
        int h;
 
2932
 
 
2933
        if (handle <= 0 || handle > MAX_CLIENTS)
 
2934
        {
 
2935
                botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle);
 
2936
                return;
 
2937
        } //end if
 
2938
        if (!botchatstates[handle])
 
2939
        {
 
2940
                botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle);
 
2941
                return;
 
2942
        } //end if
 
2943
        cs = botchatstates[handle];
 
2944
        if (LibVarGetValue("bot_reloadcharacters"))
 
2945
        {
 
2946
                BotFreeChatFile(handle);
 
2947
        } //end if
 
2948
        //free all the console messages left in the chat state
 
2949
        for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m))
 
2950
        {
 
2951
                //remove the console message
 
2952
                BotRemoveConsoleMessage(handle, h);
 
2953
        } //end for
 
2954
        FreeMemory(botchatstates[handle]);
 
2955
        botchatstates[handle] = NULL;
 
2956
} //end of the function BotFreeChatState
 
2957
//===========================================================================
 
2958
//
 
2959
// Parameter:                           -
 
2960
// Returns:                                     -
 
2961
// Changes Globals:             -
 
2962
//===========================================================================
 
2963
int BotSetupChatAI(void)
 
2964
{
 
2965
        char *file;
 
2966
 
 
2967
#ifdef DEBUG
 
2968
        int starttime = Sys_MilliSeconds();
 
2969
#endif //DEBUG
 
2970
 
 
2971
        file = LibVarString("synfile", "syn.c");
 
2972
        synonyms = BotLoadSynonyms(file);
 
2973
        file = LibVarString("rndfile", "rnd.c");
 
2974
        randomstrings = BotLoadRandomStrings(file);
 
2975
        file = LibVarString("matchfile", "match.c");
 
2976
        matchtemplates = BotLoadMatchTemplates(file);
 
2977
        //
 
2978
        if (!LibVarValue("nochat", "0"))
 
2979
        {
 
2980
                file = LibVarString("rchatfile", "rchat.c");
 
2981
                replychats = BotLoadReplyChat(file);
 
2982
        } //end if
 
2983
 
 
2984
        InitConsoleMessageHeap();
 
2985
 
 
2986
#ifdef DEBUG
 
2987
        botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime);
 
2988
#endif //DEBUG
 
2989
        return BLERR_NOERROR;
 
2990
} //end of the function BotSetupChatAI
 
2991
//===========================================================================
 
2992
//
 
2993
// Parameter:                           -
 
2994
// Returns:                                     -
 
2995
// Changes Globals:             -
 
2996
//===========================================================================
 
2997
void BotShutdownChatAI(void)
 
2998
{
 
2999
        int i;
 
3000
 
 
3001
        //free all remaining chat states
 
3002
        for(i = 0; i < MAX_CLIENTS; i++)
 
3003
        {
 
3004
                if (botchatstates[i])
 
3005
                {
 
3006
                        BotFreeChatState(i);
 
3007
                } //end if
 
3008
        } //end for
 
3009
        //free all cached chats
 
3010
        for(i = 0; i < MAX_CLIENTS; i++)
 
3011
        {
 
3012
                if (ichatdata[i])
 
3013
                {
 
3014
                        FreeMemory(ichatdata[i]->chat);
 
3015
                        FreeMemory(ichatdata[i]);
 
3016
                        ichatdata[i] = NULL;
 
3017
                } //end if
 
3018
        } //end for
 
3019
        if (consolemessageheap) FreeMemory(consolemessageheap);
 
3020
        consolemessageheap = NULL;
 
3021
        if (matchtemplates) BotFreeMatchTemplates(matchtemplates);
 
3022
        matchtemplates = NULL;
 
3023
        if (randomstrings) FreeMemory(randomstrings);
 
3024
        randomstrings = NULL;
 
3025
        if (synonyms) FreeMemory(synonyms);
 
3026
        synonyms = NULL;
 
3027
        if (replychats) BotFreeReplyChat(replychats);
 
3028
        replychats = NULL;
 
3029
} //end of the function BotShutdownChatAI