00001 #include "g_local.h"
00002 #include "q_shared.h"
00003 #include "botlib.h"
00004 #include "ai_main.h"
00005
00006 #ifdef BOT_ZMALLOC
00007 #define MAX_BALLOC 8192
00008
00009 void *BAllocList[MAX_BALLOC];
00010 #endif
00011
00012 char gBotChatBuffer[MAX_CLIENTS][MAX_CHAT_BUFFER_SIZE];
00013
00014 void *B_TempAlloc(int size)
00015 {
00016 return BG_TempAlloc(size);
00017 }
00018
00019 void B_TempFree(int size)
00020 {
00021 BG_TempFree(size);
00022 }
00023
00024
00025 void *B_Alloc(int size)
00026 {
00027 #ifdef BOT_ZMALLOC
00028 void *ptr = NULL;
00029 int i = 0;
00030
00031 #ifdef BOTMEMTRACK
00032 int free = 0;
00033 int used = 0;
00034
00035 while (i < MAX_BALLOC)
00036 {
00037 if (!BAllocList[i])
00038 {
00039 free++;
00040 }
00041 else
00042 {
00043 used++;
00044 }
00045
00046 i++;
00047 }
00048
00049 G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00050
00051 i = 0;
00052 #endif
00053
00054 ptr = trap_BotGetMemoryGame(size);
00055
00056 while (i < MAX_BALLOC)
00057 {
00058 if (!BAllocList[i])
00059 {
00060 BAllocList[i] = ptr;
00061 break;
00062 }
00063 i++;
00064 }
00065
00066 if (i == MAX_BALLOC)
00067 {
00068
00069 #ifdef DEBUG
00070 G_Printf("WARNING: MAXIMUM B_ALLOC ALLOCATIONS EXCEEDED\n");
00071 #endif
00072 }
00073
00074 return ptr;
00075 #else
00076
00077 return BG_Alloc(size);
00078
00079 #endif
00080 }
00081
00082 void B_Free(void *ptr)
00083 {
00084 #ifdef BOT_ZMALLOC
00085 int i = 0;
00086
00087 #ifdef BOTMEMTRACK
00088 int free = 0;
00089 int used = 0;
00090
00091 while (i < MAX_BALLOC)
00092 {
00093 if (!BAllocList[i])
00094 {
00095 free++;
00096 }
00097 else
00098 {
00099 used++;
00100 }
00101
00102 i++;
00103 }
00104
00105 G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00106
00107 i = 0;
00108 #endif
00109
00110 while (i < MAX_BALLOC)
00111 {
00112 if (BAllocList[i] == ptr)
00113 {
00114 BAllocList[i] = NULL;
00115 break;
00116 }
00117
00118 i++;
00119 }
00120
00121 if (i == MAX_BALLOC)
00122 {
00123
00124 #ifdef DEBUG
00125 G_Printf("WARNING: Freeing allocation which is not in the allocation structure\n");
00126 #endif
00127 }
00128
00129 trap_BotFreeMemoryGame(ptr);
00130 #endif
00131 }
00132
00133 void B_InitAlloc(void)
00134 {
00135 #ifdef BOT_ZMALLOC
00136 memset(BAllocList, 0, sizeof(BAllocList));
00137 #endif
00138
00139 memset(gWPArray, 0, sizeof(gWPArray));
00140 }
00141
00142 void B_CleanupAlloc(void)
00143 {
00144 #ifdef BOT_ZMALLOC
00145 int i = 0;
00146
00147 while (i < MAX_BALLOC)
00148 {
00149 if (BAllocList[i])
00150 {
00151 trap_BotFreeMemoryGame(BAllocList[i]);
00152 BAllocList[i] = NULL;
00153 }
00154
00155 i++;
00156 }
00157 #endif
00158 }
00159
00160 int GetValueGroup(char *buf, char *group, char *outbuf)
00161 {
00162 char *place, *placesecond;
00163 int iplace;
00164 int failure;
00165 int i;
00166 int startpoint, startletter;
00167 int subg = 0;
00168
00169 i = 0;
00170
00171 iplace = 0;
00172
00173 place = strstr(buf, group);
00174
00175 if (!place)
00176 {
00177 return 0;
00178 }
00179
00180 startpoint = place - buf + strlen(group) + 1;
00181 startletter = (place - buf) - 1;
00182
00183 failure = 0;
00184
00185 while (buf[startpoint+1] != '{' || buf[startletter] != '\n')
00186 {
00187 placesecond = strstr(place+1, group);
00188
00189 if (placesecond)
00190 {
00191 startpoint += (placesecond - place);
00192 startletter += (placesecond - place);
00193 place = placesecond;
00194 }
00195 else
00196 {
00197 failure = 1;
00198 break;
00199 }
00200 }
00201
00202 if (failure)
00203 {
00204 return 0;
00205 }
00206
00207
00208
00209
00210 while (buf[startpoint] != '{')
00211 {
00212 startpoint++;
00213 }
00214
00215 startpoint++;
00216
00217 while (buf[startpoint] != '}' || subg)
00218 {
00219 if (buf[startpoint] == '{')
00220 {
00221 subg++;
00222 }
00223 else if (buf[startpoint] == '}')
00224 {
00225 subg--;
00226 }
00227 outbuf[i] = buf[startpoint];
00228 i++;
00229 startpoint++;
00230 }
00231 outbuf[i] = '\0';
00232
00233 return 1;
00234 }
00235
00236 int GetPairedValue(char *buf, char *key, char *outbuf)
00237 {
00238 char *place, *placesecond;
00239 int startpoint, startletter;
00240 int i, found;
00241
00242 if (!buf || !key || !outbuf)
00243 {
00244 return 0;
00245 }
00246
00247 i = 0;
00248
00249 while (buf[i] && buf[i] != '\0')
00250 {
00251 if (buf[i] == '/')
00252 {
00253 if (buf[i+1] && buf[i+1] != '\0' && buf[i+1] == '/')
00254 {
00255 while (buf[i] != '\n')
00256 {
00257 buf[i] = '/';
00258 i++;
00259 }
00260 }
00261 }
00262 i++;
00263 }
00264
00265 place = strstr(buf, key);
00266
00267 if (!place)
00268 {
00269 return 0;
00270 }
00271
00272 startpoint = place - buf + strlen(key);
00273 startletter = (place - buf) - 1;
00274
00275 found = 0;
00276
00277 while (!found)
00278 {
00279 if (startletter == 0 || !buf[startletter] || buf[startletter] == '\0' || buf[startletter] == 9 || buf[startletter] == ' ' || buf[startletter] == '\n')
00280 {
00281 if (buf[startpoint] == '\0' || buf[startpoint] == 9 || buf[startpoint] == ' ' || buf[startpoint] == '\n')
00282 {
00283 found = 1;
00284 break;
00285 }
00286 }
00287
00288 placesecond = strstr(place+1, key);
00289
00290 if (placesecond)
00291 {
00292 startpoint += placesecond - place;
00293 startletter += placesecond - place;
00294 place = placesecond;
00295 }
00296 else
00297 {
00298 place = NULL;
00299 break;
00300 }
00301
00302 }
00303
00304 if (!found || !place || !buf[startpoint] || buf[startpoint] == '\0')
00305 {
00306 return 0;
00307 }
00308
00309 while (buf[startpoint] == ' ' || buf[startpoint] == 9 || buf[startpoint] == '\n')
00310 {
00311 startpoint++;
00312 }
00313
00314 i = 0;
00315
00316 while (buf[startpoint] && buf[startpoint] != '\0' && buf[startpoint] != '\n')
00317 {
00318 outbuf[i] = buf[startpoint];
00319 i++;
00320 startpoint++;
00321 }
00322
00323 outbuf[i] = '\0';
00324
00325 return 1;
00326 }
00327
00328 int BotDoChat(bot_state_t *bs, char *section, int always)
00329 {
00330 char *chatgroup;
00331 int rVal;
00332 int inc_1;
00333 int inc_2;
00334 int inc_n;
00335 int lines;
00336 int checkedline;
00337 int getthisline;
00338 gentity_t *cobject;
00339
00340 if (!bs->canChat)
00341 {
00342 return 0;
00343 }
00344
00345 if (bs->doChat)
00346 {
00347 return 0;
00348 }
00349
00350 if (trap_Cvar_VariableIntegerValue("se_language"))
00351 {
00352 return 0;
00353 }
00354
00355 if (Q_irand(1, 10) > bs->chatFrequency && !always)
00356 {
00357 return 0;
00358 }
00359
00360 bs->chatTeam = 0;
00361
00362 chatgroup = (char *)B_TempAlloc(MAX_CHAT_BUFFER_SIZE);
00363
00364 rVal = GetValueGroup(gBotChatBuffer[bs->client], section, chatgroup);
00365
00366 if (!rVal)
00367 {
00368 B_TempFree(MAX_CHAT_BUFFER_SIZE);
00369 return 0;
00370 }
00371
00372 inc_1 = 0;
00373 inc_2 = 2;
00374
00375 while (chatgroup[inc_2] && chatgroup[inc_2] != '\0')
00376 {
00377 if (chatgroup[inc_2] != 13 && chatgroup[inc_2] != 9)
00378 {
00379 chatgroup[inc_1] = chatgroup[inc_2];
00380 inc_1++;
00381 }
00382 inc_2++;
00383 }
00384 chatgroup[inc_1] = '\0';
00385
00386 inc_1 = 0;
00387
00388 lines = 0;
00389
00390 while (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00391 {
00392 if (chatgroup[inc_1] == '\n')
00393 {
00394 lines++;
00395 }
00396 inc_1++;
00397 }
00398
00399 if (!lines)
00400 {
00401 B_TempFree(MAX_CHAT_BUFFER_SIZE);
00402 return 0;
00403 }
00404
00405 getthisline = Q_irand(0, (lines+1));
00406
00407 if (getthisline < 1)
00408 {
00409 getthisline = 1;
00410 }
00411 if (getthisline > lines)
00412 {
00413 getthisline = lines;
00414 }
00415
00416 checkedline = 1;
00417
00418 inc_1 = 0;
00419
00420 while (checkedline != getthisline)
00421 {
00422 if (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00423 {
00424 if (chatgroup[inc_1] == '\n')
00425 {
00426 inc_1++;
00427 checkedline++;
00428 }
00429 }
00430
00431 if (checkedline == getthisline)
00432 {
00433 break;
00434 }
00435
00436 inc_1++;
00437 }
00438
00439
00440 inc_2 = 0;
00441
00442 while (chatgroup[inc_1] != '\n')
00443 {
00444 chatgroup[inc_2] = chatgroup[inc_1];
00445 inc_2++;
00446 inc_1++;
00447 }
00448 chatgroup[inc_2] = '\0';
00449
00450
00451 inc_1 = 0;
00452 inc_2 = 0;
00453
00454 if (strlen(chatgroup) > MAX_CHAT_LINE_SIZE)
00455 {
00456 B_TempFree(MAX_CHAT_BUFFER_SIZE);
00457 return 0;
00458 }
00459
00460 while (chatgroup[inc_1])
00461 {
00462 if (chatgroup[inc_1] == '%' && chatgroup[inc_1+1] != '%')
00463 {
00464 inc_1++;
00465
00466 if (chatgroup[inc_1] == 's' && bs->chatObject)
00467 {
00468 cobject = bs->chatObject;
00469 }
00470 else if (chatgroup[inc_1] == 'a' && bs->chatAltObject)
00471 {
00472 cobject = bs->chatAltObject;
00473 }
00474 else
00475 {
00476 cobject = NULL;
00477 }
00478
00479 if (cobject && cobject->client)
00480 {
00481 inc_n = 0;
00482
00483 while (cobject->client->pers.netname[inc_n])
00484 {
00485 bs->currentChat[inc_2] = cobject->client->pers.netname[inc_n];
00486 inc_2++;
00487 inc_n++;
00488 }
00489 inc_2--;
00490 }
00491 }
00492 else
00493 {
00494 bs->currentChat[inc_2] = chatgroup[inc_1];
00495 }
00496 inc_2++;
00497 inc_1++;
00498 }
00499 bs->currentChat[inc_2] = '\0';
00500
00501 if (strcmp(section, "GeneralGreetings") == 0)
00502 {
00503 bs->doChat = 2;
00504 }
00505 else
00506 {
00507 bs->doChat = 1;
00508 }
00509 bs->chatTime_stored = (strlen(bs->currentChat)*45)+Q_irand(1300, 1500);
00510 bs->chatTime = level.time + bs->chatTime_stored;
00511
00512 B_TempFree(MAX_CHAT_BUFFER_SIZE);
00513
00514 return 1;
00515 }
00516
00517 void ParseEmotionalAttachments(bot_state_t *bs, char *buf)
00518 {
00519 int i = 0;
00520 int i_c = 0;
00521 char tbuf[16];
00522
00523 while (buf[i] && buf[i] != '}')
00524 {
00525 while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
00526 {
00527 i++;
00528 }
00529
00530 if (buf[i] && buf[i] != '}')
00531 {
00532 i_c = 0;
00533 while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
00534 {
00535 bs->loved[bs->lovednum].name[i_c] = buf[i];
00536 i_c++;
00537 i++;
00538 }
00539 bs->loved[bs->lovednum].name[i_c] = '\0';
00540
00541 while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
00542 {
00543 i++;
00544 }
00545
00546 i_c = 0;
00547
00548 while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
00549 {
00550 tbuf[i_c] = buf[i];
00551 i_c++;
00552 i++;
00553 }
00554 tbuf[i_c] = '\0';
00555
00556 bs->loved[bs->lovednum].level = atoi(tbuf);
00557
00558 bs->lovednum++;
00559 }
00560 else
00561 {
00562 break;
00563 }
00564
00565 if (bs->lovednum >= MAX_LOVED_ONES)
00566 {
00567 return;
00568 }
00569
00570 i++;
00571 }
00572 }
00573
00574 int ReadChatGroups(bot_state_t *bs, char *buf)
00575 {
00576 char *cgroupbegin;
00577 int cgbplace;
00578 int i;
00579
00580 cgroupbegin = strstr(buf, "BEGIN_CHAT_GROUPS");
00581
00582 if (!cgroupbegin)
00583 {
00584 return 0;
00585 }
00586
00587 if (strlen(cgroupbegin) >= MAX_CHAT_BUFFER_SIZE)
00588 {
00589 G_Printf(S_COLOR_RED "Error: Personality chat section exceeds max size\n");
00590 return 0;
00591 }
00592
00593 cgbplace = cgroupbegin - buf+1;
00594
00595 while (buf[cgbplace] != '\n')
00596 {
00597 cgbplace++;
00598 }
00599
00600 i = 0;
00601
00602 while (buf[cgbplace] && buf[cgbplace] != '\0')
00603 {
00604 gBotChatBuffer[bs->client][i] = buf[cgbplace];
00605 i++;
00606 cgbplace++;
00607 }
00608
00609 gBotChatBuffer[bs->client][i] = '\0';
00610
00611 return 1;
00612 }
00613
00614 void BotUtilizePersonality(bot_state_t *bs)
00615 {
00616 fileHandle_t f;
00617 int len, rlen;
00618 int failed;
00619 int i;
00620
00621 char *buf = (char *)B_TempAlloc(131072);
00622 char *readbuf, *group;
00623
00624 len = trap_FS_FOpenFile(bs->settings.personalityfile, &f, FS_READ);
00625
00626 failed = 0;
00627
00628 if (!f)
00629 {
00630 G_Printf(S_COLOR_RED "Error: Specified personality not found\n");
00631 B_TempFree(131072);
00632 return;
00633 }
00634
00635 if (len >= 131072)
00636 {
00637 G_Printf(S_COLOR_RED "Personality file exceeds maximum length\n");
00638 B_TempFree(131072);
00639 return;
00640 }
00641
00642 trap_FS_Read(buf, len, f);
00643
00644 rlen = len;
00645
00646 while (len < 131072)
00647 {
00648 buf[len] = '\0';
00649 len++;
00650 }
00651
00652 len = rlen;
00653
00654 readbuf = (char *)B_TempAlloc(1024);
00655 group = (char *)B_TempAlloc(65536);
00656
00657 if (!GetValueGroup(buf, "GeneralBotInfo", group))
00658 {
00659 G_Printf(S_COLOR_RED "Personality file contains no GeneralBotInfo group\n");
00660 failed = 1;
00661 }
00662
00663 if (!failed && GetPairedValue(group, "reflex", readbuf))
00664 {
00665 bs->skills.reflex = atoi(readbuf);
00666 }
00667 else
00668 {
00669 bs->skills.reflex = 100;
00670 }
00671
00672 if (!failed && GetPairedValue(group, "accuracy", readbuf))
00673 {
00674 bs->skills.accuracy = atof(readbuf);
00675 }
00676 else
00677 {
00678 bs->skills.accuracy = 10;
00679 }
00680
00681 if (!failed && GetPairedValue(group, "turnspeed", readbuf))
00682 {
00683 bs->skills.turnspeed = atof(readbuf);
00684 }
00685 else
00686 {
00687 bs->skills.turnspeed = 0.01f;
00688 }
00689
00690 if (!failed && GetPairedValue(group, "turnspeed_combat", readbuf))
00691 {
00692 bs->skills.turnspeed_combat = atof(readbuf);
00693 }
00694 else
00695 {
00696 bs->skills.turnspeed_combat = 0.05f;
00697 }
00698
00699 if (!failed && GetPairedValue(group, "maxturn", readbuf))
00700 {
00701 bs->skills.maxturn = atof(readbuf);
00702 }
00703 else
00704 {
00705 bs->skills.maxturn = 360;
00706 }
00707
00708 if (!failed && GetPairedValue(group, "perfectaim", readbuf))
00709 {
00710 bs->skills.perfectaim = atoi(readbuf);
00711 }
00712 else
00713 {
00714 bs->skills.perfectaim = 0;
00715 }
00716
00717 if (!failed && GetPairedValue(group, "chatability", readbuf))
00718 {
00719 bs->canChat = atoi(readbuf);
00720 }
00721 else
00722 {
00723 bs->canChat = 0;
00724 }
00725
00726 if (!failed && GetPairedValue(group, "chatfrequency", readbuf))
00727 {
00728 bs->chatFrequency = atoi(readbuf);
00729 }
00730 else
00731 {
00732 bs->chatFrequency = 5;
00733 }
00734
00735 if (!failed && GetPairedValue(group, "hatelevel", readbuf))
00736 {
00737 bs->loved_death_thresh = atoi(readbuf);
00738 }
00739 else
00740 {
00741 bs->loved_death_thresh = 3;
00742 }
00743
00744 if (!failed && GetPairedValue(group, "camper", readbuf))
00745 {
00746 bs->isCamper = atoi(readbuf);
00747 }
00748 else
00749 {
00750 bs->isCamper = 0;
00751 }
00752
00753 if (!failed && GetPairedValue(group, "saberspecialist", readbuf))
00754 {
00755 bs->saberSpecialist = atoi(readbuf);
00756 }
00757 else
00758 {
00759 bs->saberSpecialist = 0;
00760 }
00761
00762 if (!failed && GetPairedValue(group, "forceinfo", readbuf))
00763 {
00764 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", readbuf);
00765 }
00766 else
00767 {
00768 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", DEFAULT_FORCEPOWERS);
00769 }
00770
00771 i = 0;
00772
00773 while (i < MAX_CHAT_BUFFER_SIZE)
00774 {
00775 gBotChatBuffer[bs->client][i] = '\0';
00776 i++;
00777 }
00778
00779 if (bs->canChat)
00780 {
00781 if (!ReadChatGroups(bs, buf))
00782 {
00783 bs->canChat = 0;
00784 }
00785 }
00786
00787 if (GetValueGroup(buf, "BotWeaponWeights", group))
00788 {
00789 if (GetPairedValue(group, "WP_STUN_BATON", readbuf))
00790 {
00791 bs->botWeaponWeights[WP_STUN_BATON] = atoi(readbuf);
00792 bs->botWeaponWeights[WP_MELEE] = bs->botWeaponWeights[WP_STUN_BATON];
00793 }
00794
00795 if (GetPairedValue(group, "WP_SABER", readbuf))
00796 {
00797 bs->botWeaponWeights[WP_SABER] = atoi(readbuf);
00798 }
00799
00800 if (GetPairedValue(group, "WP_BRYAR_PISTOL", readbuf))
00801 {
00802 bs->botWeaponWeights[WP_BRYAR_PISTOL] = atoi(readbuf);
00803 }
00804
00805 if (GetPairedValue(group, "WP_BLASTER", readbuf))
00806 {
00807 bs->botWeaponWeights[WP_BLASTER] = atoi(readbuf);
00808 }
00809
00810 if (GetPairedValue(group, "WP_DISRUPTOR", readbuf))
00811 {
00812 bs->botWeaponWeights[WP_DISRUPTOR] = atoi(readbuf);
00813 }
00814
00815 if (GetPairedValue(group, "WP_BOWCASTER", readbuf))
00816 {
00817 bs->botWeaponWeights[WP_BOWCASTER] = atoi(readbuf);
00818 }
00819
00820 if (GetPairedValue(group, "WP_REPEATER", readbuf))
00821 {
00822 bs->botWeaponWeights[WP_REPEATER] = atoi(readbuf);
00823 }
00824
00825 if (GetPairedValue(group, "WP_DEMP2", readbuf))
00826 {
00827 bs->botWeaponWeights[WP_DEMP2] = atoi(readbuf);
00828 }
00829
00830 if (GetPairedValue(group, "WP_FLECHETTE", readbuf))
00831 {
00832 bs->botWeaponWeights[WP_FLECHETTE] = atoi(readbuf);
00833 }
00834
00835 if (GetPairedValue(group, "WP_ROCKET_LAUNCHER", readbuf))
00836 {
00837 bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = atoi(readbuf);
00838 }
00839
00840 if (GetPairedValue(group, "WP_THERMAL", readbuf))
00841 {
00842 bs->botWeaponWeights[WP_THERMAL] = atoi(readbuf);
00843 }
00844
00845 if (GetPairedValue(group, "WP_TRIP_MINE", readbuf))
00846 {
00847 bs->botWeaponWeights[WP_TRIP_MINE] = atoi(readbuf);
00848 }
00849
00850 if (GetPairedValue(group, "WP_DET_PACK", readbuf))
00851 {
00852 bs->botWeaponWeights[WP_DET_PACK] = atoi(readbuf);
00853 }
00854 }
00855
00856 bs->lovednum = 0;
00857
00858 if (GetValueGroup(buf, "EmotionalAttachments", group))
00859 {
00860 ParseEmotionalAttachments(bs, group);
00861 }
00862
00863 B_TempFree(131072);
00864 B_TempFree(1024);
00865 B_TempFree(65536);
00866 trap_FS_FCloseFile(f);
00867 }