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