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 //===========================================================================
ReadValue(source_t * source,float * value)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 //===========================================================================
ReadFuzzyWeight(source_t * source,fuzzyseperator_t * fs)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 //===========================================================================
FreeFuzzySeperators_r(fuzzyseperator_t * fs)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 //===========================================================================
FreeWeightConfig2(weightconfig_t * config)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 //===========================================================================
FreeWeightConfig(weightconfig_t * config)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 //===========================================================================
ReadFuzzySeperators_r(source_t * source)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 //===========================================================================
ReadWeightConfig(char * filename)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 //===========================================================================
FindFuzzyWeight(weightconfig_t * wc,char * name)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 //===========================================================================
FuzzyWeight_r(int * inventory,fuzzyseperator_t * fs)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 //===========================================================================
FuzzyWeightUndecided_r(int * inventory,fuzzyseperator_t * fs)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 //===========================================================================
FuzzyWeight(int * inventory,weightconfig_t * wc,int weightnum)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 //===========================================================================
FuzzyWeightUndecided(int * inventory,weightconfig_t * wc,int weightnum)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 //===========================================================================
EvolveFuzzySeperator_r(fuzzyseperator_t * fs)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 //===========================================================================
EvolveWeightConfig(weightconfig_t * config)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 //===========================================================================
ScaleFuzzySeperator_r(fuzzyseperator_t * fs,float scale)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 //===========================================================================
ScaleWeight(weightconfig_t * config,char * name,float scale)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 //===========================================================================
ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t * fs,float scale)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 //===========================================================================
ScaleFuzzyBalanceRange(weightconfig_t * config,float scale)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 //===========================================================================
InterbreedFuzzySeperator_r(fuzzyseperator_t * fs1,fuzzyseperator_t * fs2,fuzzyseperator_t * fsout)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 //===========================================================================
InterbreedWeightConfigs(weightconfig_t * config1,weightconfig_t * config2,weightconfig_t * configout)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 //===========================================================================
BotShutdownWeights(void)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
919