00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "g_local.h"
00034 #include "botlib.h"
00035 #include "be_aas.h"
00036 #include "be_ea.h"
00037 #include "be_ai_char.h"
00038 #include "be_ai_chat.h"
00039 #include "be_ai_gen.h"
00040 #include "be_ai_goal.h"
00041 #include "be_ai_move.h"
00042 #include "be_ai_weap.h"
00043
00044 #include "ai_main.h"
00045 #include "ai_dmq3.h"
00046 #include "ai_chat.h"
00047 #include "ai_cmd.h"
00048 #include "ai_dmnet.h"
00049 #include "ai_team.h"
00050
00051 #include "chars.h"
00052 #include "inv.h"
00053 #include "syn.h"
00054 #include "match.h"
00055
00056
00057 #include "../../ui/menudef.h"
00058
00059 int notleader[MAX_CLIENTS];
00060
00061 #ifdef DEBUG
00062
00063
00064
00065
00066
00067 void BotPrintTeamGoal(bot_state_t *bs) {
00068 char netname[MAX_NETNAME];
00069 float t;
00070
00071 ClientName(bs->client, netname, sizeof(netname));
00072 t = bs->teamgoal_time - FloatTime();
00073 switch(bs->ltgtype) {
00074 case LTG_TEAMHELP:
00075 {
00076 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna help a team mate for %1.0f secs\n", netname, t);
00077 break;
00078 }
00079 case LTG_TEAMACCOMPANY:
00080 {
00081 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna accompany a team mate for %1.0f secs\n", netname, t);
00082 break;
00083 }
00084 case LTG_GETFLAG:
00085 {
00086 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get the flag for %1.0f secs\n", netname, t);
00087 break;
00088 }
00089 case LTG_RUSHBASE:
00090 {
00091 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna rush to the base for %1.0f secs\n", netname, t);
00092 break;
00093 }
00094 case LTG_RETURNFLAG:
00095 {
00096 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna try to return the flag for %1.0f secs\n", netname, t);
00097 break;
00098 }
00099 #ifdef MISSIONPACK
00100 case LTG_ATTACKENEMYBASE:
00101 {
00102 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna attack the enemy base for %1.0f secs\n", netname, t);
00103 break;
00104 }
00105 case LTG_HARVEST:
00106 {
00107 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna harvest for %1.0f secs\n", netname, t);
00108 break;
00109 }
00110 #endif
00111 case LTG_DEFENDKEYAREA:
00112 {
00113 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a key area for %1.0f secs\n", netname, t);
00114 break;
00115 }
00116 case LTG_GETITEM:
00117 {
00118 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get an item for %1.0f secs\n", netname, t);
00119 break;
00120 }
00121 case LTG_KILL:
00122 {
00123 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna kill someone for %1.0f secs\n", netname, t);
00124 break;
00125 }
00126 case LTG_CAMP:
00127 case LTG_CAMPORDER:
00128 {
00129 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna camp for %1.0f secs\n", netname, t);
00130 break;
00131 }
00132 case LTG_PATROL:
00133 {
00134 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna patrol for %1.0f secs\n", netname, t);
00135 break;
00136 }
00137 default:
00138 {
00139 if (bs->ctfroam_time > FloatTime()) {
00140 t = bs->ctfroam_time - FloatTime();
00141 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna roam for %1.0f secs\n", netname, t);
00142 }
00143 else {
00144 BotAI_Print(PRT_MESSAGE, "%s: I've got a regular goal\n", netname);
00145 }
00146 }
00147 }
00148 }
00149 #endif //DEBUG
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 int BotGetItemTeamGoal(char *goalname, bot_goal_t *goal) {
00160 int i;
00161
00162 if (!strlen(goalname)) return qfalse;
00163 i = -1;
00164 do {
00165 i = trap_BotGetLevelItemGoal(i, goalname, goal);
00166 if (i > 0) {
00167
00168 if (goal->flags & GFL_DROPPED)
00169 continue;
00170 return qtrue;
00171 }
00172 } while(i > 0);
00173 return qfalse;
00174 }
00175
00176
00177
00178
00179
00180
00181 int BotGetMessageTeamGoal(bot_state_t *bs, char *goalname, bot_goal_t *goal) {
00182 bot_waypoint_t *cp;
00183
00184 if (BotGetItemTeamGoal(goalname, goal)) return qtrue;
00185
00186 cp = BotFindWayPoint(bs->checkpoints, goalname);
00187 if (cp) {
00188 memcpy(goal, &cp->goal, sizeof(bot_goal_t));
00189 return qtrue;
00190 }
00191 return qfalse;
00192 }
00193
00194
00195
00196
00197
00198
00199 float BotGetTime(bot_match_t *match) {
00200 bot_match_t timematch;
00201 char timestring[MAX_MESSAGE_SIZE];
00202 float t;
00203
00204
00205 if (match->subtype & ST_TIME) {
00206
00207 trap_BotMatchVariable(match, TIME, timestring, MAX_MESSAGE_SIZE);
00208
00209 if (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) {
00210 if (timematch.type == MSG_FOREVER) {
00211 t = 99999999.0f;
00212 }
00213 else if (timematch.type == MSG_FORAWHILE) {
00214 t = 10 * 60;
00215 }
00216 else if (timematch.type == MSG_FORALONGTIME) {
00217 t = 30 * 60;
00218 }
00219 else {
00220 trap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE);
00221 if (timematch.type == MSG_MINUTES) t = atof(timestring) * 60;
00222 else if (timematch.type == MSG_SECONDS) t = atof(timestring);
00223 else t = 0;
00224 }
00225
00226 if (t > 0) return FloatTime() + t;
00227 }
00228 }
00229 return 0;
00230 }
00231
00232
00233
00234
00235
00236
00237 int FindClientByName(char *name) {
00238 int i;
00239 char buf[MAX_INFO_STRING];
00240 static int maxclients;
00241
00242 if (!maxclients)
00243 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00244 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00245 ClientName(i, buf, sizeof(buf));
00246 if (!Q_stricmp(buf, name)) return i;
00247 }
00248 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00249 ClientName(i, buf, sizeof(buf));
00250 if (stristr(buf, name)) return i;
00251 }
00252 return -1;
00253 }
00254
00255
00256
00257
00258
00259
00260 int FindEnemyByName(bot_state_t *bs, char *name) {
00261 int i;
00262 char buf[MAX_INFO_STRING];
00263 static int maxclients;
00264
00265 if (!maxclients)
00266 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00267 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00268 if (BotSameTeam(bs, i)) continue;
00269 ClientName(i, buf, sizeof(buf));
00270 if (!Q_stricmp(buf, name)) return i;
00271 }
00272 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00273 if (BotSameTeam(bs, i)) continue;
00274 ClientName(i, buf, sizeof(buf));
00275 if (stristr(buf, name)) return i;
00276 }
00277 return -1;
00278 }
00279
00280
00281
00282
00283
00284
00285 int NumPlayersOnSameTeam(bot_state_t *bs) {
00286 int i, num;
00287 char buf[MAX_INFO_STRING];
00288 static int maxclients;
00289
00290 if (!maxclients)
00291 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00292
00293 num = 0;
00294 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00295 trap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING);
00296 if (strlen(buf)) {
00297 if (BotSameTeam(bs, i+1)) num++;
00298 }
00299 }
00300 return num;
00301 }
00302
00303
00304
00305
00306
00307
00308 int BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) {
00309 char keyarea[MAX_MESSAGE_SIZE];
00310 int patrolflags;
00311 bot_waypoint_t *wp, *newwp, *newpatrolpoints;
00312 bot_match_t keyareamatch;
00313 bot_goal_t goal;
00314
00315 newpatrolpoints = NULL;
00316 patrolflags = 0;
00317
00318 trap_BotMatchVariable(match, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
00319
00320 while(1) {
00321 if (!trap_BotFindMatch(keyarea, &keyareamatch, MTCONTEXT_PATROLKEYAREA)) {
00322 trap_EA_SayTeam(bs->client, "what do you say?");
00323 BotFreeWaypoints(newpatrolpoints);
00324 bs->patrolpoints = NULL;
00325 return qfalse;
00326 }
00327 trap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
00328 if (!BotGetMessageTeamGoal(bs, keyarea, &goal)) {
00329
00330
00331 BotFreeWaypoints(newpatrolpoints);
00332 bs->patrolpoints = NULL;
00333 return qfalse;
00334 }
00335
00336 newwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum);
00337 if (!newwp)
00338 break;
00339
00340 newwp->next = NULL;
00341 for (wp = newpatrolpoints; wp && wp->next; wp = wp->next);
00342 if (!wp) {
00343 newpatrolpoints = newwp;
00344 newwp->prev = NULL;
00345 }
00346 else {
00347 wp->next = newwp;
00348 newwp->prev = wp;
00349 }
00350
00351 if (keyareamatch.subtype & ST_BACK) {
00352 patrolflags = PATROL_LOOP;
00353 break;
00354 }
00355 else if (keyareamatch.subtype & ST_REVERSE) {
00356 patrolflags = PATROL_REVERSE;
00357 break;
00358 }
00359 else if (keyareamatch.subtype & ST_MORE) {
00360 trap_BotMatchVariable(&keyareamatch, MORE, keyarea, MAX_MESSAGE_SIZE);
00361 }
00362 else {
00363 break;
00364 }
00365 }
00366
00367 if (!newpatrolpoints || !newpatrolpoints->next) {
00368 trap_EA_SayTeam(bs->client, "I need more key points to patrol\n");
00369 BotFreeWaypoints(newpatrolpoints);
00370 newpatrolpoints = NULL;
00371 return qfalse;
00372 }
00373
00374 BotFreeWaypoints(bs->patrolpoints);
00375 bs->patrolpoints = newpatrolpoints;
00376
00377 bs->curpatrolpoint = bs->patrolpoints;
00378 bs->patrolflags = patrolflags;
00379
00380 return qtrue;
00381 }
00382
00383
00384
00385
00386
00387
00388 int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) {
00389 char addressedto[MAX_MESSAGE_SIZE];
00390 char netname[MAX_MESSAGE_SIZE];
00391 char name[MAX_MESSAGE_SIZE];
00392 char botname[128];
00393 int client;
00394 bot_match_t addresseematch;
00395
00396 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00397 client = ClientOnSameTeamFromName(bs, netname);
00398 if (client < 0) return qfalse;
00399
00400 if (match->subtype & ST_ADDRESSED) {
00401 trap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto));
00402
00403 ClientName(bs->client, botname, 128);
00404
00405 while(trap_BotFindMatch(addressedto, &addresseematch, MTCONTEXT_ADDRESSEE)) {
00406 if (addresseematch.type == MSG_EVERYONE) {
00407 return qtrue;
00408 }
00409 else if (addresseematch.type == MSG_MULTIPLENAMES) {
00410 trap_BotMatchVariable(&addresseematch, TEAMMATE, name, sizeof(name));
00411 if (strlen(name)) {
00412 if (stristr(botname, name)) return qtrue;
00413 if (stristr(bs->subteam, name)) return qtrue;
00414 }
00415 trap_BotMatchVariable(&addresseematch, MORE, addressedto, MAX_MESSAGE_SIZE);
00416 }
00417 else {
00418 trap_BotMatchVariable(&addresseematch, TEAMMATE, name, MAX_MESSAGE_SIZE);
00419 if (strlen(name)) {
00420 if (stristr(botname, name)) return qtrue;
00421 if (stristr(bs->subteam, name)) return qtrue;
00422 }
00423 break;
00424 }
00425 }
00426
00427
00428 return qfalse;
00429 }
00430 else {
00431 bot_match_t tellmatch;
00432
00433 tellmatch.type = 0;
00434
00435 if (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) ||
00436 tellmatch.type != MSG_CHATTELL) {
00437
00438 if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse;
00439 }
00440 }
00441 return qtrue;
00442 }
00443
00444
00445
00446
00447
00448
00449 int BotGPSToPosition(char *buf, vec3_t position) {
00450 int i, j = 0;
00451 int num, sign;
00452
00453 for (i = 0; i < 3; i++) {
00454 num = 0;
00455 while(buf[j] == ' ') j++;
00456 if (buf[j] == '-') {
00457 j++;
00458 sign = -1;
00459 }
00460 else {
00461 sign = 1;
00462 }
00463 while (buf[j]) {
00464 if (buf[j] >= '0' && buf[j] <= '9') {
00465 num = num * 10 + buf[j] - '0';
00466 j++;
00467 }
00468 else {
00469 j++;
00470 break;
00471 }
00472 }
00473 BotAI_Print(PRT_MESSAGE, "%d\n", sign * num);
00474 position[i] = (float) sign * num;
00475 }
00476 return qtrue;
00477 }
00478
00479
00480
00481
00482
00483
00484 void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) {
00485 int client, other, areanum;
00486 char teammate[MAX_MESSAGE_SIZE];
00487 char netname[MAX_MESSAGE_SIZE];
00488 char itemname[MAX_MESSAGE_SIZE];
00489 bot_match_t teammatematch;
00490 aas_entityinfo_t entinfo;
00491
00492 if (!TeamPlayIsOn()) return;
00493
00494 if (!BotAddressedToBot(bs, match)) return;
00495
00496 trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
00497
00498 if (trap_BotFindMatch(teammate, &teammatematch, MTCONTEXT_TEAMMATE) &&
00499
00500 teammatematch.type == MSG_ME) {
00501
00502 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00503 client = ClientFromName(netname);
00504 other = qfalse;
00505 }
00506 else {
00507
00508 client = FindClientByName(teammate);
00509
00510 if (client == bs->client) {
00511 other = qfalse;
00512 }
00513 else if (!BotSameTeam(bs, client)) {
00514
00515 return;
00516 }
00517 else {
00518 other = qtrue;
00519 }
00520 }
00521
00522 if (client < 0) {
00523 if (other) BotAI_BotInitialChat(bs, "whois", teammate, NULL);
00524 else BotAI_BotInitialChat(bs, "whois", netname, NULL);
00525 client = ClientFromName(netname);
00526 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
00527 return;
00528 }
00529
00530 if (client == bs->client) {
00531 return;
00532 }
00533
00534 bs->teamgoal.entitynum = -1;
00535 BotEntityInfo(client, &entinfo);
00536
00537 if (entinfo.valid) {
00538 areanum = BotPointAreaNum(entinfo.origin);
00539 if (areanum) {
00540 bs->teamgoal.entitynum = client;
00541 bs->teamgoal.areanum = areanum;
00542 VectorCopy(entinfo.origin, bs->teamgoal.origin);
00543 VectorSet(bs->teamgoal.mins, -8, -8, -8);
00544 VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00545 }
00546 }
00547
00548 if (bs->teamgoal.entitynum < 0) {
00549
00550 if (match->subtype & ST_NEARITEM) {
00551
00552 trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
00553
00554 if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00555
00556
00557 return;
00558 }
00559 }
00560 }
00561
00562 if (bs->teamgoal.entitynum < 0) {
00563 if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
00564 else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
00565 client = ClientFromName(netname);
00566 trap_BotEnterChat(bs->cs, client, CHAT_TEAM);
00567 return;
00568 }
00569
00570 bs->teammate = client;
00571
00572 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00573
00574 client = ClientFromName(netname);
00575
00576 bs->decisionmaker = client;
00577 bs->ordered = qtrue;
00578 bs->order_time = FloatTime();
00579
00580 bs->teammatevisible_time = FloatTime();
00581
00582 bs->teammessage_time = FloatTime() + 2 * random();
00583
00584 bs->teamgoal_time = BotGetTime(match);
00585
00586 if (match->type == MSG_HELP) {
00587 bs->ltgtype = LTG_TEAMHELP;
00588 if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME;
00589 }
00590 else {
00591 bs->ltgtype = LTG_TEAMACCOMPANY;
00592 if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
00593 bs->formation_dist = 3.5 * 32;
00594 bs->arrive_time = 0;
00595
00596 BotSetTeamStatus(bs);
00597
00598 BotRememberLastOrderedTask(bs);
00599 }
00600 #ifdef DEBUG
00601 BotPrintTeamGoal(bs);
00602 #endif //DEBUG
00603 }
00604
00605
00606
00607
00608
00609
00610 void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) {
00611 char itemname[MAX_MESSAGE_SIZE];
00612 char netname[MAX_MESSAGE_SIZE];
00613 int client;
00614
00615 if (!TeamPlayIsOn()) return;
00616
00617 if (!BotAddressedToBot(bs, match)) return;
00618
00619 trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
00620
00621 if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00622
00623
00624 return;
00625 }
00626
00627 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00628
00629 client = ClientFromName(netname);
00630
00631 bs->decisionmaker = client;
00632 bs->ordered = qtrue;
00633 bs->order_time = FloatTime();
00634
00635 bs->teammessage_time = FloatTime() + 2 * random();
00636
00637 bs->ltgtype = LTG_DEFENDKEYAREA;
00638
00639 bs->teamgoal_time = BotGetTime(match);
00640
00641 if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
00642
00643 bs->defendaway_time = 0;
00644
00645 BotSetTeamStatus(bs);
00646
00647 BotRememberLastOrderedTask(bs);
00648 #ifdef DEBUG
00649 BotPrintTeamGoal(bs);
00650 #endif //DEBUG
00651 }
00652
00653
00654
00655
00656
00657
00658 void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) {
00659 char itemname[MAX_MESSAGE_SIZE];
00660 char netname[MAX_MESSAGE_SIZE];
00661 int client;
00662
00663 if (!TeamPlayIsOn()) return;
00664
00665 if (!BotAddressedToBot(bs, match)) return;
00666
00667 trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
00668
00669 if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00670
00671
00672 return;
00673 }
00674 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00675 client = ClientOnSameTeamFromName(bs, netname);
00676
00677 bs->decisionmaker = client;
00678 bs->ordered = qtrue;
00679 bs->order_time = FloatTime();
00680
00681 bs->teammessage_time = FloatTime() + 2 * random();
00682
00683 bs->ltgtype = LTG_GETITEM;
00684
00685 bs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME;
00686
00687 BotSetTeamStatus(bs);
00688 #ifdef DEBUG
00689 BotPrintTeamGoal(bs);
00690 #endif //DEBUG
00691 }
00692
00693
00694
00695
00696
00697
00698 void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) {
00699 int client, areanum;
00700 char netname[MAX_MESSAGE_SIZE];
00701 char itemname[MAX_MESSAGE_SIZE];
00702 aas_entityinfo_t entinfo;
00703
00704 if (!TeamPlayIsOn()) return;
00705
00706 if (!BotAddressedToBot(bs, match)) return;
00707
00708 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00709
00710 client = FindClientByName(netname);
00711
00712 if (client < 0) {
00713 BotAI_BotInitialChat(bs, "whois", netname, NULL);
00714 trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
00715 return;
00716 }
00717
00718 trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
00719
00720 if (match->subtype & ST_THERE) {
00721
00722 bs->teamgoal.entitynum = bs->entitynum;
00723 bs->teamgoal.areanum = bs->areanum;
00724 VectorCopy(bs->origin, bs->teamgoal.origin);
00725 VectorSet(bs->teamgoal.mins, -8, -8, -8);
00726 VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00727 }
00728 else if (match->subtype & ST_HERE) {
00729
00730 if (client == bs->client) return;
00731
00732 bs->teamgoal.entitynum = -1;
00733 BotEntityInfo(client, &entinfo);
00734
00735 if (entinfo.valid) {
00736 areanum = BotPointAreaNum(entinfo.origin);
00737 if (areanum) {
00738
00739
00740 bs->teamgoal.entitynum = client;
00741 bs->teamgoal.areanum = areanum;
00742 VectorCopy(entinfo.origin, bs->teamgoal.origin);
00743 VectorSet(bs->teamgoal.mins, -8, -8, -8);
00744 VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00745
00746 }
00747 }
00748
00749 if (bs->teamgoal.entitynum < 0) {
00750 BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
00751 client = ClientFromName(netname);
00752 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
00753 return;
00754 }
00755 }
00756 else if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00757
00758
00759
00760 return;
00761 }
00762
00763 bs->decisionmaker = client;
00764 bs->ordered = qtrue;
00765 bs->order_time = FloatTime();
00766
00767 bs->teammessage_time = FloatTime() + 2 * random();
00768
00769 bs->ltgtype = LTG_CAMPORDER;
00770
00771 bs->teamgoal_time = BotGetTime(match);
00772
00773 if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
00774
00775 bs->arrive_time = 0;
00776
00777 BotSetTeamStatus(bs);
00778
00779 BotRememberLastOrderedTask(bs);
00780 #ifdef DEBUG
00781 BotPrintTeamGoal(bs);
00782 #endif //DEBUG
00783 }
00784
00785
00786
00787
00788
00789
00790 void BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) {
00791 char netname[MAX_MESSAGE_SIZE];
00792 int client;
00793
00794 if (!TeamPlayIsOn()) return;
00795
00796 if (!BotAddressedToBot(bs, match)) return;
00797
00798 if (!BotGetPatrolWaypoints(bs, match)) return;
00799
00800 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00801
00802 client = FindClientByName(netname);
00803
00804 bs->decisionmaker = client;
00805 bs->ordered = qtrue;
00806 bs->order_time = FloatTime();
00807
00808 bs->teammessage_time = FloatTime() + 2 * random();
00809
00810 bs->ltgtype = LTG_PATROL;
00811
00812 bs->teamgoal_time = BotGetTime(match);
00813
00814 if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME;
00815
00816 BotSetTeamStatus(bs);
00817
00818 BotRememberLastOrderedTask(bs);
00819 #ifdef DEBUG
00820 BotPrintTeamGoal(bs);
00821 #endif //DEBUG
00822 }
00823
00824
00825
00826
00827
00828
00829 void BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) {
00830 char netname[MAX_MESSAGE_SIZE];
00831 int client;
00832
00833 if (gametype == GT_CTF) {
00834 if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
00835 return;
00836 }
00837 #ifdef MISSIONPACK
00838 else if (gametype == GT_1FCTF) {
00839 if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
00840 return;
00841 }
00842 #endif
00843 else {
00844 return;
00845 }
00846
00847 if (!BotAddressedToBot(bs, match)) return;
00848
00849 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00850
00851 client = FindClientByName(netname);
00852
00853 bs->decisionmaker = client;
00854 bs->ordered = qtrue;
00855 bs->order_time = FloatTime();
00856
00857 bs->teammessage_time = FloatTime() + 2 * random();
00858
00859 bs->ltgtype = LTG_GETFLAG;
00860
00861 bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
00862
00863 if (gametype == GT_CTF) {
00864
00865 BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00866 }
00867
00868 BotSetTeamStatus(bs);
00869
00870 BotRememberLastOrderedTask(bs);
00871 #ifdef DEBUG
00872 BotPrintTeamGoal(bs);
00873 #endif //DEBUG
00874 }
00875
00876
00877
00878
00879
00880
00881 void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) {
00882 char netname[MAX_MESSAGE_SIZE];
00883 int client;
00884
00885 if (gametype == GT_CTF) {
00886 BotMatch_GetFlag(bs, match);
00887 }
00888 #ifdef MISSIONPACK
00889 else if (gametype == GT_1FCTF || gametype == GT_OBELISK || gametype == GT_HARVESTER) {
00890 if (!redobelisk.areanum || !blueobelisk.areanum)
00891 return;
00892 }
00893 #endif
00894 else {
00895 return;
00896 }
00897
00898 if (!BotAddressedToBot(bs, match)) return;
00899
00900 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00901
00902 client = FindClientByName(netname);
00903
00904 bs->decisionmaker = client;
00905 bs->ordered = qtrue;
00906 bs->order_time = FloatTime();
00907
00908 bs->teammessage_time = FloatTime() + 2 * random();
00909
00910 bs->ltgtype = LTG_ATTACKENEMYBASE;
00911
00912 bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
00913 bs->attackaway_time = 0;
00914
00915 BotSetTeamStatus(bs);
00916
00917 BotRememberLastOrderedTask(bs);
00918 #ifdef DEBUG
00919 BotPrintTeamGoal(bs);
00920 #endif //DEBUG
00921 }
00922
00923 #ifdef MISSIONPACK
00924
00925
00926
00927
00928
00929 void BotMatch_Harvest(bot_state_t *bs, bot_match_t *match) {
00930 char netname[MAX_MESSAGE_SIZE];
00931 int client;
00932
00933 if (gametype == GT_HARVESTER) {
00934 if (!neutralobelisk.areanum || !redobelisk.areanum || !blueobelisk.areanum)
00935 return;
00936 }
00937 else {
00938 return;
00939 }
00940
00941 if (!BotAddressedToBot(bs, match)) return;
00942
00943 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00944
00945 client = FindClientByName(netname);
00946
00947 bs->decisionmaker = client;
00948 bs->ordered = qtrue;
00949 bs->order_time = FloatTime();
00950
00951 bs->teammessage_time = FloatTime() + 2 * random();
00952
00953 bs->ltgtype = LTG_HARVEST;
00954
00955 bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
00956 bs->harvestaway_time = 0;
00957
00958 BotSetTeamStatus(bs);
00959
00960 BotRememberLastOrderedTask(bs);
00961 #ifdef DEBUG
00962 BotPrintTeamGoal(bs);
00963 #endif //DEBUG
00964 }
00965 #endif
00966
00967
00968
00969
00970
00971
00972 void BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) {
00973 char netname[MAX_MESSAGE_SIZE];
00974 int client;
00975
00976 if (gametype == GT_CTF) {
00977 if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
00978 return;
00979 }
00980 #ifdef MISSIONPACK
00981 else if (gametype == GT_1FCTF || gametype == GT_HARVESTER) {
00982 if (!redobelisk.areanum || !blueobelisk.areanum)
00983 return;
00984 }
00985 #endif
00986 else {
00987 return;
00988 }
00989
00990 if (!BotAddressedToBot(bs, match)) return;
00991
00992 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00993
00994 client = FindClientByName(netname);
00995
00996 bs->decisionmaker = client;
00997 bs->ordered = qtrue;
00998 bs->order_time = FloatTime();
00999
01000 bs->teammessage_time = FloatTime() + 2 * random();
01001
01002 bs->ltgtype = LTG_RUSHBASE;
01003
01004 bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
01005 bs->rushbaseaway_time = 0;
01006
01007 BotSetTeamStatus(bs);
01008 #ifdef DEBUG
01009 BotPrintTeamGoal(bs);
01010 #endif //DEBUG
01011 }
01012
01013
01014
01015
01016
01017
01018 void BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) {
01019 char netname[MAX_NETNAME];
01020 char teammatename[MAX_MESSAGE_SIZE];
01021 int teammate, preference;
01022
01023 ClientName(bs->client, netname, sizeof(netname));
01024 if (Q_stricmp(netname, bs->teamleader) != 0) return;
01025
01026 trap_BotMatchVariable(match, NETNAME, teammatename, sizeof(teammatename));
01027 teammate = ClientFromName(teammatename);
01028 if (teammate < 0) return;
01029
01030 preference = BotGetTeamMateTaskPreference(bs, teammate);
01031 switch(match->subtype)
01032 {
01033 case ST_DEFENDER:
01034 {
01035 preference &= ~TEAMTP_ATTACKER;
01036 preference |= TEAMTP_DEFENDER;
01037 break;
01038 }
01039 case ST_ATTACKER:
01040 {
01041 preference &= ~TEAMTP_DEFENDER;
01042 preference |= TEAMTP_ATTACKER;
01043 break;
01044 }
01045 case ST_ROAMER:
01046 {
01047 preference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER);
01048 break;
01049 }
01050 }
01051 BotSetTeamMateTaskPreference(bs, teammate, preference);
01052
01053 EasyClientName(teammate, teammatename, sizeof(teammatename));
01054 BotAI_BotInitialChat(bs, "keepinmind", teammatename, NULL);
01055 trap_BotEnterChat(bs->cs, teammate, CHAT_TELL);
01056 BotVoiceChatOnly(bs, teammate, VOICECHAT_YES);
01057 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
01058 }
01059
01060
01061
01062
01063
01064
01065 void BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) {
01066 char netname[MAX_MESSAGE_SIZE];
01067 int client;
01068
01069
01070 if (
01071 gametype != GT_CTF
01072 #ifdef MISSIONPACK
01073 && gametype != GT_1FCTF
01074 #endif
01075 )
01076 return;
01077
01078 if (!BotAddressedToBot(bs, match))
01079 return;
01080
01081 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01082
01083 client = FindClientByName(netname);
01084
01085 bs->decisionmaker = client;
01086 bs->ordered = qtrue;
01087 bs->order_time = FloatTime();
01088
01089 bs->teammessage_time = FloatTime() + 2 * random();
01090
01091 bs->ltgtype = LTG_RETURNFLAG;
01092
01093 bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
01094 bs->rushbaseaway_time = 0;
01095
01096 BotSetTeamStatus(bs);
01097 #ifdef DEBUG
01098 BotPrintTeamGoal(bs);
01099 #endif //DEBUG
01100 }
01101
01102
01103
01104
01105
01106
01107 void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) {
01108 char teammate[MAX_MESSAGE_SIZE];
01109 char netname[MAX_MESSAGE_SIZE];
01110 int client;
01111
01112 if (!TeamPlayIsOn()) return;
01113
01114 if (!BotAddressedToBot(bs, match)) return;
01115
01116 trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate));
01117
01118 strncpy(bs->subteam, teammate, 32);
01119 bs->subteam[31] = '\0';
01120
01121 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01122 BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL);
01123 client = ClientFromName(netname);
01124 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01125 }
01126
01127
01128
01129
01130
01131
01132 void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) {
01133 char netname[MAX_MESSAGE_SIZE];
01134 int client;
01135
01136 if (!TeamPlayIsOn()) return;
01137
01138 if (!BotAddressedToBot(bs, match)) return;
01139
01140 if (strlen(bs->subteam))
01141 {
01142 BotAI_BotInitialChat(bs, "leftteam", bs->subteam, NULL);
01143 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01144 client = ClientFromName(netname);
01145 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01146 }
01147 strcpy(bs->subteam, "");
01148 }
01149
01150
01151
01152
01153
01154
01155 void BotMatch_WhichTeam(bot_state_t *bs, bot_match_t *match) {
01156 if (!TeamPlayIsOn()) return;
01157
01158 if (!BotAddressedToBot(bs, match)) return;
01159
01160 if (strlen(bs->subteam)) {
01161 BotAI_BotInitialChat(bs, "inteam", bs->subteam, NULL);
01162 }
01163 else {
01164 BotAI_BotInitialChat(bs, "noteam", NULL);
01165 }
01166 trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01167 }
01168
01169
01170
01171
01172
01173
01174 void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) {
01175 int areanum, client;
01176 char buf[MAX_MESSAGE_SIZE];
01177 char netname[MAX_MESSAGE_SIZE];
01178 vec3_t position;
01179 bot_waypoint_t *cp;
01180
01181 if (!TeamPlayIsOn()) return;
01182
01183 trap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE);
01184 VectorClear(position);
01185
01186 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01187 client = ClientFromName(netname);
01188
01189 sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]);
01190 position[2] += 0.5;
01191 areanum = BotPointAreaNum(position);
01192 if (!areanum) {
01193 if (BotAddressedToBot(bs, match)) {
01194 BotAI_BotInitialChat(bs, "checkpoint_invalid", NULL);
01195 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01196 }
01197 return;
01198 }
01199
01200 trap_BotMatchVariable(match, NAME, buf, MAX_MESSAGE_SIZE);
01201
01202 cp = BotFindWayPoint(bs->checkpoints, buf);
01203 if (cp) {
01204 if (cp->next) cp->next->prev = cp->prev;
01205 if (cp->prev) cp->prev->next = cp->next;
01206 else bs->checkpoints = cp->next;
01207 cp->inuse = qfalse;
01208 }
01209
01210 cp = BotCreateWayPoint(buf, position, areanum);
01211
01212 cp->next = bs->checkpoints;
01213 if (bs->checkpoints) bs->checkpoints->prev = cp;
01214 bs->checkpoints = cp;
01215
01216 if (BotAddressedToBot(bs, match)) {
01217 Com_sprintf(buf, sizeof(buf), "%1.0f %1.0f %1.0f", cp->goal.origin[0],
01218 cp->goal.origin[1],
01219 cp->goal.origin[2]);
01220
01221 BotAI_BotInitialChat(bs, "checkpoint_confirm", cp->name, buf, NULL);
01222 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01223 }
01224 }
01225
01226
01227
01228
01229
01230
01231 void BotMatch_FormationSpace(bot_state_t *bs, bot_match_t *match) {
01232 char buf[MAX_MESSAGE_SIZE];
01233 float space;
01234
01235 if (!TeamPlayIsOn()) return;
01236
01237 if (!BotAddressedToBot(bs, match)) return;
01238
01239 trap_BotMatchVariable(match, NUMBER, buf, MAX_MESSAGE_SIZE);
01240
01241 if (match->subtype & ST_FEET) space = 0.3048 * 32 * atof(buf);
01242
01243 else space = 32 * atof(buf);
01244
01245 if (space < 48 || space > 500) space = 100;
01246 bs->formation_dist = space;
01247 }
01248
01249
01250
01251
01252
01253
01254 void BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) {
01255 char netname[MAX_MESSAGE_SIZE];
01256 int client;
01257
01258 if (!TeamPlayIsOn()) return;
01259
01260 if (!BotAddressedToBot(bs, match)) return;
01261 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01262 client = ClientFromName(netname);
01263
01264 bs->decisionmaker = client;
01265
01266 bs->ltgtype = 0;
01267 bs->lead_time = 0;
01268 bs->lastgoal_ltgtype = 0;
01269
01270 BotAI_BotInitialChat(bs, "dismissed", NULL);
01271 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01272 }
01273
01274
01275
01276
01277
01278
01279 void BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) {
01280 char netname[MAX_MESSAGE_SIZE];
01281 int client;
01282
01283 if (!TeamPlayIsOn()) return;
01284
01285 if (!BotAddressedToBot(bs, match)) return;
01286
01287 trap_EA_Command(bs->client, "kill");
01288
01289 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01290 client = ClientFromName(netname);
01291
01292 BotVoiceChat(bs, client, VOICECHAT_TAUNT);
01293 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
01294 }
01295
01296
01297
01298
01299
01300
01301 void BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
01302 int client;
01303 char teammate[MAX_MESSAGE_SIZE];
01304
01305 if (!TeamPlayIsOn()) return;
01306
01307 if (match->subtype & ST_I) {
01308
01309 trap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate));
01310 strncpy(bs->teamleader, teammate, sizeof(bs->teamleader));
01311 bs->teamleader[sizeof(bs->teamleader)] = '\0';
01312 }
01313
01314 else {
01315
01316 trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01317 client = FindClientByName(teammate);
01318 if (client >= 0) ClientName(client, bs->teamleader, sizeof(bs->teamleader));
01319 }
01320 }
01321
01322
01323
01324
01325
01326
01327 void BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
01328 int client;
01329 char teammate[MAX_MESSAGE_SIZE];
01330 char netname[MAX_MESSAGE_SIZE];
01331
01332 if (!TeamPlayIsOn()) return;
01333
01334 trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01335
01336 if (match->subtype & ST_I) {
01337 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01338 client = FindClientByName(netname);
01339 }
01340
01341 else {
01342 client = FindClientByName(teammate);
01343 }
01344 if (client >= 0) {
01345 if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
01346 bs->teamleader[0] = '\0';
01347 notleader[client] = qtrue;
01348 }
01349 }
01350 }
01351
01352
01353
01354
01355
01356
01357 void BotMatch_WhoIsTeamLeader(bot_state_t *bs, bot_match_t *match) {
01358 char netname[MAX_MESSAGE_SIZE];
01359
01360 if (!TeamPlayIsOn()) return;
01361
01362 ClientName(bs->client, netname, sizeof(netname));
01363
01364 if (!Q_stricmp(netname, bs->teamleader)) {
01365 trap_EA_SayTeam(bs->client, "I'm the team leader\n");
01366 }
01367 }
01368
01369
01370
01371
01372
01373
01374 void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) {
01375 char netname[MAX_MESSAGE_SIZE];
01376 char goalname[MAX_MESSAGE_SIZE];
01377 int client;
01378
01379
01380 if (!BotAddressedToBot(bs, match)) return;
01381
01382 switch(bs->ltgtype) {
01383 case LTG_TEAMHELP:
01384 {
01385 EasyClientName(bs->teammate, netname, sizeof(netname));
01386 BotAI_BotInitialChat(bs, "helping", netname, NULL);
01387 break;
01388 }
01389 case LTG_TEAMACCOMPANY:
01390 {
01391 EasyClientName(bs->teammate, netname, sizeof(netname));
01392 BotAI_BotInitialChat(bs, "accompanying", netname, NULL);
01393 break;
01394 }
01395 case LTG_DEFENDKEYAREA:
01396 {
01397 trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
01398 BotAI_BotInitialChat(bs, "defending", goalname, NULL);
01399 break;
01400 }
01401 case LTG_GETITEM:
01402 {
01403 trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
01404 BotAI_BotInitialChat(bs, "gettingitem", goalname, NULL);
01405 break;
01406 }
01407 case LTG_KILL:
01408 {
01409 ClientName(bs->teamgoal.entitynum, netname, sizeof(netname));
01410 BotAI_BotInitialChat(bs, "killing", netname, NULL);
01411 break;
01412 }
01413 case LTG_CAMP:
01414 case LTG_CAMPORDER:
01415 {
01416 BotAI_BotInitialChat(bs, "camping", NULL);
01417 break;
01418 }
01419 case LTG_PATROL:
01420 {
01421 BotAI_BotInitialChat(bs, "patrolling", NULL);
01422 break;
01423 }
01424 case LTG_GETFLAG:
01425 {
01426 BotAI_BotInitialChat(bs, "capturingflag", NULL);
01427 break;
01428 }
01429 case LTG_RUSHBASE:
01430 {
01431 BotAI_BotInitialChat(bs, "rushingbase", NULL);
01432 break;
01433 }
01434 case LTG_RETURNFLAG:
01435 {
01436 BotAI_BotInitialChat(bs, "returningflag", NULL);
01437 break;
01438 }
01439 #ifdef MISSIONPACK
01440 case LTG_ATTACKENEMYBASE:
01441 {
01442 BotAI_BotInitialChat(bs, "attackingenemybase", NULL);
01443 break;
01444 }
01445 case LTG_HARVEST:
01446 {
01447 BotAI_BotInitialChat(bs, "harvesting", NULL);
01448 break;
01449 }
01450 #endif
01451 default:
01452 {
01453 BotAI_BotInitialChat(bs, "roaming", NULL);
01454 break;
01455 }
01456 }
01457
01458 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01459 client = ClientFromName(netname);
01460 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01461 }
01462
01463
01464
01465
01466
01467
01468 void BotMatch_WhatIsMyCommand(bot_state_t *bs, bot_match_t *match) {
01469 char netname[MAX_NETNAME];
01470
01471 ClientName(bs->client, netname, sizeof(netname));
01472 if (Q_stricmp(netname, bs->teamleader) != 0) return;
01473 bs->forceorders = qtrue;
01474 }
01475
01476
01477
01478
01479
01480
01481 float BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) {
01482 int i;
01483 char name[64];
01484 bot_goal_t tmpgoal;
01485 float dist, bestdist;
01486 vec3_t dir;
01487 bsp_trace_t trace;
01488
01489 bestdist = 999999;
01490 i = -1;
01491 do {
01492 i = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal);
01493 trap_BotGoalName(tmpgoal.number, name, sizeof(name));
01494 if (Q_stricmp(itemname, name) != 0)
01495 continue;
01496 VectorSubtract(tmpgoal.origin, bs->origin, dir);
01497 dist = VectorLength(dir);
01498 if (dist < bestdist) {
01499
01500 BotAI_Trace(&trace, bs->eye, NULL, NULL, tmpgoal.origin, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
01501 if (trace.fraction >= 1.0) {
01502 bestdist = dist;
01503 memcpy(goal, &tmpgoal, sizeof(bot_goal_t));
01504 }
01505 }
01506 } while(i > 0);
01507 return bestdist;
01508 }
01509
01510
01511
01512
01513
01514
01515 void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) {
01516 float dist, bestdist;
01517 int i, bestitem, redtt, bluett, client;
01518 bot_goal_t goal;
01519 char netname[MAX_MESSAGE_SIZE];
01520 char *nearbyitems[] = {
01521 "Shotgun",
01522 "Grenade Launcher",
01523 "Rocket Launcher",
01524 "Plasmagun",
01525 "Railgun",
01526 "Lightning Gun",
01527 "BFG10K",
01528 "Quad Damage",
01529 "Regeneration",
01530 "Battle Suit",
01531 "Speed",
01532 "Invisibility",
01533 "Flight",
01534 "Armor",
01535 "Heavy Armor",
01536 "Red Flag",
01537 "Blue Flag",
01538 #ifdef MISSIONPACK
01539 "Nailgun",
01540 "Prox Launcher",
01541 "Chaingun",
01542 "Scout",
01543 "Guard",
01544 "Doubler",
01545 "Ammo Regen",
01546 "Neutral Flag",
01547 "Red Obelisk",
01548 "Blue Obelisk",
01549 "Neutral Obelisk",
01550 #endif
01551 NULL
01552 };
01553
01554 if (!TeamPlayIsOn())
01555 return;
01556
01557 if (!BotAddressedToBot(bs, match))
01558 return;
01559
01560 bestitem = -1;
01561 bestdist = 999999;
01562 for (i = 0; nearbyitems[i]; i++) {
01563 dist = BotNearestVisibleItem(bs, nearbyitems[i], &goal);
01564 if (dist < bestdist) {
01565 bestdist = dist;
01566 bestitem = i;
01567 }
01568 }
01569 if (bestitem != -1) {
01570 if (gametype == GT_CTF
01571 #ifdef MISSIONPACK
01572 || gametype == GT_1FCTF
01573 #endif
01574 ) {
01575 redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT);
01576 bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT);
01577 if (redtt < (redtt + bluett) * 0.4) {
01578 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
01579 }
01580 else if (bluett < (redtt + bluett) * 0.4) {
01581 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
01582 }
01583 else {
01584 BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01585 }
01586 }
01587 #ifdef MISSIONPACK
01588 else if (gametype == GT_OBELISK || gametype == GT_HARVESTER) {
01589 redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, redobelisk.areanum, TFL_DEFAULT);
01590 bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, blueobelisk.areanum, TFL_DEFAULT);
01591 if (redtt < (redtt + bluett) * 0.4) {
01592 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
01593 }
01594 else if (bluett < (redtt + bluett) * 0.4) {
01595 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
01596 }
01597 else {
01598 BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01599 }
01600 }
01601 #endif
01602 else {
01603 BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01604 }
01605 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01606 client = ClientFromName(netname);
01607 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01608 }
01609 }
01610
01611
01612
01613
01614
01615
01616 void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) {
01617 aas_entityinfo_t entinfo;
01618 char netname[MAX_MESSAGE_SIZE], teammate[MAX_MESSAGE_SIZE];
01619 int client, areanum, other;
01620
01621 if (!TeamPlayIsOn()) return;
01622
01623 if (!BotAddressedToBot(bs, match)) return;
01624
01625 if (match->subtype & ST_SOMEONE) {
01626
01627 trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01628 client = FindClientByName(teammate);
01629
01630 if (client == bs->client) {
01631 other = qfalse;
01632 }
01633 else if (!BotSameTeam(bs, client)) {
01634
01635 return;
01636 }
01637 else {
01638 other = qtrue;
01639 }
01640 }
01641 else {
01642
01643 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01644 client = ClientFromName(netname);
01645 other = qfalse;
01646 }
01647
01648 if (client < 0) {
01649 BotAI_BotInitialChat(bs, "whois", netname, NULL);
01650 trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01651 return;
01652 }
01653
01654 bs->lead_teamgoal.entitynum = -1;
01655 BotEntityInfo(client, &entinfo);
01656
01657 if (entinfo.valid) {
01658 areanum = BotPointAreaNum(entinfo.origin);
01659 if (areanum) {
01660 bs->lead_teamgoal.entitynum = client;
01661 bs->lead_teamgoal.areanum = areanum;
01662 VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
01663 VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
01664 VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
01665 }
01666 }
01667
01668 if (bs->teamgoal.entitynum < 0) {
01669 if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
01670 else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
01671 trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01672 return;
01673 }
01674 bs->lead_teammate = client;
01675 bs->lead_time = FloatTime() + TEAM_LEAD_TIME;
01676 bs->leadvisible_time = 0;
01677 bs->leadmessage_time = -(FloatTime() + 2 * random());
01678 }
01679
01680
01681
01682
01683
01684
01685 void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) {
01686 char enemy[MAX_MESSAGE_SIZE];
01687 char netname[MAX_MESSAGE_SIZE];
01688 int client;
01689
01690 if (!TeamPlayIsOn()) return;
01691
01692 if (!BotAddressedToBot(bs, match)) return;
01693
01694 trap_BotMatchVariable(match, ENEMY, enemy, sizeof(enemy));
01695
01696 client = FindEnemyByName(bs, enemy);
01697 if (client < 0) {
01698 BotAI_BotInitialChat(bs, "whois", enemy, NULL);
01699 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01700 client = ClientFromName(netname);
01701 trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01702 return;
01703 }
01704 bs->teamgoal.entitynum = client;
01705
01706 bs->teammessage_time = FloatTime() + 2 * random();
01707
01708 bs->ltgtype = LTG_KILL;
01709
01710 bs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE;
01711
01712 BotSetTeamStatus(bs);
01713 #ifdef DEBUG
01714 BotPrintTeamGoal(bs);
01715 #endif //DEBUG
01716 }
01717
01718
01719
01720
01721
01722
01723 void BotMatch_CTF(bot_state_t *bs, bot_match_t *match) {
01724
01725 char flag[128], netname[MAX_NETNAME];
01726
01727 if (gametype == GT_CTF) {
01728 trap_BotMatchVariable(match, FLAG, flag, sizeof(flag));
01729 if (match->subtype & ST_GOTFLAG) {
01730 if (!Q_stricmp(flag, "red")) {
01731 bs->redflagstatus = 1;
01732 if (BotTeam(bs) == TEAM_BLUE) {
01733 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01734 bs->flagcarrier = ClientFromName(netname);
01735 }
01736 }
01737 else {
01738 bs->blueflagstatus = 1;
01739 if (BotTeam(bs) == TEAM_RED) {
01740 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01741 bs->flagcarrier = ClientFromName(netname);
01742 }
01743 }
01744 bs->flagstatuschanged = 1;
01745 bs->lastflagcapture_time = FloatTime();
01746 }
01747 else if (match->subtype & ST_CAPTUREDFLAG) {
01748 bs->redflagstatus = 0;
01749 bs->blueflagstatus = 0;
01750 bs->flagcarrier = 0;
01751 bs->flagstatuschanged = 1;
01752 }
01753 else if (match->subtype & ST_RETURNEDFLAG) {
01754 if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0;
01755 else bs->blueflagstatus = 0;
01756 bs->flagstatuschanged = 1;
01757 }
01758 }
01759 #ifdef MISSIONPACK
01760 else if (gametype == GT_1FCTF) {
01761 if (match->subtype & ST_1FCTFGOTFLAG) {
01762 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01763 bs->flagcarrier = ClientFromName(netname);
01764 }
01765 }
01766 #endif
01767 }
01768
01769 void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) {
01770 int client;
01771 char netname[MAX_NETNAME];
01772
01773 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01774 client = FindClientByName(netname);
01775 if (client >= 0) {
01776 notleader[client] = qfalse;
01777 }
01778
01779
01780
01781 }
01782
01783 void BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) {
01784 int client;
01785 char netname[MAX_NETNAME];
01786
01787 trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01788 client = FindClientByName(netname);
01789 if (!BotSameTeam(bs, client))
01790 return;
01791 Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader));
01792 }
01793
01794
01795
01796
01797
01798
01799 int BotMatchMessage(bot_state_t *bs, char *message) {
01800 bot_match_t match;
01801
01802 match.type = 0;
01803
01804 if (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC
01805 |MTCONTEXT_INITIALTEAMCHAT
01806 |MTCONTEXT_CTF)) {
01807 return qfalse;
01808 }
01809
01810 switch(match.type)
01811 {
01812 case MSG_HELP:
01813 case MSG_ACCOMPANY:
01814 {
01815 BotMatch_HelpAccompany(bs, &match);
01816 break;
01817 }
01818 case MSG_DEFENDKEYAREA:
01819 {
01820 BotMatch_DefendKeyArea(bs, &match);
01821 break;
01822 }
01823 case MSG_CAMP:
01824 {
01825 BotMatch_Camp(bs, &match);
01826 break;
01827 }
01828 case MSG_PATROL:
01829 {
01830 BotMatch_Patrol(bs, &match);
01831 break;
01832 }
01833
01834 case MSG_GETFLAG:
01835 {
01836 BotMatch_GetFlag(bs, &match);
01837 break;
01838 }
01839 #ifdef MISSIONPACK
01840
01841 case MSG_ATTACKENEMYBASE:
01842 {
01843 BotMatch_AttackEnemyBase(bs, &match);
01844 break;
01845 }
01846
01847 case MSG_HARVEST:
01848 {
01849 BotMatch_Harvest(bs, &match);
01850 break;
01851 }
01852 #endif
01853
01854 case MSG_RUSHBASE:
01855 {
01856 BotMatch_RushBase(bs, &match);
01857 break;
01858 }
01859
01860 case MSG_RETURNFLAG:
01861 {
01862 BotMatch_ReturnFlag(bs, &match);
01863 break;
01864 }
01865
01866 case MSG_TASKPREFERENCE:
01867 {
01868 BotMatch_TaskPreference(bs, &match);
01869 break;
01870 }
01871
01872 case MSG_CTF:
01873 {
01874 BotMatch_CTF(bs, &match);
01875 break;
01876 }
01877 case MSG_GETITEM:
01878 {
01879 BotMatch_GetItem(bs, &match);
01880 break;
01881 }
01882 case MSG_JOINSUBTEAM:
01883 {
01884 BotMatch_JoinSubteam(bs, &match);
01885 break;
01886 }
01887 case MSG_LEAVESUBTEAM:
01888 {
01889 BotMatch_LeaveSubteam(bs, &match);
01890 break;
01891 }
01892 case MSG_WHICHTEAM:
01893 {
01894 BotMatch_WhichTeam(bs, &match);
01895 break;
01896 }
01897 case MSG_CHECKPOINT:
01898 {
01899 BotMatch_CheckPoint(bs, &match);
01900 break;
01901 }
01902 case MSG_CREATENEWFORMATION:
01903 {
01904 trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
01905 break;
01906 }
01907 case MSG_FORMATIONPOSITION:
01908 {
01909 trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
01910 break;
01911 }
01912 case MSG_FORMATIONSPACE:
01913 {
01914 BotMatch_FormationSpace(bs, &match);
01915 break;
01916 }
01917 case MSG_DOFORMATION:
01918 {
01919 break;
01920 }
01921 case MSG_DISMISS:
01922 {
01923 BotMatch_Dismiss(bs, &match);
01924 break;
01925 }
01926 case MSG_STARTTEAMLEADERSHIP:
01927 {
01928 BotMatch_StartTeamLeaderShip(bs, &match);
01929 break;
01930 }
01931 case MSG_STOPTEAMLEADERSHIP:
01932 {
01933 BotMatch_StopTeamLeaderShip(bs, &match);
01934 break;
01935 }
01936 case MSG_WHOISTEAMLAEDER:
01937 {
01938 BotMatch_WhoIsTeamLeader(bs, &match);
01939 break;
01940 }
01941 case MSG_WHATAREYOUDOING:
01942 {
01943 BotMatch_WhatAreYouDoing(bs, &match);
01944 break;
01945 }
01946 case MSG_WHATISMYCOMMAND:
01947 {
01948 BotMatch_WhatIsMyCommand(bs, &match);
01949 break;
01950 }
01951 case MSG_WHEREAREYOU:
01952 {
01953 BotMatch_WhereAreYou(bs, &match);
01954 break;
01955 }
01956 case MSG_LEADTHEWAY:
01957 {
01958 BotMatch_LeadTheWay(bs, &match);
01959 break;
01960 }
01961 case MSG_KILL:
01962 {
01963 BotMatch_Kill(bs, &match);
01964 break;
01965 }
01966 case MSG_ENTERGAME:
01967 {
01968 BotMatch_EnterGame(bs, &match);
01969 break;
01970 }
01971 case MSG_NEWLEADER:
01972 {
01973 BotMatch_NewLeader(bs, &match);
01974 break;
01975 }
01976 case MSG_WAIT:
01977 {
01978 break;
01979 }
01980 case MSG_SUICIDE:
01981 {
01982 BotMatch_Suicide(bs, &match);
01983 break;
01984 }
01985 default:
01986 {
01987 BotAI_Print(PRT_MESSAGE, "unknown match type\n");
01988 break;
01989 }
01990 }
01991 return qtrue;
01992 }