ai_main.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. //
  19. /*****************************************************************************
  20. * name: ai_main.c
  21. *
  22. * desc: Quake3 bot AI
  23. *
  24. * $Archive: /MissionPack/code/game/ai_main.c $
  25. *
  26. *****************************************************************************/
  27. #include "g_local.h"
  28. #include "q_shared.h"
  29. #include "botlib.h" //bot lib interface
  30. #include "be_aas.h"
  31. #include "be_ea.h"
  32. #include "be_ai_char.h"
  33. #include "be_ai_chat.h"
  34. #include "be_ai_gen.h"
  35. #include "be_ai_goal.h"
  36. #include "be_ai_move.h"
  37. #include "be_ai_weap.h"
  38. //
  39. #include "ai_main.h"
  40. #include "ai_dmq3.h"
  41. #include "ai_chat.h"
  42. #include "ai_cmd.h"
  43. #include "ai_dmnet.h"
  44. #include "ai_vcmd.h"
  45. //
  46. #include "chars.h"
  47. #include "inv.h"
  48. #include "syn.h"
  49. #define MAX_PATH 144
  50. //bot states
  51. bot_state_t *botstates[MAX_CLIENTS];
  52. //number of bots
  53. int numbots;
  54. //floating point time
  55. float floattime;
  56. //time to do a regular update
  57. float regularupdate_time;
  58. //
  59. int bot_interbreed;
  60. int bot_interbreedmatchcount;
  61. //
  62. vmCvar_t bot_thinktime;
  63. vmCvar_t bot_memorydump;
  64. vmCvar_t bot_saveroutingcache;
  65. vmCvar_t bot_pause;
  66. vmCvar_t bot_report;
  67. vmCvar_t bot_testsolid;
  68. vmCvar_t bot_testclusters;
  69. vmCvar_t bot_developer;
  70. vmCvar_t bot_interbreedchar;
  71. vmCvar_t bot_interbreedbots;
  72. vmCvar_t bot_interbreedcycle;
  73. vmCvar_t bot_interbreedwrite;
  74. void ExitLevel( void );
  75. /*
  76. ==================
  77. BotAI_Print
  78. ==================
  79. */
  80. void QDECL BotAI_Print(int type, char *fmt, ...) {
  81. char str[2048];
  82. va_list ap;
  83. va_start(ap, fmt);
  84. vsprintf(str, fmt, ap);
  85. va_end(ap);
  86. switch(type) {
  87. case PRT_MESSAGE: {
  88. G_Printf("%s", str);
  89. break;
  90. }
  91. case PRT_WARNING: {
  92. G_Printf( S_COLOR_YELLOW "Warning: %s", str );
  93. break;
  94. }
  95. case PRT_ERROR: {
  96. G_Printf( S_COLOR_RED "Error: %s", str );
  97. break;
  98. }
  99. case PRT_FATAL: {
  100. G_Printf( S_COLOR_RED "Fatal: %s", str );
  101. break;
  102. }
  103. case PRT_EXIT: {
  104. G_Error( S_COLOR_RED "Exit: %s", str );
  105. break;
  106. }
  107. default: {
  108. G_Printf( "unknown print type\n" );
  109. break;
  110. }
  111. }
  112. }
  113. /*
  114. ==================
  115. BotAI_Trace
  116. ==================
  117. */
  118. void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
  119. trace_t trace;
  120. trap_Trace(&trace, start, mins, maxs, end, passent, contentmask);
  121. //copy the trace information
  122. bsptrace->allsolid = trace.allsolid;
  123. bsptrace->startsolid = trace.startsolid;
  124. bsptrace->fraction = trace.fraction;
  125. VectorCopy(trace.endpos, bsptrace->endpos);
  126. bsptrace->plane.dist = trace.plane.dist;
  127. VectorCopy(trace.plane.normal, bsptrace->plane.normal);
  128. bsptrace->plane.signbits = trace.plane.signbits;
  129. bsptrace->plane.type = trace.plane.type;
  130. bsptrace->surface.value = trace.surfaceFlags;
  131. bsptrace->ent = trace.entityNum;
  132. bsptrace->exp_dist = 0;
  133. bsptrace->sidenum = 0;
  134. bsptrace->contents = 0;
  135. }
  136. /*
  137. ==================
  138. BotAI_GetClientState
  139. ==================
  140. */
  141. int BotAI_GetClientState( int clientNum, playerState_t *state ) {
  142. gentity_t *ent;
  143. ent = &g_entities[clientNum];
  144. if ( !ent->inuse ) {
  145. return qfalse;
  146. }
  147. if ( !ent->client ) {
  148. return qfalse;
  149. }
  150. memcpy( state, &ent->client->ps, sizeof(playerState_t) );
  151. return qtrue;
  152. }
  153. /*
  154. ==================
  155. BotAI_GetEntityState
  156. ==================
  157. */
  158. int BotAI_GetEntityState( int entityNum, entityState_t *state ) {
  159. gentity_t *ent;
  160. ent = &g_entities[entityNum];
  161. memset( state, 0, sizeof(entityState_t) );
  162. if (!ent->inuse) return qfalse;
  163. if (!ent->r.linked) return qfalse;
  164. if (ent->r.svFlags & SVF_NOCLIENT) return qfalse;
  165. memcpy( state, &ent->s, sizeof(entityState_t) );
  166. return qtrue;
  167. }
  168. /*
  169. ==================
  170. BotAI_GetSnapshotEntity
  171. ==================
  172. */
  173. int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state ) {
  174. int entNum;
  175. entNum = trap_BotGetSnapshotEntity( clientNum, sequence );
  176. if ( entNum == -1 ) {
  177. memset(state, 0, sizeof(entityState_t));
  178. return -1;
  179. }
  180. BotAI_GetEntityState( entNum, state );
  181. return sequence + 1;
  182. }
  183. /*
  184. ==================
  185. BotAI_BotInitialChat
  186. ==================
  187. */
  188. void QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... ) {
  189. int i, mcontext;
  190. va_list ap;
  191. char *p;
  192. char *vars[MAX_MATCHVARIABLES];
  193. memset(vars, 0, sizeof(vars));
  194. va_start(ap, type);
  195. p = va_arg(ap, char *);
  196. for (i = 0; i < MAX_MATCHVARIABLES; i++) {
  197. if( !p ) {
  198. break;
  199. }
  200. vars[i] = p;
  201. p = va_arg(ap, char *);
  202. }
  203. va_end(ap);
  204. mcontext = BotSynonymContext(bs);
  205. trap_BotInitialChat( bs->cs, type, mcontext, vars[0], vars[1], vars[2], vars[3], vars[4], vars[5], vars[6], vars[7] );
  206. }
  207. /*
  208. ==================
  209. BotTestAAS
  210. ==================
  211. */
  212. void BotTestAAS(vec3_t origin) {
  213. int areanum;
  214. aas_areainfo_t info;
  215. trap_Cvar_Update(&bot_testsolid);
  216. trap_Cvar_Update(&bot_testclusters);
  217. if (bot_testsolid.integer) {
  218. if (!trap_AAS_Initialized()) return;
  219. areanum = BotPointAreaNum(origin);
  220. if (areanum) BotAI_Print(PRT_MESSAGE, "\remtpy area");
  221. else BotAI_Print(PRT_MESSAGE, "\r^1SOLID area");
  222. }
  223. else if (bot_testclusters.integer) {
  224. if (!trap_AAS_Initialized()) return;
  225. areanum = BotPointAreaNum(origin);
  226. if (!areanum)
  227. BotAI_Print(PRT_MESSAGE, "\r^1Solid! ");
  228. else {
  229. trap_AAS_AreaInfo(areanum, &info);
  230. BotAI_Print(PRT_MESSAGE, "\rarea %d, cluster %d ", areanum, info.cluster);
  231. }
  232. }
  233. }
  234. /*
  235. ==================
  236. BotReportStatus
  237. ==================
  238. */
  239. void BotReportStatus(bot_state_t *bs) {
  240. char goalname[MAX_MESSAGE_SIZE];
  241. char netname[MAX_MESSAGE_SIZE];
  242. char *leader, flagstatus[32];
  243. //
  244. ClientName(bs->client, netname, sizeof(netname));
  245. if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
  246. else leader = " ";
  247. strcpy(flagstatus, " ");
  248. if (gametype == GT_CTF) {
  249. if (BotCTFCarryingFlag(bs)) {
  250. if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
  251. else strcpy(flagstatus, S_COLOR_BLUE"F ");
  252. }
  253. }
  254. #ifdef MISSIONPACK
  255. else if (gametype == GT_1FCTF) {
  256. if (Bot1FCTFCarryingFlag(bs)) {
  257. if (BotTeam(bs) == TEAM_RED) strcpy(flagstatus, S_COLOR_RED"F ");
  258. else strcpy(flagstatus, S_COLOR_BLUE"F ");
  259. }
  260. }
  261. else if (gametype == GT_HARVESTER) {
  262. if (BotHarvesterCarryingCubes(bs)) {
  263. if (BotTeam(bs) == TEAM_RED) Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_RED"%2d", bs->inventory[INVENTORY_REDCUBE]);
  264. else Com_sprintf(flagstatus, sizeof(flagstatus), S_COLOR_BLUE"%2d", bs->inventory[INVENTORY_BLUECUBE]);
  265. }
  266. }
  267. #endif
  268. switch(bs->ltgtype) {
  269. case LTG_TEAMHELP:
  270. {
  271. EasyClientName(bs->teammate, goalname, sizeof(goalname));
  272. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: helping %s\n", netname, leader, flagstatus, goalname);
  273. break;
  274. }
  275. case LTG_TEAMACCOMPANY:
  276. {
  277. EasyClientName(bs->teammate, goalname, sizeof(goalname));
  278. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: accompanying %s\n", netname, leader, flagstatus, goalname);
  279. break;
  280. }
  281. case LTG_DEFENDKEYAREA:
  282. {
  283. trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
  284. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: defending %s\n", netname, leader, flagstatus, goalname);
  285. break;
  286. }
  287. case LTG_GETITEM:
  288. {
  289. trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
  290. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: getting item %s\n", netname, leader, flagstatus, goalname);
  291. break;
  292. }
  293. case LTG_KILL:
  294. {
  295. ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
  296. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: killing %s\n", netname, leader, flagstatus, goalname);
  297. break;
  298. }
  299. case LTG_CAMP:
  300. case LTG_CAMPORDER:
  301. {
  302. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: camping\n", netname, leader, flagstatus);
  303. break;
  304. }
  305. case LTG_PATROL:
  306. {
  307. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: patrolling\n", netname, leader, flagstatus);
  308. break;
  309. }
  310. case LTG_GETFLAG:
  311. {
  312. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: capturing flag\n", netname, leader, flagstatus);
  313. break;
  314. }
  315. case LTG_RUSHBASE:
  316. {
  317. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: rushing base\n", netname, leader, flagstatus);
  318. break;
  319. }
  320. case LTG_RETURNFLAG:
  321. {
  322. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: returning flag\n", netname, leader, flagstatus);
  323. break;
  324. }
  325. case LTG_ATTACKENEMYBASE:
  326. {
  327. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: attacking the enemy base\n", netname, leader, flagstatus);
  328. break;
  329. }
  330. case LTG_HARVEST:
  331. {
  332. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: harvesting\n", netname, leader, flagstatus);
  333. break;
  334. }
  335. default:
  336. {
  337. BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus);
  338. break;
  339. }
  340. }
  341. }
  342. /*
  343. ==================
  344. BotTeamplayReport
  345. ==================
  346. */
  347. void BotTeamplayReport(void) {
  348. int i;
  349. char buf[MAX_INFO_STRING];
  350. BotAI_Print(PRT_MESSAGE, S_COLOR_RED"RED\n");
  351. for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  352. //
  353. if ( !botstates[i] || !botstates[i]->inuse ) continue;
  354. //
  355. trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  356. //if no config string or no name
  357. if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  358. //skip spectators
  359. if (atoi(Info_ValueForKey(buf, "t")) == TEAM_RED) {
  360. BotReportStatus(botstates[i]);
  361. }
  362. }
  363. BotAI_Print(PRT_MESSAGE, S_COLOR_BLUE"BLUE\n");
  364. for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  365. //
  366. if ( !botstates[i] || !botstates[i]->inuse ) continue;
  367. //
  368. trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  369. //if no config string or no name
  370. if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
  371. //skip spectators
  372. if (atoi(Info_ValueForKey(buf, "t")) == TEAM_BLUE) {
  373. BotReportStatus(botstates[i]);
  374. }
  375. }
  376. }
  377. /*
  378. ==================
  379. BotSetInfoConfigString
  380. ==================
  381. */
  382. void BotSetInfoConfigString(bot_state_t *bs) {
  383. char goalname[MAX_MESSAGE_SIZE];
  384. char netname[MAX_MESSAGE_SIZE];
  385. char action[MAX_MESSAGE_SIZE];
  386. char *leader, carrying[32], *cs;
  387. bot_goal_t goal;
  388. //
  389. ClientName(bs->client, netname, sizeof(netname));
  390. if (Q_stricmp(netname, bs->teamleader) == 0) leader = "L";
  391. else leader = " ";
  392. strcpy(carrying, " ");
  393. if (gametype == GT_CTF) {
  394. if (BotCTFCarryingFlag(bs)) {
  395. strcpy(carrying, "F ");
  396. }
  397. }
  398. #ifdef MISSIONPACK
  399. else if (gametype == GT_1FCTF) {
  400. if (Bot1FCTFCarryingFlag(bs)) {
  401. strcpy(carrying, "F ");
  402. }
  403. }
  404. else if (gametype == GT_HARVESTER) {
  405. if (BotHarvesterCarryingCubes(bs)) {
  406. if (BotTeam(bs) == TEAM_RED) Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_REDCUBE]);
  407. else Com_sprintf(carrying, sizeof(carrying), "%2d", bs->inventory[INVENTORY_BLUECUBE]);
  408. }
  409. }
  410. #endif
  411. switch(bs->ltgtype) {
  412. case LTG_TEAMHELP:
  413. {
  414. EasyClientName(bs->teammate, goalname, sizeof(goalname));
  415. Com_sprintf(action, sizeof(action), "helping %s", goalname);
  416. break;
  417. }
  418. case LTG_TEAMACCOMPANY:
  419. {
  420. EasyClientName(bs->teammate, goalname, sizeof(goalname));
  421. Com_sprintf(action, sizeof(action), "accompanying %s", goalname);
  422. break;
  423. }
  424. case LTG_DEFENDKEYAREA:
  425. {
  426. trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
  427. Com_sprintf(action, sizeof(action), "defending %s", goalname);
  428. break;
  429. }
  430. case LTG_GETITEM:
  431. {
  432. trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
  433. Com_sprintf(action, sizeof(action), "getting item %s", goalname);
  434. break;
  435. }
  436. case LTG_KILL:
  437. {
  438. ClientName(bs->teamgoal.entitynum, goalname, sizeof(goalname));
  439. Com_sprintf(action, sizeof(action), "killing %s", goalname);
  440. break;
  441. }
  442. case LTG_CAMP:
  443. case LTG_CAMPORDER:
  444. {
  445. Com_sprintf(action, sizeof(action), "camping");
  446. break;
  447. }
  448. case LTG_PATROL:
  449. {
  450. Com_sprintf(action, sizeof(action), "patrolling");
  451. break;
  452. }
  453. case LTG_GETFLAG:
  454. {
  455. Com_sprintf(action, sizeof(action), "capturing flag");
  456. break;
  457. }
  458. case LTG_RUSHBASE:
  459. {
  460. Com_sprintf(action, sizeof(action), "rushing base");
  461. break;
  462. }
  463. case LTG_RETURNFLAG:
  464. {
  465. Com_sprintf(action, sizeof(action), "returning flag");
  466. break;
  467. }
  468. case LTG_ATTACKENEMYBASE:
  469. {
  470. Com_sprintf(action, sizeof(action), "attacking the enemy base");
  471. break;
  472. }
  473. case LTG_HARVEST:
  474. {
  475. Com_sprintf(action, sizeof(action), "harvesting");
  476. break;
  477. }
  478. default:
  479. {
  480. trap_BotGetTopGoal(bs->gs, &goal);
  481. trap_BotGoalName(goal.number, goalname, sizeof(goalname));
  482. Com_sprintf(action, sizeof(action), "roaming %s", goalname);
  483. break;
  484. }
  485. }
  486. cs = va("l\\%s\\c\\%s\\a\\%s",
  487. leader,
  488. carrying,
  489. action);
  490. trap_SetConfigstring (CS_BOTINFO + bs->client, cs);
  491. }
  492. /*
  493. ==============
  494. BotUpdateInfoConfigStrings
  495. ==============
  496. */
  497. void BotUpdateInfoConfigStrings(void) {
  498. int i;
  499. char buf[MAX_INFO_STRING];
  500. for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
  501. //
  502. if ( !botstates[i] || !botstates[i]->inuse )
  503. continue;
  504. //
  505. trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
  506. //if no config string or no name
  507. if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
  508. continue;
  509. BotSetInfoConfigString(botstates[i]);
  510. }
  511. }
  512. /*
  513. ==============
  514. BotInterbreedBots
  515. ==============
  516. */
  517. void BotInterbreedBots(void) {
  518. float ranks[MAX_CLIENTS];
  519. int parent1, parent2, child;
  520. int i;
  521. // get rankings for all the bots
  522. for (i = 0; i < MAX_CLIENTS; i++) {
  523. if ( botstates[i] && botstates[i]->inuse ) {
  524. ranks[i] = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
  525. }
  526. else {
  527. ranks[i] = -1;
  528. }
  529. }
  530. if (trap_GeneticParentsAndChildSelection(MAX_CLIENTS, ranks, &parent1, &parent2, &child)) {
  531. trap_BotInterbreedGoalFuzzyLogic(botstates[parent1]->gs, botstates[parent2]->gs, botstates[child]->gs);
  532. trap_BotMutateGoalFuzzyLogic(botstates[child]->gs, 1);
  533. }
  534. // reset the kills and deaths
  535. for (i = 0; i < MAX_CLIENTS; i++) {
  536. if (botstates[i] && botstates[i]->inuse) {
  537. botstates[i]->num_kills = 0;
  538. botstates[i]->num_deaths = 0;
  539. }
  540. }
  541. }
  542. /*
  543. ==============
  544. BotWriteInterbreeded
  545. ==============
  546. */
  547. void BotWriteInterbreeded(char *filename) {
  548. float rank, bestrank;
  549. int i, bestbot;
  550. bestrank = 0;
  551. bestbot = -1;
  552. // get the best bot
  553. for (i = 0; i < MAX_CLIENTS; i++) {
  554. if ( botstates[i] && botstates[i]->inuse ) {
  555. rank = botstates[i]->num_kills * 2 - botstates[i]->num_deaths;
  556. }
  557. else {
  558. rank = -1;
  559. }
  560. if (rank > bestrank) {
  561. bestrank = rank;
  562. bestbot = i;
  563. }
  564. }
  565. if (bestbot >= 0) {
  566. //write out the new goal fuzzy logic
  567. trap_BotSaveGoalFuzzyLogic(botstates[bestbot]->gs, filename);
  568. }
  569. }
  570. /*
  571. ==============
  572. BotInterbreedEndMatch
  573. add link back into ExitLevel?
  574. ==============
  575. */
  576. void BotInterbreedEndMatch(void) {
  577. if (!bot_interbreed) return;
  578. bot_interbreedmatchcount++;
  579. if (bot_interbreedmatchcount >= bot_interbreedcycle.integer) {
  580. bot_interbreedmatchcount = 0;
  581. //
  582. trap_Cvar_Update(&bot_interbreedwrite);
  583. if (strlen(bot_interbreedwrite.string)) {
  584. BotWriteInterbreeded(bot_interbreedwrite.string);
  585. trap_Cvar_Set("bot_interbreedwrite", "");
  586. }
  587. BotInterbreedBots();
  588. }
  589. }
  590. /*
  591. ==============
  592. BotInterbreeding
  593. ==============
  594. */
  595. void BotInterbreeding(void) {
  596. int i;
  597. trap_Cvar_Update(&bot_interbreedchar);
  598. if (!strlen(bot_interbreedchar.string)) return;
  599. //make sure we are in tournament mode
  600. if (gametype != GT_TOURNAMENT) {
  601. trap_Cvar_Set("g_gametype", va("%d", GT_TOURNAMENT));
  602. ExitLevel();
  603. return;
  604. }
  605. //shutdown all the bots
  606. for (i = 0; i < MAX_CLIENTS; i++) {
  607. if (botstates[i] && botstates[i]->inuse) {
  608. BotAIShutdownClient(botstates[i]->client, qfalse);
  609. }
  610. }
  611. //make sure all item weight configs are reloaded and Not shared
  612. trap_BotLibVarSet("bot_reloadcharacters", "1");
  613. //add a number of bots using the desired bot character
  614. for (i = 0; i < bot_interbreedbots.integer; i++) {
  615. trap_SendConsoleCommand( EXEC_INSERT, va("addbot %s 4 free %i %s%d\n",
  616. bot_interbreedchar.string, i * 50, bot_interbreedchar.string, i) );
  617. }
  618. //
  619. trap_Cvar_Set("bot_interbreedchar", "");
  620. bot_interbreed = qtrue;
  621. }
  622. /*
  623. ==============
  624. BotEntityInfo
  625. ==============
  626. */
  627. void BotEntityInfo(int entnum, aas_entityinfo_t *info) {
  628. trap_AAS_EntityInfo(entnum, info);
  629. }
  630. /*
  631. ==============
  632. NumBots
  633. ==============
  634. */
  635. int NumBots(void) {
  636. return numbots;
  637. }
  638. /*
  639. ==============
  640. BotTeamLeader
  641. ==============
  642. */
  643. int BotTeamLeader(bot_state_t *bs) {
  644. int leader;
  645. leader = ClientFromName(bs->teamleader);
  646. if (leader < 0) return qfalse;
  647. if (!botstates[leader] || !botstates[leader]->inuse) return qfalse;
  648. return qtrue;
  649. }
  650. /*
  651. ==============
  652. AngleDifference
  653. ==============
  654. */
  655. float AngleDifference(float ang1, float ang2) {
  656. float diff;
  657. diff = ang1 - ang2;
  658. if (ang1 > ang2) {
  659. if (diff > 180.0) diff -= 360.0;
  660. }
  661. else {
  662. if (diff < -180.0) diff += 360.0;
  663. }
  664. return diff;
  665. }
  666. /*
  667. ==============
  668. BotChangeViewAngle
  669. ==============
  670. */
  671. float BotChangeViewAngle(float angle, float ideal_angle, float speed) {
  672. float move;
  673. angle = AngleMod(angle);
  674. ideal_angle = AngleMod(ideal_angle);
  675. if (angle == ideal_angle) return angle;
  676. move = ideal_angle - angle;
  677. if (ideal_angle > angle) {
  678. if (move > 180.0) move -= 360.0;
  679. }
  680. else {
  681. if (move < -180.0) move += 360.0;
  682. }
  683. if (move > 0) {
  684. if (move > speed) move = speed;
  685. }
  686. else {
  687. if (move < -speed) move = -speed;
  688. }
  689. return AngleMod(angle + move);
  690. }
  691. /*
  692. ==============
  693. BotChangeViewAngles
  694. ==============
  695. */
  696. void BotChangeViewAngles(bot_state_t *bs, float thinktime) {
  697. float diff, factor, maxchange, anglespeed, disired_speed;
  698. int i;
  699. if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
  700. //
  701. if (bs->enemy >= 0) {
  702. factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1);
  703. maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800);
  704. }
  705. else {
  706. factor = 0.05f;
  707. maxchange = 360;
  708. }
  709. if (maxchange < 240) maxchange = 240;
  710. maxchange *= thinktime;
  711. for (i = 0; i < 2; i++) {
  712. //
  713. if (bot_challenge.integer) {
  714. //smooth slowdown view model
  715. diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
  716. anglespeed = diff * factor;
  717. if (anglespeed > maxchange) anglespeed = maxchange;
  718. bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i],
  719. bs->ideal_viewangles[i], anglespeed);
  720. }
  721. else {
  722. //over reaction view model
  723. bs->viewangles[i] = AngleMod(bs->viewangles[i]);
  724. bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);
  725. diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);
  726. disired_speed = diff * factor;
  727. bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);
  728. if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;
  729. if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;
  730. anglespeed = bs->viewanglespeed[i];
  731. if (anglespeed > maxchange) anglespeed = maxchange;
  732. if (anglespeed < -maxchange) anglespeed = -maxchange;
  733. bs->viewangles[i] += anglespeed;
  734. bs->viewangles[i] = AngleMod(bs->viewangles[i]);
  735. //demping
  736. bs->viewanglespeed[i] *= 0.45 * (1 - factor);
  737. }
  738. //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);`
  739. //bs->viewangles[i] = bs->ideal_viewangles[i];
  740. }
  741. //bs->viewangles[PITCH] = 0;
  742. if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;
  743. //elementary action: view
  744. trap_EA_View(bs->client, bs->viewangles);
  745. }
  746. /*
  747. ==============
  748. BotInputToUserCommand
  749. ==============
  750. */
  751. void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time) {
  752. vec3_t angles, forward, right;
  753. short temp;
  754. int j;
  755. //clear the whole structure
  756. memset(ucmd, 0, sizeof(usercmd_t));
  757. //
  758. //Com_Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);
  759. //the duration for the user command in milli seconds
  760. ucmd->serverTime = time;
  761. //
  762. if (bi->actionflags & ACTION_DELAYEDJUMP) {
  763. bi->actionflags |= ACTION_JUMP;
  764. bi->actionflags &= ~ACTION_DELAYEDJUMP;
  765. }
  766. //set the buttons
  767. if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
  768. if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
  769. if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
  770. if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
  771. if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
  772. if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;
  773. if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
  774. if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
  775. if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
  776. if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
  777. if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
  778. if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
  779. //
  780. ucmd->weapon = bi->weapon;
  781. //set the view angles
  782. //NOTE: the ucmd->angles are the angles WITHOUT the delta angles
  783. ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
  784. ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
  785. ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
  786. //subtract the delta angles
  787. for (j = 0; j < 3; j++) {
  788. temp = ucmd->angles[j] - delta_angles[j];
  789. /*NOTE: disabled because temp should be mod first
  790. if ( j == PITCH ) {
  791. // don't let the player look up or down more than 90 degrees
  792. if ( temp > 16000 ) temp = 16000;
  793. else if ( temp < -16000 ) temp = -16000;
  794. }
  795. */
  796. ucmd->angles[j] = temp;
  797. }
  798. //NOTE: movement is relative to the REAL view angles
  799. //get the horizontal forward and right vector
  800. //get the pitch in the range [-180, 180]
  801. if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
  802. else angles[PITCH] = 0;
  803. angles[YAW] = bi->viewangles[YAW];
  804. angles[ROLL] = 0;
  805. AngleVectors(angles, forward, right, NULL);
  806. //bot input speed is in the range [0, 400]
  807. bi->speed = bi->speed * 127 / 400;
  808. //set the view independent movement
  809. ucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed;
  810. ucmd->rightmove = DotProduct(right, bi->dir) * bi->speed;
  811. ucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed;
  812. //normal keyboard movement
  813. if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127;
  814. if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127;
  815. if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127;
  816. if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127;
  817. //jump/moveup
  818. if (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127;
  819. //crouch/movedown
  820. if (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127;
  821. //
  822. //Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);
  823. //Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime);
  824. }
  825. /*
  826. ==============
  827. BotUpdateInput
  828. ==============
  829. */
  830. void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time) {
  831. bot_input_t bi;
  832. int j;
  833. //add the delta angles to the bot's current view angles
  834. for (j = 0; j < 3; j++) {
  835. bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
  836. }
  837. //change the bot view angles
  838. BotChangeViewAngles(bs, (float) elapsed_time / 1000);
  839. //retrieve the bot input
  840. trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
  841. //respawn hack
  842. if (bi.actionflags & ACTION_RESPAWN) {
  843. if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
  844. }
  845. //convert the bot input to a usercmd
  846. BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time);
  847. //subtract the delta angles
  848. for (j = 0; j < 3; j++) {
  849. bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
  850. }
  851. }
  852. /*
  853. ==============
  854. BotAIRegularUpdate
  855. ==============
  856. */
  857. void BotAIRegularUpdate(void) {
  858. if (regularupdate_time < FloatTime()) {
  859. trap_BotUpdateEntityItems();
  860. regularupdate_time = FloatTime() + 0.3;
  861. }
  862. }
  863. /*
  864. ==============
  865. RemoveColorEscapeSequences
  866. ==============
  867. */
  868. void RemoveColorEscapeSequences( char *text ) {
  869. int i, l;
  870. l = 0;
  871. for ( i = 0; text[i]; i++ ) {
  872. if (Q_IsColorString(&text[i])) {
  873. i++;
  874. continue;
  875. }
  876. if (text[i] > 0x7E)
  877. continue;
  878. text[l++] = text[i];
  879. }
  880. text[l] = '\0';
  881. }
  882. /*
  883. ==============
  884. BotAI
  885. ==============
  886. */
  887. int BotAI(int client, float thinktime) {
  888. bot_state_t *bs;
  889. char buf[1024], *args;
  890. int j;
  891. trap_EA_ResetInput(client);
  892. //
  893. bs = botstates[client];
  894. if (!bs || !bs->inuse) {
  895. BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client);
  896. return qfalse;
  897. }
  898. //retrieve the current client state
  899. BotAI_GetClientState( client, &bs->cur_ps );
  900. //retrieve any waiting server commands
  901. while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {
  902. //have buf point to the command and args to the command arguments
  903. args = strchr( buf, ' ');
  904. if (!args) continue;
  905. *args++ = '\0';
  906. //remove color espace sequences from the arguments
  907. RemoveColorEscapeSequences( args );
  908. if (!Q_stricmp(buf, "cp "))
  909. { /*CenterPrintf*/ }
  910. else if (!Q_stricmp(buf, "cs"))
  911. { /*ConfigStringModified*/ }
  912. else if (!Q_stricmp(buf, "print")) {
  913. //remove first and last quote from the chat message
  914. memmove(args, args+1, strlen(args));
  915. args[strlen(args)-1] = '\0';
  916. trap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args);
  917. }
  918. else if (!Q_stricmp(buf, "chat")) {
  919. //remove first and last quote from the chat message
  920. memmove(args, args+1, strlen(args));
  921. args[strlen(args)-1] = '\0';
  922. trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
  923. }
  924. else if (!Q_stricmp(buf, "tchat")) {
  925. //remove first and last quote from the chat message
  926. memmove(args, args+1, strlen(args));
  927. args[strlen(args)-1] = '\0';
  928. trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args);
  929. }
  930. #ifdef MISSIONPACK
  931. else if (!Q_stricmp(buf, "vchat")) {
  932. BotVoiceChatCommand(bs, SAY_ALL, args);
  933. }
  934. else if (!Q_stricmp(buf, "vtchat")) {
  935. BotVoiceChatCommand(bs, SAY_TEAM, args);
  936. }
  937. else if (!Q_stricmp(buf, "vtell")) {
  938. BotVoiceChatCommand(bs, SAY_TELL, args);
  939. }
  940. #endif
  941. else if (!Q_stricmp(buf, "scores"))
  942. { /*FIXME: parse scores?*/ }
  943. else if (!Q_stricmp(buf, "clientLevelShot"))
  944. { /*ignore*/ }
  945. }
  946. //add the delta angles to the bot's current view angles
  947. for (j = 0; j < 3; j++) {
  948. bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
  949. }
  950. //increase the local time of the bot
  951. bs->ltime += thinktime;
  952. //
  953. bs->thinktime = thinktime;
  954. //origin of the bot
  955. VectorCopy(bs->cur_ps.origin, bs->origin);
  956. //eye coordinates of the bot
  957. VectorCopy(bs->cur_ps.origin, bs->eye);
  958. bs->eye[2] += bs->cur_ps.viewheight;
  959. //get the area the bot is in
  960. bs->areanum = BotPointAreaNum(bs->origin);
  961. //the real AI
  962. BotDeathmatchAI(bs, thinktime);
  963. //set the weapon selection every AI frame
  964. trap_EA_SelectWeapon(bs->client, bs->weaponnum);
  965. //subtract the delta angles
  966. for (j = 0; j < 3; j++) {
  967. bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
  968. }
  969. //everything was ok
  970. return qtrue;
  971. }
  972. /*
  973. ==================
  974. BotScheduleBotThink
  975. ==================
  976. */
  977. void BotScheduleBotThink(void) {
  978. int i, botnum;
  979. botnum = 0;
  980. for( i = 0; i < MAX_CLIENTS; i++ ) {
  981. if( !botstates[i] || !botstates[i]->inuse ) {
  982. continue;
  983. }
  984. //initialize the bot think residual time
  985. botstates[i]->botthink_residual = bot_thinktime.integer * botnum / numbots;
  986. botnum++;
  987. }
  988. }
  989. /*
  990. ==============
  991. BotWriteSessionData
  992. ==============
  993. */
  994. void BotWriteSessionData(bot_state_t *bs) {
  995. const char *s;
  996. const char *var;
  997. s = va(
  998. "%i %i %i %i %i %i %i %i"
  999. " %f %f %f"
  1000. " %f %f %f"
  1001. " %f %f %f",
  1002. bs->lastgoal_decisionmaker,
  1003. bs->lastgoal_ltgtype,
  1004. bs->lastgoal_teammate,
  1005. bs->lastgoal_teamgoal.areanum,
  1006. bs->lastgoal_teamgoal.entitynum,
  1007. bs->lastgoal_teamgoal.flags,
  1008. bs->lastgoal_teamgoal.iteminfo,
  1009. bs->lastgoal_teamgoal.number,
  1010. bs->lastgoal_teamgoal.origin[0],
  1011. bs->lastgoal_teamgoal.origin[1],
  1012. bs->lastgoal_teamgoal.origin[2],
  1013. bs->lastgoal_teamgoal.mins[0],
  1014. bs->lastgoal_teamgoal.mins[1],
  1015. bs->lastgoal_teamgoal.mins[2],
  1016. bs->lastgoal_teamgoal.maxs[0],
  1017. bs->lastgoal_teamgoal.maxs[1],
  1018. bs->lastgoal_teamgoal.maxs[2]
  1019. );
  1020. var = va( "botsession%i", bs->client );
  1021. trap_Cvar_Set( var, s );
  1022. }
  1023. /*
  1024. ==============
  1025. BotReadSessionData
  1026. ==============
  1027. */
  1028. void BotReadSessionData(bot_state_t *bs) {
  1029. char s[MAX_STRING_CHARS];
  1030. const char *var;
  1031. var = va( "botsession%i", bs->client );
  1032. trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
  1033. sscanf(s,
  1034. "%i %i %i %i %i %i %i %i"
  1035. " %f %f %f"
  1036. " %f %f %f"
  1037. " %f %f %f",
  1038. &bs->lastgoal_decisionmaker,
  1039. &bs->lastgoal_ltgtype,
  1040. &bs->lastgoal_teammate,
  1041. &bs->lastgoal_teamgoal.areanum,
  1042. &bs->lastgoal_teamgoal.entitynum,
  1043. &bs->lastgoal_teamgoal.flags,
  1044. &bs->lastgoal_teamgoal.iteminfo,
  1045. &bs->lastgoal_teamgoal.number,
  1046. &bs->lastgoal_teamgoal.origin[0],
  1047. &bs->lastgoal_teamgoal.origin[1],
  1048. &bs->lastgoal_teamgoal.origin[2],
  1049. &bs->lastgoal_teamgoal.mins[0],
  1050. &bs->lastgoal_teamgoal.mins[1],
  1051. &bs->lastgoal_teamgoal.mins[2],
  1052. &bs->lastgoal_teamgoal.maxs[0],
  1053. &bs->lastgoal_teamgoal.maxs[1],
  1054. &bs->lastgoal_teamgoal.maxs[2]
  1055. );
  1056. }
  1057. /*
  1058. ==============
  1059. BotAISetupClient
  1060. ==============
  1061. */
  1062. int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) {
  1063. char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];
  1064. bot_state_t *bs;
  1065. int errnum;
  1066. if (!botstates[client]) botstates[client] = G_Alloc(sizeof(bot_state_t));
  1067. bs = botstates[client];
  1068. if (bs && bs->inuse) {
  1069. BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client);
  1070. return qfalse;
  1071. }
  1072. if (!trap_AAS_Initialized()) {
  1073. BotAI_Print(PRT_FATAL, "AAS not initialized\n");
  1074. return qfalse;
  1075. }
  1076. //load the bot character
  1077. bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill);
  1078. if (!bs->character) {
  1079. BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile);
  1080. return qfalse;
  1081. }
  1082. //copy the settings
  1083. memcpy(&bs->settings, settings, sizeof(bot_settings_t));
  1084. //allocate a goal state
  1085. bs->gs = trap_BotAllocGoalState(client);
  1086. //load the item weights
  1087. trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);
  1088. errnum = trap_BotLoadItemWeights(bs->gs, filename);
  1089. if (errnum != BLERR_NOERROR) {
  1090. trap_BotFreeGoalState(bs->gs);
  1091. return qfalse;
  1092. }
  1093. //allocate a weapon state
  1094. bs->ws = trap_BotAllocWeaponState();
  1095. //load the weapon weights
  1096. trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);
  1097. errnum = trap_BotLoadWeaponWeights(bs->ws, filename);
  1098. if (errnum != BLERR_NOERROR) {
  1099. trap_BotFreeGoalState(bs->gs);
  1100. trap_BotFreeWeaponState(bs->ws);
  1101. return qfalse;
  1102. }
  1103. //allocate a chat state
  1104. bs->cs = trap_BotAllocChatState();
  1105. //load the chat file
  1106. trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);
  1107. trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);
  1108. errnum = trap_BotLoadChatFile(bs->cs, filename, name);
  1109. if (errnum != BLERR_NOERROR) {
  1110. trap_BotFreeChatState(bs->cs);
  1111. trap_BotFreeGoalState(bs->gs);
  1112. trap_BotFreeWeaponState(bs->ws);
  1113. return qfalse;
  1114. }
  1115. //get the gender characteristic
  1116. trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);
  1117. //set the chat gender
  1118. if (*gender == 'f' || *gender == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
  1119. else if (*gender == 'm' || *gender == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
  1120. else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS);
  1121. bs->inuse = qtrue;
  1122. bs->client = client;
  1123. bs->entitynum = client;
  1124. bs->setupcount = 4;
  1125. bs->entergame_time = FloatTime();
  1126. bs->ms = trap_BotAllocMoveState();
  1127. bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1);
  1128. numbots++;
  1129. if (trap_Cvar_VariableIntegerValue("bot_testichat")) {
  1130. trap_BotLibVarSet("bot_testichat", "1");
  1131. BotChatTest(bs);
  1132. }
  1133. //NOTE: reschedule the bot thinking
  1134. BotScheduleBotThink();
  1135. //if interbreeding start with a mutation
  1136. if (bot_interbreed) {
  1137. trap_BotMutateGoalFuzzyLogic(bs->gs, 1);
  1138. }
  1139. // if we kept the bot client
  1140. if (restart) {
  1141. BotReadSessionData(bs);
  1142. }
  1143. //bot has been setup succesfully
  1144. return qtrue;
  1145. }
  1146. /*
  1147. ==============
  1148. BotAIShutdownClient
  1149. ==============
  1150. */
  1151. int BotAIShutdownClient(int client, qboolean restart) {
  1152. bot_state_t *bs;
  1153. bs = botstates[client];
  1154. if (!bs || !bs->inuse) {
  1155. //BotAI_Print(PRT_ERROR, "BotAIShutdownClient: client %d already shutdown\n", client);
  1156. return qfalse;
  1157. }
  1158. if (restart) {
  1159. BotWriteSessionData(bs);
  1160. }
  1161. if (BotChat_ExitGame(bs)) {
  1162. trap_BotEnterChat(bs->cs, bs->client, CHAT_ALL);
  1163. }
  1164. trap_BotFreeMoveState(bs->ms);
  1165. //free the goal state`
  1166. trap_BotFreeGoalState(bs->gs);
  1167. //free the chat file
  1168. trap_BotFreeChatState(bs->cs);
  1169. //free the weapon weights
  1170. trap_BotFreeWeaponState(bs->ws);
  1171. //free the bot character
  1172. trap_BotFreeCharacter(bs->character);
  1173. //
  1174. BotFreeWaypoints(bs->checkpoints);
  1175. BotFreeWaypoints(bs->patrolpoints);
  1176. //clear activate goal stack
  1177. BotClearActivateGoalStack(bs);
  1178. //clear the bot state
  1179. memset(bs, 0, sizeof(bot_state_t));
  1180. //set the inuse flag to qfalse
  1181. bs->inuse = qfalse;
  1182. //there's one bot less
  1183. numbots--;
  1184. //everything went ok
  1185. return qtrue;
  1186. }
  1187. /*
  1188. ==============
  1189. BotResetState
  1190. called when a bot enters the intermission or observer mode and
  1191. when the level is changed
  1192. ==============
  1193. */
  1194. void BotResetState(bot_state_t *bs) {
  1195. int client, entitynum, inuse;
  1196. int movestate, goalstate, chatstate, weaponstate;
  1197. bot_settings_t settings;
  1198. int character;
  1199. playerState_t ps; //current player state
  1200. float entergame_time;
  1201. //save some things that should not be reset here
  1202. memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
  1203. memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
  1204. inuse = bs->inuse;
  1205. client = bs->client;
  1206. entitynum = bs->entitynum;
  1207. character = bs->character;
  1208. movestate = bs->ms;
  1209. goalstate = bs->gs;
  1210. chatstate = bs->cs;
  1211. weaponstate = bs->ws;
  1212. entergame_time = bs->entergame_time;
  1213. //free checkpoints and patrol points
  1214. BotFreeWaypoints(bs->checkpoints);
  1215. BotFreeWaypoints(bs->patrolpoints);
  1216. //reset the whole state
  1217. memset(bs, 0, sizeof(bot_state_t));
  1218. //copy back some state stuff that should not be reset
  1219. bs->ms = movestate;
  1220. bs->gs = goalstate;
  1221. bs->cs = chatstate;
  1222. bs->ws = weaponstate;
  1223. memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
  1224. memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
  1225. bs->inuse = inuse;
  1226. bs->client = client;
  1227. bs->entitynum = entitynum;
  1228. bs->character = character;
  1229. bs->entergame_time = entergame_time;
  1230. //reset several states
  1231. if (bs->ms) trap_BotResetMoveState(bs->ms);
  1232. if (bs->gs) trap_BotResetGoalState(bs->gs);
  1233. if (bs->ws) trap_BotResetWeaponState(bs->ws);
  1234. if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
  1235. if (bs->ms) trap_BotResetAvoidReach(bs->ms);
  1236. }
  1237. /*
  1238. ==============
  1239. BotAILoadMap
  1240. ==============
  1241. */
  1242. int BotAILoadMap( int restart ) {
  1243. int i;
  1244. vmCvar_t mapname;
  1245. if (!restart) {
  1246. trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
  1247. trap_BotLibLoadMap( mapname.string );
  1248. }
  1249. for (i = 0; i < MAX_CLIENTS; i++) {
  1250. if (botstates[i] && botstates[i]->inuse) {
  1251. BotResetState( botstates[i] );
  1252. botstates[i]->setupcount = 4;
  1253. }
  1254. }
  1255. BotSetupDeathmatchAI();
  1256. return qtrue;
  1257. }
  1258. #ifdef MISSIONPACK
  1259. void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace );
  1260. #endif
  1261. /*
  1262. ==================
  1263. BotAIStartFrame
  1264. ==================
  1265. */
  1266. int BotAIStartFrame(int time) {
  1267. int i;
  1268. gentity_t *ent;
  1269. bot_entitystate_t state;
  1270. int elapsed_time, thinktime;
  1271. static int local_time;
  1272. static int botlib_residual;
  1273. static int lastbotthink_time;
  1274. G_CheckBotSpawn();
  1275. trap_Cvar_Update(&bot_rocketjump);
  1276. trap_Cvar_Update(&bot_grapple);
  1277. trap_Cvar_Update(&bot_fastchat);
  1278. trap_Cvar_Update(&bot_nochat);
  1279. trap_Cvar_Update(&bot_testrchat);
  1280. trap_Cvar_Update(&bot_thinktime);
  1281. trap_Cvar_Update(&bot_memorydump);
  1282. trap_Cvar_Update(&bot_saveroutingcache);
  1283. trap_Cvar_Update(&bot_pause);
  1284. trap_Cvar_Update(&bot_report);
  1285. if (bot_report.integer) {
  1286. // BotTeamplayReport();
  1287. // trap_Cvar_Set("bot_report", "0");
  1288. BotUpdateInfoConfigStrings();
  1289. }
  1290. if (bot_pause.integer) {
  1291. // execute bot user commands every frame
  1292. for( i = 0; i < MAX_CLIENTS; i++ ) {
  1293. if( !botstates[i] || !botstates[i]->inuse ) {
  1294. continue;
  1295. }
  1296. if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
  1297. continue;
  1298. }
  1299. botstates[i]->lastucmd.forwardmove = 0;
  1300. botstates[i]->lastucmd.rightmove = 0;
  1301. botstates[i]->lastucmd.upmove = 0;
  1302. botstates[i]->lastucmd.buttons = 0;
  1303. botstates[i]->lastucmd.serverTime = time;
  1304. trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
  1305. }
  1306. return qtrue;
  1307. }
  1308. if (bot_memorydump.integer) {
  1309. trap_BotLibVarSet("memorydump", "1");
  1310. trap_Cvar_Set("bot_memorydump", "0");
  1311. }
  1312. if (bot_saveroutingcache.integer) {
  1313. trap_BotLibVarSet("saveroutingcache", "1");
  1314. trap_Cvar_Set("bot_saveroutingcache", "0");
  1315. }
  1316. //check if bot interbreeding is activated
  1317. BotInterbreeding();
  1318. //cap the bot think time
  1319. if (bot_thinktime.integer > 200) {
  1320. trap_Cvar_Set("bot_thinktime", "200");
  1321. }
  1322. //if the bot think time changed we should reschedule the bots
  1323. if (bot_thinktime.integer != lastbotthink_time) {
  1324. lastbotthink_time = bot_thinktime.integer;
  1325. BotScheduleBotThink();
  1326. }
  1327. elapsed_time = time - local_time;
  1328. local_time = time;
  1329. botlib_residual += elapsed_time;
  1330. if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time;
  1331. else thinktime = bot_thinktime.integer;
  1332. // update the bot library
  1333. if ( botlib_residual >= thinktime ) {
  1334. botlib_residual -= thinktime;
  1335. trap_BotLibStartFrame((float) time / 1000);
  1336. if (!trap_AAS_Initialized()) return qfalse;
  1337. //update entities in the botlib
  1338. for (i = 0; i < MAX_GENTITIES; i++) {
  1339. ent = &g_entities[i];
  1340. if (!ent->inuse) {
  1341. trap_BotLibUpdateEntity(i, NULL);
  1342. continue;
  1343. }
  1344. if (!ent->r.linked) {
  1345. trap_BotLibUpdateEntity(i, NULL);
  1346. continue;
  1347. }
  1348. if (ent->r.svFlags & SVF_NOCLIENT) {
  1349. trap_BotLibUpdateEntity(i, NULL);
  1350. continue;
  1351. }
  1352. // do not update missiles
  1353. if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) {
  1354. trap_BotLibUpdateEntity(i, NULL);
  1355. continue;
  1356. }
  1357. // do not update event only entities
  1358. if (ent->s.eType > ET_EVENTS) {
  1359. trap_BotLibUpdateEntity(i, NULL);
  1360. continue;
  1361. }
  1362. #ifdef MISSIONPACK
  1363. // never link prox mine triggers
  1364. if (ent->r.contents == CONTENTS_TRIGGER) {
  1365. if (ent->touch == ProximityMine_Trigger) {
  1366. trap_BotLibUpdateEntity(i, NULL);
  1367. continue;
  1368. }
  1369. }
  1370. #endif
  1371. //
  1372. memset(&state, 0, sizeof(bot_entitystate_t));
  1373. //
  1374. VectorCopy(ent->r.currentOrigin, state.origin);
  1375. if (i < MAX_CLIENTS) {
  1376. VectorCopy(ent->s.apos.trBase, state.angles);
  1377. } else {
  1378. VectorCopy(ent->r.currentAngles, state.angles);
  1379. }
  1380. VectorCopy(ent->s.origin2, state.old_origin);
  1381. VectorCopy(ent->r.mins, state.mins);
  1382. VectorCopy(ent->r.maxs, state.maxs);
  1383. state.type = ent->s.eType;
  1384. state.flags = ent->s.eFlags;
  1385. if (ent->r.bmodel) state.solid = SOLID_BSP;
  1386. else state.solid = SOLID_BBOX;
  1387. state.groundent = ent->s.groundEntityNum;
  1388. state.modelindex = ent->s.modelindex;
  1389. state.modelindex2 = ent->s.modelindex2;
  1390. state.frame = ent->s.frame;
  1391. state.event = ent->s.event;
  1392. state.eventParm = ent->s.eventParm;
  1393. state.powerups = ent->s.powerups;
  1394. state.legsAnim = ent->s.legsAnim;
  1395. state.torsoAnim = ent->s.torsoAnim;
  1396. state.weapon = ent->s.weapon;
  1397. //
  1398. trap_BotLibUpdateEntity(i, &state);
  1399. }
  1400. BotAIRegularUpdate();
  1401. }
  1402. floattime = trap_AAS_Time();
  1403. // execute scheduled bot AI
  1404. for( i = 0; i < MAX_CLIENTS; i++ ) {
  1405. if( !botstates[i] || !botstates[i]->inuse ) {
  1406. continue;
  1407. }
  1408. //
  1409. botstates[i]->botthink_residual += elapsed_time;
  1410. //
  1411. if ( botstates[i]->botthink_residual >= thinktime ) {
  1412. botstates[i]->botthink_residual -= thinktime;
  1413. if (!trap_AAS_Initialized()) return qfalse;
  1414. if (g_entities[i].client->pers.connected == CON_CONNECTED) {
  1415. BotAI(i, (float) thinktime / 1000);
  1416. }
  1417. }
  1418. }
  1419. // execute bot user commands every frame
  1420. for( i = 0; i < MAX_CLIENTS; i++ ) {
  1421. if( !botstates[i] || !botstates[i]->inuse ) {
  1422. continue;
  1423. }
  1424. if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
  1425. continue;
  1426. }
  1427. BotUpdateInput(botstates[i], time, elapsed_time);
  1428. trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
  1429. }
  1430. return qtrue;
  1431. }
  1432. /*
  1433. ==============
  1434. BotInitLibrary
  1435. ==============
  1436. */
  1437. int BotInitLibrary(void) {
  1438. char buf[144];
  1439. //set the maxclients and maxentities library variables before calling BotSetupLibrary
  1440. trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf));
  1441. if (!strlen(buf)) strcpy(buf, "8");
  1442. trap_BotLibVarSet("maxclients", buf);
  1443. Com_sprintf(buf, sizeof(buf), "%d", MAX_GENTITIES);
  1444. trap_BotLibVarSet("maxentities", buf);
  1445. //bsp checksum
  1446. trap_Cvar_VariableStringBuffer("sv_mapChecksum", buf, sizeof(buf));
  1447. if (strlen(buf)) trap_BotLibVarSet("sv_mapChecksum", buf);
  1448. //maximum number of aas links
  1449. trap_Cvar_VariableStringBuffer("max_aaslinks", buf, sizeof(buf));
  1450. if (strlen(buf)) trap_BotLibVarSet("max_aaslinks", buf);
  1451. //maximum number of items in a level
  1452. trap_Cvar_VariableStringBuffer("max_levelitems", buf, sizeof(buf));
  1453. if (strlen(buf)) trap_BotLibVarSet("max_levelitems", buf);
  1454. //game type
  1455. trap_Cvar_VariableStringBuffer("g_gametype", buf, sizeof(buf));
  1456. if (!strlen(buf)) strcpy(buf, "0");
  1457. trap_BotLibVarSet("g_gametype", buf);
  1458. //bot developer mode and log file
  1459. trap_BotLibVarSet("bot_developer", bot_developer.string);
  1460. trap_BotLibVarSet("log", buf);
  1461. //no chatting
  1462. trap_Cvar_VariableStringBuffer("bot_nochat", buf, sizeof(buf));
  1463. if (strlen(buf)) trap_BotLibVarSet("nochat", "0");
  1464. //visualize jump pads
  1465. trap_Cvar_VariableStringBuffer("bot_visualizejumppads", buf, sizeof(buf));
  1466. if (strlen(buf)) trap_BotLibVarSet("bot_visualizejumppads", buf);
  1467. //forced clustering calculations
  1468. trap_Cvar_VariableStringBuffer("bot_forceclustering", buf, sizeof(buf));
  1469. if (strlen(buf)) trap_BotLibVarSet("forceclustering", buf);
  1470. //forced reachability calculations
  1471. trap_Cvar_VariableStringBuffer("bot_forcereachability", buf, sizeof(buf));
  1472. if (strlen(buf)) trap_BotLibVarSet("forcereachability", buf);
  1473. //force writing of AAS to file
  1474. trap_Cvar_VariableStringBuffer("bot_forcewrite", buf, sizeof(buf));
  1475. if (strlen(buf)) trap_BotLibVarSet("forcewrite", buf);
  1476. //no AAS optimization
  1477. trap_Cvar_VariableStringBuffer("bot_aasoptimize", buf, sizeof(buf));
  1478. if (strlen(buf)) trap_BotLibVarSet("aasoptimize", buf);
  1479. //
  1480. trap_Cvar_VariableStringBuffer("bot_saveroutingcache", buf, sizeof(buf));
  1481. if (strlen(buf)) trap_BotLibVarSet("saveroutingcache", buf);
  1482. //reload instead of cache bot character files
  1483. trap_Cvar_VariableStringBuffer("bot_reloadcharacters", buf, sizeof(buf));
  1484. if (!strlen(buf)) strcpy(buf, "0");
  1485. trap_BotLibVarSet("bot_reloadcharacters", buf);
  1486. //base directory
  1487. trap_Cvar_VariableStringBuffer("fs_basepath", buf, sizeof(buf));
  1488. if (strlen(buf)) trap_BotLibVarSet("basedir", buf);
  1489. //game directory
  1490. trap_Cvar_VariableStringBuffer("fs_game", buf, sizeof(buf));
  1491. if (strlen(buf)) trap_BotLibVarSet("gamedir", buf);
  1492. //cd directory
  1493. trap_Cvar_VariableStringBuffer("fs_cdpath", buf, sizeof(buf));
  1494. if (strlen(buf)) trap_BotLibVarSet("cddir", buf);
  1495. //
  1496. #ifdef MISSIONPACK
  1497. trap_BotLibDefine("MISSIONPACK");
  1498. #endif
  1499. //setup the bot library
  1500. return trap_BotLibSetup();
  1501. }
  1502. /*
  1503. ==============
  1504. BotAISetup
  1505. ==============
  1506. */
  1507. int BotAISetup( int restart ) {
  1508. int errnum;
  1509. trap_Cvar_Register(&bot_thinktime, "bot_thinktime", "100", CVAR_CHEAT);
  1510. trap_Cvar_Register(&bot_memorydump, "bot_memorydump", "0", CVAR_CHEAT);
  1511. trap_Cvar_Register(&bot_saveroutingcache, "bot_saveroutingcache", "0", CVAR_CHEAT);
  1512. trap_Cvar_Register(&bot_pause, "bot_pause", "0", CVAR_CHEAT);
  1513. trap_Cvar_Register(&bot_report, "bot_report", "0", CVAR_CHEAT);
  1514. trap_Cvar_Register(&bot_testsolid, "bot_testsolid", "0", CVAR_CHEAT);
  1515. trap_Cvar_Register(&bot_testclusters, "bot_testclusters", "0", CVAR_CHEAT);
  1516. trap_Cvar_Register(&bot_developer, "bot_developer", "0", CVAR_CHEAT);
  1517. trap_Cvar_Register(&bot_interbreedchar, "bot_interbreedchar", "", 0);
  1518. trap_Cvar_Register(&bot_interbreedbots, "bot_interbreedbots", "10", 0);
  1519. trap_Cvar_Register(&bot_interbreedcycle, "bot_interbreedcycle", "20", 0);
  1520. trap_Cvar_Register(&bot_interbreedwrite, "bot_interbreedwrite", "", 0);
  1521. //if the game is restarted for a tournament
  1522. if (restart) {
  1523. return qtrue;
  1524. }
  1525. //initialize the bot states
  1526. memset( botstates, 0, sizeof(botstates) );
  1527. errnum = BotInitLibrary();
  1528. if (errnum != BLERR_NOERROR) return qfalse;
  1529. return qtrue;
  1530. }
  1531. /*
  1532. ==============
  1533. BotAIShutdown
  1534. ==============
  1535. */
  1536. int BotAIShutdown( int restart ) {
  1537. int i;
  1538. //if the game is restarted for a tournament
  1539. if ( restart ) {
  1540. //shutdown all the bots in the botlib
  1541. for (i = 0; i < MAX_CLIENTS; i++) {
  1542. if (botstates[i] && botstates[i]->inuse) {
  1543. BotAIShutdownClient(botstates[i]->client, restart);
  1544. }
  1545. }
  1546. //don't shutdown the bot library
  1547. }
  1548. else {
  1549. trap_BotLibShutdown();
  1550. }
  1551. return qtrue;
  1552. }