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