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