PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/game/ai_wpnav.c

https://bitbucket.org/bshaw/jk3game_sdk_mingw
C | 3813 lines | 3083 code | 670 blank | 60 comment | 777 complexity | 87627928173391e4577879087fa43f7e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #include "g_local.h"
  2. #include "q_shared.h"
  3. #include "botlib.h"
  4. #include "ai_main.h"
  5. float gWPRenderTime = 0;
  6. float gDeactivated = 0;
  7. float gBotEdit = 0;
  8. int gWPRenderedFrame = 0;
  9. #include "../namespace_begin.h"
  10. wpobject_t *gWPArray[MAX_WPARRAY_SIZE];
  11. int gWPNum = 0;
  12. #include "../namespace_end.h"
  13. int gLastPrintedIndex = -1;
  14. #ifndef _XBOX
  15. nodeobject_t nodetable[MAX_NODETABLE_SIZE];
  16. int nodenum; //so we can connect broken trails
  17. #endif
  18. int gLevelFlags = 0;
  19. char *GetFlagStr( int flags )
  20. {
  21. char *flagstr;
  22. int i;
  23. flagstr = (char *)B_TempAlloc(128);
  24. i = 0;
  25. if (!flags)
  26. {
  27. strcpy(flagstr, "none\0");
  28. goto fend;
  29. }
  30. if (flags & WPFLAG_JUMP)
  31. {
  32. flagstr[i] = 'j';
  33. i++;
  34. }
  35. if (flags & WPFLAG_DUCK)
  36. {
  37. flagstr[i] = 'd';
  38. i++;
  39. }
  40. if (flags & WPFLAG_SNIPEORCAMPSTAND)
  41. {
  42. flagstr[i] = 'c';
  43. i++;
  44. }
  45. if (flags & WPFLAG_WAITFORFUNC)
  46. {
  47. flagstr[i] = 'f';
  48. i++;
  49. }
  50. if (flags & WPFLAG_SNIPEORCAMP)
  51. {
  52. flagstr[i] = 's';
  53. i++;
  54. }
  55. if (flags & WPFLAG_ONEWAY_FWD)
  56. {
  57. flagstr[i] = 'x';
  58. i++;
  59. }
  60. if (flags & WPFLAG_ONEWAY_BACK)
  61. {
  62. flagstr[i] = 'y';
  63. i++;
  64. }
  65. if (flags & WPFLAG_GOALPOINT)
  66. {
  67. flagstr[i] = 'g';
  68. i++;
  69. }
  70. if (flags & WPFLAG_NOVIS)
  71. {
  72. flagstr[i] = 'n';
  73. i++;
  74. }
  75. if (flags & WPFLAG_NOMOVEFUNC)
  76. {
  77. flagstr[i] = 'm';
  78. i++;
  79. }
  80. if (flags & WPFLAG_RED_FLAG)
  81. {
  82. if (i)
  83. {
  84. flagstr[i] = ' ';
  85. i++;
  86. }
  87. flagstr[i] = 'r';
  88. i++;
  89. flagstr[i] = 'e';
  90. i++;
  91. flagstr[i] = 'd';
  92. i++;
  93. flagstr[i] = ' ';
  94. i++;
  95. flagstr[i] = 'f';
  96. i++;
  97. flagstr[i] = 'l';
  98. i++;
  99. flagstr[i] = 'a';
  100. i++;
  101. flagstr[i] = 'g';
  102. i++;
  103. }
  104. if (flags & WPFLAG_BLUE_FLAG)
  105. {
  106. if (i)
  107. {
  108. flagstr[i] = ' ';
  109. i++;
  110. }
  111. flagstr[i] = 'b';
  112. i++;
  113. flagstr[i] = 'l';
  114. i++;
  115. flagstr[i] = 'u';
  116. i++;
  117. flagstr[i] = 'e';
  118. i++;
  119. flagstr[i] = ' ';
  120. i++;
  121. flagstr[i] = 'f';
  122. i++;
  123. flagstr[i] = 'l';
  124. i++;
  125. flagstr[i] = 'a';
  126. i++;
  127. flagstr[i] = 'g';
  128. i++;
  129. }
  130. if (flags & WPFLAG_SIEGE_IMPERIALOBJ)
  131. {
  132. if (i)
  133. {
  134. flagstr[i] = ' ';
  135. i++;
  136. }
  137. flagstr[i] = 's';
  138. i++;
  139. flagstr[i] = 'a';
  140. i++;
  141. flagstr[i] = 'g';
  142. i++;
  143. flagstr[i] = 'a';
  144. i++;
  145. flagstr[i] = '_';
  146. i++;
  147. flagstr[i] = 'i';
  148. i++;
  149. flagstr[i] = 'm';
  150. i++;
  151. flagstr[i] = 'p';
  152. i++;
  153. }
  154. if (flags & WPFLAG_SIEGE_REBELOBJ)
  155. {
  156. if (i)
  157. {
  158. flagstr[i] = ' ';
  159. i++;
  160. }
  161. flagstr[i] = 's';
  162. i++;
  163. flagstr[i] = 'a';
  164. i++;
  165. flagstr[i] = 'g';
  166. i++;
  167. flagstr[i] = 'a';
  168. i++;
  169. flagstr[i] = '_';
  170. i++;
  171. flagstr[i] = 'r';
  172. i++;
  173. flagstr[i] = 'e';
  174. i++;
  175. flagstr[i] = 'b';
  176. i++;
  177. }
  178. flagstr[i] = '\0';
  179. if (i == 0)
  180. {
  181. strcpy(flagstr, "unknown\0");
  182. }
  183. fend:
  184. return flagstr;
  185. }
  186. void G_TestLine(vec3_t start, vec3_t end, int color, int time)
  187. {
  188. gentity_t *te;
  189. te = G_TempEntity( start, EV_TESTLINE );
  190. VectorCopy(start, te->s.origin);
  191. VectorCopy(end, te->s.origin2);
  192. te->s.time2 = time;
  193. te->s.weapon = color;
  194. te->r.svFlags |= SVF_BROADCAST;
  195. }
  196. void BotWaypointRender(void)
  197. {
  198. int i, n;
  199. int inc_checker;
  200. int bestindex;
  201. int gotbestindex;
  202. float bestdist;
  203. float checkdist;
  204. gentity_t *plum;
  205. gentity_t *viewent;
  206. char *flagstr;
  207. vec3_t a;
  208. if (!gBotEdit)
  209. {
  210. return;
  211. }
  212. bestindex = 0;
  213. if (gWPRenderTime > level.time)
  214. {
  215. goto checkprint;
  216. }
  217. gWPRenderTime = level.time + 100;
  218. i = gWPRenderedFrame;
  219. inc_checker = gWPRenderedFrame;
  220. while (i < gWPNum)
  221. {
  222. if (gWPArray[i] && gWPArray[i]->inuse)
  223. {
  224. plum = G_TempEntity( gWPArray[i]->origin, EV_SCOREPLUM );
  225. plum->r.svFlags |= SVF_BROADCAST;
  226. plum->s.time = i;
  227. n = 0;
  228. while (n < gWPArray[i]->neighbornum)
  229. {
  230. if (gWPArray[i]->neighbors[n].forceJumpTo && gWPArray[gWPArray[i]->neighbors[n].num])
  231. {
  232. G_TestLine(gWPArray[i]->origin, gWPArray[gWPArray[i]->neighbors[n].num]->origin, 0x0000ff, 5000);
  233. }
  234. n++;
  235. }
  236. gWPRenderedFrame++;
  237. }
  238. else
  239. {
  240. gWPRenderedFrame = 0;
  241. break;
  242. }
  243. if ((i - inc_checker) > 4)
  244. {
  245. break; //don't render too many at once
  246. }
  247. i++;
  248. }
  249. if (i >= gWPNum)
  250. {
  251. gWPRenderTime = level.time + 1500; //wait a bit after we finish doing the whole trail
  252. gWPRenderedFrame = 0;
  253. }
  254. checkprint:
  255. if (!bot_wp_info.value)
  256. {
  257. return;
  258. }
  259. viewent = &g_entities[0]; //only show info to the first client
  260. if (!viewent || !viewent->client)
  261. { //client isn't in the game yet?
  262. return;
  263. }
  264. bestdist = 256; //max distance for showing point info
  265. gotbestindex = 0;
  266. i = 0;
  267. while (i < gWPNum)
  268. {
  269. if (gWPArray[i] && gWPArray[i]->inuse)
  270. {
  271. VectorSubtract(viewent->client->ps.origin, gWPArray[i]->origin, a);
  272. checkdist = VectorLength(a);
  273. if (checkdist < bestdist)
  274. {
  275. bestdist = checkdist;
  276. bestindex = i;
  277. gotbestindex = 1;
  278. }
  279. }
  280. i++;
  281. }
  282. if (gotbestindex && bestindex != gLastPrintedIndex)
  283. {
  284. flagstr = GetFlagStr(gWPArray[bestindex]->flags);
  285. gLastPrintedIndex = bestindex;
  286. G_Printf(S_COLOR_YELLOW "Waypoint %i\nFlags - %i (%s) (w%f)\nOrigin - (%i %i %i)\n", (int)(gWPArray[bestindex]->index), (int)(gWPArray[bestindex]->flags), flagstr, gWPArray[bestindex]->weight, (int)(gWPArray[bestindex]->origin[0]), (int)(gWPArray[bestindex]->origin[1]), (int)(gWPArray[bestindex]->origin[2]));
  287. //GetFlagStr allocates 128 bytes for this, if it's changed then obviously this must be as well
  288. B_TempFree(128); //flagstr
  289. plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM );
  290. plum->r.svFlags |= SVF_BROADCAST;
  291. plum->s.time = bestindex; //render it once
  292. }
  293. else if (!gotbestindex)
  294. {
  295. gLastPrintedIndex = -1;
  296. }
  297. }
  298. void TransferWPData(int from, int to)
  299. {
  300. if (!gWPArray[to])
  301. {
  302. gWPArray[to] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
  303. }
  304. if (!gWPArray[to])
  305. {
  306. G_Printf(S_COLOR_RED "FATAL ERROR: Could not allocated memory for waypoint\n");
  307. }
  308. gWPArray[to]->flags = gWPArray[from]->flags;
  309. gWPArray[to]->weight = gWPArray[from]->weight;
  310. gWPArray[to]->associated_entity = gWPArray[from]->associated_entity;
  311. gWPArray[to]->disttonext = gWPArray[from]->disttonext;
  312. gWPArray[to]->forceJumpTo = gWPArray[from]->forceJumpTo;
  313. gWPArray[to]->index = to;
  314. gWPArray[to]->inuse = gWPArray[from]->inuse;
  315. VectorCopy(gWPArray[from]->origin, gWPArray[to]->origin);
  316. }
  317. void CreateNewWP(vec3_t origin, int flags)
  318. {
  319. if (gWPNum >= MAX_WPARRAY_SIZE)
  320. {
  321. if (!g_RMG.integer)
  322. {
  323. G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
  324. }
  325. return;
  326. }
  327. if (!gWPArray[gWPNum])
  328. {
  329. gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
  330. }
  331. if (!gWPArray[gWPNum])
  332. {
  333. G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n");
  334. }
  335. gWPArray[gWPNum]->flags = flags;
  336. gWPArray[gWPNum]->weight = 0; //calculated elsewhere
  337. gWPArray[gWPNum]->associated_entity = ENTITYNUM_NONE; //set elsewhere
  338. gWPArray[gWPNum]->forceJumpTo = 0;
  339. gWPArray[gWPNum]->disttonext = 0; //calculated elsewhere
  340. gWPArray[gWPNum]->index = gWPNum;
  341. gWPArray[gWPNum]->inuse = 1;
  342. VectorCopy(origin, gWPArray[gWPNum]->origin);
  343. gWPNum++;
  344. }
  345. void CreateNewWP_FromObject(wpobject_t *wp)
  346. {
  347. int i;
  348. if (gWPNum >= MAX_WPARRAY_SIZE)
  349. {
  350. return;
  351. }
  352. if (!gWPArray[gWPNum])
  353. {
  354. gWPArray[gWPNum] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
  355. }
  356. if (!gWPArray[gWPNum])
  357. {
  358. G_Printf(S_COLOR_RED "ERROR: Could not allocated memory for waypoint\n");
  359. }
  360. gWPArray[gWPNum]->flags = wp->flags;
  361. gWPArray[gWPNum]->weight = wp->weight;
  362. gWPArray[gWPNum]->associated_entity = wp->associated_entity;
  363. gWPArray[gWPNum]->disttonext = wp->disttonext;
  364. gWPArray[gWPNum]->forceJumpTo = wp->forceJumpTo;
  365. gWPArray[gWPNum]->index = gWPNum;
  366. gWPArray[gWPNum]->inuse = 1;
  367. VectorCopy(wp->origin, gWPArray[gWPNum]->origin);
  368. gWPArray[gWPNum]->neighbornum = wp->neighbornum;
  369. i = wp->neighbornum;
  370. while (i >= 0)
  371. {
  372. gWPArray[gWPNum]->neighbors[i].num = wp->neighbors[i].num;
  373. gWPArray[gWPNum]->neighbors[i].forceJumpTo = wp->neighbors[i].forceJumpTo;
  374. i--;
  375. }
  376. if (gWPArray[gWPNum]->flags & WPFLAG_RED_FLAG)
  377. {
  378. flagRed = gWPArray[gWPNum];
  379. oFlagRed = flagRed;
  380. }
  381. else if (gWPArray[gWPNum]->flags & WPFLAG_BLUE_FLAG)
  382. {
  383. flagBlue = gWPArray[gWPNum];
  384. oFlagBlue = flagBlue;
  385. }
  386. gWPNum++;
  387. }
  388. void RemoveWP(void)
  389. {
  390. if (gWPNum <= 0)
  391. {
  392. return;
  393. }
  394. gWPNum--;
  395. if (!gWPArray[gWPNum] || !gWPArray[gWPNum]->inuse)
  396. {
  397. return;
  398. }
  399. //B_Free((wpobject_t *)gWPArray[gWPNum]);
  400. if (gWPArray[gWPNum])
  401. {
  402. memset( gWPArray[gWPNum], 0, sizeof(gWPArray[gWPNum]) );
  403. }
  404. //gWPArray[gWPNum] = NULL;
  405. if (gWPArray[gWPNum])
  406. {
  407. gWPArray[gWPNum]->inuse = 0;
  408. }
  409. }
  410. void RemoveAllWP(void)
  411. {
  412. while(gWPNum) {
  413. RemoveWP();
  414. }
  415. }
  416. void RemoveWP_InTrail(int afterindex)
  417. {
  418. int foundindex;
  419. int foundanindex;
  420. int didchange;
  421. int i;
  422. foundindex = 0;
  423. foundanindex = 0;
  424. didchange = 0;
  425. i = 0;
  426. if (afterindex < 0 || afterindex >= gWPNum)
  427. {
  428. G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
  429. return;
  430. }
  431. while (i < gWPNum)
  432. {
  433. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
  434. {
  435. foundindex = i;
  436. foundanindex = 1;
  437. break;
  438. }
  439. i++;
  440. }
  441. if (!foundanindex)
  442. {
  443. G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
  444. return;
  445. }
  446. i = 0;
  447. while (i <= gWPNum)
  448. {
  449. if (gWPArray[i] && gWPArray[i]->index == foundindex)
  450. {
  451. //B_Free(gWPArray[i]);
  452. //Keep reusing the memory
  453. memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
  454. //gWPArray[i] = NULL;
  455. gWPArray[i]->inuse = 0;
  456. didchange = 1;
  457. }
  458. else if (gWPArray[i] && didchange)
  459. {
  460. TransferWPData(i, i-1);
  461. //B_Free(gWPArray[i]);
  462. //Keep reusing the memory
  463. memset( gWPArray[i], 0, sizeof(gWPArray[i]) );
  464. //gWPArray[i] = NULL;
  465. gWPArray[i]->inuse = 0;
  466. }
  467. i++;
  468. }
  469. gWPNum--;
  470. }
  471. int CreateNewWP_InTrail(vec3_t origin, int flags, int afterindex)
  472. {
  473. int foundindex;
  474. int foundanindex;
  475. int i;
  476. foundindex = 0;
  477. foundanindex = 0;
  478. i = 0;
  479. if (gWPNum >= MAX_WPARRAY_SIZE)
  480. {
  481. if (!g_RMG.integer)
  482. {
  483. G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
  484. }
  485. return 0;
  486. }
  487. if (afterindex < 0 || afterindex >= gWPNum)
  488. {
  489. G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
  490. return 0;
  491. }
  492. while (i < gWPNum)
  493. {
  494. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
  495. {
  496. foundindex = i;
  497. foundanindex = 1;
  498. break;
  499. }
  500. i++;
  501. }
  502. if (!foundanindex)
  503. {
  504. G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
  505. return 0;
  506. }
  507. i = gWPNum;
  508. while (i >= 0)
  509. {
  510. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex)
  511. {
  512. TransferWPData(i, i+1);
  513. }
  514. else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex)
  515. {
  516. i++;
  517. if (!gWPArray[i])
  518. {
  519. gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
  520. }
  521. gWPArray[i]->flags = flags;
  522. gWPArray[i]->weight = 0; //calculated elsewhere
  523. gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere
  524. gWPArray[i]->disttonext = 0; //calculated elsewhere
  525. gWPArray[i]->forceJumpTo = 0;
  526. gWPArray[i]->index = i;
  527. gWPArray[i]->inuse = 1;
  528. VectorCopy(origin, gWPArray[i]->origin);
  529. gWPNum++;
  530. break;
  531. }
  532. i--;
  533. }
  534. return 1;
  535. }
  536. int CreateNewWP_InsertUnder(vec3_t origin, int flags, int afterindex)
  537. {
  538. int foundindex;
  539. int foundanindex;
  540. int i;
  541. foundindex = 0;
  542. foundanindex = 0;
  543. i = 0;
  544. if (gWPNum >= MAX_WPARRAY_SIZE)
  545. {
  546. if (!g_RMG.integer)
  547. {
  548. G_Printf(S_COLOR_YELLOW "Warning: Waypoint limit hit (%i)\n", MAX_WPARRAY_SIZE);
  549. }
  550. return 0;
  551. }
  552. if (afterindex < 0 || afterindex >= gWPNum)
  553. {
  554. G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
  555. return 0;
  556. }
  557. while (i < gWPNum)
  558. {
  559. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
  560. {
  561. foundindex = i;
  562. foundanindex = 1;
  563. break;
  564. }
  565. i++;
  566. }
  567. if (!foundanindex)
  568. {
  569. G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
  570. return 0;
  571. }
  572. i = gWPNum;
  573. while (i >= 0)
  574. {
  575. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index != foundindex)
  576. {
  577. TransferWPData(i, i+1);
  578. }
  579. else if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == foundindex)
  580. {
  581. //i++;
  582. TransferWPData(i, i+1);
  583. if (!gWPArray[i])
  584. {
  585. gWPArray[i] = (wpobject_t *)B_Alloc(sizeof(wpobject_t));
  586. }
  587. gWPArray[i]->flags = flags;
  588. gWPArray[i]->weight = 0; //calculated elsewhere
  589. gWPArray[i]->associated_entity = ENTITYNUM_NONE; //set elsewhere
  590. gWPArray[i]->disttonext = 0; //calculated elsewhere
  591. gWPArray[i]->forceJumpTo = 0;
  592. gWPArray[i]->index = i;
  593. gWPArray[i]->inuse = 1;
  594. VectorCopy(origin, gWPArray[i]->origin);
  595. gWPNum++;
  596. break;
  597. }
  598. i--;
  599. }
  600. return 1;
  601. }
  602. void TeleportToWP(gentity_t *pl, int afterindex)
  603. {
  604. int foundindex;
  605. int foundanindex;
  606. int i;
  607. if (!pl || !pl->client)
  608. {
  609. return;
  610. }
  611. foundindex = 0;
  612. foundanindex = 0;
  613. i = 0;
  614. if (afterindex < 0 || afterindex >= gWPNum)
  615. {
  616. G_Printf(S_COLOR_YELLOW "Waypoint number %i does not exist\n", afterindex);
  617. return;
  618. }
  619. while (i < gWPNum)
  620. {
  621. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->index == afterindex)
  622. {
  623. foundindex = i;
  624. foundanindex = 1;
  625. break;
  626. }
  627. i++;
  628. }
  629. if (!foundanindex)
  630. {
  631. G_Printf(S_COLOR_YELLOW "Waypoint index %i should exist, but does not (?)\n", afterindex);
  632. return;
  633. }
  634. VectorCopy(gWPArray[foundindex]->origin, pl->client->ps.origin);
  635. return;
  636. }
  637. void WPFlagsModify(int wpnum, int flags)
  638. {
  639. if (wpnum < 0 || wpnum >= gWPNum || !gWPArray[wpnum] || !gWPArray[wpnum]->inuse)
  640. {
  641. G_Printf(S_COLOR_YELLOW "WPFlagsModify: Waypoint %i does not exist\n", wpnum);
  642. return;
  643. }
  644. gWPArray[wpnum]->flags = flags;
  645. }
  646. static int NotWithinRange(int base, int extent)
  647. {
  648. if (extent > base && base+5 >= extent)
  649. {
  650. return 0;
  651. }
  652. if (extent < base && base-5 <= extent)
  653. {
  654. return 0;
  655. }
  656. return 1;
  657. }
  658. #ifndef _XBOX
  659. int NodeHere(vec3_t spot)
  660. {
  661. int i;
  662. i = 0;
  663. while (i < nodenum)
  664. {
  665. if ((int)nodetable[i].origin[0] == (int)spot[0] &&
  666. (int)nodetable[i].origin[1] == (int)spot[1])
  667. {
  668. if ((int)nodetable[i].origin[2] == (int)spot[2] ||
  669. ((int)nodetable[i].origin[2] < (int)spot[2] && (int)nodetable[i].origin[2]+5 > (int)spot[2]) ||
  670. ((int)nodetable[i].origin[2] > (int)spot[2] && (int)nodetable[i].origin[2]-5 < (int)spot[2]))
  671. {
  672. return 1;
  673. }
  674. }
  675. i++;
  676. }
  677. return 0;
  678. }
  679. #endif
  680. int CanGetToVector(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs)
  681. {
  682. trace_t tr;
  683. trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID);
  684. if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
  685. {
  686. return 1;
  687. }
  688. return 0;
  689. }
  690. #if 0
  691. int CanGetToVectorTravel(vec3_t org1, vec3_t org2, vec3_t mins, vec3_t maxs)
  692. {
  693. trace_t tr;
  694. vec3_t a, ang, fwd;
  695. vec3_t midpos, dmid;
  696. float startheight, midheight, fLen;
  697. mins[2] = -13;
  698. maxs[2] = 13;
  699. trap_Trace(&tr, org1, mins, maxs, org2, ENTITYNUM_NONE, MASK_SOLID);
  700. if (tr.fraction != 1 || tr.startsolid || tr.allsolid)
  701. {
  702. return 0;
  703. }
  704. VectorSubtract(org2, org1, a);
  705. vectoangles(a, ang);
  706. AngleVectors(ang, fwd, NULL, NULL);
  707. fLen = VectorLength(a)/2;
  708. midpos[0] = org1[0] + fwd[0]*fLen;
  709. midpos[1] = org1[1] + fwd[1]*fLen;
  710. midpos[2] = org1[2] + fwd[2]*fLen;
  711. VectorCopy(org1, dmid);
  712. dmid[2] -= 1024;
  713. trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID);
  714. startheight = org1[2] - tr.endpos[2];
  715. VectorCopy(midpos, dmid);
  716. dmid[2] -= 1024;
  717. trap_Trace(&tr, midpos, NULL, NULL, dmid, ENTITYNUM_NONE, MASK_SOLID);
  718. if (tr.startsolid || tr.allsolid)
  719. {
  720. return 1;
  721. }
  722. midheight = midpos[2] - tr.endpos[2];
  723. if (midheight > startheight*2)
  724. {
  725. return 0; //too steep of a drop.. can't go on
  726. }
  727. return 1;
  728. }
  729. #else
  730. int CanGetToVectorTravel(vec3_t org1, vec3_t moveTo, vec3_t mins, vec3_t maxs)
  731. //int ExampleAnimEntMove(gentity_t *self, vec3_t moveTo, float stepSize)
  732. {
  733. trace_t tr;
  734. vec3_t stepTo;
  735. vec3_t stepSub;
  736. vec3_t stepGoal;
  737. vec3_t workingOrg;
  738. vec3_t lastIncrement;
  739. vec3_t finalMeasure;
  740. float stepSize = 0;
  741. float measureLength = 0;
  742. int didMove = 0;
  743. int traceMask = MASK_PLAYERSOLID;
  744. qboolean initialDone = qfalse;
  745. VectorCopy(org1, workingOrg);
  746. VectorCopy(org1, lastIncrement);
  747. VectorCopy(moveTo, stepTo);
  748. stepTo[2] = workingOrg[2];
  749. VectorSubtract(stepTo, workingOrg, stepSub);
  750. stepSize = VectorLength(stepSub); //make the step size the length of the original positions without Z
  751. VectorNormalize(stepSub);
  752. while (!initialDone || didMove)
  753. {
  754. initialDone = qtrue;
  755. didMove = 0;
  756. stepGoal[0] = workingOrg[0] + stepSub[0]*stepSize;
  757. stepGoal[1] = workingOrg[1] + stepSub[1]*stepSize;
  758. stepGoal[2] = workingOrg[2] + stepSub[2]*stepSize;
  759. trap_Trace(&tr, workingOrg, mins, maxs, stepGoal, ENTITYNUM_NONE, traceMask);
  760. if (!tr.startsolid && !tr.allsolid && tr.fraction)
  761. {
  762. vec3_t vecSub;
  763. VectorSubtract(workingOrg, tr.endpos, vecSub);
  764. if (VectorLength(vecSub) > (stepSize/2))
  765. {
  766. workingOrg[0] = tr.endpos[0];
  767. workingOrg[1] = tr.endpos[1];
  768. //trap_LinkEntity(self);
  769. didMove = 1;
  770. }
  771. }
  772. if (didMove != 1)
  773. { //stair check
  774. vec3_t trFrom;
  775. vec3_t trTo;
  776. vec3_t trDir;
  777. vec3_t vecMeasure;
  778. VectorCopy(tr.endpos, trFrom);
  779. trFrom[2] += 16;
  780. VectorSubtract(/*tr.endpos*/stepGoal, workingOrg, trDir);
  781. VectorNormalize(trDir);
  782. trTo[0] = tr.endpos[0] + trDir[0]*2;
  783. trTo[1] = tr.endpos[1] + trDir[1]*2;
  784. trTo[2] = tr.endpos[2] + trDir[2]*2;
  785. trTo[2] += 16;
  786. VectorSubtract(trFrom, trTo, vecMeasure);
  787. if (VectorLength(vecMeasure) > 1)
  788. {
  789. trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask);
  790. if (!tr.startsolid && !tr.allsolid && tr.fraction == 1)
  791. { //clear trace here, probably up a step
  792. vec3_t trDown;
  793. vec3_t trUp;
  794. VectorCopy(tr.endpos, trUp);
  795. VectorCopy(tr.endpos, trDown);
  796. trDown[2] -= 16;
  797. trap_Trace(&tr, trFrom, mins, maxs, trTo, ENTITYNUM_NONE, traceMask);
  798. if (!tr.startsolid && !tr.allsolid)
  799. { //plop us down on the step after moving up
  800. VectorCopy(tr.endpos, workingOrg);
  801. //trap_LinkEntity(self);
  802. didMove = 1;
  803. }
  804. }
  805. }
  806. }
  807. VectorSubtract(lastIncrement, workingOrg, finalMeasure);
  808. measureLength = VectorLength(finalMeasure);
  809. if (!measureLength)
  810. { //no progress, break out. If last movement was a sucess didMove will equal 1.
  811. break;
  812. }
  813. stepSize -= measureLength; //subtract the progress distance from the step size so we don't overshoot the mark.
  814. if (stepSize <= 0)
  815. {
  816. break;
  817. }
  818. VectorCopy(workingOrg, lastIncrement);
  819. }
  820. return didMove;
  821. }
  822. #endif
  823. #ifndef _XBOX
  824. int ConnectTrail(int startindex, int endindex, qboolean behindTheScenes)
  825. {
  826. int foundit;
  827. int cancontinue;
  828. int i;
  829. int failsafe;
  830. int successnodeindex;
  831. int insertindex;
  832. int prenodestart;
  833. byte extendednodes[MAX_NODETABLE_SIZE]; //for storing checked nodes and not trying to extend them each a bazillion times
  834. float fvecmeas;
  835. float baseheight;
  836. float branchDistance;
  837. float maxDistFactor = 256;
  838. vec3_t a;
  839. vec3_t startplace, starttrace;
  840. vec3_t mins, maxs;
  841. vec3_t testspot;
  842. vec3_t validspotpos;
  843. trace_t tr;
  844. if (g_RMG.integer)
  845. { //this might be temporary. Or not.
  846. if (!(gWPArray[startindex]->flags & WPFLAG_NEVERONEWAY) &&
  847. !(gWPArray[endindex]->flags & WPFLAG_NEVERONEWAY))
  848. {
  849. gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD;
  850. gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK;
  851. }
  852. return 0;
  853. }
  854. if (!g_RMG.integer)
  855. {
  856. branchDistance = TABLE_BRANCH_DISTANCE;
  857. }
  858. else
  859. {
  860. branchDistance = 512; //be less precise here, terrain is fairly broad, and we don't want to take an hour precalculating
  861. }
  862. if (g_RMG.integer)
  863. {
  864. maxDistFactor = 700;
  865. }
  866. mins[0] = -15;
  867. mins[1] = -15;
  868. mins[2] = 0;
  869. maxs[0] = 15;
  870. maxs[1] = 15;
  871. maxs[2] = 0;
  872. nodenum = 0;
  873. foundit = 0;
  874. i = 0;
  875. successnodeindex = 0;
  876. while (i < MAX_NODETABLE_SIZE) //clear it out before using it
  877. {
  878. nodetable[i].flags = 0;
  879. // nodetable[i].index = 0;
  880. nodetable[i].inuse = 0;
  881. nodetable[i].neighbornum = 0;
  882. nodetable[i].origin[0] = 0;
  883. nodetable[i].origin[1] = 0;
  884. nodetable[i].origin[2] = 0;
  885. nodetable[i].weight = 0;
  886. extendednodes[i] = 0;
  887. i++;
  888. }
  889. i = 0;
  890. if (!behindTheScenes)
  891. {
  892. G_Printf(S_COLOR_YELLOW "Point %i is not connected to %i - Repairing...\n", startindex, endindex);
  893. }
  894. VectorCopy(gWPArray[startindex]->origin, startplace);
  895. VectorCopy(startplace, starttrace);
  896. starttrace[2] -= 4096;
  897. trap_Trace(&tr, startplace, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
  898. baseheight = startplace[2] - tr.endpos[2];
  899. cancontinue = 1;
  900. VectorCopy(startplace, nodetable[nodenum].origin);
  901. nodetable[nodenum].weight = 1;
  902. nodetable[nodenum].inuse = 1;
  903. // nodetable[nodenum].index = nodenum;
  904. nodenum++;
  905. while (nodenum < MAX_NODETABLE_SIZE && !foundit && cancontinue)
  906. {
  907. if (g_RMG.integer)
  908. { //adjust the branch distance dynamically depending on the distance from the start and end points.
  909. vec3_t startDist;
  910. vec3_t endDist;
  911. float startDistf;
  912. float endDistf;
  913. VectorSubtract(nodetable[nodenum-1].origin, gWPArray[startindex]->origin, startDist);
  914. VectorSubtract(nodetable[nodenum-1].origin, gWPArray[endindex]->origin, endDist);
  915. startDistf = VectorLength(startDist);
  916. endDistf = VectorLength(endDist);
  917. if (startDistf < 64 || endDistf < 64)
  918. {
  919. branchDistance = 64;
  920. }
  921. else if (startDistf < 128 || endDistf < 128)
  922. {
  923. branchDistance = 128;
  924. }
  925. else if (startDistf < 256 || endDistf < 256)
  926. {
  927. branchDistance = 256;
  928. }
  929. else if (startDistf < 512 || endDistf < 512)
  930. {
  931. branchDistance = 512;
  932. }
  933. else
  934. {
  935. branchDistance = 800;
  936. }
  937. }
  938. cancontinue = 0;
  939. i = 0;
  940. prenodestart = nodenum;
  941. while (i < prenodestart)
  942. {
  943. if (extendednodes[i] != 1)
  944. {
  945. VectorSubtract(gWPArray[endindex]->origin, nodetable[i].origin, a);
  946. fvecmeas = VectorLength(a);
  947. if (fvecmeas < 128 && CanGetToVector(gWPArray[endindex]->origin, nodetable[i].origin, mins, maxs))
  948. {
  949. foundit = 1;
  950. successnodeindex = i;
  951. break;
  952. }
  953. VectorCopy(nodetable[i].origin, testspot);
  954. testspot[0] += branchDistance;
  955. VectorCopy(testspot, starttrace);
  956. starttrace[2] -= 4096;
  957. trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
  958. testspot[2] = tr.endpos[2]+baseheight;
  959. if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
  960. {
  961. VectorCopy(testspot, nodetable[nodenum].origin);
  962. nodetable[nodenum].inuse = 1;
  963. // nodetable[nodenum].index = nodenum;
  964. nodetable[nodenum].weight = nodetable[i].weight+1;
  965. nodetable[nodenum].neighbornum = i;
  966. if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
  967. { //if there's a big drop, make sure we know we can't just magically fly back up
  968. nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
  969. }
  970. nodenum++;
  971. cancontinue = 1;
  972. }
  973. if (nodenum >= MAX_NODETABLE_SIZE)
  974. {
  975. break; //failure
  976. }
  977. VectorCopy(nodetable[i].origin, testspot);
  978. testspot[0] -= branchDistance;
  979. VectorCopy(testspot, starttrace);
  980. starttrace[2] -= 4096;
  981. trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
  982. testspot[2] = tr.endpos[2]+baseheight;
  983. if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
  984. {
  985. VectorCopy(testspot, nodetable[nodenum].origin);
  986. nodetable[nodenum].inuse = 1;
  987. // nodetable[nodenum].index = nodenum;
  988. nodetable[nodenum].weight = nodetable[i].weight+1;
  989. nodetable[nodenum].neighbornum = i;
  990. if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
  991. { //if there's a big drop, make sure we know we can't just magically fly back up
  992. nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
  993. }
  994. nodenum++;
  995. cancontinue = 1;
  996. }
  997. if (nodenum >= MAX_NODETABLE_SIZE)
  998. {
  999. break; //failure
  1000. }
  1001. VectorCopy(nodetable[i].origin, testspot);
  1002. testspot[1] += branchDistance;
  1003. VectorCopy(testspot, starttrace);
  1004. starttrace[2] -= 4096;
  1005. trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
  1006. testspot[2] = tr.endpos[2]+baseheight;
  1007. if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
  1008. {
  1009. VectorCopy(testspot, nodetable[nodenum].origin);
  1010. nodetable[nodenum].inuse = 1;
  1011. // nodetable[nodenum].index = nodenum;
  1012. nodetable[nodenum].weight = nodetable[i].weight+1;
  1013. nodetable[nodenum].neighbornum = i;
  1014. if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
  1015. { //if there's a big drop, make sure we know we can't just magically fly back up
  1016. nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
  1017. }
  1018. nodenum++;
  1019. cancontinue = 1;
  1020. }
  1021. if (nodenum >= MAX_NODETABLE_SIZE)
  1022. {
  1023. break; //failure
  1024. }
  1025. VectorCopy(nodetable[i].origin, testspot);
  1026. testspot[1] -= branchDistance;
  1027. VectorCopy(testspot, starttrace);
  1028. starttrace[2] -= 4096;
  1029. trap_Trace(&tr, testspot, NULL, NULL, starttrace, ENTITYNUM_NONE, MASK_SOLID);
  1030. testspot[2] = tr.endpos[2]+baseheight;
  1031. if (!NodeHere(testspot) && !tr.startsolid && !tr.allsolid && CanGetToVector(nodetable[i].origin, testspot, mins, maxs))
  1032. {
  1033. VectorCopy(testspot, nodetable[nodenum].origin);
  1034. nodetable[nodenum].inuse = 1;
  1035. // nodetable[nodenum].index = nodenum;
  1036. nodetable[nodenum].weight = nodetable[i].weight+1;
  1037. nodetable[nodenum].neighbornum = i;
  1038. if ((nodetable[i].origin[2] - nodetable[nodenum].origin[2]) > 50)
  1039. { //if there's a big drop, make sure we know we can't just magically fly back up
  1040. nodetable[nodenum].flags = WPFLAG_ONEWAY_FWD;
  1041. }
  1042. nodenum++;
  1043. cancontinue = 1;
  1044. }
  1045. if (nodenum >= MAX_NODETABLE_SIZE)
  1046. {
  1047. break; //failure
  1048. }
  1049. extendednodes[i] = 1;
  1050. }
  1051. i++;
  1052. }
  1053. }
  1054. if (!foundit)
  1055. {
  1056. #ifndef _DEBUG //if debug just always print this.
  1057. if (!behindTheScenes)
  1058. #endif
  1059. {
  1060. G_Printf(S_COLOR_RED "Could not link %i to %i, unreachable by node branching.\n", startindex, endindex);
  1061. }
  1062. gWPArray[startindex]->flags |= WPFLAG_ONEWAY_FWD;
  1063. gWPArray[endindex]->flags |= WPFLAG_ONEWAY_BACK;
  1064. if (!behindTheScenes)
  1065. {
  1066. G_Printf(S_COLOR_YELLOW "Since points cannot be connected, point %i has been flagged as only-forward and point %i has been flagged as only-backward.\n", startindex, endindex);
  1067. }
  1068. /*while (nodenum >= 0)
  1069. {
  1070. if (nodetable[nodenum].origin[0] || nodetable[nodenum].origin[1] || nodetable[nodenum].origin[2])
  1071. {
  1072. CreateNewWP(nodetable[nodenum].origin, nodetable[nodenum].flags);
  1073. }
  1074. nodenum--;
  1075. }*/
  1076. //The above code transfers nodes into the "rendered" waypoint array. Strictly for debugging.
  1077. if (!behindTheScenes)
  1078. { //just use what we have if we're auto-pathing the level
  1079. return 0;
  1080. }
  1081. else
  1082. {
  1083. vec3_t endDist;
  1084. int nCount = 0;
  1085. int idealNode = -1;
  1086. float bestDist = 0;
  1087. float testDist;
  1088. if (nodenum <= 10)
  1089. { //not enough to even really bother.
  1090. return 0;
  1091. }
  1092. //Since it failed, find whichever node is closest to the desired end.
  1093. while (nCount < nodenum)
  1094. {
  1095. VectorSubtract(nodetable[nCount].origin, gWPArray[endindex]->origin, endDist);
  1096. testDist = VectorLength(endDist);
  1097. if (idealNode == -1)
  1098. {
  1099. idealNode = nCount;
  1100. bestDist = testDist;
  1101. nCount++;
  1102. continue;
  1103. }
  1104. if (testDist < bestDist)
  1105. {
  1106. idealNode = nCount;
  1107. bestDist = testDist;
  1108. }
  1109. nCount++;
  1110. }
  1111. if (idealNode == -1)
  1112. {
  1113. return 0;
  1114. }
  1115. successnodeindex = idealNode;
  1116. }
  1117. }
  1118. i = successnodeindex;
  1119. insertindex = startindex;
  1120. failsafe = 0;
  1121. VectorCopy(gWPArray[startindex]->origin, validspotpos);
  1122. while (failsafe < MAX_NODETABLE_SIZE && i < MAX_NODETABLE_SIZE && i >= 0)
  1123. {
  1124. VectorSubtract(validspotpos, nodetable[i].origin, a);
  1125. if (!nodetable[nodetable[i].neighbornum].inuse || !CanGetToVectorTravel(validspotpos, /*nodetable[nodetable[i].neighbornum].origin*/nodetable[i].origin, mins, maxs) || VectorLength(a) > maxDistFactor || (!CanGetToVectorTravel(validspotpos, gWPArray[endindex]->origin, mins, maxs) && CanGetToVectorTravel(nodetable[i].origin, gWPArray[endindex]->origin, mins, maxs)) )
  1126. {
  1127. nodetable[i].flags |= WPFLAG_CALCULATED;
  1128. if (!CreateNewWP_InTrail(nodetable[i].origin, nodetable[i].flags, insertindex))
  1129. {
  1130. if (!behindTheScenes)
  1131. {
  1132. G_Printf(S_COLOR_RED "Could not link %i to %i, waypoint limit hit.\n", startindex, endindex);
  1133. }
  1134. return 0;
  1135. }
  1136. VectorCopy(nodetable[i].origin, validspotpos);
  1137. }
  1138. if (i == 0)
  1139. {
  1140. break;
  1141. }
  1142. i = nodetable[i].neighbornum;
  1143. failsafe++;
  1144. }
  1145. if (!behindTheScenes)
  1146. {
  1147. G_Printf(S_COLOR_YELLOW "Finished connecting %i to %i.\n", startindex, endindex);
  1148. }
  1149. return 1;
  1150. }
  1151. #endif
  1152. int OpposingEnds(int start, int end)
  1153. {
  1154. if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse)
  1155. {
  1156. return 0;
  1157. }
  1158. if ((gWPArray[start]->flags & WPFLAG_ONEWAY_FWD) &&
  1159. (gWPArray[end]->flags & WPFLAG_ONEWAY_BACK))
  1160. {
  1161. return 1;
  1162. }
  1163. return 0;
  1164. }
  1165. int DoorBlockingSection(int start, int end)
  1166. { //if a door blocks the trail, we'll just have to assume the points on each side are in visibility when it's open
  1167. trace_t tr;
  1168. gentity_t *testdoor;
  1169. int start_trace_index;
  1170. if (!gWPArray[start] || !gWPArray[start]->inuse || !gWPArray[end] || !gWPArray[end]->inuse)
  1171. {
  1172. return 0;
  1173. }
  1174. trap_Trace(&tr, gWPArray[start]->origin, NULL, NULL, gWPArray[end]->origin, ENTITYNUM_NONE, MASK_SOLID);
  1175. if (tr.fraction == 1)
  1176. {
  1177. return 0;
  1178. }
  1179. testdoor = &g_entities[tr.entityNum];
  1180. if (!testdoor)
  1181. {
  1182. return 0;
  1183. }
  1184. if (!strstr(testdoor->classname, "func_"))
  1185. {
  1186. return 0;
  1187. }
  1188. start_trace_index = tr.entityNum;
  1189. trap_Trace(&tr, gWPArray[end]->origin, NULL, NULL, gWPArray[start]->origin, ENTITYNUM_NONE, MASK_SOLID);
  1190. if (tr.fraction == 1)
  1191. {
  1192. return 0;
  1193. }
  1194. if (start_trace_index == tr.entityNum)
  1195. {
  1196. return 1;
  1197. }
  1198. return 0;
  1199. }
  1200. #ifndef _XBOX
  1201. int RepairPaths(qboolean behindTheScenes)
  1202. {
  1203. int i;
  1204. int preAmount = 0;
  1205. int ctRet;
  1206. vec3_t a;
  1207. float maxDistFactor = 400;
  1208. if (!gWPNum)
  1209. {
  1210. return 0;
  1211. }
  1212. if (g_RMG.integer)
  1213. {
  1214. maxDistFactor = 800; //higher tolerance here.
  1215. }
  1216. i = 0;
  1217. preAmount = gWPNum;
  1218. trap_Cvar_Update(&bot_wp_distconnect);
  1219. trap_Cvar_Update(&bot_wp_visconnect);
  1220. while (i < gWPNum)
  1221. {
  1222. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i+1] && gWPArray[i+1]->inuse)
  1223. {
  1224. VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a);
  1225. if (!(gWPArray[i+1]->flags & WPFLAG_NOVIS) &&
  1226. !(gWPArray[i+1]->flags & WPFLAG_JUMP) && //don't calculate on jump points because they might not always want to be visible (in cases of force jumping)
  1227. !(gWPArray[i]->flags & WPFLAG_CALCULATED) && //don't calculate it again
  1228. !OpposingEnds(i, i+1) &&
  1229. ((bot_wp_distconnect.value && VectorLength(a) > maxDistFactor) || (!OrgVisible(gWPArray[i]->origin, gWPArray[i+1]->origin, ENTITYNUM_NONE) && bot_wp_visconnect.value) ) &&
  1230. !DoorBlockingSection(i, i+1))
  1231. {
  1232. ctRet = ConnectTrail(i, i+1, behindTheScenes);
  1233. if (gWPNum >= MAX_WPARRAY_SIZE)
  1234. { //Bad!
  1235. gWPNum = MAX_WPARRAY_SIZE;
  1236. break;
  1237. }
  1238. /*if (!ctRet)
  1239. {
  1240. return 0;
  1241. }*/ //we still want to write it..
  1242. }
  1243. }
  1244. i++;
  1245. }
  1246. return 1;
  1247. }
  1248. #endif
  1249. int OrgVisibleCurve(vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore)
  1250. {
  1251. trace_t tr;
  1252. vec3_t evenorg1;
  1253. VectorCopy(org1, evenorg1);
  1254. evenorg1[2] = org2[2];
  1255. trap_Trace(&tr, evenorg1, mins, maxs, org2, ignore, MASK_SOLID);
  1256. if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
  1257. {
  1258. trap_Trace(&tr, evenorg1, mins, maxs, org1, ignore, MASK_SOLID);
  1259. if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
  1260. {
  1261. return 1;
  1262. }
  1263. }
  1264. return 0;
  1265. }
  1266. int CanForceJumpTo(int baseindex, int testingindex, float distance)
  1267. {
  1268. float heightdif;
  1269. vec3_t xy_base, xy_test, v, mins, maxs;
  1270. wpobject_t *wpBase = gWPArray[baseindex];
  1271. wpobject_t *wpTest = gWPArray[testingindex];
  1272. mins[0] = -15;
  1273. mins[1] = -15;
  1274. mins[2] = -15; //-1
  1275. maxs[0] = 15;
  1276. maxs[1] = 15;
  1277. maxs[2] = 15; //1
  1278. if (!wpBase || !wpBase->inuse || !wpTest || !wpTest->inuse)
  1279. {
  1280. return 0;
  1281. }
  1282. if (distance > 400)
  1283. {
  1284. return 0;
  1285. }
  1286. VectorCopy(wpBase->origin, xy_base);
  1287. VectorCopy(wpTest->origin, xy_test);
  1288. xy_base[2] = xy_test[2];
  1289. VectorSubtract(xy_base, xy_test, v);
  1290. if (VectorLength(v) > MAX_NEIGHBOR_LINK_DISTANCE)
  1291. {
  1292. return 0;
  1293. }
  1294. if ((int)wpBase->origin[2] < (int)wpTest->origin[2])
  1295. {
  1296. heightdif = wpTest->origin[2] - wpBase->origin[2];
  1297. }
  1298. else
  1299. {
  1300. return 0; //err..
  1301. }
  1302. if (heightdif < 128)
  1303. { //don't bother..
  1304. return 0;
  1305. }
  1306. if (heightdif > 512)
  1307. { //too high
  1308. return 0;
  1309. }
  1310. if (!OrgVisibleCurve(wpBase->origin, mins, maxs, wpTest->origin, ENTITYNUM_NONE))
  1311. {
  1312. return 0;
  1313. }
  1314. if (heightdif > 400)
  1315. {
  1316. return 3;
  1317. }
  1318. else if (heightdif > 256)
  1319. {
  1320. return 2;
  1321. }
  1322. else
  1323. {
  1324. return 1;
  1325. }
  1326. }
  1327. void CalculatePaths(void)
  1328. {
  1329. int i;
  1330. int c;
  1331. int forceJumpable;
  1332. int maxNeighborDist = MAX_NEIGHBOR_LINK_DISTANCE;
  1333. float nLDist;
  1334. vec3_t a;
  1335. vec3_t mins, maxs;
  1336. if (!gWPNum)
  1337. {
  1338. return;
  1339. }
  1340. if (g_RMG.integer)
  1341. {
  1342. maxNeighborDist = DEFAULT_GRID_SPACING + (DEFAULT_GRID_SPACING*0.5);
  1343. }
  1344. mins[0] = -15;
  1345. mins[1] = -15;
  1346. mins[2] = -15; //-1
  1347. maxs[0] = 15;
  1348. maxs[1] = 15;
  1349. maxs[2] = 15; //1
  1350. //now clear out all the neighbor data before we recalculate
  1351. i = 0;
  1352. while (i < gWPNum)
  1353. {
  1354. if (gWPArray[i] && gWPArray[i]->inuse && gWPArray[i]->neighbornum)
  1355. {
  1356. while (gWPArray[i]->neighbornum >= 0)
  1357. {
  1358. gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = 0;
  1359. gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0;
  1360. gWPArray[i]->neighbornum--;
  1361. }
  1362. gWPArray[i]->neighbornum = 0;
  1363. }
  1364. i++;
  1365. }
  1366. i = 0;
  1367. while (i < gWPNum)
  1368. {
  1369. if (gWPArray[i] && gWPArray[i]->inuse)
  1370. {
  1371. c = 0;
  1372. while (c < gWPNum)
  1373. {
  1374. if (gWPArray[c] && gWPArray[c]->inuse && i != c &&
  1375. NotWithinRange(i, c))
  1376. {
  1377. VectorSubtract(gWPArray[i]->origin, gWPArray[c]->origin, a);
  1378. nLDist = VectorLength(a);
  1379. forceJumpable = CanForceJumpTo(i, c, nLDist);
  1380. if ((nLDist < maxNeighborDist || forceJumpable) &&
  1381. ((int)gWPArray[i]->origin[2] == (int)gWPArray[c]->origin[2] || forceJumpable) &&
  1382. (OrgVisibleBox(gWPArray[i]->origin, mins, maxs, gWPArray[c]->origin, ENTITYNUM_NONE) || forceJumpable))
  1383. {
  1384. gWPArray[i]->neighbors[gWPArray[i]->neighbornum].num = c;
  1385. if (forceJumpable && ((int)gWPArray[i]->origin[2] != (int)gWPArray[c]->origin[2] || nLDist < maxNeighborDist))
  1386. {
  1387. gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 999;//forceJumpable; //FJSR
  1388. }
  1389. else
  1390. {
  1391. gWPArray[i]->neighbors[gWPArray[i]->neighbornum].forceJumpTo = 0;
  1392. }
  1393. gWPArray[i]->neighbornum++;
  1394. }
  1395. if (gWPArray[i]->neighbornum >= MAX_NEIGHBOR_SIZE)
  1396. {
  1397. break;
  1398. }
  1399. }
  1400. c++;
  1401. }
  1402. }
  1403. i++;
  1404. }
  1405. }
  1406. gentity_t *GetObjectThatTargets(gentity_t *ent)
  1407. {
  1408. gentity_t *next = NULL;
  1409. if (!ent->targetname)
  1410. {
  1411. return NULL;
  1412. }
  1413. next = G_Find( next, FOFS(target), ent->targetname );
  1414. if (next)
  1415. {
  1416. return next;
  1417. }
  1418. return NULL;
  1419. }
  1420. void CalculateSiegeGoals(void)
  1421. {
  1422. int i = 0;
  1423. int looptracker = 0;
  1424. int wpindex = 0;
  1425. vec3_t dif;
  1426. gentity_t *ent;
  1427. gentity_t *tent = NULL, *t2ent = NULL;
  1428. while (i < level.num_entities)
  1429. {
  1430. ent = &g_entities[i];
  1431. tent = NULL;
  1432. if (ent && ent->classname && strcmp(ent->classname, "info_siege_objective") == 0)
  1433. {
  1434. tent = ent;
  1435. t2ent = GetObjectThatTargets(tent);
  1436. looptracker = 0;
  1437. while (t2ent && looptracker < 2048)
  1438. { //looptracker keeps us from getting stuck in case something is set up weird on this map
  1439. tent = t2ent;
  1440. t2ent = GetObjectThatTargets(tent);
  1441. looptracker++;
  1442. }
  1443. if (looptracker >= 2048)
  1444. { //something unpleasent has happened
  1445. tent = NULL;
  1446. break;
  1447. }
  1448. }
  1449. if (tent && ent && tent != ent)
  1450. { //tent should now be the object attached to the mission objective
  1451. dif[0] = (tent->r.absmax[0]+tent->r.absmin[0])/2;
  1452. dif[1] = (tent->r.absmax[1]+tent->r.absmin[1])/2;
  1453. dif[2] = (tent->r.absmax[2]+tent->r.absmin[2])/2;
  1454. wpindex = GetNearestVisibleWP(dif, tent->s.number);
  1455. if (wpindex != -1 && gWPArray[wpindex] && gWPArray[wpindex]->inuse)
  1456. { //found the waypoint nearest the center of this objective-related object
  1457. if (ent->side == SIEGETEAM_TEAM1)
  1458. {
  1459. gWPArray[wpindex]->flags |= WPFLAG_SIEGE_IMPERIALOBJ;
  1460. }
  1461. else
  1462. {
  1463. gWPArray[wpindex]->flags |= WPFLAG_SIEGE_REBELOBJ;
  1464. }
  1465. gWPArray[wpindex]->associated_entity = tent->s.number;
  1466. }
  1467. }
  1468. i++;
  1469. }
  1470. }
  1471. float botGlobalNavWeaponWeights[WP_NUM_WEAPONS] =
  1472. {
  1473. 0,//WP_NONE,
  1474. 0,//WP_STUN_BATON,
  1475. 0,//WP_MELEE
  1476. 0,//WP_SABER, // NOTE: lots of code assumes this is the first weapon (... which is crap) so be careful -Ste.
  1477. 0,//WP_BRYAR_PISTOL,
  1478. 3,//WP_BLASTER,
  1479. 5,//WP_DISRUPTOR,
  1480. 4,//WP_BOWCASTER,
  1481. 6,//WP_REPEATER,
  1482. 7,//WP_DEMP2,
  1483. 8,//WP_FLECHETTE,
  1484. 9,//WP_ROCKET_LAUNCHER,
  1485. 3,//WP_THERMAL,
  1486. 3,//WP_TRIP_MINE,
  1487. 3,//WP_DET_PACK,
  1488. 0//WP_EMPLACED_GUN,
  1489. };
  1490. int GetNearestVisibleWPToItem(vec3_t org, int ignore)
  1491. {
  1492. int i;
  1493. float bestdist;
  1494. float flLen;
  1495. int bestindex;
  1496. vec3_t a, mins, maxs;
  1497. i = 0;
  1498. bestdist = 64; //has to be less than 64 units to the item or it isn't safe enough
  1499. bestindex = -1;
  1500. mins[0] = -15;
  1501. mins[1] = -15;
  1502. mins[2] = 0;
  1503. maxs[0] = 15;
  1504. maxs[1] = 15;
  1505. maxs[2] = 0;
  1506. while (i < gWPNum)
  1507. {
  1508. if (gWPArray[i] && gWPArray[i]->inuse &&
  1509. gWPArray[i]->origin[2]-15 < org[2] &&
  1510. gWPArray[i]->origin[2]+15 > org[2])
  1511. {
  1512. VectorSubtract(org, gWPArray[i]->origin, a);
  1513. flLen = VectorLength(a);
  1514. if (flLen < bestdist && trap_InPVS(org, gWPArray[i]->origin) && OrgVisibleBox(org, mins, maxs, gWPArray[i]->origin, ignore))
  1515. {
  1516. bestdist = flLen;
  1517. bestindex = i;
  1518. }
  1519. }
  1520. i++;
  1521. }
  1522. return bestindex;
  1523. }
  1524. void CalculateWeightGoals(void)
  1525. { //set waypoint weights depending on weapon and item placement
  1526. int i = 0;
  1527. int wpindex = 0;
  1528. gentity_t *ent;
  1529. float weight;
  1530. trap_Cvar_Update(&bot_wp_clearweight);
  1531. if (bot_wp_clearweight.integer)
  1532. { //if set then flush out all weight/goal values before calculating them again
  1533. while (i < gWPNum)
  1534. {
  1535. if (gWPArray[i] && gWPArray[i]->inuse)
  1536. {
  1537. gWPArray[i]->weight = 0;
  1538. if (gWPArray[i]->flags & WPFLAG_GOALPOINT)
  1539. {
  1540. gWPArray[i]->flags -= WPFLAG_GOALPOINT;
  1541. }
  1542. }
  1543. i++;
  1544. }
  1545. }
  1546. i = 0;
  1547. while (i < level.num_entities)
  1548. {
  1549. ent = &g_entities[i];
  1550. weight = 0;
  1551. if (ent && ent->classname)
  1552. {
  1553. if (strcmp(ent->classname, "item_seeker") == 0)
  1554. {
  1555. weight = 2;
  1556. }
  1557. else if (strcmp(ent->classname, "item_shield") == 0)
  1558. {
  1559. weight = 2;
  1560. }
  1561. else if (strcmp(ent->classname, "item_medpac") == 0)
  1562. {
  1563. weight = 2;
  1564. }
  1565. else if (strcmp(ent->classname, "item_sentry_gun") == 0)
  1566. {
  1567. weight = 2;
  1568. }
  1569. else if (strcmp(ent->classname, "item_force_enlighten_dark") == 0)
  1570. {
  1571. weight = 5;
  1572. }
  1573. else if (strcmp(ent->classname, "item_force_enlighten_light") == 0)
  1574. {
  1575. weight = 5;
  1576. }
  1577. else if (strcmp(ent->classname, "item_force_boon") == 0)
  1578. {
  1579. weight = 5;
  1580. }
  1581. else if (strcmp(ent->classname, "item_ysalimari") == 0)
  1582. {
  1583. weight = 2;
  1584. }
  1585. else if (strstr(ent->classname, "weapon_") && ent->item)
  1586. {
  1587. weight = botGlobalNavWeaponWeights[ent->item->giTag];
  1588. }
  1589. else if (ent->item && ent->item->giType == IT_AMMO)
  1590. {
  1591. weight = 3;
  1592. }
  1593. }
  1594. if (ent && weight)
  1595. {
  1596. wpindex = GetNearestVisibleWPToItem(ent->s.pos.trBase, ent->s.number);
  1597. if (wpindex != -1 && gWPArray[wpindex] && gWPArray[wpindex]->inuse)
  1598. { //found the waypoint nearest the center of this object
  1599. gWPArray[wpindex]->weight = weight;
  1600. gWPArray[wpindex]->flags |= WPFLAG_GOALPOINT;
  1601. gWPArray[wpindex]->associated_entity = ent->s.number;
  1602. }
  1603. }
  1604. i++;
  1605. }
  1606. }
  1607. void CalculateJumpRoutes(void)
  1608. {
  1609. int i = 0;
  1610. float nheightdif = 0;
  1611. float pheightdif = 0;
  1612. while (i < gWPNum)
  1613. {
  1614. if (gWPArray[i] && gWPArray[i]->inuse)
  1615. {
  1616. if (gWPArray[i]->flags & WPFLAG_JUMP)
  1617. {
  1618. nheightdif = 0;
  1619. pheightdif = 0;
  1620. gWPArray[i]->forceJumpTo = 0;
  1621. if (gWPArray[i-1] && gWPArray[i-1]->inuse && (gWPArray[i-1]->origin[2]+16) < gWPArray[i]->origin[2])
  1622. {
  1623. nheightdif = (gWPArray[i]->origin[2] - gWPArray[i-1]->origin[2]);
  1624. }
  1625. if (gWPArray[i+1] && gWPArray[i+1]->inuse && (gWPArray[i+1]->origin[2]+16) < gWPArray[i]->origin[2])
  1626. {
  1627. pheightdif = (gWPArray[i]->origin[2] - gWPArray[i+1]->origin[2]);
  1628. }
  1629. if (nheightdif > pheightdif)
  1630. {
  1631. pheightdif = nheightdif;
  1632. }
  1633. if (pheightdif)
  1634. {
  1635. if (pheightdif > 500)
  1636. {
  1637. gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_3; //FJSR
  1638. }
  1639. else if (pheightdif > 256)
  1640. {
  1641. gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_2; //FJSR
  1642. }
  1643. else if (pheightdif > 128)
  1644. {
  1645. gWPArray[i]->forceJumpTo = 999; //FORCE_LEVEL_1; //FJSR
  1646. }
  1647. }
  1648. }
  1649. }
  1650. i++;
  1651. }
  1652. }
  1653. int LoadPathData(const char *filename)
  1654. {
  1655. fileHandle_t f;
  1656. char *fileString;
  1657. char *currentVar;
  1658. char *routePath;
  1659. wpobject_t thiswp;
  1660. int len;
  1661. int i, i_cv;
  1662. int nei_num;
  1663. i = 0;
  1664. i_cv = 0;
  1665. routePath = (char *)B_TempAlloc(1024);
  1666. Com_sprintf(routePath, 1024, "botroutes/%s.wnt\0", filename);
  1667. len = trap_FS_FOpenFile(routePath, &f, FS_READ);
  1668. B_TempFree(1024); //routePath
  1669. if (!f)
  1670. {
  1671. G_Printf(S_COLOR_YELLOW "Bot route data not found for %s\n", filename);
  1672. return 2;
  1673. }
  1674. if (len >= 524288)
  1675. {
  1676. G_Printf(S_COLOR_RED "Route file exceeds maximum length\n");
  1677. return 0;
  1678. }
  1679. fileString = (char *)B_TempAlloc(524288);
  1680. currentVar = (char *)B_TempAlloc(2048);
  1681. trap_FS_Read(fileString, len, f);
  1682. if (fileString[i] == 'l')
  1683. { //contains a "levelflags" entry..
  1684. char readLFlags[64];
  1685. i_cv = 0;
  1686. while (fileString[i] != ' ')
  1687. {
  1688. i++;
  1689. }
  1690. i++;
  1691. while (fileString[i] != '\n')
  1692. {
  1693. readLFlags[i_cv] = fileString[i];
  1694. i_cv++;
  1695. i++;
  1696. }
  1697. readLFlags[i_cv] = 0;
  1698. i++;
  1699. gLevelFlags = atoi(readLFlags);
  1700. }
  1701. else
  1702. {
  1703. gLevelFlags = 0;
  1704. }
  1705. while (i < len)
  1706. {
  1707. i_cv = 0;
  1708. thiswp.index = 0;
  1709. thiswp.flags = 0;
  1710. thiswp.inuse = 0;
  1711. thiswp.neighbornum = 0;
  1712. thiswp.origin[0] = 0;
  1713. thiswp.origin[1] = 0;
  1714. thiswp.origin[2] = 0;
  1715. thiswp.weight = 0;
  1716. thiswp.associated_entity = ENTITYNUM_NONE;
  1717. thiswp.forceJumpTo = 0;
  1718. thiswp.disttonext = 0;
  1719. nei_num = 0;
  1720. while (nei_num < MAX_NEIGHBOR_SIZE)
  1721. {
  1722. thiswp.neighbors[nei_num].num = 0;
  1723. thiswp.neighbors[nei_num].forceJumpTo = 0;
  1724. nei_num++;
  1725. }
  1726. while (fileString[i] != ' ')
  1727. {
  1728. currentVar[i_cv] = fileString[i];
  1729. i_cv++;
  1730. i++;
  1731. }
  1732. currentVar[i_cv] = '\0';
  1733. thiswp.index = atoi(currentVar);
  1734. i_cv = 0;
  1735. i++;
  1736. while (fileString[i] != ' ')
  1737. {
  1738. currentVar[i_cv] = fileString[i];
  1739. i_cv++;
  1740. i++;
  1741. }
  1742. currentVar[i_cv] = '\0';
  1743. thiswp.flags = atoi(currentVar);
  1744. i_cv = 0;
  1745. i++;
  1746. while (fileString[i] != ' ')
  1747. {
  1748. currentVar[i_cv] = fileString[i];
  1749. i_cv++;
  1750. i++;
  1751. }
  1752. currentVar[i_cv] = '\0';
  1753. thiswp.weight = atof(currentVar);
  1754. i_cv = 0;
  1755. i++;
  1756. i++;
  1757. while (fileString[i] != ' ')
  1758. {
  1759. currentVar[i_cv] = fileString[i];
  1760. i_cv++;
  1761. i++;
  1762. }
  1763. currentVar[i_cv] = '\0';
  1764. thiswp.origin[0] = atof(currentVar);
  1765. i_cv = 0;
  1766. i++;
  1767. while (fileString[i] != ' ')
  1768. {
  1769. currentVar[i_cv] = fileString[i];
  1770. i_cv++;
  1771. i++;
  1772. }
  1773. currentVar[i_cv] = '\0';
  1774. thiswp.origin[1] = atof(currentVar);
  1775. i_cv = 0;
  1776. i++;
  1777. while (fileString[i] != ')')
  1778. {
  1779. currentVar[i_cv] = fileString[i];
  1780. i_cv++;
  1781. i++;
  1782. }
  1783. currentVar[i_cv] = '\0';
  1784. thiswp.origin[2] = atof(currentVar);
  1785. i += 4;
  1786. while (fileString[i] != '}')
  1787. {
  1788. i_cv = 0;
  1789. while (fileString[i] != ' ' && fileString[i] != '-')
  1790. {
  1791. currentVar[i_cv] = fileString[i];
  1792. i_cv++;
  1793. i++;
  1794. }
  1795. currentVar[i_cv] = '\0';
  1796. thiswp.neighbors[thiswp.neighbornum].num = atoi(currentVar);
  1797. if (fileString[i] == '-')
  1798. {
  1799. i_cv = 0;
  1800. i++;
  1801. while (fileString[i] != ' ')
  1802. {
  1803. currentVar[i_cv] = fileString[i];
  1804. i_cv++;
  1805. i++;
  1806. }
  1807. currentVar[i_cv] = '\0';
  1808. thiswp.neighbors[thiswp.neighbornum].forceJumpTo = 999; //atoi(currentVar); //FJSR
  1809. }
  1810. else
  1811. {
  1812. thiswp.neighbors[thiswp.neighbornum].forceJumpTo = 0;
  1813. }
  1814. thiswp.neighbornum++;
  1815. i++;
  1816. }
  1817. i_cv = 0;
  1818. i++;
  1819. i++;
  1820. while (fileString[i] != '\n')
  1821. {
  1822. currentVar[i_cv] = fileString[i];
  1823. i_cv++;
  1824. i++;
  1825. }
  1826. currentVar[i_cv] = '\0';
  1827. thiswp.disttonext = atof(currentVar);
  1828. CreateNewWP_FromObject(&thiswp);
  1829. i++;
  1830. }
  1831. B_TempFree(524288); //fileString
  1832. B_TempFree(2048); //currentVar
  1833. trap_FS_FCloseFile(f);
  1834. if (g_gametype.integer == GT_SIEGE)
  1835. {
  1836. CalculateSiegeGoals();
  1837. }
  1838. CalculateWeightGoals();
  1839. //calculate weights for idle activity goals when
  1840. //the bot has absolutely nothing else to do
  1841. CalculateJumpRoutes();
  1842. //Look at jump points and mark them as requiring
  1843. //force jumping as needed
  1844. return 1;
  1845. }
  1846. void FlagObjects(void)
  1847. {
  1848. int i = 0, bestindex = 0, found = 0;
  1849. float bestdist = 999999, tlen = 0;
  1850. gentity_t *flag_red, *flag_blue, *ent;
  1851. vec3_t a, mins, maxs;
  1852. trace_t tr;
  1853. flag_red = NULL;
  1854. flag_blue = NULL;
  1855. mins[0] = -15;
  1856. mins[1] = -15;
  1857. mins[2] = -5;
  1858. maxs[0] = 15;
  1859. maxs[1] = 15;
  1860. maxs[2] = 5;
  1861. while (i < level.num_entities)
  1862. {
  1863. ent = &g_entities[i];
  1864. if (ent && ent->inuse && ent->classname)
  1865. {
  1866. if (!flag_red && strcmp(ent->classname, "team_CTF_redflag") == 0)
  1867. {
  1868. flag_red = ent;
  1869. }
  1870. else if (!flag_blue && strcmp(ent->classname, "team_CTF_blueflag") == 0)
  1871. {
  1872. flag_blue = ent;
  1873. }
  1874. if (flag_red && flag_blue)
  1875. {
  1876. break;
  1877. }
  1878. }
  1879. i++;
  1880. }
  1881. i = 0;
  1882. if (!flag_red || !flag_blue)
  1883. {
  1884. return;
  1885. }
  1886. while (i < gWPNum)
  1887. {
  1888. if (gWPArray[i] && gWPArray[i]->inuse)
  1889. {
  1890. VectorSubtract(flag_red->s.pos.trBase, gWPArray[i]->origin, a);
  1891. tlen = VectorLength(a);
  1892. if (tlen < bestdist)
  1893. {
  1894. trap_Trace(&tr, flag_red->s.pos.trBase, mins, maxs, gWPArray[i]->origin, flag_red->s.number, MASK_SOLID);
  1895. if (tr.fraction == 1 || tr.entityNum == flag_red->s.number)
  1896. {
  1897. bestdist = tlen;
  1898. bestindex = i;
  1899. found = 1;
  1900. }
  1901. }
  1902. }
  1903. i++;
  1904. }
  1905. if (found)
  1906. {
  1907. gWPArray[bestindex]->flags |= WPFLAG_RED_FLAG;
  1908. flagRed = gWPArray[bestindex];
  1909. oFlagRed = flagRed;
  1910. eFlagRed = flag_red;
  1911. }
  1912. bestdist = 999999;
  1913. bestindex = 0;
  1914. found = 0;
  1915. i = 0;
  1916. while (i < gWPNum)
  1917. {
  1918. if (gWPArray[i] && gWPArray[i]->inuse)
  1919. {
  1920. VectorSubtract(flag_blue->s.pos.trBase, gWPArray[i]->origin, a);
  1921. tlen = VectorLength(a);
  1922. if (tlen < bestdist)
  1923. {
  1924. trap_Trace(&tr, flag_blue->s.pos.trBase, mins, maxs, gWPArray[i]->origin, flag_blue->s.number, MASK_SOLID);
  1925. if (tr.fraction == 1 || tr.entityNum == flag_blue->s.number)
  1926. {
  1927. bestdist = tlen;
  1928. bestindex = i;
  1929. found = 1;
  1930. }
  1931. }
  1932. }
  1933. i++;
  1934. }
  1935. if (found)
  1936. {
  1937. gWPArray[bestindex]->flags |= WPFLAG_BLUE_FLAG;
  1938. flagBlue = gWPArray[bestindex];
  1939. oFlagBlue = flagBlue;
  1940. eFlagBlue = flag_blue;
  1941. }
  1942. }
  1943. #ifndef _XBOX
  1944. int SavePathData(const char *filename)
  1945. {
  1946. fileHandle_t f;
  1947. char *fileString;
  1948. char *storeString;
  1949. char *routePath;
  1950. vec3_t a;
  1951. float flLen;
  1952. int i, s, n;
  1953. fileString = NULL;
  1954. i = 0;
  1955. s = 0;
  1956. if (!gWPNum)
  1957. {
  1958. return 0;
  1959. }
  1960. routePath = (char *)B_TempAlloc(1024);
  1961. Com_sprintf(routePath, 1024, "botroutes/%s.wnt\0", filename);
  1962. trap_FS_FOpenFile(routePath, &f, FS_WRITE);
  1963. B_TempFree(1024); //routePath
  1964. if (!f)
  1965. {
  1966. G_Printf(S_COLOR_RED "ERROR: Could not open file to write path data\n");
  1967. return 0;
  1968. }
  1969. if (!RepairPaths(qfalse)) //check if we can see all waypoints from the last. If not, try to branch over.
  1970. {
  1971. trap_FS_FCloseFile(f);
  1972. return 0;
  1973. }
  1974. CalculatePaths(); //make everything nice and connected before saving
  1975. FlagObjects(); //currently only used for flagging waypoints nearest CTF flags
  1976. fileString = (char *)B_TempAlloc(524288);
  1977. storeString = (char *)B_TempAlloc(4096);
  1978. Com_sprintf(fileString, 524288, "%i %i %f (%f %f %f) { ", gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]);
  1979. n = 0;
  1980. while (n < gWPArray[i]->neighbornum)
  1981. {
  1982. if (gWPArray[i]->neighbors[n].forceJumpTo)
  1983. {
  1984. Com_sprintf(storeString, 4096, "%s%i-%i ", storeString, gWPArray[i]->neighbors[n].num, gWPArray[i]->neighbors[n].forceJumpTo);
  1985. }
  1986. else
  1987. {
  1988. Com_sprintf(storeString, 4096, "%s%i ", storeString, gWPArray[i]->neighbors[n].num);
  1989. }
  1990. n++;
  1991. }
  1992. if (gWPArray[i+1] && gWPArray[i+1]->inuse && gWPArray[i+1]->index)
  1993. {
  1994. VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a);
  1995. flLen = VectorLength(a);
  1996. }
  1997. else
  1998. {
  1999. flLen = 0;
  2000. }
  2001. gWPArray[i]->disttonext = flLen;
  2002. Com_sprintf(fileString, 524288, "%s} %f\n", fileString, flLen);
  2003. i++;
  2004. while (i < gWPNum)
  2005. {
  2006. //sprintf(fileString, "%s%i %i %f (%f %f %f) { ", fileString, gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]);
  2007. Com_sprintf(storeString, 4096, "%i %i %f (%f %f %f) { ", gWPArray[i]->index, gWPArray[i]->flags, gWPArray[i]->weight, gWPArray[i]->origin[0], gWPArray[i]->origin[1], gWPArray[i]->origin[2]);
  2008. n = 0;
  2009. while (n < gWPArray[i]->neighbornum)
  2010. {
  2011. if (gWPArray[i]->neighbors[n].forceJumpTo)
  2012. {
  2013. Com_sprintf(storeString, 4096, "%s%i-%i ", storeString, gWPArray[i]->neighbors[n].num, gWPArray[i]->neighbors[n].forceJumpTo);
  2014. }
  2015. else
  2016. {
  2017. Com_sprintf(storeString, 4096, "%s%i ", storeString, gWPArray[i]->neighbors[n].num);
  2018. }
  2019. n++;
  2020. }
  2021. if (gWPArray[i+1] && gWPArray[i+1]->inuse && gWPArray[i+1]->index)
  2022. {
  2023. VectorSubtract(gWPArray[i]->origin, gWPArray[i+1]->origin, a);
  2024. flLen = VectorLength(a);
  2025. }
  2026. else
  2027. {
  2028. flLen = 0;
  2029. }
  2030. gWPArray[i]->disttonext = flLen;
  2031. Com_sprintf(storeString, 4096, "%s} %f\n", storeString, flLen);
  2032. strcat(fileString, storeString);
  2033. i++;
  2034. }
  2035. trap_FS_Write(fileString, strlen(fileString), f);
  2036. B_TempFree(524288); //fileString
  2037. B_TempFree(4096); //storeString
  2038. trap_FS_FCloseFile(f);
  2039. G_Printf("Path data has been saved and updated. You may need to restart the level for some things to be properly calculated.\n");
  2040. return 1;
  2041. }
  2042. #endif
  2043. //#define PAINFULLY_DEBUGGING_THROUGH_VM
  2044. #define MAX_SPAWNPOINT_ARRAY 64
  2045. int gSpawnPointNum = 0;
  2046. gentity_t *gSpawnPoints[MAX_SPAWNPOINT_ARRAY];
  2047. #ifn

Large files files are truncated, but you can click here to view the full file