PageRenderTime 51ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/game/ai_util.c

https://bitbucket.org/bshaw/jk3game_sdk_mingw
C | 867 lines | 699 code | 160 blank | 8 comment | 231 complexity | 73d78551aaea2e88244e3a5b5e4be055 MD5 | raw file
  1. #include "g_local.h"
  2. #include "q_shared.h"
  3. #include "botlib.h"
  4. #include "ai_main.h"
  5. #ifdef BOT_ZMALLOC
  6. #define MAX_BALLOC 8192
  7. void *BAllocList[MAX_BALLOC];
  8. #endif
  9. char gBotChatBuffer[MAX_CLIENTS][MAX_CHAT_BUFFER_SIZE];
  10. void *B_TempAlloc(int size)
  11. {
  12. return BG_TempAlloc(size);
  13. }
  14. void B_TempFree(int size)
  15. {
  16. BG_TempFree(size);
  17. }
  18. void *B_Alloc(int size)
  19. {
  20. #ifdef BOT_ZMALLOC
  21. void *ptr = NULL;
  22. int i = 0;
  23. #ifdef BOTMEMTRACK
  24. int free = 0;
  25. int used = 0;
  26. while (i < MAX_BALLOC)
  27. {
  28. if (!BAllocList[i])
  29. {
  30. free++;
  31. }
  32. else
  33. {
  34. used++;
  35. }
  36. i++;
  37. }
  38. G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
  39. i = 0;
  40. #endif
  41. ptr = trap_BotGetMemoryGame(size);
  42. while (i < MAX_BALLOC)
  43. {
  44. if (!BAllocList[i])
  45. {
  46. BAllocList[i] = ptr;
  47. break;
  48. }
  49. i++;
  50. }
  51. if (i == MAX_BALLOC)
  52. {
  53. //If this happens we'll have to rely on this chunk being freed manually with B_Free, which it hopefully will be
  54. #ifdef DEBUG
  55. G_Printf("WARNING: MAXIMUM B_ALLOC ALLOCATIONS EXCEEDED\n");
  56. #endif
  57. }
  58. return ptr;
  59. #else
  60. return BG_Alloc(size);
  61. #endif
  62. }
  63. void B_Free(void *ptr)
  64. {
  65. #ifdef BOT_ZMALLOC
  66. int i = 0;
  67. #ifdef BOTMEMTRACK
  68. int free = 0;
  69. int used = 0;
  70. while (i < MAX_BALLOC)
  71. {
  72. if (!BAllocList[i])
  73. {
  74. free++;
  75. }
  76. else
  77. {
  78. used++;
  79. }
  80. i++;
  81. }
  82. G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
  83. i = 0;
  84. #endif
  85. while (i < MAX_BALLOC)
  86. {
  87. if (BAllocList[i] == ptr)
  88. {
  89. BAllocList[i] = NULL;
  90. break;
  91. }
  92. i++;
  93. }
  94. if (i == MAX_BALLOC)
  95. {
  96. //Likely because the limit was exceeded and we're now freeing the chunk manually as we hoped would happen
  97. #ifdef DEBUG
  98. G_Printf("WARNING: Freeing allocation which is not in the allocation structure\n");
  99. #endif
  100. }
  101. trap_BotFreeMemoryGame(ptr);
  102. #endif
  103. }
  104. void B_InitAlloc(void)
  105. {
  106. #ifdef BOT_ZMALLOC
  107. memset(BAllocList, 0, sizeof(BAllocList));
  108. #endif
  109. memset(gWPArray, 0, sizeof(gWPArray));
  110. }
  111. void B_CleanupAlloc(void)
  112. {
  113. #ifdef BOT_ZMALLOC
  114. int i = 0;
  115. while (i < MAX_BALLOC)
  116. {
  117. if (BAllocList[i])
  118. {
  119. trap_BotFreeMemoryGame(BAllocList[i]);
  120. BAllocList[i] = NULL;
  121. }
  122. i++;
  123. }
  124. #endif
  125. }
  126. int GetValueGroup(char *buf, char *group, char *outbuf)
  127. {
  128. char *place, *placesecond;
  129. int iplace;
  130. int failure;
  131. int i;
  132. int startpoint, startletter;
  133. int subg = 0;
  134. i = 0;
  135. iplace = 0;
  136. place = strstr(buf, group);
  137. if (!place)
  138. {
  139. return 0;
  140. }
  141. startpoint = place - buf + strlen(group) + 1;
  142. startletter = (place - buf) - 1;
  143. failure = 0;
  144. while (buf[startpoint+1] != '{' || buf[startletter] != '\n')
  145. {
  146. placesecond = strstr(place+1, group);
  147. if (placesecond)
  148. {
  149. startpoint += (placesecond - place);
  150. startletter += (placesecond - place);
  151. place = placesecond;
  152. }
  153. else
  154. {
  155. failure = 1;
  156. break;
  157. }
  158. }
  159. if (failure)
  160. {
  161. return 0;
  162. }
  163. //we have found the proper group name if we made it here, so find the opening brace and read into the outbuf
  164. //until hitting the end brace
  165. while (buf[startpoint] != '{')
  166. {
  167. startpoint++;
  168. }
  169. startpoint++;
  170. while (buf[startpoint] != '}' || subg)
  171. {
  172. if (buf[startpoint] == '{')
  173. {
  174. subg++;
  175. }
  176. else if (buf[startpoint] == '}')
  177. {
  178. subg--;
  179. }
  180. outbuf[i] = buf[startpoint];
  181. i++;
  182. startpoint++;
  183. }
  184. outbuf[i] = '\0';
  185. return 1;
  186. }
  187. int GetPairedValue(char *buf, char *key, char *outbuf)
  188. {
  189. char *place, *placesecond;
  190. int startpoint, startletter;
  191. int i, found;
  192. if (!buf || !key || !outbuf)
  193. {
  194. return 0;
  195. }
  196. i = 0;
  197. while (buf[i] && buf[i] != '\0')
  198. {
  199. if (buf[i] == '/')
  200. {
  201. if (buf[i+1] && buf[i+1] != '\0' && buf[i+1] == '/')
  202. {
  203. while (buf[i] != '\n')
  204. {
  205. buf[i] = '/';
  206. i++;
  207. }
  208. }
  209. }
  210. i++;
  211. }
  212. place = strstr(buf, key);
  213. if (!place)
  214. {
  215. return 0;
  216. }
  217. //tab == 9
  218. startpoint = place - buf + strlen(key);
  219. startletter = (place - buf) - 1;
  220. found = 0;
  221. while (!found)
  222. {
  223. if (startletter == 0 || !buf[startletter] || buf[startletter] == '\0' || buf[startletter] == 9 || buf[startletter] == ' ' || buf[startletter] == '\n')
  224. {
  225. if (buf[startpoint] == '\0' || buf[startpoint] == 9 || buf[startpoint] == ' ' || buf[startpoint] == '\n')
  226. {
  227. found = 1;
  228. break;
  229. }
  230. }
  231. placesecond = strstr(place+1, key);
  232. if (placesecond)
  233. {
  234. startpoint += placesecond - place;
  235. startletter += placesecond - place;
  236. place = placesecond;
  237. }
  238. else
  239. {
  240. place = NULL;
  241. break;
  242. }
  243. }
  244. if (!found || !place || !buf[startpoint] || buf[startpoint] == '\0')
  245. {
  246. return 0;
  247. }
  248. while (buf[startpoint] == ' ' || buf[startpoint] == 9 || buf[startpoint] == '\n')
  249. {
  250. startpoint++;
  251. }
  252. i = 0;
  253. while (buf[startpoint] && buf[startpoint] != '\0' && buf[startpoint] != '\n')
  254. {
  255. outbuf[i] = buf[startpoint];
  256. i++;
  257. startpoint++;
  258. }
  259. outbuf[i] = '\0';
  260. return 1;
  261. }
  262. int BotDoChat(bot_state_t *bs, char *section, int always)
  263. {
  264. char *chatgroup;
  265. int rVal;
  266. int inc_1;
  267. int inc_2;
  268. int inc_n;
  269. int lines;
  270. int checkedline;
  271. int getthisline;
  272. gentity_t *cobject;
  273. if (!bs->canChat)
  274. {
  275. return 0;
  276. }
  277. if (bs->doChat)
  278. { //already have a chat scheduled
  279. return 0;
  280. }
  281. if (trap_Cvar_VariableIntegerValue("se_language"))
  282. { //no chatting unless English.
  283. return 0;
  284. }
  285. if (Q_irand(1, 10) > bs->chatFrequency && !always)
  286. {
  287. return 0;
  288. }
  289. bs->chatTeam = 0;
  290. chatgroup = (char *)B_TempAlloc(MAX_CHAT_BUFFER_SIZE);
  291. rVal = GetValueGroup(gBotChatBuffer[bs->client], section, chatgroup);
  292. if (!rVal) //the bot has no group defined for the specified chat event
  293. {
  294. B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
  295. return 0;
  296. }
  297. inc_1 = 0;
  298. inc_2 = 2;
  299. while (chatgroup[inc_2] && chatgroup[inc_2] != '\0')
  300. {
  301. if (chatgroup[inc_2] != 13 && chatgroup[inc_2] != 9)
  302. {
  303. chatgroup[inc_1] = chatgroup[inc_2];
  304. inc_1++;
  305. }
  306. inc_2++;
  307. }
  308. chatgroup[inc_1] = '\0';
  309. inc_1 = 0;
  310. lines = 0;
  311. while (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
  312. {
  313. if (chatgroup[inc_1] == '\n')
  314. {
  315. lines++;
  316. }
  317. inc_1++;
  318. }
  319. if (!lines)
  320. {
  321. B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
  322. return 0;
  323. }
  324. getthisline = Q_irand(0, (lines+1));
  325. if (getthisline < 1)
  326. {
  327. getthisline = 1;
  328. }
  329. if (getthisline > lines)
  330. {
  331. getthisline = lines;
  332. }
  333. checkedline = 1;
  334. inc_1 = 0;
  335. while (checkedline != getthisline)
  336. {
  337. if (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
  338. {
  339. if (chatgroup[inc_1] == '\n')
  340. {
  341. inc_1++;
  342. checkedline++;
  343. }
  344. }
  345. if (checkedline == getthisline)
  346. {
  347. break;
  348. }
  349. inc_1++;
  350. }
  351. //we're at the starting position of the desired line here
  352. inc_2 = 0;
  353. while (chatgroup[inc_1] != '\n')
  354. {
  355. chatgroup[inc_2] = chatgroup[inc_1];
  356. inc_2++;
  357. inc_1++;
  358. }
  359. chatgroup[inc_2] = '\0';
  360. //trap_EA_Say(bs->client, chatgroup);
  361. inc_1 = 0;
  362. inc_2 = 0;
  363. if (strlen(chatgroup) > MAX_CHAT_LINE_SIZE)
  364. {
  365. B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
  366. return 0;
  367. }
  368. while (chatgroup[inc_1])
  369. {
  370. if (chatgroup[inc_1] == '%' && chatgroup[inc_1+1] != '%')
  371. {
  372. inc_1++;
  373. if (chatgroup[inc_1] == 's' && bs->chatObject)
  374. {
  375. cobject = bs->chatObject;
  376. }
  377. else if (chatgroup[inc_1] == 'a' && bs->chatAltObject)
  378. {
  379. cobject = bs->chatAltObject;
  380. }
  381. else
  382. {
  383. cobject = NULL;
  384. }
  385. if (cobject && cobject->client)
  386. {
  387. inc_n = 0;
  388. while (cobject->client->pers.netname[inc_n])
  389. {
  390. bs->currentChat[inc_2] = cobject->client->pers.netname[inc_n];
  391. inc_2++;
  392. inc_n++;
  393. }
  394. inc_2--; //to make up for the auto-increment below
  395. }
  396. }
  397. else
  398. {
  399. bs->currentChat[inc_2] = chatgroup[inc_1];
  400. }
  401. inc_2++;
  402. inc_1++;
  403. }
  404. bs->currentChat[inc_2] = '\0';
  405. if (strcmp(section, "GeneralGreetings") == 0)
  406. {
  407. bs->doChat = 2;
  408. }
  409. else
  410. {
  411. bs->doChat = 1;
  412. }
  413. bs->chatTime_stored = (strlen(bs->currentChat)*45)+Q_irand(1300, 1500);
  414. bs->chatTime = level.time + bs->chatTime_stored;
  415. B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
  416. return 1;
  417. }
  418. void ParseEmotionalAttachments(bot_state_t *bs, char *buf)
  419. {
  420. int i = 0;
  421. int i_c = 0;
  422. char tbuf[16];
  423. while (buf[i] && buf[i] != '}')
  424. {
  425. while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
  426. {
  427. i++;
  428. }
  429. if (buf[i] && buf[i] != '}')
  430. {
  431. i_c = 0;
  432. while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
  433. {
  434. bs->loved[bs->lovednum].name[i_c] = buf[i];
  435. i_c++;
  436. i++;
  437. }
  438. bs->loved[bs->lovednum].name[i_c] = '\0';
  439. while (buf[i] == ' ' || buf[i] == '{' || buf[i] == 9 || buf[i] == 13 || buf[i] == '\n')
  440. {
  441. i++;
  442. }
  443. i_c = 0;
  444. while (buf[i] != '{' && buf[i] != 9 && buf[i] != 13 && buf[i] != '\n')
  445. {
  446. tbuf[i_c] = buf[i];
  447. i_c++;
  448. i++;
  449. }
  450. tbuf[i_c] = '\0';
  451. bs->loved[bs->lovednum].level = atoi(tbuf);
  452. bs->lovednum++;
  453. }
  454. else
  455. {
  456. break;
  457. }
  458. if (bs->lovednum >= MAX_LOVED_ONES)
  459. {
  460. return;
  461. }
  462. i++;
  463. }
  464. }
  465. int ReadChatGroups(bot_state_t *bs, char *buf)
  466. {
  467. char *cgroupbegin;
  468. int cgbplace;
  469. int i;
  470. cgroupbegin = strstr(buf, "BEGIN_CHAT_GROUPS");
  471. if (!cgroupbegin)
  472. {
  473. return 0;
  474. }
  475. if (strlen(cgroupbegin) >= MAX_CHAT_BUFFER_SIZE)
  476. {
  477. G_Printf(S_COLOR_RED "Error: Personality chat section exceeds max size\n");
  478. return 0;
  479. }
  480. cgbplace = cgroupbegin - buf+1;
  481. while (buf[cgbplace] != '\n')
  482. {
  483. cgbplace++;
  484. }
  485. i = 0;
  486. while (buf[cgbplace] && buf[cgbplace] != '\0')
  487. {
  488. gBotChatBuffer[bs->client][i] = buf[cgbplace];
  489. i++;
  490. cgbplace++;
  491. }
  492. gBotChatBuffer[bs->client][i] = '\0';
  493. return 1;
  494. }
  495. void BotUtilizePersonality(bot_state_t *bs)
  496. {
  497. fileHandle_t f;
  498. int len, rlen;
  499. int failed;
  500. int i;
  501. //char buf[131072];
  502. char *buf = (char *)B_TempAlloc(131072);
  503. char *readbuf, *group;
  504. len = trap_FS_FOpenFile(bs->settings.personalityfile, &f, FS_READ);
  505. failed = 0;
  506. if (!f)
  507. {
  508. G_Printf(S_COLOR_RED "Error: Specified personality not found\n");
  509. B_TempFree(131072); //buf
  510. return;
  511. }
  512. if (len >= 131072)
  513. {
  514. G_Printf(S_COLOR_RED "Personality file exceeds maximum length\n");
  515. B_TempFree(131072); //buf
  516. return;
  517. }
  518. trap_FS_Read(buf, len, f);
  519. rlen = len;
  520. while (len < 131072)
  521. { //kill all characters after the file length, since sometimes FS_Read doesn't do that entirely (or so it seems)
  522. buf[len] = '\0';
  523. len++;
  524. }
  525. len = rlen;
  526. readbuf = (char *)B_TempAlloc(1024);
  527. group = (char *)B_TempAlloc(65536);
  528. if (!GetValueGroup(buf, "GeneralBotInfo", group))
  529. {
  530. G_Printf(S_COLOR_RED "Personality file contains no GeneralBotInfo group\n");
  531. failed = 1; //set failed so we know to set everything to default values
  532. }
  533. if (!failed && GetPairedValue(group, "reflex", readbuf))
  534. {
  535. bs->skills.reflex = atoi(readbuf);
  536. }
  537. else
  538. {
  539. bs->skills.reflex = 100; //default
  540. }
  541. if (!failed && GetPairedValue(group, "accuracy", readbuf))
  542. {
  543. bs->skills.accuracy = atof(readbuf);
  544. }
  545. else
  546. {
  547. bs->skills.accuracy = 10; //default
  548. }
  549. if (!failed && GetPairedValue(group, "turnspeed", readbuf))
  550. {
  551. bs->skills.turnspeed = atof(readbuf);
  552. }
  553. else
  554. {
  555. bs->skills.turnspeed = 0.01f; //default
  556. }
  557. if (!failed && GetPairedValue(group, "turnspeed_combat", readbuf))
  558. {
  559. bs->skills.turnspeed_combat = atof(readbuf);
  560. }
  561. else
  562. {
  563. bs->skills.turnspeed_combat = 0.05f; //default
  564. }
  565. if (!failed && GetPairedValue(group, "maxturn", readbuf))
  566. {
  567. bs->skills.maxturn = atof(readbuf);
  568. }
  569. else
  570. {
  571. bs->skills.maxturn = 360; //default
  572. }
  573. if (!failed && GetPairedValue(group, "perfectaim", readbuf))
  574. {
  575. bs->skills.perfectaim = atoi(readbuf);
  576. }
  577. else
  578. {
  579. bs->skills.perfectaim = 0; //default
  580. }
  581. if (!failed && GetPairedValue(group, "chatability", readbuf))
  582. {
  583. bs->canChat = atoi(readbuf);
  584. }
  585. else
  586. {
  587. bs->canChat = 0; //default
  588. }
  589. if (!failed && GetPairedValue(group, "chatfrequency", readbuf))
  590. {
  591. bs->chatFrequency = atoi(readbuf);
  592. }
  593. else
  594. {
  595. bs->chatFrequency = 5; //default
  596. }
  597. if (!failed && GetPairedValue(group, "hatelevel", readbuf))
  598. {
  599. bs->loved_death_thresh = atoi(readbuf);
  600. }
  601. else
  602. {
  603. bs->loved_death_thresh = 3; //default
  604. }
  605. if (!failed && GetPairedValue(group, "camper", readbuf))
  606. {
  607. bs->isCamper = atoi(readbuf);
  608. }
  609. else
  610. {
  611. bs->isCamper = 0; //default
  612. }
  613. if (!failed && GetPairedValue(group, "saberspecialist", readbuf))
  614. {
  615. bs->saberSpecialist = atoi(readbuf);
  616. }
  617. else
  618. {
  619. bs->saberSpecialist = 0; //default
  620. }
  621. if (!failed && GetPairedValue(group, "forceinfo", readbuf))
  622. {
  623. Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", readbuf);
  624. }
  625. else
  626. {
  627. Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", DEFAULT_FORCEPOWERS);
  628. }
  629. i = 0;
  630. while (i < MAX_CHAT_BUFFER_SIZE)
  631. { //clear out the chat buffer for this bot
  632. gBotChatBuffer[bs->client][i] = '\0';
  633. i++;
  634. }
  635. if (bs->canChat)
  636. {
  637. if (!ReadChatGroups(bs, buf))
  638. {
  639. bs->canChat = 0;
  640. }
  641. }
  642. if (GetValueGroup(buf, "BotWeaponWeights", group))
  643. {
  644. if (GetPairedValue(group, "WP_STUN_BATON", readbuf))
  645. {
  646. bs->botWeaponWeights[WP_STUN_BATON] = atoi(readbuf);
  647. bs->botWeaponWeights[WP_MELEE] = bs->botWeaponWeights[WP_STUN_BATON];
  648. }
  649. if (GetPairedValue(group, "WP_SABER", readbuf))
  650. {
  651. bs->botWeaponWeights[WP_SABER] = atoi(readbuf);
  652. }
  653. if (GetPairedValue(group, "WP_BRYAR_PISTOL", readbuf))
  654. {
  655. bs->botWeaponWeights[WP_BRYAR_PISTOL] = atoi(readbuf);
  656. }
  657. if (GetPairedValue(group, "WP_BLASTER", readbuf))
  658. {
  659. bs->botWeaponWeights[WP_BLASTER] = atoi(readbuf);
  660. }
  661. if (GetPairedValue(group, "WP_DISRUPTOR", readbuf))
  662. {
  663. bs->botWeaponWeights[WP_DISRUPTOR] = atoi(readbuf);
  664. }
  665. if (GetPairedValue(group, "WP_BOWCASTER", readbuf))
  666. {
  667. bs->botWeaponWeights[WP_BOWCASTER] = atoi(readbuf);
  668. }
  669. if (GetPairedValue(group, "WP_REPEATER", readbuf))
  670. {
  671. bs->botWeaponWeights[WP_REPEATER] = atoi(readbuf);
  672. }
  673. if (GetPairedValue(group, "WP_DEMP2", readbuf))
  674. {
  675. bs->botWeaponWeights[WP_DEMP2] = atoi(readbuf);
  676. }
  677. if (GetPairedValue(group, "WP_FLECHETTE", readbuf))
  678. {
  679. bs->botWeaponWeights[WP_FLECHETTE] = atoi(readbuf);
  680. }
  681. if (GetPairedValue(group, "WP_ROCKET_LAUNCHER", readbuf))
  682. {
  683. bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = atoi(readbuf);
  684. }
  685. if (GetPairedValue(group, "WP_THERMAL", readbuf))
  686. {
  687. bs->botWeaponWeights[WP_THERMAL] = atoi(readbuf);
  688. }
  689. if (GetPairedValue(group, "WP_TRIP_MINE", readbuf))
  690. {
  691. bs->botWeaponWeights[WP_TRIP_MINE] = atoi(readbuf);
  692. }
  693. if (GetPairedValue(group, "WP_DET_PACK", readbuf))
  694. {
  695. bs->botWeaponWeights[WP_DET_PACK] = atoi(readbuf);
  696. }
  697. }
  698. bs->lovednum = 0;
  699. if (GetValueGroup(buf, "EmotionalAttachments", group))
  700. {
  701. ParseEmotionalAttachments(bs, group);
  702. }
  703. B_TempFree(131072); //buf
  704. B_TempFree(1024); //readbuf
  705. B_TempFree(65536); //group
  706. trap_FS_FCloseFile(f);
  707. }