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
00060 #define GFL_AIR 128
00061
00062 int numnodeswitches;
00063 char nodeswitch[MAX_NODESWITCHES+1][144];
00064
00065 #define LOOKAHEAD_DISTANCE 300
00066
00067
00068
00069
00070
00071
00072 void BotResetNodeSwitches(void) {
00073 numnodeswitches = 0;
00074 }
00075
00076
00077
00078
00079
00080
00081 void BotDumpNodeSwitches(bot_state_t *bs) {
00082 int i;
00083 char netname[MAX_NETNAME];
00084
00085 ClientName(bs->client, netname, sizeof(netname));
00086 BotAI_Print(PRT_MESSAGE, "%s at %1.1f switched more than %d AI nodes\n", netname, FloatTime(), MAX_NODESWITCHES);
00087 for (i = 0; i < numnodeswitches; i++) {
00088 BotAI_Print(PRT_MESSAGE, nodeswitch[i]);
00089 }
00090 BotAI_Print(PRT_FATAL, "");
00091 }
00092
00093
00094
00095
00096
00097
00098 void BotRecordNodeSwitch(bot_state_t *bs, char *node, char *str, char *s) {
00099 char netname[MAX_NETNAME];
00100
00101 ClientName(bs->client, netname, sizeof(netname));
00102 Com_sprintf(nodeswitch[numnodeswitches], 144, "%s at %2.1f entered %s: %s from %s\n", netname, FloatTime(), node, str, s);
00103 #ifdef DEBUG
00104 if (0) {
00105 BotAI_Print(PRT_MESSAGE, nodeswitch[numnodeswitches]);
00106 }
00107 #endif //DEBUG
00108 numnodeswitches++;
00109 }
00110
00111
00112
00113
00114
00115
00116 int BotGetAirGoal(bot_state_t *bs, bot_goal_t *goal) {
00117 bsp_trace_t bsptrace;
00118 vec3_t end, mins = {-15, -15, -2}, maxs = {15, 15, 2};
00119 int areanum;
00120
00121
00122 VectorCopy(bs->origin, end);
00123 end[2] += 1000;
00124 BotAI_Trace(&bsptrace, bs->origin, mins, maxs, end, bs->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
00125
00126 VectorCopy(bsptrace.endpos, end);
00127 BotAI_Trace(&bsptrace, end, mins, maxs, bs->origin, bs->entitynum, CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA);
00128
00129 if (bsptrace.fraction > 0) {
00130 areanum = BotPointAreaNum(bsptrace.endpos);
00131 if (areanum) {
00132 VectorCopy(bsptrace.endpos, goal->origin);
00133 goal->origin[2] -= 2;
00134 goal->areanum = areanum;
00135 goal->mins[0] = -15;
00136 goal->mins[1] = -15;
00137 goal->mins[2] = -1;
00138 goal->maxs[0] = 15;
00139 goal->maxs[1] = 15;
00140 goal->maxs[2] = 1;
00141 goal->flags = GFL_AIR;
00142 goal->number = 0;
00143 goal->iteminfo = 0;
00144 goal->entitynum = 0;
00145 return qtrue;
00146 }
00147 }
00148 return qfalse;
00149 }
00150
00151
00152
00153
00154
00155
00156 int BotGoForAir(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
00157 bot_goal_t goal;
00158
00159
00160 if (bs->lastair_time < FloatTime() - 6) {
00161
00162 #ifdef DEBUG
00163
00164 #endif //DEBUG
00165
00166 if (BotGetAirGoal(bs, &goal)) {
00167 trap_BotPushGoal(bs->gs, &goal);
00168 return qtrue;
00169 }
00170 else {
00171
00172 while(trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range)) {
00173 trap_BotGetTopGoal(bs->gs, &goal);
00174
00175 if (!(trap_AAS_PointContents(goal.origin) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
00176 return qtrue;
00177 }
00178 trap_BotPopGoal(bs->gs);
00179 }
00180 trap_BotResetAvoidGoals(bs->gs);
00181 }
00182 }
00183 return qfalse;
00184 }
00185
00186
00187
00188
00189
00190
00191 int BotNearbyGoal(bot_state_t *bs, int tfl, bot_goal_t *ltg, float range) {
00192 int ret;
00193
00194
00195 if (BotGoForAir(bs, tfl, ltg, range)) return qtrue;
00196
00197 if (BotCTFCarryingFlag(bs)) {
00198
00199 if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
00200 bs->teamgoal.areanum, TFL_DEFAULT) < 300) {
00201
00202 range = 50;
00203 }
00204 }
00205
00206 ret = trap_BotChooseNBGItem(bs->gs, bs->origin, bs->inventory, tfl, ltg, range);
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 return ret;
00218 }
00219
00220
00221
00222
00223
00224
00225 int BotReachedGoal(bot_state_t *bs, bot_goal_t *goal) {
00226 if (goal->flags & GFL_ITEM) {
00227
00228 if (trap_BotTouchingGoal(bs->origin, goal)) {
00229 if (!(goal->flags & GFL_DROPPED)) {
00230 trap_BotSetAvoidGoalTime(bs->gs, goal->number, -1);
00231 }
00232 return qtrue;
00233 }
00234
00235 if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 return qtrue;
00248 }
00249
00250 if (bs->areanum == goal->areanum) {
00251 if (bs->origin[0] > goal->origin[0] + goal->mins[0] && bs->origin[0] < goal->origin[0] + goal->maxs[0]) {
00252 if (bs->origin[1] > goal->origin[1] + goal->mins[1] && bs->origin[1] < goal->origin[1] + goal->maxs[1]) {
00253 if (!trap_AAS_Swimming(bs->origin)) {
00254 return qtrue;
00255 }
00256 }
00257 }
00258 }
00259 }
00260 else if (goal->flags & GFL_AIR) {
00261
00262 if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
00263
00264 if (bs->lastair_time > FloatTime() - 1) return qtrue;
00265 }
00266 else {
00267
00268 if (trap_BotTouchingGoal(bs->origin, goal)) return qtrue;
00269 }
00270 return qfalse;
00271 }
00272
00273
00274
00275
00276
00277
00278 int BotGetItemLongTermGoal(bot_state_t *bs, int tfl, bot_goal_t *goal) {
00279
00280 if (!trap_BotGetTopGoal(bs->gs, goal)) {
00281
00282 bs->ltg_time = 0;
00283 }
00284
00285 else if (BotReachedGoal(bs, goal)) {
00286 BotChooseWeapon(bs);
00287 bs->ltg_time = 0;
00288 }
00289
00290 if (bs->ltg_time < FloatTime()) {
00291
00292 trap_BotPopGoal(bs->gs);
00293
00294
00295
00296 if (trap_BotChooseLTGItem(bs->gs, bs->origin, bs->inventory, tfl)) {
00297
00298
00299
00300
00301
00302
00303
00304 bs->ltg_time = FloatTime() + 20;
00305 }
00306 else {
00307
00308 #ifdef DEBUG
00309 char netname[128];
00310
00311 BotAI_Print(PRT_MESSAGE, "%s: no valid ltg (probably stuck)\n", ClientName(bs->client, netname, sizeof(netname)));
00312 #endif
00313
00314
00315 trap_BotResetAvoidGoals(bs->gs);
00316 trap_BotResetAvoidReach(bs->ms);
00317 }
00318
00319 return trap_BotGetTopGoal(bs->gs, goal);
00320 }
00321 return qtrue;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) {
00333 vec3_t target, dir, dir2;
00334 char netname[MAX_NETNAME];
00335 char buf[MAX_MESSAGE_SIZE];
00336 int areanum;
00337 float croucher;
00338 aas_entityinfo_t entinfo, botinfo;
00339 bot_waypoint_t *wp;
00340
00341 if (bs->ltgtype == LTG_TEAMHELP && !retreat) {
00342
00343 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00344 BotAI_BotInitialChat(bs, "help_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00345 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00346 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
00347 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
00348 bs->teammessage_time = 0;
00349 }
00350
00351 if (bs->teamgoal_time < FloatTime())
00352 bs->ltgtype = 0;
00353
00354 if (bs->teammatevisible_time < FloatTime() - 10) bs->ltgtype = 0;
00355
00356 BotEntityInfo(bs->teammate, &entinfo);
00357
00358 if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
00359
00360 VectorSubtract(entinfo.origin, bs->origin, dir);
00361 if (VectorLengthSquared(dir) < Square(100)) {
00362 trap_BotResetAvoidReach(bs->ms);
00363 return qfalse;
00364 }
00365 }
00366 else {
00367
00368 bs->teammatevisible_time = FloatTime();
00369 }
00370
00371 if (entinfo.valid) {
00372 areanum = BotPointAreaNum(entinfo.origin);
00373 if (areanum && trap_AAS_AreaReachability(areanum)) {
00374
00375 bs->teamgoal.entitynum = bs->teammate;
00376 bs->teamgoal.areanum = areanum;
00377 VectorCopy(entinfo.origin, bs->teamgoal.origin);
00378 VectorSet(bs->teamgoal.mins, -8, -8, -8);
00379 VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00380 }
00381 }
00382 memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
00383 return qtrue;
00384 }
00385
00386 if (bs->ltgtype == LTG_TEAMACCOMPANY && !retreat) {
00387
00388 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00389 BotAI_BotInitialChat(bs, "accompany_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00390 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00391 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
00392 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
00393 bs->teammessage_time = 0;
00394 }
00395
00396 if (bs->teamgoal_time < FloatTime()) {
00397 BotAI_BotInitialChat(bs, "accompany_stop", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00398 trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
00399 bs->ltgtype = 0;
00400 }
00401
00402 BotEntityInfo(bs->teammate, &entinfo);
00403
00404 if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->teammate)) {
00405
00406 bs->teammatevisible_time = FloatTime();
00407 VectorSubtract(entinfo.origin, bs->origin, dir);
00408 if (VectorLengthSquared(dir) < Square(bs->formation_dist)) {
00409
00410
00411
00412 BotEntityInfo(bs->entitynum, &botinfo);
00413
00414 if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2]) {
00415
00416 if (botinfo.origin[0] + botinfo.maxs[0] > entinfo.origin[0] + entinfo.mins[0] - 4&&
00417 botinfo.origin[0] + botinfo.mins[0] < entinfo.origin[0] + entinfo.maxs[0] + 4) {
00418 if (botinfo.origin[1] + botinfo.maxs[1] > entinfo.origin[1] + entinfo.mins[1] - 4 &&
00419 botinfo.origin[1] + botinfo.mins[1] < entinfo.origin[1] + entinfo.maxs[1] + 4) {
00420 if (botinfo.origin[2] + botinfo.maxs[2] > entinfo.origin[2] + entinfo.mins[2] - 4 &&
00421 botinfo.origin[2] + botinfo.mins[2] < entinfo.origin[2] + entinfo.maxs[2] + 4) {
00422
00423 AngleVectors(entinfo.angles, dir, NULL, NULL);
00424 dir[2] = 0;
00425 VectorNormalize(dir);
00426
00427 VectorSubtract(bs->origin, entinfo.origin, dir2);
00428 VectorNormalize(dir2);
00429 if (DotProduct(dir, dir2) > 0.7) {
00430
00431 BotSetupForMovement(bs);
00432 trap_BotMoveInDirection(bs->ms, dir2, 400, MOVE_WALK);
00433 }
00434 }
00435 }
00436 }
00437 }
00438
00439
00440 if (bs->attackcrouch_time < FloatTime() - 5) {
00441 croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
00442 if (random() < bs->thinktime * croucher) {
00443 bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
00444 }
00445 }
00446
00447 if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
00448
00449 if (bs->arrive_time < FloatTime() - 2) {
00450
00451 if (!bs->arrive_time) {
00452 trap_EA_Gesture(bs->client);
00453 BotAI_BotInitialChat(bs, "accompany_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00454 trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
00455 bs->arrive_time = FloatTime();
00456 }
00457
00458 else if (bs->attackcrouch_time > FloatTime()) {
00459 trap_EA_Crouch(bs->client);
00460 }
00461
00462 else if (random() < bs->thinktime * 0.05) {
00463
00464 trap_EA_Gesture(bs->client);
00465 }
00466 }
00467
00468 if (bs->arrive_time > FloatTime() - 2) {
00469 VectorSubtract(entinfo.origin, bs->origin, dir);
00470 vectoangles(dir, bs->ideal_viewangles);
00471 bs->ideal_viewangles[2] *= 0.5;
00472 }
00473
00474 else if (random() < bs->thinktime * 0.8) {
00475 BotRoamGoal(bs, target);
00476 VectorSubtract(target, bs->origin, dir);
00477 vectoangles(dir, bs->ideal_viewangles);
00478 bs->ideal_viewangles[2] *= 0.5;
00479 }
00480
00481 if (BotGoForAir(bs, bs->tfl, &bs->teamgoal, 400)) {
00482 trap_BotResetLastAvoidReach(bs->ms);
00483
00484
00485
00486
00487
00488 bs->nbg_time = FloatTime() + 8;
00489 AIEnter_Seek_NBG(bs, "BotLongTermGoal: go for air");
00490 return qfalse;
00491 }
00492
00493 trap_BotResetAvoidReach(bs->ms);
00494 return qfalse;
00495 }
00496 }
00497
00498 if (entinfo.valid) {
00499 areanum = BotPointAreaNum(entinfo.origin);
00500 if (areanum && trap_AAS_AreaReachability(areanum)) {
00501
00502 bs->teamgoal.entitynum = bs->teammate;
00503 bs->teamgoal.areanum = areanum;
00504 VectorCopy(entinfo.origin, bs->teamgoal.origin);
00505 VectorSet(bs->teamgoal.mins, -8, -8, -8);
00506 VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00507 }
00508 }
00509
00510 memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
00511
00512 if (bs->teammatevisible_time < FloatTime() - 60) {
00513 BotAI_BotInitialChat(bs, "accompany_cannotfind", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00514 trap_BotEnterChat(bs->cs, bs->teammate, CHAT_TELL);
00515 bs->ltgtype = 0;
00516
00517 bs->teammatevisible_time = FloatTime();
00518 }
00519 return qtrue;
00520 }
00521
00522 if (bs->ltgtype == LTG_DEFENDKEYAREA) {
00523 if (trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin,
00524 bs->teamgoal.areanum, TFL_DEFAULT) > bs->defendaway_range) {
00525 bs->defendaway_time = 0;
00526 }
00527 }
00528
00529 if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat &&
00530 bs->defendaway_time < FloatTime()) {
00531
00532 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00533 trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
00534 BotAI_BotInitialChat(bs, "defend_start", buf, NULL);
00535 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00536 BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE);
00537 bs->teammessage_time = 0;
00538 }
00539
00540 memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
00541
00542 if (bs->teamgoal_time < FloatTime()) {
00543 trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
00544 BotAI_BotInitialChat(bs, "defend_stop", buf, NULL);
00545 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00546 bs->ltgtype = 0;
00547 }
00548
00549 VectorSubtract(goal->origin, bs->origin, dir);
00550 if (VectorLengthSquared(dir) < Square(70)) {
00551 trap_BotResetAvoidReach(bs->ms);
00552 bs->defendaway_time = FloatTime() + 3 + 3 * random();
00553 if (BotHasPersistantPowerupAndWeapon(bs)) {
00554 bs->defendaway_range = 100;
00555 }
00556 else {
00557 bs->defendaway_range = 350;
00558 }
00559 }
00560 return qtrue;
00561 }
00562
00563 if (bs->ltgtype == LTG_KILL && !retreat) {
00564
00565 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00566 EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
00567 BotAI_BotInitialChat(bs, "kill_start", buf, NULL);
00568 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00569 bs->teammessage_time = 0;
00570 }
00571
00572 if (bs->lastkilledplayer == bs->teamgoal.entitynum) {
00573 EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
00574 BotAI_BotInitialChat(bs, "kill_done", buf, NULL);
00575 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00576 bs->lastkilledplayer = -1;
00577 bs->ltgtype = 0;
00578 }
00579
00580 if (bs->teamgoal_time < FloatTime()) {
00581 bs->ltgtype = 0;
00582 }
00583
00584 return BotGetItemLongTermGoal(bs, tfl, goal);
00585 }
00586
00587 if (bs->ltgtype == LTG_GETITEM && !retreat) {
00588
00589 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00590 trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
00591 BotAI_BotInitialChat(bs, "getitem_start", buf, NULL);
00592 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00593 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
00594 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
00595 bs->teammessage_time = 0;
00596 }
00597
00598 memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
00599
00600 if (bs->teamgoal_time < FloatTime()) {
00601 bs->ltgtype = 0;
00602 }
00603
00604 if (trap_BotItemGoalInVisButNotVisible(bs->entitynum, bs->eye, bs->viewangles, goal)) {
00605 trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
00606 BotAI_BotInitialChat(bs, "getitem_notthere", buf, NULL);
00607 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00608 bs->ltgtype = 0;
00609 }
00610 else if (BotReachedGoal(bs, goal)) {
00611 trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf));
00612 BotAI_BotInitialChat(bs, "getitem_gotit", buf, NULL);
00613 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00614 bs->ltgtype = 0;
00615 }
00616 return qtrue;
00617 }
00618
00619 if ((bs->ltgtype == LTG_CAMP || bs->ltgtype == LTG_CAMPORDER) && !retreat) {
00620
00621 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00622 if (bs->ltgtype == LTG_CAMPORDER) {
00623 BotAI_BotInitialChat(bs, "camp_start", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00624 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00625 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
00626 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
00627 }
00628 bs->teammessage_time = 0;
00629 }
00630
00631 memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t));
00632
00633 if (bs->teamgoal_time < FloatTime()) {
00634 if (bs->ltgtype == LTG_CAMPORDER) {
00635 BotAI_BotInitialChat(bs, "camp_stop", NULL);
00636 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00637 }
00638 bs->ltgtype = 0;
00639 }
00640
00641 VectorSubtract(goal->origin, bs->origin, dir);
00642 if (VectorLengthSquared(dir) < Square(60))
00643 {
00644
00645 if (!bs->arrive_time) {
00646 if (bs->ltgtype == LTG_CAMPORDER) {
00647 BotAI_BotInitialChat(bs, "camp_arrive", EasyClientName(bs->teammate, netname, sizeof(netname)), NULL);
00648 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00649 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_INPOSITION);
00650 }
00651 bs->arrive_time = FloatTime();
00652 }
00653
00654 if (random() < bs->thinktime * 0.8) {
00655 BotRoamGoal(bs, target);
00656 VectorSubtract(target, bs->origin, dir);
00657 vectoangles(dir, bs->ideal_viewangles);
00658 bs->ideal_viewangles[2] *= 0.5;
00659 }
00660
00661
00662 if (bs->attackcrouch_time < FloatTime() - 5) {
00663 croucher = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CROUCHER, 0, 1);
00664 if (random() < bs->thinktime * croucher) {
00665 bs->attackcrouch_time = FloatTime() + 5 + croucher * 15;
00666 }
00667 }
00668
00669 if (bs->attackcrouch_time > FloatTime()) {
00670 trap_EA_Crouch(bs->client);
00671 }
00672
00673 if (trap_AAS_Swimming(bs->origin)) bs->attackcrouch_time = FloatTime() - 1;
00674
00675 if (trap_PointContents(bs->eye,bs->entitynum) & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) {
00676 if (bs->ltgtype == LTG_CAMPORDER) {
00677 BotAI_BotInitialChat(bs, "camp_stop", NULL);
00678 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00679
00680 if (bs->lastgoal_ltgtype == LTG_CAMPORDER) {
00681 bs->lastgoal_ltgtype = 0;
00682 }
00683 }
00684 bs->ltgtype = 0;
00685 }
00686
00687 if (bs->camp_range > 0) {
00688
00689 }
00690
00691 trap_BotResetAvoidReach(bs->ms);
00692 return qfalse;
00693 }
00694 return qtrue;
00695 }
00696
00697 if (bs->ltgtype == LTG_PATROL && !retreat) {
00698
00699 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00700 strcpy(buf, "");
00701 for (wp = bs->patrolpoints; wp; wp = wp->next) {
00702 strcat(buf, wp->name);
00703 if (wp->next) strcat(buf, " to ");
00704 }
00705 BotAI_BotInitialChat(bs, "patrol_start", buf, NULL);
00706 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00707 BotVoiceChatOnly(bs, bs->decisionmaker, VOICECHAT_YES);
00708 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
00709 bs->teammessage_time = 0;
00710 }
00711
00712 if (!bs->curpatrolpoint) {
00713 bs->ltgtype = 0;
00714 return qfalse;
00715 }
00716
00717 if (trap_BotTouchingGoal(bs->origin, &bs->curpatrolpoint->goal)) {
00718 if (bs->patrolflags & PATROL_BACK) {
00719 if (bs->curpatrolpoint->prev) {
00720 bs->curpatrolpoint = bs->curpatrolpoint->prev;
00721 }
00722 else {
00723 bs->curpatrolpoint = bs->curpatrolpoint->next;
00724 bs->patrolflags &= ~PATROL_BACK;
00725 }
00726 }
00727 else {
00728 if (bs->curpatrolpoint->next) {
00729 bs->curpatrolpoint = bs->curpatrolpoint->next;
00730 }
00731 else {
00732 bs->curpatrolpoint = bs->curpatrolpoint->prev;
00733 bs->patrolflags |= PATROL_BACK;
00734 }
00735 }
00736 }
00737
00738 if (bs->teamgoal_time < FloatTime()) {
00739 BotAI_BotInitialChat(bs, "patrol_stop", NULL);
00740 trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
00741 bs->ltgtype = 0;
00742 }
00743 if (!bs->curpatrolpoint) {
00744 bs->ltgtype = 0;
00745 return qfalse;
00746 }
00747 memcpy(goal, &bs->curpatrolpoint->goal, sizeof(bot_goal_t));
00748 return qtrue;
00749 }
00750 #ifdef CTF
00751 if (gametype == GT_CTF) {
00752
00753 if (bs->ltgtype == LTG_GETFLAG) {
00754
00755 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00756 BotAI_BotInitialChat(bs, "captureflag_start", NULL);
00757 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00758 BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
00759 bs->teammessage_time = 0;
00760 }
00761
00762 switch(BotTeam(bs)) {
00763 case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
00764 case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
00765 default: bs->ltgtype = 0; return qfalse;
00766 }
00767
00768 if (trap_BotTouchingGoal(bs->origin, goal)) {
00769
00770 switch(BotTeam(bs)) {
00771 case TEAM_RED: bs->blueflagstatus = 1; break;
00772 case TEAM_BLUE: bs->redflagstatus = 1; break;
00773 }
00774 bs->ltgtype = 0;
00775 }
00776
00777 if (bs->teamgoal_time < FloatTime()) {
00778 bs->ltgtype = 0;
00779 }
00780 BotAlternateRoute(bs, goal);
00781 return qtrue;
00782 }
00783
00784 if (bs->ltgtype == LTG_RUSHBASE && bs->rushbaseaway_time < FloatTime()) {
00785 switch(BotTeam(bs)) {
00786 case TEAM_RED: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
00787 case TEAM_BLUE: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
00788 default: bs->ltgtype = 0; return qfalse;
00789 }
00790
00791 if (!BotCTFCarryingFlag(bs)) bs->ltgtype = 0;
00792
00793 if (bs->teamgoal_time < FloatTime()) bs->ltgtype = 0;
00794
00795 if (trap_BotTouchingGoal(bs->origin, goal)) {
00796
00797
00798 if (BotCTFCarryingFlag(bs)) {
00799 trap_BotResetAvoidReach(bs->ms);
00800 bs->rushbaseaway_time = FloatTime() + 5 + 10 * random();
00801
00802 }
00803 else {
00804 bs->ltgtype = 0;
00805 }
00806 }
00807 BotAlternateRoute(bs, goal);
00808 return qtrue;
00809 }
00810
00811 if (bs->ltgtype == LTG_RETURNFLAG) {
00812
00813 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00814 BotAI_BotInitialChat(bs, "returnflag_start", NULL);
00815 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00816 BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
00817 bs->teammessage_time = 0;
00818 }
00819
00820 switch(BotTeam(bs)) {
00821 case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
00822 case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
00823 default: bs->ltgtype = 0; return qfalse;
00824 }
00825
00826 if (trap_BotTouchingGoal(bs->origin, goal)) bs->ltgtype = 0;
00827
00828 if (bs->teamgoal_time < FloatTime()) {
00829 bs->ltgtype = 0;
00830 }
00831 BotAlternateRoute(bs, goal);
00832 return qtrue;
00833 }
00834 }
00835 #endif //CTF
00836 #ifdef MISSIONPACK
00837 else if (gametype == GT_1FCTF) {
00838 if (bs->ltgtype == LTG_GETFLAG) {
00839
00840 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00841 BotAI_BotInitialChat(bs, "captureflag_start", NULL);
00842 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00843 BotVoiceChatOnly(bs, -1, VOICECHAT_ONGETFLAG);
00844 bs->teammessage_time = 0;
00845 }
00846 memcpy(goal, &ctf_neutralflag, sizeof(bot_goal_t));
00847
00848 if (trap_BotTouchingGoal(bs->origin, goal)) {
00849 bs->ltgtype = 0;
00850 }
00851
00852 if (bs->teamgoal_time < FloatTime()) {
00853 bs->ltgtype = 0;
00854 }
00855 return qtrue;
00856 }
00857
00858 if (bs->ltgtype == LTG_RUSHBASE) {
00859 switch(BotTeam(bs)) {
00860 case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
00861 case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
00862 default: bs->ltgtype = 0; return qfalse;
00863 }
00864
00865 if (!Bot1FCTFCarryingFlag(bs)) {
00866 bs->ltgtype = 0;
00867 }
00868
00869 if (bs->teamgoal_time < FloatTime()) {
00870 bs->ltgtype = 0;
00871 }
00872
00873 if (trap_BotTouchingGoal(bs->origin, goal)) {
00874 bs->ltgtype = 0;
00875 }
00876 BotAlternateRoute(bs, goal);
00877 return qtrue;
00878 }
00879
00880 if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
00881 bs->attackaway_time < FloatTime()) {
00882
00883 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00884 BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
00885 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00886 BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
00887 bs->teammessage_time = 0;
00888 }
00889 switch(BotTeam(bs)) {
00890 case TEAM_RED: memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); break;
00891 case TEAM_BLUE: memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); break;
00892 default: bs->ltgtype = 0; return qfalse;
00893 }
00894
00895 if (bs->teamgoal_time < FloatTime()) {
00896 bs->ltgtype = 0;
00897 }
00898
00899 if (trap_BotTouchingGoal(bs->origin, goal)) {
00900 bs->attackaway_time = FloatTime() + 2 + 5 * random();
00901 }
00902 return qtrue;
00903 }
00904
00905 if (bs->ltgtype == LTG_RETURNFLAG) {
00906
00907 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00908 BotAI_BotInitialChat(bs, "returnflag_start", NULL);
00909 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00910 BotVoiceChatOnly(bs, -1, VOICECHAT_ONRETURNFLAG);
00911 bs->teammessage_time = 0;
00912 }
00913
00914 if (bs->teamgoal_time < FloatTime()) {
00915 bs->ltgtype = 0;
00916 }
00917
00918 return BotGetItemLongTermGoal(bs, tfl, goal);
00919 }
00920 }
00921 else if (gametype == GT_OBELISK) {
00922 if (bs->ltgtype == LTG_ATTACKENEMYBASE &&
00923 bs->attackaway_time < FloatTime()) {
00924
00925
00926 if (bs->teammessage_time && bs->teammessage_time < FloatTime()) {
00927 BotAI_BotInitialChat(bs, "attackenemybase_start", NULL);
00928 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00929 BotVoiceChatOnly(bs, -1, VOICECHAT_ONOFFENSE);
00930 bs->teammessage_time = 0;
00931 }
00932 switch(BotTeam(bs)) {
00933 case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
00934 case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
00935 default: bs->ltgtype = 0; return qfalse;
00936 }
00937
00938 if (BotFeelingBad(bs) > 50) {
00939 return BotGetItemLongTermGoal(bs, tfl, goal);
00940 }
00941
00942 if (trap_BotTouchingGoal(bs->origin, goal)) {
00943 bs->attackaway_time = FloatTime() + 3 + 5 * random();
00944 }
00945
00946 VectorSubtract(bs->origin, goal->origin, dir);
00947 if (VectorLengthSquared(dir) < Square(60)) {
00948 bs->attackaway_time = FloatTime() + 3 + 5 * random();
00949 }
00950
00951 if (bs->teamgoal_time < FloatTime()) {
00952 bs->ltgtype = 0;
00953 }
00954 BotAlternateRoute(bs, goal);
00955
00956 return qtrue;
00957 }
00958 }
00959 else if (gametype == GT_HARVESTER) {
00960
00961 if (bs->ltgtype == LTG_RUSHBASE) {
00962 switch(BotTeam(bs)) {
00963 case TEAM_RED: memcpy(goal, &blueobelisk, sizeof(bot_goal_t)); break;
00964 case TEAM_BLUE: memcpy(goal, &redobelisk, sizeof(bot_goal_t)); break;
00965 default: BotGoHarvest(bs); return qfalse;
00966 }
00967
00968 if (!BotHarvesterCarryingCubes(bs)) {
00969 BotGoHarvest(bs);
00970 return qfalse;
00971 }
00972
00973 if (bs->teamgoal_time < FloatTime()) {
00974 BotGoHarvest(bs);
00975 return qfalse;
00976 }
00977
00978 if (trap_BotTouchingGoal(bs->origin, goal)) {
00979 BotGoHarvest(bs);
00980 return qfalse;
00981 }
00982 BotAlternateRoute(bs, goal);
00983 return qtrue;
00984 }
00985
00986 if (bs->ltgtype ==