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