ai_vcmd.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  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_vcmd.c
  21. *
  22. * desc: Quake3 bot AI
  23. *
  24. * $Archive: /MissionPack/code/game/ai_vcmd.c $
  25. *
  26. *****************************************************************************/
  27. #include "g_local.h"
  28. #include "botlib.h"
  29. #include "be_aas.h"
  30. #include "be_ea.h"
  31. #include "be_ai_char.h"
  32. #include "be_ai_chat.h"
  33. #include "be_ai_gen.h"
  34. #include "be_ai_goal.h"
  35. #include "be_ai_move.h"
  36. #include "be_ai_weap.h"
  37. //
  38. #include "ai_main.h"
  39. #include "ai_dmq3.h"
  40. #include "ai_chat.h"
  41. #include "ai_cmd.h"
  42. #include "ai_dmnet.h"
  43. #include "ai_team.h"
  44. #include "ai_vcmd.h"
  45. //
  46. #include "chars.h" //characteristics
  47. #include "inv.h" //indexes into the inventory
  48. #include "syn.h" //synonyms
  49. #include "match.h" //string matching types and vars
  50. // for the voice chats
  51. #include "../../ui/menudef.h"
  52. typedef struct voiceCommand_s
  53. {
  54. char *cmd;
  55. void (*func)(bot_state_t *bs, int client, int mode);
  56. } voiceCommand_t;
  57. /*
  58. ==================
  59. BotVoiceChat_GetFlag
  60. ==================
  61. */
  62. void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) {
  63. //
  64. if (gametype == GT_CTF) {
  65. if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
  66. return;
  67. }
  68. #ifdef MISSIONPACK
  69. else if (gametype == GT_1FCTF) {
  70. if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
  71. return;
  72. }
  73. #endif
  74. else {
  75. return;
  76. }
  77. //
  78. bs->decisionmaker = client;
  79. bs->ordered = qtrue;
  80. bs->order_time = FloatTime();
  81. //set the time to send a message to the team mates
  82. bs->teammessage_time = FloatTime() + 2 * random();
  83. //set the ltg type
  84. bs->ltgtype = LTG_GETFLAG;
  85. //set the team goal time
  86. bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
  87. // get an alternate route in ctf
  88. if (gametype == GT_CTF) {
  89. //get an alternative route goal towards the enemy base
  90. BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
  91. }
  92. //
  93. BotSetTeamStatus(bs);
  94. // remember last ordered task
  95. BotRememberLastOrderedTask(bs);
  96. #ifdef DEBUG
  97. BotPrintTeamGoal(bs);
  98. #endif //DEBUG
  99. }
  100. /*
  101. ==================
  102. BotVoiceChat_Offense
  103. ==================
  104. */
  105. void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) {
  106. if ( gametype == GT_CTF
  107. #ifdef MISSIONPACK
  108. || gametype == GT_1FCTF
  109. #endif
  110. ) {
  111. BotVoiceChat_GetFlag(bs, client, mode);
  112. return;
  113. }
  114. #ifdef MISSIONPACK
  115. if (gametype == GT_HARVESTER) {
  116. //
  117. bs->decisionmaker = client;
  118. bs->ordered = qtrue;
  119. bs->order_time = FloatTime();
  120. //set the time to send a message to the team mates
  121. bs->teammessage_time = FloatTime() + 2 * random();
  122. //set the ltg type
  123. bs->ltgtype = LTG_HARVEST;
  124. //set the team goal time
  125. bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
  126. bs->harvestaway_time = 0;
  127. //
  128. BotSetTeamStatus(bs);
  129. // remember last ordered task
  130. BotRememberLastOrderedTask(bs);
  131. }
  132. else
  133. #endif
  134. {
  135. //
  136. bs->decisionmaker = client;
  137. bs->ordered = qtrue;
  138. bs->order_time = FloatTime();
  139. //set the time to send a message to the team mates
  140. bs->teammessage_time = FloatTime() + 2 * random();
  141. //set the ltg type
  142. bs->ltgtype = LTG_ATTACKENEMYBASE;
  143. //set the team goal time
  144. bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
  145. bs->attackaway_time = 0;
  146. //
  147. BotSetTeamStatus(bs);
  148. // remember last ordered task
  149. BotRememberLastOrderedTask(bs);
  150. }
  151. #ifdef DEBUG
  152. BotPrintTeamGoal(bs);
  153. #endif //DEBUG
  154. }
  155. /*
  156. ==================
  157. BotVoiceChat_Defend
  158. ==================
  159. */
  160. void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) {
  161. #ifdef MISSIONPACK
  162. if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) {
  163. //
  164. switch(BotTeam(bs)) {
  165. case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break;
  166. case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break;
  167. default: return;
  168. }
  169. }
  170. else
  171. #endif
  172. if (gametype == GT_CTF
  173. #ifdef MISSIONPACK
  174. || gametype == GT_1FCTF
  175. #endif
  176. ) {
  177. //
  178. switch(BotTeam(bs)) {
  179. case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break;
  180. case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break;
  181. default: return;
  182. }
  183. }
  184. else {
  185. return;
  186. }
  187. //
  188. bs->decisionmaker = client;
  189. bs->ordered = qtrue;
  190. bs->order_time = FloatTime();
  191. //set the time to send a message to the team mates
  192. bs->teammessage_time = FloatTime() + 2 * random();
  193. //set the ltg type
  194. bs->ltgtype = LTG_DEFENDKEYAREA;
  195. //get the team goal time
  196. bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
  197. //away from defending
  198. bs->defendaway_time = 0;
  199. //
  200. BotSetTeamStatus(bs);
  201. // remember last ordered task
  202. BotRememberLastOrderedTask(bs);
  203. #ifdef DEBUG
  204. BotPrintTeamGoal(bs);
  205. #endif //DEBUG
  206. }
  207. /*
  208. ==================
  209. BotVoiceChat_DefendFlag
  210. ==================
  211. */
  212. void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) {
  213. BotVoiceChat_Defend(bs, client, mode);
  214. }
  215. /*
  216. ==================
  217. BotVoiceChat_Patrol
  218. ==================
  219. */
  220. void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) {
  221. //
  222. bs->decisionmaker = client;
  223. //
  224. bs->ltgtype = 0;
  225. bs->lead_time = 0;
  226. bs->lastgoal_ltgtype = 0;
  227. //
  228. BotAI_BotInitialChat(bs, "dismissed", NULL);
  229. trap_BotEnterChat(bs->cs, client, CHAT_TELL);
  230. BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL);
  231. //
  232. BotSetTeamStatus(bs);
  233. #ifdef DEBUG
  234. BotPrintTeamGoal(bs);
  235. #endif //DEBUG
  236. }
  237. /*
  238. ==================
  239. BotVoiceChat_Camp
  240. ==================
  241. */
  242. void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) {
  243. int areanum;
  244. aas_entityinfo_t entinfo;
  245. char netname[MAX_NETNAME];
  246. //
  247. bs->teamgoal.entitynum = -1;
  248. BotEntityInfo(client, &entinfo);
  249. //if info is valid (in PVS)
  250. if (entinfo.valid) {
  251. areanum = BotPointAreaNum(entinfo.origin);
  252. if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
  253. //NOTE: just assume the bot knows where the person is
  254. //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {
  255. bs->teamgoal.entitynum = client;
  256. bs->teamgoal.areanum = areanum;
  257. VectorCopy(entinfo.origin, bs->teamgoal.origin);
  258. VectorSet(bs->teamgoal.mins, -8, -8, -8);
  259. VectorSet(bs->teamgoal.maxs, 8, 8, 8);
  260. //}
  261. }
  262. }
  263. //if the other is not visible
  264. if (bs->teamgoal.entitynum < 0) {
  265. BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
  266. trap_BotEnterChat(bs->cs, client, CHAT_TELL);
  267. return;
  268. }
  269. //
  270. bs->decisionmaker = client;
  271. bs->ordered = qtrue;
  272. bs->order_time = FloatTime();
  273. //set the time to send a message to the team mates
  274. bs->teammessage_time = FloatTime() + 2 * random();
  275. //set the ltg type
  276. bs->ltgtype = LTG_CAMPORDER;
  277. //get the team goal time
  278. bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
  279. //the teammate that requested the camping
  280. bs->teammate = client;
  281. //not arrived yet
  282. bs->arrive_time = 0;
  283. //
  284. BotSetTeamStatus(bs);
  285. // remember last ordered task
  286. BotRememberLastOrderedTask(bs);
  287. #ifdef DEBUG
  288. BotPrintTeamGoal(bs);
  289. #endif //DEBUG
  290. }
  291. /*
  292. ==================
  293. BotVoiceChat_FollowMe
  294. ==================
  295. */
  296. void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) {
  297. int areanum;
  298. aas_entityinfo_t entinfo;
  299. char netname[MAX_NETNAME];
  300. bs->teamgoal.entitynum = -1;
  301. BotEntityInfo(client, &entinfo);
  302. //if info is valid (in PVS)
  303. if (entinfo.valid) {
  304. areanum = BotPointAreaNum(entinfo.origin);
  305. if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
  306. bs->teamgoal.entitynum = client;
  307. bs->teamgoal.areanum = areanum;
  308. VectorCopy(entinfo.origin, bs->teamgoal.origin);
  309. VectorSet(bs->teamgoal.mins, -8, -8, -8);
  310. VectorSet(bs->teamgoal.maxs, 8, 8, 8);
  311. }
  312. }
  313. //if the other is not visible
  314. if (bs->teamgoal.entitynum < 0) {
  315. BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
  316. trap_BotEnterChat(bs->cs, client, CHAT_TELL);
  317. return;
  318. }
  319. //
  320. bs->decisionmaker = client;
  321. bs->ordered = qtrue;
  322. bs->order_time = FloatTime();
  323. //the team mate
  324. bs->teammate = client;
  325. //last time the team mate was assumed visible
  326. bs->teammatevisible_time = FloatTime();
  327. //set the time to send a message to the team mates
  328. bs->teammessage_time = FloatTime() + 2 * random();
  329. //get the team goal time
  330. bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
  331. //set the ltg type
  332. bs->ltgtype = LTG_TEAMACCOMPANY;
  333. bs->formation_dist = 3.5 * 32; //3.5 meter
  334. bs->arrive_time = 0;
  335. //
  336. BotSetTeamStatus(bs);
  337. // remember last ordered task
  338. BotRememberLastOrderedTask(bs);
  339. #ifdef DEBUG
  340. BotPrintTeamGoal(bs);
  341. #endif //DEBUG
  342. }
  343. /*
  344. ==================
  345. BotVoiceChat_FollowFlagCarrier
  346. ==================
  347. */
  348. void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) {
  349. int carrier;
  350. carrier = BotTeamFlagCarrier(bs);
  351. if (carrier >= 0)
  352. BotVoiceChat_FollowMe(bs, carrier, mode);
  353. #ifdef DEBUG
  354. BotPrintTeamGoal(bs);
  355. #endif //DEBUG
  356. }
  357. /*
  358. ==================
  359. BotVoiceChat_ReturnFlag
  360. ==================
  361. */
  362. void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) {
  363. //if not in CTF mode
  364. if (
  365. gametype != GT_CTF
  366. #ifdef MISSIONPACK
  367. && gametype != GT_1FCTF
  368. #endif
  369. ) {
  370. return;
  371. }
  372. //
  373. bs->decisionmaker = client;
  374. bs->ordered = qtrue;
  375. bs->order_time = FloatTime();
  376. //set the time to send a message to the team mates
  377. bs->teammessage_time = FloatTime() + 2 * random();
  378. //set the ltg type
  379. bs->ltgtype = LTG_RETURNFLAG;
  380. //set the team goal time
  381. bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
  382. bs->rushbaseaway_time = 0;
  383. BotSetTeamStatus(bs);
  384. #ifdef DEBUG
  385. BotPrintTeamGoal(bs);
  386. #endif //DEBUG
  387. }
  388. /*
  389. ==================
  390. BotVoiceChat_StartLeader
  391. ==================
  392. */
  393. void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) {
  394. ClientName(client, bs->teamleader, sizeof(bs->teamleader));
  395. }
  396. /*
  397. ==================
  398. BotVoiceChat_StopLeader
  399. ==================
  400. */
  401. void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) {
  402. char netname[MAX_MESSAGE_SIZE];
  403. if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
  404. bs->teamleader[0] = '\0';
  405. notleader[client] = qtrue;
  406. }
  407. }
  408. /*
  409. ==================
  410. BotVoiceChat_WhoIsLeader
  411. ==================
  412. */
  413. void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) {
  414. char netname[MAX_MESSAGE_SIZE];
  415. if (!TeamPlayIsOn()) return;
  416. ClientName(bs->client, netname, sizeof(netname));
  417. //if this bot IS the team leader
  418. if (!Q_stricmp(netname, bs->teamleader)) {
  419. BotAI_BotInitialChat(bs, "iamteamleader", NULL);
  420. trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
  421. BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER);
  422. }
  423. }
  424. /*
  425. ==================
  426. BotVoiceChat_WantOnDefense
  427. ==================
  428. */
  429. void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) {
  430. char netname[MAX_NETNAME];
  431. int preference;
  432. preference = BotGetTeamMateTaskPreference(bs, client);
  433. preference &= ~TEAMTP_ATTACKER;
  434. preference |= TEAMTP_DEFENDER;
  435. BotSetTeamMateTaskPreference(bs, client, preference);
  436. //
  437. EasyClientName(client, netname, sizeof(netname));
  438. BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
  439. trap_BotEnterChat(bs->cs, client, CHAT_TELL);
  440. BotVoiceChatOnly(bs, client, VOICECHAT_YES);
  441. trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
  442. }
  443. /*
  444. ==================
  445. BotVoiceChat_WantOnOffense
  446. ==================
  447. */
  448. void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) {
  449. char netname[MAX_NETNAME];
  450. int preference;
  451. preference = BotGetTeamMateTaskPreference(bs, client);
  452. preference &= ~TEAMTP_DEFENDER;
  453. preference |= TEAMTP_ATTACKER;
  454. BotSetTeamMateTaskPreference(bs, client, preference);
  455. //
  456. EasyClientName(client, netname, sizeof(netname));
  457. BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
  458. trap_BotEnterChat(bs->cs, client, CHAT_TELL);
  459. BotVoiceChatOnly(bs, client, VOICECHAT_YES);
  460. trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
  461. }
  462. void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) {
  463. }
  464. voiceCommand_t voiceCommands[] = {
  465. {VOICECHAT_GETFLAG, BotVoiceChat_GetFlag},
  466. {VOICECHAT_OFFENSE, BotVoiceChat_Offense },
  467. {VOICECHAT_DEFEND, BotVoiceChat_Defend },
  468. {VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag },
  469. {VOICECHAT_PATROL, BotVoiceChat_Patrol },
  470. {VOICECHAT_CAMP, BotVoiceChat_Camp },
  471. {VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe },
  472. {VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier },
  473. {VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag },
  474. {VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader },
  475. {VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader },
  476. {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader },
  477. {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense },
  478. {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense },
  479. {NULL, BotVoiceChat_Dummy}
  480. };
  481. int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) {
  482. int i, voiceOnly, clientNum, color;
  483. char *ptr, buf[MAX_MESSAGE_SIZE], *cmd;
  484. if (!TeamPlayIsOn()) {
  485. return qfalse;
  486. }
  487. if ( mode == SAY_ALL ) {
  488. return qfalse; // don't do anything with voice chats to everyone
  489. }
  490. Q_strncpyz(buf, voiceChat, sizeof(buf));
  491. cmd = buf;
  492. for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
  493. while (*cmd && *cmd <= ' ') *cmd++ = '\0';
  494. voiceOnly = atoi(ptr);
  495. for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
  496. while (*cmd && *cmd <= ' ') *cmd++ = '\0';
  497. clientNum = atoi(ptr);
  498. for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
  499. while (*cmd && *cmd <= ' ') *cmd++ = '\0';
  500. color = atoi(ptr);
  501. if (!BotSameTeam(bs, clientNum)) {
  502. return qfalse;
  503. }
  504. for (i = 0; voiceCommands[i].cmd; i++) {
  505. if (!Q_stricmp(cmd, voiceCommands[i].cmd)) {
  506. voiceCommands[i].func(bs, clientNum, mode);
  507. return qtrue;
  508. }
  509. }
  510. return qfalse;
  511. }