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

« back to all changes in this revision

Viewing changes to code/botlib/be_ai_weight.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_weight.c
 
25
 *
 
26
 * desc:                fuzzy logic
 
27
 *
 
28
 * $Archive: /MissionPack/code/botlib/be_ai_weight.c $
 
29
 *
 
30
 *****************************************************************************/
 
31
 
 
32
#include "../qcommon/q_shared.h"
 
33
#include "l_memory.h"
 
34
#include "l_log.h"
 
35
#include "l_utils.h"
 
36
#include "l_script.h"
 
37
#include "l_precomp.h"
 
38
#include "l_struct.h"
 
39
#include "l_libvar.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_ai_weight.h"
 
46
 
 
47
#define MAX_INVENTORYVALUE                      999999
 
48
#define EVALUATERECURSIVELY
 
49
 
 
50
#define MAX_WEIGHT_FILES                        128
 
51
weightconfig_t  *weightFileList[MAX_WEIGHT_FILES];
 
52
 
 
53
//===========================================================================
 
54
//
 
55
// Parameter:                           -
 
56
// Returns:                                     -
 
57
// Changes Globals:             -
 
58
//===========================================================================
 
59
int ReadValue(source_t *source, float *value)
 
60
{
 
61
        token_t token;
 
62
 
 
63
        if (!PC_ExpectAnyToken(source, &token)) return qfalse;
 
64
        if (!strcmp(token.string, "-"))
 
65
        {
 
66
                SourceWarning(source, "negative value set to zero\n");
 
67
                if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) return qfalse;
 
68
        } //end if
 
69
        if (token.type != TT_NUMBER)
 
70
        {
 
71
                SourceError(source, "invalid return value %s\n", token.string);
 
72
                return qfalse;
 
73
        } //end if
 
74
        *value = token.floatvalue;
 
75
        return qtrue;
 
76
} //end of the function ReadValue
 
77
//===========================================================================
 
78
//
 
79
// Parameter:                           -
 
80
// Returns:                                     -
 
81
// Changes Globals:             -
 
82
//===========================================================================
 
83
int ReadFuzzyWeight(source_t *source, fuzzyseperator_t *fs)
 
84
{
 
85
        if (PC_CheckTokenString(source, "balance"))
 
86
        {
 
87
                fs->type = WT_BALANCE;
 
88
                if (!PC_ExpectTokenString(source, "(")) return qfalse;
 
89
                if (!ReadValue(source, &fs->weight)) return qfalse;
 
90
                if (!PC_ExpectTokenString(source, ",")) return qfalse;
 
91
                if (!ReadValue(source, &fs->minweight)) return qfalse;
 
92
                if (!PC_ExpectTokenString(source, ",")) return qfalse;
 
93
                if (!ReadValue(source, &fs->maxweight)) return qfalse;
 
94
                if (!PC_ExpectTokenString(source, ")")) return qfalse;
 
95
        } //end if
 
96
        else
 
97
        {
 
98
                fs->type = 0;
 
99
                if (!ReadValue(source, &fs->weight)) return qfalse;
 
100
                fs->minweight = fs->weight;
 
101
                fs->maxweight = fs->weight;
 
102
        } //end if
 
103
        if (!PC_ExpectTokenString(source, ";")) return qfalse;
 
104
        return qtrue;
 
105
} //end of the function ReadFuzzyWeight
 
106
//===========================================================================
 
107
//
 
108
// Parameter:                           -
 
109
// Returns:                                     -
 
110
// Changes Globals:             -
 
111
//===========================================================================
 
112
void FreeFuzzySeperators_r(fuzzyseperator_t *fs)
 
113
{
 
114
        if (!fs) return;
 
115
        if (fs->child) FreeFuzzySeperators_r(fs->child);
 
116
        if (fs->next) FreeFuzzySeperators_r(fs->next);
 
117
        FreeMemory(fs);
 
118
} //end of the function FreeFuzzySeperators
 
119
//===========================================================================
 
120
//
 
121
// Parameter:                   -
 
122
// Returns:                             -
 
123
// Changes Globals:             -
 
124
//===========================================================================
 
125
void FreeWeightConfig2(weightconfig_t *config)
 
126
{
 
127
        int i;
 
128
 
 
129
        for (i = 0; i < config->numweights; i++)
 
130
        {
 
131
                FreeFuzzySeperators_r(config->weights[i].firstseperator);
 
132
                if (config->weights[i].name) FreeMemory(config->weights[i].name);
 
133
        } //end for
 
134
        FreeMemory(config);
 
135
} //end of the function FreeWeightConfig2
 
136
//===========================================================================
 
137
//
 
138
// Parameter:                   -
 
139
// Returns:                             -
 
140
// Changes Globals:             -
 
141
//===========================================================================
 
142
void FreeWeightConfig(weightconfig_t *config)
 
143
{
 
144
        if (!LibVarGetValue("bot_reloadcharacters")) return;
 
145
        FreeWeightConfig2(config);
 
146
} //end of the function FreeWeightConfig
 
147
//===========================================================================
 
148
//
 
149
// Parameter:                   -
 
150
// Returns:                             -
 
151
// Changes Globals:             -
 
152
//===========================================================================
 
153
fuzzyseperator_t *ReadFuzzySeperators_r(source_t *source)
 
154
{
 
155
        int newindent, index, def, founddefault;
 
156
        token_t token;
 
157
        fuzzyseperator_t *fs, *lastfs, *firstfs;
 
158
 
 
159
        founddefault = qfalse;
 
160
        firstfs = NULL;
 
161
        lastfs = NULL;
 
162
        if (!PC_ExpectTokenString(source, "(")) return NULL;
 
163
        if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) return NULL;
 
164
        index = token.intvalue;
 
165
        if (!PC_ExpectTokenString(source, ")")) return NULL;
 
166
        if (!PC_ExpectTokenString(source, "{")) return NULL;
 
167
        if (!PC_ExpectAnyToken(source, &token)) return NULL;
 
168
        do
 
169
        {
 
170
                def = !strcmp(token.string, "default");
 
171
                if (def || !strcmp(token.string, "case"))
 
172
                {
 
173
                        fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
 
174
                        fs->index = index;
 
175
                        if (lastfs) lastfs->next = fs;
 
176
                        else firstfs = fs;
 
177
                        lastfs = fs;
 
178
                        if (def)
 
179
                        {
 
180
                                if (founddefault)
 
181
                                {
 
182
                                        SourceError(source, "switch already has a default\n");
 
183
                                        FreeFuzzySeperators_r(firstfs);
 
184
                                        return NULL;
 
185
                                } //end if
 
186
                                fs->value = MAX_INVENTORYVALUE;
 
187
                                founddefault = qtrue;
 
188
                        } //end if
 
189
                        else
 
190
                        {
 
191
                                if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token))
 
192
                                {
 
193
                                        FreeFuzzySeperators_r(firstfs);
 
194
                                        return NULL;
 
195
                                } //end if
 
196
                                fs->value = token.intvalue;
 
197
                        } //end else
 
198
                        if (!PC_ExpectTokenString(source, ":") || !PC_ExpectAnyToken(source, &token))
 
199
                        {
 
200
                                FreeFuzzySeperators_r(firstfs);
 
201
                                return NULL;
 
202
                        } //end if
 
203
                        newindent = qfalse;
 
204
                        if (!strcmp(token.string, "{"))
 
205
                        {
 
206
                                newindent = qtrue;
 
207
                                if (!PC_ExpectAnyToken(source, &token))
 
208
                                {
 
209
                                        FreeFuzzySeperators_r(firstfs);
 
210
                                        return NULL;
 
211
                                } //end if
 
212
                        } //end if
 
213
                        if (!strcmp(token.string, "return"))
 
214
                        {
 
215
                                if (!ReadFuzzyWeight(source, fs))
 
216
                                {
 
217
                                        FreeFuzzySeperators_r(firstfs);
 
218
                                        return NULL;
 
219
                                } //end if
 
220
                        } //end if
 
221
                        else if (!strcmp(token.string, "switch"))
 
222
                        {
 
223
                                fs->child = ReadFuzzySeperators_r(source);
 
224
                                if (!fs->child)
 
225
                                {
 
226
                                        FreeFuzzySeperators_r(firstfs);
 
227
                                        return NULL;
 
228
                                } //end if
 
229
                        } //end else if
 
230
                        else
 
231
                        {
 
232
                                SourceError(source, "invalid name %s\n", token.string);
 
233
                                return NULL;
 
234
                        } //end else
 
235
                        if (newindent)
 
236
                        {
 
237
                                if (!PC_ExpectTokenString(source, "}"))
 
238
                                {
 
239
                                        FreeFuzzySeperators_r(firstfs);
 
240
                                        return NULL;
 
241
                                } //end if
 
242
                        } //end if
 
243
                } //end if
 
244
                else
 
245
                {
 
246
                        FreeFuzzySeperators_r(firstfs);
 
247
                        SourceError(source, "invalid name %s\n", token.string);
 
248
                        return NULL;
 
249
                } //end else
 
250
                if (!PC_ExpectAnyToken(source, &token))
 
251
                {
 
252
                        FreeFuzzySeperators_r(firstfs);
 
253
                        return NULL;
 
254
                } //end if
 
255
        } while(strcmp(token.string, "}"));
 
256
        //
 
257
        if (!founddefault)
 
258
        {
 
259
                SourceWarning(source, "switch without default\n");
 
260
                fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
 
261
                fs->index = index;
 
262
                fs->value = MAX_INVENTORYVALUE;
 
263
                fs->weight = 0;
 
264
                fs->next = NULL;
 
265
                fs->child = NULL;
 
266
                if (lastfs) lastfs->next = fs;
 
267
                else firstfs = fs;
 
268
                lastfs = fs;
 
269
        } //end if
 
270
        //
 
271
        return firstfs;
 
272
} //end of the function ReadFuzzySeperators_r
 
273
//===========================================================================
 
274
//
 
275
// Parameter:                           -
 
276
// Returns:                                     -
 
277
// Changes Globals:             -
 
278
//===========================================================================
 
279
weightconfig_t *ReadWeightConfig(char *filename)
 
280
{
 
281
        int newindent, avail = 0, n;
 
282
        token_t token;
 
283
        source_t *source;
 
284
        fuzzyseperator_t *fs;
 
285
        weightconfig_t *config = NULL;
 
286
#ifdef DEBUG
 
287
        int starttime;
 
288
 
 
289
        starttime = Sys_MilliSeconds();
 
290
#endif //DEBUG
 
291
 
 
292
        if (!LibVarGetValue("bot_reloadcharacters"))
 
293
        {
 
294
                avail = -1;
 
295
                for( n = 0; n < MAX_WEIGHT_FILES; n++ )
 
296
                {
 
297
                        config = weightFileList[n];
 
298
                        if( !config )
 
299
                        {
 
300
                                if( avail == -1 )
 
301
                                {
 
302
                                        avail = n;
 
303
                                } //end if
 
304
                                continue;
 
305
                        } //end if
 
306
                        if( strcmp( filename, config->filename ) == 0 )
 
307
                        {
 
308
                                //botimport.Print( PRT_MESSAGE, "retained %s\n", filename );
 
309
                                return config;
 
310
                        } //end if
 
311
                } //end for
 
312
 
 
313
                if( avail == -1 )
 
314
                {
 
315
                        botimport.Print( PRT_ERROR, "weightFileList was full trying to load %s\n", filename );
 
316
                        return NULL;
 
317
                } //end if
 
318
        } //end if
 
319
 
 
320
        PC_SetBaseFolder(BOTFILESBASEFOLDER);
 
321
        source = LoadSourceFile(filename);
 
322
        if (!source)
 
323
        {
 
324
                botimport.Print(PRT_ERROR, "counldn't load %s\n", filename);
 
325
                return NULL;
 
326
        } //end if
 
327
        //
 
328
        config = (weightconfig_t *) GetClearedMemory(sizeof(weightconfig_t));
 
329
        config->numweights = 0;
 
330
        Q_strncpyz( config->filename, filename, sizeof(config->filename) );
 
331
        //parse the item config file
 
332
        while(PC_ReadToken(source, &token))
 
333
        {
 
334
                if (!strcmp(token.string, "weight"))
 
335
                {
 
336
                        if (config->numweights >= MAX_WEIGHTS)
 
337
                        {
 
338
                                SourceWarning(source, "too many fuzzy weights\n");
 
339
                                break;
 
340
                        } //end if
 
341
                        if (!PC_ExpectTokenType(source, TT_STRING, 0, &token))
 
342
                        {
 
343
                                FreeWeightConfig(config);
 
344
                                FreeSource(source);
 
345
                                return NULL;
 
346
                        } //end if
 
347
                        StripDoubleQuotes(token.string);
 
348
                        config->weights[config->numweights].name = (char *) GetClearedMemory(strlen(token.string) + 1);
 
349
                        strcpy(config->weights[config->numweights].name, token.string);
 
350
                        if (!PC_ExpectAnyToken(source, &token))
 
351
                        {
 
352
                                FreeWeightConfig(config);
 
353
                                FreeSource(source);
 
354
                                return NULL;
 
355
                        } //end if
 
356
                        newindent = qfalse;
 
357
                        if (!strcmp(token.string, "{"))
 
358
                        {
 
359
                                newindent = qtrue;
 
360
                                if (!PC_ExpectAnyToken(source, &token))
 
361
                                {
 
362
                                        FreeWeightConfig(config);
 
363
                                        FreeSource(source);
 
364
                                        return NULL;
 
365
                                } //end if
 
366
                        } //end if
 
367
                        if (!strcmp(token.string, "switch"))
 
368
                        {
 
369
                                fs = ReadFuzzySeperators_r(source);
 
370
                                if (!fs)
 
371
                                {
 
372
                                        FreeWeightConfig(config);
 
373
                                        FreeSource(source);
 
374
                                        return NULL;
 
375
                                } //end if
 
376
                                config->weights[config->numweights].firstseperator = fs;
 
377
                        } //end if
 
378
                        else if (!strcmp(token.string, "return"))
 
379
                        {
 
380
                                fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t));
 
381
                                fs->index = 0;
 
382
                                fs->value = MAX_INVENTORYVALUE;
 
383
                                fs->next = NULL;
 
384
                                fs->child = NULL;
 
385
                                if (!ReadFuzzyWeight(source, fs))
 
386
                                {
 
387
                                        FreeMemory(fs);
 
388
                                        FreeWeightConfig(config);
 
389
                                        FreeSource(source);
 
390
                                        return NULL;
 
391
                                } //end if
 
392
                                config->weights[config->numweights].firstseperator = fs;
 
393
                        } //end else if
 
394
                        else
 
395
                        {
 
396
                                SourceError(source, "invalid name %s\n", token.string);
 
397
                                FreeWeightConfig(config);
 
398
                                FreeSource(source);
 
399
                                return NULL;
 
400
                        } //end else
 
401
                        if (newindent)
 
402
                        {
 
403
                                if (!PC_ExpectTokenString(source, "}"))
 
404
                                {
 
405
                                        FreeWeightConfig(config);
 
406
                                        FreeSource(source);
 
407
                                        return NULL;
 
408
                                } //end if
 
409
                        } //end if
 
410
                        config->numweights++;
 
411
                } //end if
 
412
                else
 
413
                {
 
414
                        SourceError(source, "invalid name %s\n", token.string);
 
415
                        FreeWeightConfig(config);
 
416
                        FreeSource(source);
 
417
                        return NULL;
 
418
                } //end else
 
419
        } //end while
 
420
        //free the source at the end of a pass
 
421
        FreeSource(source);
 
422
        //if the file was located in a pak file
 
423
        botimport.Print(PRT_MESSAGE, "loaded %s\n", filename);
 
424
#ifdef DEBUG
 
425
        if (bot_developer)
 
426
        {
 
427
                botimport.Print(PRT_MESSAGE, "weights loaded in %d msec\n", Sys_MilliSeconds() - starttime);
 
428
        } //end if
 
429
#endif //DEBUG
 
430
        //
 
431
        if (!LibVarGetValue("bot_reloadcharacters"))
 
432
        {
 
433
                weightFileList[avail] = config;
 
434
        } //end if
 
435
        //
 
436
        return config;
 
437
} //end of the function ReadWeightConfig
 
438
#if 0
 
439
//===========================================================================
 
440
//
 
441
// Parameter:                           -
 
442
// Returns:                                     -
 
443
// Changes Globals:             -
 
444
//===========================================================================
 
445
qboolean WriteFuzzyWeight(FILE *fp, fuzzyseperator_t *fs)
 
446
{
 
447
        if (fs->type == WT_BALANCE)
 
448
        {
 
449
                if (fprintf(fp, " return balance(") < 0) return qfalse;
 
450
                if (!WriteFloat(fp, fs->weight)) return qfalse;
 
451
                if (fprintf(fp, ",") < 0) return qfalse;
 
452
                if (!WriteFloat(fp, fs->minweight)) return qfalse;
 
453
                if (fprintf(fp, ",") < 0) return qfalse;
 
454
                if (!WriteFloat(fp, fs->maxweight)) return qfalse;
 
455
                if (fprintf(fp, ");\n") < 0) return qfalse;
 
456
        } //end if
 
457
        else
 
458
        {
 
459
                if (fprintf(fp, " return ") < 0) return qfalse;
 
460
                if (!WriteFloat(fp, fs->weight)) return qfalse;
 
461
                if (fprintf(fp, ";\n") < 0) return qfalse;
 
462
        } //end else
 
463
        return qtrue;
 
464
} //end of the function WriteFuzzyWeight
 
465
//===========================================================================
 
466
//
 
467
// Parameter:                           -
 
468
// Returns:                                     -
 
469
// Changes Globals:             -
 
470
//===========================================================================
 
471
qboolean WriteFuzzySeperators_r(FILE *fp, fuzzyseperator_t *fs, int indent)
 
472
{
 
473
        if (!WriteIndent(fp, indent)) return qfalse;
 
474
        if (fprintf(fp, "switch(%d)\n", fs->index) < 0) return qfalse;
 
475
        if (!WriteIndent(fp, indent)) return qfalse;
 
476
        if (fprintf(fp, "{\n") < 0) return qfalse;
 
477
        indent++;
 
478
        do
 
479
        {
 
480
                if (!WriteIndent(fp, indent)) return qfalse;
 
481
                if (fs->next)
 
482
                {
 
483
                        if (fprintf(fp, "case %d:", fs->value) < 0) return qfalse;
 
484
                } //end if
 
485
                else
 
486
                {
 
487
                        if (fprintf(fp, "default:") < 0) return qfalse;
 
488
                } //end else
 
489
                if (fs->child)
 
490
                {
 
491
                        if (fprintf(fp, "\n") < 0) return qfalse;
 
492
                        if (!WriteIndent(fp, indent)) return qfalse;
 
493
                        if (fprintf(fp, "{\n") < 0) return qfalse;
 
494
                        if (!WriteFuzzySeperators_r(fp, fs->child, indent + 1)) return qfalse;
 
495
                        if (!WriteIndent(fp, indent)) return qfalse;
 
496
                        if (fs->next)
 
497
                        {
 
498
                                if (fprintf(fp, "} //end case\n") < 0) return qfalse;
 
499
                        } //end if
 
500
                        else
 
501
                        {
 
502
                                if (fprintf(fp, "} //end default\n") < 0) return qfalse;
 
503
                        } //end else
 
504
                } //end if
 
505
                else
 
506
                {
 
507
                        if (!WriteFuzzyWeight(fp, fs)) return qfalse;
 
508
                } //end else
 
509
                fs = fs->next;
 
510
        } while(fs);
 
511
        indent--;
 
512
        if (!WriteIndent(fp, indent)) return qfalse;
 
513
        if (fprintf(fp, "} //end switch\n") < 0) return qfalse;
 
514
        return qtrue;
 
515
} //end of the function WriteItemFuzzyWeights_r
 
516
//===========================================================================
 
517
//
 
518
// Parameter:                           -
 
519
// Returns:                                     -
 
520
// Changes Globals:             -
 
521
//===========================================================================
 
522
qboolean WriteWeightConfig(char *filename, weightconfig_t *config)
 
523
{
 
524
        int i;
 
525
        FILE *fp;
 
526
        weight_t *ifw;
 
527
 
 
528
        fp = fopen(filename, "wb");
 
529
        if (!fp) return qfalse;
 
530
 
 
531
        for (i = 0; i < config->numweights; i++)
 
532
        {
 
533
                ifw = &config->weights[i];
 
534
                if (fprintf(fp, "\nweight \"%s\"\n", ifw->name) < 0) return qfalse;
 
535
                if (fprintf(fp, "{\n") < 0) return qfalse;
 
536
                if (ifw->firstseperator->index > 0)
 
537
                {
 
538
                        if (!WriteFuzzySeperators_r(fp, ifw->firstseperator, 1)) return qfalse;
 
539
                } //end if
 
540
                else
 
541
                {
 
542
                        if (!WriteIndent(fp, 1)) return qfalse;
 
543
                        if (!WriteFuzzyWeight(fp, ifw->firstseperator)) return qfalse;
 
544
                } //end else
 
545
                if (fprintf(fp, "} //end weight\n") < 0) return qfalse;
 
546
        } //end for
 
547
        fclose(fp);
 
548
        return qtrue;
 
549
} //end of the function WriteWeightConfig
 
550
#endif
 
551
//===========================================================================
 
552
//
 
553
// Parameter:                           -
 
554
// Returns:                                     -
 
555
// Changes Globals:             -
 
556
//===========================================================================
 
557
int FindFuzzyWeight(weightconfig_t *wc, char *name)
 
558
{
 
559
        int i;
 
560
 
 
561
        for (i = 0; i < wc->numweights; i++)
 
562
        {
 
563
                if (!strcmp(wc->weights[i].name, name))
 
564
                {
 
565
                        return i;
 
566
                } //end if
 
567
        } //end if
 
568
        return -1;
 
569
} //end of the function FindFuzzyWeight
 
570
//===========================================================================
 
571
//
 
572
// Parameter:                           -
 
573
// Returns:                                     -
 
574
// Changes Globals:             -
 
575
//===========================================================================
 
576
float FuzzyWeight_r(int *inventory, fuzzyseperator_t *fs)
 
577
{
 
578
        float scale, w1, w2;
 
579
 
 
580
        if (inventory[fs->index] < fs->value)
 
581
        {
 
582
                if (fs->child) return FuzzyWeight_r(inventory, fs->child);
 
583
                else return fs->weight;
 
584
        } //end if
 
585
        else if (fs->next)
 
586
        {
 
587
                if (inventory[fs->index] < fs->next->value)
 
588
                {
 
589
                        //first weight
 
590
                        if (fs->child) w1 = FuzzyWeight_r(inventory, fs->child);
 
591
                        else w1 = fs->weight;
 
592
                        //second weight
 
593
                        if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);
 
594
                        else w2 = fs->next->weight;
 
595
                        //the scale factor
 
596
                        if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case?
 
597
                        return w2;      // can't interpolate, return default weight
 
598
                        else
 
599
                                scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);
 
600
                        //scale between the two weights
 
601
                        return (1 - scale) * w1 + scale * w2;
 
602
                } //end if
 
603
                return FuzzyWeight_r(inventory, fs->next);
 
604
        } //end else if
 
605
        return fs->weight;
 
606
} //end of the function FuzzyWeight_r
 
607
//===========================================================================
 
608
//
 
609
// Parameter:                           -
 
610
// Returns:                                     -
 
611
// Changes Globals:             -
 
612
//===========================================================================
 
613
float FuzzyWeightUndecided_r(int *inventory, fuzzyseperator_t *fs)
 
614
{
 
615
        float scale, w1, w2;
 
616
 
 
617
        if (inventory[fs->index] < fs->value)
 
618
        {
 
619
                if (fs->child) return FuzzyWeightUndecided_r(inventory, fs->child);
 
620
                else return fs->minweight + random() * (fs->maxweight - fs->minweight);
 
621
        } //end if
 
622
        else if (fs->next)
 
623
        {
 
624
                if (inventory[fs->index] < fs->next->value)
 
625
                {
 
626
                        //first weight
 
627
                        if (fs->child) w1 = FuzzyWeightUndecided_r(inventory, fs->child);
 
628
                        else w1 = fs->minweight + random() * (fs->maxweight - fs->minweight);
 
629
                        //second weight
 
630
                        if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child);
 
631
                        else w2 = fs->next->minweight + random() * (fs->next->maxweight - fs->next->minweight);
 
632
                        //the scale factor
 
633
                        if(fs->next->value == MAX_INVENTORYVALUE) // is fs->next the default case?
 
634
                        return w2;      // can't interpolate, return default weight
 
635
                        else
 
636
                                scale = (float) (inventory[fs->index] - fs->value) / (fs->next->value - fs->value);
 
637
                        //scale between the two weights
 
638
                        return (1 - scale) * w1 + scale * w2;
 
639
                } //end if
 
640
                return FuzzyWeightUndecided_r(inventory, fs->next);
 
641
        } //end else if
 
642
        return fs->weight;
 
643
} //end of the function FuzzyWeightUndecided_r
 
644
//===========================================================================
 
645
//
 
646
// Parameter:                           -
 
647
// Returns:                                     -
 
648
// Changes Globals:             -
 
649
//===========================================================================
 
650
float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum)
 
651
{
 
652
#ifdef EVALUATERECURSIVELY
 
653
        return FuzzyWeight_r(inventory, wc->weights[weightnum].firstseperator);
 
654
#else
 
655
        fuzzyseperator_t *s;
 
656
 
 
657
        s = wc->weights[weightnum].firstseperator;
 
658
        if (!s) return 0;
 
659
        while(1)
 
660
        {
 
661
                if (inventory[s->index] < s->value)
 
662
                {
 
663
                        if (s->child) s = s->child;
 
664
                        else return s->weight;
 
665
                } //end if
 
666
                else
 
667
                {
 
668
                        if (s->next) s = s->next;
 
669
                        else return s->weight;
 
670
                } //end else
 
671
        } //end if
 
672
        return 0;
 
673
#endif
 
674
} //end of the function FuzzyWeight
 
675
//===========================================================================
 
676
//
 
677
// Parameter:                           -
 
678
// Returns:                                     -
 
679
// Changes Globals:             -
 
680
//===========================================================================
 
681
float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum)
 
682
{
 
683
#ifdef EVALUATERECURSIVELY
 
684
        return FuzzyWeightUndecided_r(inventory, wc->weights[weightnum].firstseperator);
 
685
#else
 
686
        fuzzyseperator_t *s;
 
687
 
 
688
        s = wc->weights[weightnum].firstseperator;
 
689
        if (!s) return 0;
 
690
        while(1)
 
691
        {
 
692
                if (inventory[s->index] < s->value)
 
693
                {
 
694
                        if (s->child) s = s->child;
 
695
                        else return s->minweight + random() * (s->maxweight - s->minweight);
 
696
                } //end if
 
697
                else
 
698
                {
 
699
                        if (s->next) s = s->next;
 
700
                        else return s->minweight + random() * (s->maxweight - s->minweight);
 
701
                } //end else
 
702
        } //end if
 
703
        return 0;
 
704
#endif
 
705
} //end of the function FuzzyWeightUndecided
 
706
//===========================================================================
 
707
//
 
708
// Parameter:                           -
 
709
// Returns:                                     -
 
710
// Changes Globals:             -
 
711
//===========================================================================
 
712
void EvolveFuzzySeperator_r(fuzzyseperator_t *fs)
 
713
{
 
714
        if (fs->child)
 
715
        {
 
716
                EvolveFuzzySeperator_r(fs->child);
 
717
        } //end if
 
718
        else if (fs->type == WT_BALANCE)
 
719
        {
 
720
                //every once in a while an evolution leap occurs, mutation
 
721
                if (random() < 0.01) fs->weight += crandom() * (fs->maxweight - fs->minweight);
 
722
                else fs->weight += crandom() * (fs->maxweight - fs->minweight) * 0.5;
 
723
                //modify bounds if necesary because of mutation
 
724
                if (fs->weight < fs->minweight) fs->minweight = fs->weight;
 
725
                else if (fs->weight > fs->maxweight) fs->maxweight = fs->weight;
 
726
        } //end else if
 
727
        if (fs->next) EvolveFuzzySeperator_r(fs->next);
 
728
} //end of the function EvolveFuzzySeperator_r
 
729
//===========================================================================
 
730
//
 
731
// Parameter:                           -
 
732
// Returns:                                     -
 
733
// Changes Globals:             -
 
734
//===========================================================================
 
735
void EvolveWeightConfig(weightconfig_t *config)
 
736
{
 
737
        int i;
 
738
 
 
739
        for (i = 0; i < config->numweights; i++)
 
740
        {
 
741
                EvolveFuzzySeperator_r(config->weights[i].firstseperator);
 
742
        } //end for
 
743
} //end of the function EvolveWeightConfig
 
744
//===========================================================================
 
745
//
 
746
// Parameter:                           -
 
747
// Returns:                                     -
 
748
// Changes Globals:             -
 
749
//===========================================================================
 
750
void ScaleFuzzySeperator_r(fuzzyseperator_t *fs, float scale)
 
751
{
 
752
        if (fs->child)
 
753
        {
 
754
                ScaleFuzzySeperator_r(fs->child, scale);
 
755
        } //end if
 
756
        else if (fs->type == WT_BALANCE)
 
757
        {
 
758
                //
 
759
                fs->weight = (float) (fs->maxweight + fs->minweight) * scale;
 
760
                //get the weight between bounds
 
761
                if (fs->weight < fs->minweight) fs->weight = fs->minweight;
 
762
                else if (fs->weight > fs->maxweight) fs->weight = fs->maxweight;
 
763
        } //end else if
 
764
        if (fs->next) ScaleFuzzySeperator_r(fs->next, scale);
 
765
} //end of the function ScaleFuzzySeperator_r
 
766
//===========================================================================
 
767
//
 
768
// Parameter:                           -
 
769
// Returns:                                     -
 
770
// Changes Globals:             -
 
771
//===========================================================================
 
772
void ScaleWeight(weightconfig_t *config, char *name, float scale)
 
773
{
 
774
        int i;
 
775
 
 
776
        if (scale < 0) scale = 0;
 
777
        else if (scale > 1) scale = 1;
 
778
        for (i = 0; i < config->numweights; i++)
 
779
        {
 
780
                if (!strcmp(name, config->weights[i].name))
 
781
                {
 
782
                        ScaleFuzzySeperator_r(config->weights[i].firstseperator, scale);
 
783
                        break;
 
784
                } //end if
 
785
        } //end for
 
786
} //end of the function ScaleWeight
 
787
//===========================================================================
 
788
//
 
789
// Parameter:                           -
 
790
// Returns:                                     -
 
791
// Changes Globals:             -
 
792
//===========================================================================
 
793
void ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t *fs, float scale)
 
794
{
 
795
        if (fs->child)
 
796
        {
 
797
                ScaleFuzzySeperatorBalanceRange_r(fs->child, scale);
 
798
        } //end if
 
799
        else if (fs->type == WT_BALANCE)
 
800
        {
 
801
                float mid = (fs->minweight + fs->maxweight) * 0.5;
 
802
                //get the weight between bounds
 
803
                fs->maxweight = mid + (fs->maxweight - mid) * scale;
 
804
                fs->minweight = mid + (fs->minweight - mid) * scale;
 
805
                if (fs->maxweight < fs->minweight)
 
806
                {
 
807
                        fs->maxweight = fs->minweight;
 
808
                } //end if
 
809
        } //end else if
 
810
        if (fs->next) ScaleFuzzySeperatorBalanceRange_r(fs->next, scale);
 
811
} //end of the function ScaleFuzzySeperatorBalanceRange_r
 
812
//===========================================================================
 
813
//
 
814
// Parameter:                           -
 
815
// Returns:                                     -
 
816
// Changes Globals:             -
 
817
//===========================================================================
 
818
void ScaleFuzzyBalanceRange(weightconfig_t *config, float scale)
 
819
{
 
820
        int i;
 
821
 
 
822
        if (scale < 0) scale = 0;
 
823
        else if (scale > 100) scale = 100;
 
824
        for (i = 0; i < config->numweights; i++)
 
825
        {
 
826
                ScaleFuzzySeperatorBalanceRange_r(config->weights[i].firstseperator, scale);
 
827
        } //end for
 
828
} //end of the function ScaleFuzzyBalanceRange
 
829
//===========================================================================
 
830
//
 
831
// Parameter:                           -
 
832
// Returns:                                     -
 
833
// Changes Globals:             -
 
834
//===========================================================================
 
835
int InterbreedFuzzySeperator_r(fuzzyseperator_t *fs1, fuzzyseperator_t *fs2,
 
836
                                                                fuzzyseperator_t *fsout)
 
837
{
 
838
        if (fs1->child)
 
839
        {
 
840
                if (!fs2->child || !fsout->child)
 
841
                {
 
842
                        botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal child\n");
 
843
                        return qfalse;
 
844
                } //end if
 
845
                if (!InterbreedFuzzySeperator_r(fs2->child, fs2->child, fsout->child))
 
846
                {
 
847
                        return qfalse;
 
848
                } //end if
 
849
        } //end if
 
850
        else if (fs1->type == WT_BALANCE)
 
851
        {
 
852
                if (fs2->type != WT_BALANCE || fsout->type != WT_BALANCE)
 
853
                {
 
854
                        botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal balance\n");
 
855
                        return qfalse;
 
856
                } //end if
 
857
                fsout->weight = (fs1->weight + fs2->weight) / 2;
 
858
                if (fsout->weight > fsout->maxweight) fsout->maxweight = fsout->weight;
 
859
                if (fsout->weight > fsout->minweight) fsout->minweight = fsout->weight;
 
860
        } //end else if
 
861
        if (fs1->next)
 
862
        {
 
863
                if (!fs2->next || !fsout->next)
 
864
                {
 
865
                        botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal next\n");
 
866
                        return qfalse;
 
867
                } //end if
 
868
                if (!InterbreedFuzzySeperator_r(fs1->next, fs2->next, fsout->next))
 
869
                {
 
870
                        return qfalse;
 
871
                } //end if
 
872
        } //end if
 
873
        return qtrue;
 
874
} //end of the function InterbreedFuzzySeperator_r
 
875
//===========================================================================
 
876
// config1 and config2 are interbreeded and stored in configout
 
877
//
 
878
// Parameter:                           -
 
879
// Returns:                                     -
 
880
// Changes Globals:             -
 
881
//===========================================================================
 
882
void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2,
 
883
                                                                weightconfig_t *configout)
 
884
{
 
885
        int i;
 
886
 
 
887
        if (config1->numweights != config2->numweights ||
 
888
                config1->numweights != configout->numweights)
 
889
        {
 
890
                botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal numweights\n");
 
891
                return;
 
892
        } //end if
 
893
        for (i = 0; i < config1->numweights; i++)
 
894
        {
 
895
                InterbreedFuzzySeperator_r(config1->weights[i].firstseperator,
 
896
                                                                        config2->weights[i].firstseperator,
 
897
                                                                        configout->weights[i].firstseperator);
 
898
        } //end for
 
899
} //end of the function InterbreedWeightConfigs
 
900
//===========================================================================
 
901
//
 
902
// Parameter:                   -
 
903
// Returns:                             -
 
904
// Changes Globals:             -
 
905
//===========================================================================
 
906
void BotShutdownWeights(void)
 
907
{
 
908
        int i;
 
909
 
 
910
        for( i = 0; i < MAX_WEIGHT_FILES; i++ )
 
911
        {
 
912
                if (weightFileList[i])
 
913
                {
 
914
                        FreeWeightConfig2(weightFileList[i]);
 
915
                        weightFileList[i] = NULL;
 
916
                } //end if
 
917
        } //end for
 
918
} //end of the function BotShutdownWeights