#include "bg_saga.h"#include "../namespace_begin.h"#include "../namespace_end.h"Go to the source code of this file.
|
|
Definition at line 74 of file ai_main.h. Referenced by BotGetFlagHome(). |
|
|
Definition at line 75 of file ai_main.h. Referenced by BotGetEnemyFlag(). |
|
|
Definition at line 73 of file ai_main.h. Referenced by BotDefendFlag(). |
|
|
Definition at line 77 of file ai_main.h. Referenced by CTFFlagMovement(). |
|
|
Definition at line 68 of file ai_main.h. Referenced by CTFTakesPriority(). |
|
|
Definition at line 66 of file ai_main.h. Referenced by SiegeTakesPriority(). |
|
|
Definition at line 65 of file ai_main.h. Referenced by CTFTakesPriority(), and SiegeTakesPriority(). |
|
|
Definition at line 70 of file ai_main.h. Referenced by Siege_TargetClosestObjective(). |
|
|
Definition at line 71 of file ai_main.h. Referenced by Siege_TargetClosestObjective(). |
|
|
Definition at line 63 of file ai_main.h. Referenced by BotCheckDetPacks(). |
|
|
Definition at line 61 of file ai_main.h. Referenced by StandardBotAI(). |
|
|
Definition at line 62 of file ai_main.h. Referenced by StandardBotAI(). |
|
|
Definition at line 55 of file ai_main.h. Referenced by BotIsAChickenWuss(). |
|
|
Definition at line 79 of file ai_main.h. Referenced by StandardBotAI(). |
|
|
Definition at line 56 of file ai_main.h. Referenced by StandardBotAI(). |
|
|
Definition at line 48 of file ai_main.h. Referenced by BotGetWeaponRange(), GetIdealDestination(), and StandardBotAI(). |
|
|
Definition at line 46 of file ai_main.h. Referenced by BotGetWeaponRange(), BotIsAChickenWuss(), BotTrace_Jump(), CombatBotAI(), GetIdealDestination(), Siege_TargetClosestObjective(), and StandardBotAI(). |
|
|
Definition at line 47 of file ai_main.h. Referenced by BotGetWeaponRange(), GetIdealDestination(), and StandardBotAI(). |
|
|
Definition at line 49 of file ai_main.h. Referenced by BotGetWeaponRange(), BotIsAChickenWuss(), BotTrace_Jump(), CombatBotAI(), GetIdealDestination(), Siege_TargetClosestObjective(), and StandardBotAI(). |
|
|
|
|
|
Definition at line 57 of file ai_main.h. Referenced by BotDamageNotification(), GetNearestBadThing(), and StandardBotAI(). |
|
|
Definition at line 411 of file ai_main.h. Referenced by BotAIRegularUpdate(), and BotAISetupClient(). |
|
|
Definition at line 41 of file ai_main.h. Referenced by PassStandardEnemyChecks(). |
|
|
Definition at line 42 of file ai_main.h. Referenced by BotIsAChickenWuss(). |
|
|
Definition at line 40 of file ai_main.h. Referenced by LoadPath_ThisLevel(), and StandardBotAI(). |
|
|
|
|
|
Definition at line 10 of file ai_main.h. Referenced by BotDoChat(), BotUtilizePersonality(), and ReadChatGroups(). |
|
|
Definition at line 12 of file ai_main.h. Referenced by BotDoChat(). |
|
|
Definition at line 53 of file ai_main.h. Referenced by BotIsAChickenWuss(). |
|
|
|
|
|
Definition at line 17 of file ai_main.h. Referenced by ParseEmotionalAttachments(). |
|
|
Definition at line 15 of file ai_main.h. Referenced by ConnectTrail(), and G_RMGPathing(). |
|
|
Definition at line 51 of file ai_main.h. Referenced by CombatBotAI(), and StandardBotAI(). |
|
|
Definition at line 52 of file ai_main.h. Referenced by CombatBotAI(), and StandardBotAI(). |
|
|
Definition at line 14 of file ai_main.h. Referenced by ConnectTrail(). |
|
|
Definition at line 44 of file ai_main.h. Referenced by GetNewFlagPoint(). |
|
|
Definition at line 32 of file ai_main.h. Referenced by CreateNewWP_FromObject(), FlagObjects(), GetFlagStr(), PassWayCheck(), and StandardBotAI(). |
|
|
Definition at line 37 of file ai_main.h. Referenced by ConnectTrail(), and RepairPaths(). |
|
|
Definition at line 23 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), and WPConstantRoutine(). |
|
|
Definition at line 30 of file ai_main.h. Referenced by AcceptBotCommand(), CalculateWeightGoals(), GetBestIdleGoal(), and GetFlagStr(). |
|
|
Definition at line 22 of file ai_main.h. Referenced by AcceptBotCommand(), CalculateJumpRoutes(), GetFlagStr(), RepairPaths(), WPConstantRoutine(), and WPTouchRoutine(). |
|
|
Definition at line 38 of file ai_main.h. Referenced by ConnectTrail(), and G_RMGPathing(). |
|
|
Definition at line 35 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), StandardBotAI(), and WPTouchRoutine(). |
|
|
Definition at line 24 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), RepairPaths(), and StandardBotAI(). |
|
|
Definition at line 29 of file ai_main.h. Referenced by AcceptBotCommand(), ConnectTrail(), GetFlagStr(), OpposingEnds(), PassWayCheck(), and TotalTrailDistance(). |
|
|
Definition at line 28 of file ai_main.h. Referenced by AcceptBotCommand(), ConnectTrail(), GetFlagStr(), OpposingEnds(), PassWayCheck(), and TotalTrailDistance(). |
|
|
Definition at line 31 of file ai_main.h. Referenced by CreateNewWP_FromObject(), FlagObjects(), GetFlagStr(), PassWayCheck(), and StandardBotAI(). |
|
|
Definition at line 34 of file ai_main.h. Referenced by CalculateSiegeGoals(), GetFlagStr(), and SiegeTakesPriority(). |
|
|
Definition at line 33 of file ai_main.h. Referenced by CalculateSiegeGoals(), GetFlagStr(), and SiegeTakesPriority(). |
|
|
Definition at line 27 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), and WPTouchRoutine(). |
|
|
Definition at line 25 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), and WPTouchRoutine(). |
|
|
Definition at line 26 of file ai_main.h. Referenced by AcceptBotCommand(), GetFlagStr(), and StandardBotAI(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition at line 81 of file ai_main.h.
00082 {
00083 CTFSTATE_NONE,
00084 CTFSTATE_ATTACKER,
00085 CTFSTATE_DEFENDER,
00086 CTFSTATE_RETRIEVAL,
00087 CTFSTATE_GUARDCARRIER,
00088 CTFSTATE_GETFLAGHOME,
00089 CTFSTATE_MAXCTFSTATES
00090 } bot_ctf_state_t;
|
|
|
Definition at line 92 of file ai_main.h.
00093 {
00094 SIEGESTATE_NONE,
00095 SIEGESTATE_ATTACKER,
00096 SIEGESTATE_DEFENDER,
00097 SIEGESTATE_MAXSIEGESTATES
00098 } bot_siege_state_t;
|
|
|
Definition at line 100 of file ai_main.h.
00101 {
00102 TEAMPLAYSTATE_NONE,
00103 TEAMPLAYSTATE_FOLLOWING,
00104 TEAMPLAYSTATE_ASSISTING,
00105 TEAMPLAYSTATE_REGROUP,
00106 TEAMPLAYSTATE_MAXTPSTATES
00107 } bot_teamplay_state_t;
|
|
|
Definition at line 25 of file ai_util.c. References BG_Alloc(), G_Printf(), and NULL. Referenced by BotAISetupClient(), CreateNewWP(), CreateNewWP_FromObject(), CreateNewWP_InsertUnder(), CreateNewWP_InTrail(), and TransferWPData().
00026 {
00027 #ifdef BOT_ZMALLOC
00028 void *ptr = NULL;
00029 int i = 0;
00030
00031 #ifdef BOTMEMTRACK
00032 int free = 0;
00033 int used = 0;
00034
00035 while (i < MAX_BALLOC)
00036 {
00037 if (!BAllocList[i])
00038 {
00039 free++;
00040 }
00041 else
00042 {
00043 used++;
00044 }
00045
00046 i++;
00047 }
00048
00049 G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00050
00051 i = 0;
00052 #endif
00053
00054 ptr = trap_BotGetMemoryGame(size);
00055
00056 while (i < MAX_BALLOC)
00057 {
00058 if (!BAllocList[i])
00059 {
00060 BAllocList[i] = ptr;
00061 break;
00062 }
00063 i++;
00064 }
00065
00066 if (i == MAX_BALLOC)
00067 {
00068 //If this happens we'll have to rely on this chunk being freed manually with B_Free, which it hopefully will be
00069 #ifdef DEBUG
00070 G_Printf("WARNING: MAXIMUM B_ALLOC ALLOCATIONS EXCEEDED\n");
00071 #endif
00072 }
00073
00074 return ptr;
00075 #else
00076
00077 return BG_Alloc(size);
00078
00079 #endif
00080 }
|
|
|
Definition at line 82 of file ai_util.c. References G_Printf(), and NULL.
00083 {
00084 #ifdef BOT_ZMALLOC
00085 int i = 0;
00086
00087 #ifdef BOTMEMTRACK
00088 int free = 0;
00089 int used = 0;
00090
00091 while (i < MAX_BALLOC)
00092 {
00093 if (!BAllocList[i])
00094 {
00095 free++;
00096 }
00097 else
00098 {
00099 used++;
00100 }
00101
00102 i++;
00103 }
00104
00105 G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00106
00107 i = 0;
00108 #endif
00109
00110 while (i < MAX_BALLOC)
00111 {
00112 if (BAllocList[i] == ptr)
00113 {
00114 BAllocList[i] = NULL;
00115 break;
00116 }
00117
00118 i++;
00119 }
00120
00121 if (i == MAX_BALLOC)
00122 {
00123 //Likely because the limit was exceeded and we're now freeing the chunk manually as we hoped would happen
00124 #ifdef DEBUG
00125 G_Printf("WARNING: Freeing allocation which is not in the allocation structure\n");
00126 #endif
00127 }
00128
00129 trap_BotFreeMemoryGame(ptr);
00130 #endif
00131 }
|
|
|
Definition at line 14 of file ai_util.c. References BG_TempAlloc(). Referenced by BotDoChat(), BotUtilizePersonality(), GetFlagStr(), LoadPathData(), and SavePathData().
00015 {
00016 return BG_TempAlloc(size);
00017 }
|
|
|
Definition at line 19 of file ai_util.c. References BG_TempFree(). Referenced by BotDoChat(), BotUtilizePersonality(), BotWaypointRender(), LoadPathData(), and SavePathData().
00020 {
00021 BG_TempFree(size);
00022 }
|
|
||||||||||||||||
|
Definition at line 328 of file ai_util.c. References B_TempAlloc(), B_TempFree(), bot_state_t, bot_state_s::canChat, bot_state_s::chatAltObject, bot_state_s::chatFrequency, bot_state_s::chatObject, bot_state_s::chatTeam, bot_state_s::chatTime, bot_state_s::chatTime_stored, bot_state_s::client, gentity_s::client, bot_state_s::currentChat, bot_state_s::doChat, gBotChatBuffer, gentity_t, GetValueGroup(), level, MAX_CHAT_BUFFER_SIZE, MAX_CHAT_LINE_SIZE, clientPersistant_t::netname, NULL, gclient_s::pers, Q_irand(), strcmp(), strlen(), level_locals_t::time, and trap_Cvar_VariableIntegerValue(). Referenced by BotAISetupClient(), BotLovedOneDied(), BotOrder(), BotReplyGreetings(), and StandardBotAI().
00329 {
00330 char *chatgroup;
00331 int rVal;
00332 int inc_1;
00333 int inc_2;
00334 int inc_n;
00335 int lines;
00336 int checkedline;
00337 int getthisline;
00338 gentity_t *cobject;
00339
00340 if (!bs->canChat)
00341 {
00342 return 0;
00343 }
00344
00345 if (bs->doChat)
00346 { //already have a chat scheduled
00347 return 0;
00348 }
00349
00350 if (trap_Cvar_VariableIntegerValue("se_language"))
00351 { //no chatting unless English.
00352 return 0;
00353 }
00354
00355 if (Q_irand(1, 10) > bs->chatFrequency && !always)
00356 {
00357 return 0;
00358 }
00359
00360 bs->chatTeam = 0;
00361
00362 chatgroup = (char *)B_TempAlloc(MAX_CHAT_BUFFER_SIZE);
00363
00364 rVal = GetValueGroup(gBotChatBuffer[bs->client], section, chatgroup);
00365
00366 if (!rVal) //the bot has no group defined for the specified chat event
00367 {
00368 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00369 return 0;
00370 }
00371
00372 inc_1 = 0;
00373 inc_2 = 2;
00374
00375 while (chatgroup[inc_2] && chatgroup[inc_2] != '\0')
00376 {
00377 if (chatgroup[inc_2] != 13 && chatgroup[inc_2] != 9)
00378 {
00379 chatgroup[inc_1] = chatgroup[inc_2];
00380 inc_1++;
00381 }
00382 inc_2++;
00383 }
00384 chatgroup[inc_1] = '\0';
00385
00386 inc_1 = 0;
00387
00388 lines = 0;
00389
00390 while (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00391 {
00392 if (chatgroup[inc_1] == '\n')
00393 {
00394 lines++;
00395 }
00396 inc_1++;
00397 }
00398
00399 if (!lines)
00400 {
00401 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00402 return 0;
00403 }
00404
00405 getthisline = Q_irand(0, (lines+1));
00406
00407 if (getthisline < 1)
00408 {
00409 getthisline = 1;
00410 }
00411 if (getthisline > lines)
00412 {
00413 getthisline = lines;
00414 }
00415
00416 checkedline = 1;
00417
00418 inc_1 = 0;
00419
00420 while (checkedline != getthisline)
00421 {
00422 if (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00423 {
00424 if (chatgroup[inc_1] == '\n')
00425 {
00426 inc_1++;
00427 checkedline++;
00428 }
00429 }
00430
00431 if (checkedline == getthisline)
00432 {
00433 break;
00434 }
00435
00436 inc_1++;
00437 }
00438
00439 //we're at the starting position of the desired line here
00440 inc_2 = 0;
00441
00442 while (chatgroup[inc_1] != '\n')
00443 {
00444 chatgroup[inc_2] = chatgroup[inc_1];
00445 inc_2++;
00446 inc_1++;
00447 }
00448 chatgroup[inc_2] = '\0';
00449
00450 //trap_EA_Say(bs->client, chatgroup);
00451 inc_1 = 0;
00452 inc_2 = 0;
00453
00454 if (strlen(chatgroup) > MAX_CHAT_LINE_SIZE)
00455 {
00456 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00457 return 0;
00458 }
00459
00460 while (chatgroup[inc_1])
00461 {
00462 if (chatgroup[inc_1] == '%' && chatgroup[inc_1+1] != '%')
00463 {
00464 inc_1++;
00465
00466 if (chatgroup[inc_1] == 's' && bs->chatObject)
00467 {
00468 cobject = bs->chatObject;
00469 }
00470 else if (chatgroup[inc_1] == 'a' && bs->chatAltObject)
00471 {
00472 cobject = bs->chatAltObject;
00473 }
00474 else
00475 {
00476 cobject = NULL;
00477 }
00478
00479 if (cobject && cobject->client)
00480 {
00481 inc_n = 0;
00482
00483 while (cobject->client->pers.netname[inc_n])
00484 {
00485 bs->currentChat[inc_2] = cobject->client->pers.netname[inc_n];
00486 inc_2++;
00487 inc_n++;
00488 }
00489 inc_2--; //to make up for the auto-increment below
00490 }
00491 }
00492 else
00493 {
00494 bs->currentChat[inc_2] = chatgroup[inc_1];
00495 }
00496 inc_2++;
00497 inc_1++;
00498 }
00499 bs->currentChat[inc_2] = '\0';
00500
00501 if (strcmp(section, "GeneralGreetings") == 0)
00502 {
00503 bs->doChat = 2;
00504 }
00505 else
00506 {
00507 bs->doChat = 1;
00508 }
00509 bs->chatTime_stored = (strlen(bs->currentChat)*45)+Q_irand(1300, 1500);
00510 bs->chatTime = level.time + bs->chatTime_stored;
00511
00512 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00513
00514 return 1;
00515 }
|
|
|
Definition at line 2301 of file ai_main.c. References BOT_RUN_HEALTH, bot_state_t, BotGetWeaponRange(), BWEAPONRANGE_MELEE, BWEAPONRANGE_SABER, bot_state_s::chickenWussCalculationTime, bot_state_s::client, gentity_s::client, bot_state_s::cur_ps, bot_state_s::currentEnemy, playerState_s::electrifyTime, playerState_s::fd, forcedata_s::forcePowersActive, FP_RAGE, bot_state_s::frame_Enemy_Len, g_entities, g_gametype, gLevelFlags, GT_CTF, GT_JEDIMASTER, GT_SINGLE_PLAYER, gentity_s::health, vmCvar_t::integer, playerState_s::isJediMaster, level, LEVELFLAG_IMUSTNTRUNAWAY, MAX_CHICKENWUSS_TIME, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_REDFLAG, bot_state_s::saberSpecialist, level_locals_t::time, playerState_s::weapon, WP_BRYAR_PISTOL, WP_ROCKET_LAUNCHER, and WP_SABER. Referenced by GetIdealDestination(), and WPTouchRoutine().
02302 {
02303 int bWRange;
02304
02305 if (gLevelFlags & LEVELFLAG_IMUSTNTRUNAWAY)
02306 { //The level says we mustn't run away!
02307 return 0;
02308 }
02309
02310 if (g_gametype.integer == GT_SINGLE_PLAYER)
02311 { //"coop" (not really)
02312 return 0;
02313 }
02314
02315 if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster)
02316 { //Then you may know no fear.
02317 //Well, unless he's strong.
02318 if (bs->currentEnemy && bs->currentEnemy->client &&
02319 bs->currentEnemy->client->ps.isJediMaster &&
02320 bs->currentEnemy->health > 40 &&
02321 bs->cur_ps.weapon < WP_ROCKET_LAUNCHER)
02322 { //explosive weapons are most effective against the Jedi Master
02323 goto jmPass;
02324 }
02325 return 0;
02326 }
02327
02328 if (g_gametype.integer == GT_CTF && bs->currentEnemy && bs->currentEnemy->client)
02329 {
02330 if (bs->currentEnemy->client->ps.powerups[PW_REDFLAG] ||
02331 bs->currentEnemy->client->ps.powerups[PW_BLUEFLAG])
02332 { //don't be afraid of flag carriers, they must die!
02333 return 0;
02334 }
02335 }
02336
02337 jmPass:
02338 if (bs->chickenWussCalculationTime > level.time)
02339 {
02340 return 2; //don't want to keep going between two points...
02341 }
02342
02343 if (bs->cur_ps.fd.forcePowersActive & (1 << FP_RAGE))
02344 { //don't run while raging
02345 return 0;
02346 }
02347
02348 if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster)
02349 { //be frightened of the jedi master? I guess in this case.
02350 return 1;
02351 }
02352
02353 bs->chickenWussCalculationTime = level.time + MAX_CHICKENWUSS_TIME;
02354
02355 if (g_entities[bs->client].health < BOT_RUN_HEALTH)
02356 { //we're low on health, let's get away
02357 return 1;
02358 }
02359
02360 bWRange = BotGetWeaponRange(bs);
02361
02362 if (bWRange == BWEAPONRANGE_MELEE || bWRange == BWEAPONRANGE_SABER)
02363 {
02364 if (bWRange != BWEAPONRANGE_SABER || !bs->saberSpecialist)
02365 { //run away if we're using melee, or if we're using a saber and not a "saber specialist"
02366 return 1;
02367 }
02368 }
02369
02370 if (bs->cur_ps.weapon == WP_BRYAR_PISTOL)
02371 { //the bryar is a weak weapon, so just try to find a new one if it's what you're having to use
02372 return 1;
02373 }
02374
02375 if (bs->currentEnemy && bs->currentEnemy->client &&
02376 bs->currentEnemy->client->ps.weapon == WP_SABER &&
02377 bs->frame_Enemy_Len < 512 && bs->cur_ps.weapon != WP_SABER)
02378 { //if close to an enemy with a saber and not using a saber, then try to back off
02379 return 1;
02380 }
02381
02382 if ((level.time-bs->cur_ps.electrifyTime) < 16000)
02383 { //lightning is dangerous.
02384 return 1;
02385 }
02386
02387 //didn't run, reset the timer
02388 bs->chickenWussCalculationTime = 0;
02389
02390 return 0;
02391 }
|
|
|
Definition at line 924 of file ai_main.c. References bot_settings_t, bot_state_t, bot_state_s::client, client, bot_state_s::cur_ps, bot_state_s::entergame_time, bot_state_s::entitynum, bot_state_s::gs, bot_state_s::inuse, memcpy(), memset(), bot_state_s::ms, playerState_t, bot_state_s::settings, trap_BotResetAvoidGoals(), trap_BotResetAvoidReach(), trap_BotResetGoalState(), trap_BotResetMoveState(), trap_BotResetWeaponState(), and bot_state_s::ws. Referenced by BotAILoadMap().
00924 {
00925 int client, entitynum, inuse;
00926 int movestate, goalstate, weaponstate;
00927 bot_settings_t settings;
00928 playerState_t ps; //current player state
00929 float entergame_time;
00930
00931 //save some things that should not be reset here
00932 memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
00933 memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
00934 inuse = bs->inuse;
00935 client = bs->client;
00936 entitynum = bs->entitynum;
00937 movestate = bs->ms;
00938 goalstate = bs->gs;
00939 weaponstate = bs->ws;
00940 entergame_time = bs->entergame_time;
00941 //reset the whole state
00942 memset(bs, 0, sizeof(bot_state_t));
00943 //copy back some state stuff that should not be reset
00944 bs->ms = movestate;
00945 bs->gs = goalstate;
00946 bs->ws = weaponstate;
00947 memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
00948 memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
00949 bs->inuse = inuse;
00950 bs->client = client;
00951 bs->entitynum = entitynum;
00952 bs->entergame_time = entergame_time;
00953 //reset several states
00954 if (bs->ms) trap_BotResetMoveState(bs->ms);
00955 if (bs->gs) trap_BotResetGoalState(bs->gs);
00956 if (bs->ws) trap_BotResetWeaponState(bs->ws);
00957 if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
00958 if (bs->ms) trap_BotResetAvoidReach(bs->ms);
00959 }
|
|
|
Definition at line 614 of file ai_util.c. References botskills_s::accuracy, atof(), atoi(), B_TempAlloc(), B_TempFree(), bot_state_t, bot_state_s::botWeaponWeights, bot_state_s::canChat, bot_state_s::chatFrequency, bot_state_s::client, Com_sprintf(), DEFAULT_FORCEPOWERS, fileHandle_t, bot_state_s::forceinfo, FS_READ, G_Printf(), gBotChatBuffer, GetPairedValue(), GetValueGroup(), bot_state_s::isCamper, bot_state_s::loved_death_thresh, bot_state_s::lovednum, MAX_CHAT_BUFFER_SIZE, botskills_s::maxturn, ParseEmotionalAttachments(), botskills_s::perfectaim, bot_settings_s::personalityfile, ReadChatGroups(), botskills_s::reflex, S_COLOR_RED, bot_state_s::saberSpecialist, bot_state_s::settings, bot_state_s::skills, trap_FS_FCloseFile(), trap_FS_FOpenFile(), trap_FS_Read(), botskills_s::turnspeed, botskills_s::turnspeed_combat, WP_BLASTER, WP_BOWCASTER, WP_BRYAR_PISTOL, WP_DEMP2, WP_DET_PACK, WP_DISRUPTOR, WP_FLECHETTE, WP_MELEE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_STUN_BATON, WP_THERMAL, and WP_TRIP_MINE. Referenced by BotAISetupClient().
00615 {
00616 fileHandle_t f;
00617 int len, rlen;
00618 int failed;
00619 int i;
00620 //char buf[131072];
00621 char *buf = (char *)B_TempAlloc(131072);
00622 char *readbuf, *group;
00623
00624 len = trap_FS_FOpenFile(bs->settings.personalityfile, &f, FS_READ);
00625
00626 failed = 0;
00627
00628 if (!f)
00629 {
00630 G_Printf(S_COLOR_RED "Error: Specified personality not found\n");
00631 B_TempFree(131072); //buf
00632 return;
00633 }
00634
00635 if (len >= 131072)
00636 {
00637 G_Printf(S_COLOR_RED "Personality file exceeds maximum length\n");
00638 B_TempFree(131072); //buf
00639 return;
00640 }
00641
00642 trap_FS_Read(buf, len, f);
00643
00644 rlen = len;
00645
00646 while (len < 131072)
00647 { //kill all characters after the file length, since sometimes FS_Read doesn't do that entirely (or so it seems)
00648 buf[len] = '\0';
00649 len++;
00650 }
00651
00652 len = rlen;
00653
00654 readbuf = (char *)B_TempAlloc(1024);
00655 group = (char *)B_TempAlloc(65536);
00656
00657 if (!GetValueGroup(buf, "GeneralBotInfo", group))
00658 {
00659 G_Printf(S_COLOR_RED "Personality file contains no GeneralBotInfo group\n");
00660 failed = 1; //set failed so we know to set everything to default values
00661 }
00662
00663 if (!failed && GetPairedValue(group, "reflex", readbuf))
00664 {
00665 bs->skills.reflex = atoi(readbuf);
00666 }
00667 else
00668 {
00669 bs->skills.reflex = 100; //default
00670 }
00671
00672 if (!failed && GetPairedValue(group, "accuracy", readbuf))
00673 {
00674 bs->skills.accuracy = atof(readbuf);
00675 }
00676 else
00677 {
00678 bs->skills.accuracy = 10; //default
00679 }
00680
00681 if (!failed && GetPairedValue(group, "turnspeed", readbuf))
00682 {
00683 bs->skills.turnspeed = atof(readbuf);
00684 }
00685 else
00686 {
00687 bs->skills.turnspeed = 0.01f; //default
00688 }
00689
00690 if (!failed && GetPairedValue(group, "turnspeed_combat", readbuf))
00691 {
00692 bs->skills.turnspeed_combat = atof(readbuf);
00693 }
00694 else
00695 {
00696 bs->skills.turnspeed_combat = 0.05f; //default
00697 }
00698
00699 if (!failed && GetPairedValue(group, "maxturn", readbuf))
00700 {
00701 bs->skills.maxturn = atof(readbuf);
00702 }
00703 else
00704 {
00705 bs->skills.maxturn = 360; //default
00706 }
00707
00708 if (!failed && GetPairedValue(group, "perfectaim", readbuf))
00709 {
00710 bs->skills.perfectaim = atoi(readbuf);
00711 }
00712 else
00713 {
00714 bs->skills.perfectaim = 0; //default
00715 }
00716
00717 if (!failed && GetPairedValue(group, "chatability", readbuf))
00718 {
00719 bs->canChat = atoi(readbuf);
00720 }
00721 else
00722 {
00723 bs->canChat = 0; //default
00724 }
00725
00726 if (!failed && GetPairedValue(group, "chatfrequency", readbuf))
00727 {
00728 bs->chatFrequency = atoi(readbuf);
00729 }
00730 else
00731 {
00732 bs->chatFrequency = 5; //default
00733 }
00734
00735 if (!failed && GetPairedValue(group, "hatelevel", readbuf))
00736 {
00737 bs->loved_death_thresh = atoi(readbuf);
00738 }
00739 else
00740 {
00741 bs->loved_death_thresh = 3; //default
00742 }
00743
00744 if (!failed && GetPairedValue(group, "camper", readbuf))
00745 {
00746 bs->isCamper = atoi(readbuf);
00747 }
00748 else
00749 {
00750 bs->isCamper = 0; //default
00751 }
00752
00753 if (!failed && GetPairedValue(group, "saberspecialist", readbuf))
00754 {
00755 bs->saberSpecialist = atoi(readbuf);
00756 }
00757 else
00758 {
00759 bs->saberSpecialist = 0; //default
00760 }
00761
00762 if (!failed && GetPairedValue(group, "forceinfo", readbuf))
00763 {
00764 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", readbuf);
00765 }
00766 else
00767 {
00768 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", DEFAULT_FORCEPOWERS);
00769 }
00770
00771 i = 0;
00772
00773 while (i < MAX_CHAT_BUFFER_SIZE)
00774 { //clear out the chat buffer for this bot
00775 gBotChatBuffer[bs->client][i] = '\0';
00776 i++;
00777 }
00778
00779 if (bs->canChat)
00780 {
00781 if (!ReadChatGroups(bs, buf))
00782 {
00783 bs->canChat = 0;
00784 }
00785 }
00786
00787 if (GetValueGroup(buf, "BotWeaponWeights", group))
00788 {
00789 if (GetPairedValue(group, "WP_STUN_BATON", readbuf))
00790 {
00791 bs->botWeaponWeights[WP_STUN_BATON] = atoi(readbuf);
00792 bs->botWeaponWeights[WP_MELEE] = bs->botWeaponWeights[WP_STUN_BATON];
00793 }
00794
00795 if (GetPairedValue(group, "WP_SABER", readbuf))
00796 {
00797 bs->botWeaponWeights[WP_SABER] = atoi(readbuf);
00798 }
00799
00800 if (GetPairedValue(group, "WP_BRYAR_PISTOL", readbuf))
00801 {
00802 bs->botWeaponWeights[WP_BRYAR_PISTOL] = atoi(readbuf);
00803 }
00804
00805 if (GetPairedValue(group, "WP_BLASTER", readbuf))
00806 {
00807 bs->botWeaponWeights[WP_BLASTER] = atoi(readbuf);
00808 }
00809
00810 if (GetPairedValue(group, "WP_DISRUPTOR", readbuf))
00811 {
00812 bs->botWeaponWeights[WP_DISRUPTOR] = atoi(readbuf);
00813 }
00814
00815 if (GetPairedValue(group, "WP_BOWCASTER", readbuf))
00816 {
00817 bs->botWeaponWeights[WP_BOWCASTER] = atoi(readbuf);
00818 }
00819
00820 if (GetPairedValue(group, "WP_REPEATER", readbuf))
00821 {
00822 bs->botWeaponWeights[WP_REPEATER] = atoi(readbuf);
00823 }
00824
00825 if (GetPairedValue(group, "WP_DEMP2", readbuf))
00826 {
00827 bs->botWeaponWeights[WP_DEMP2] = atoi(readbuf);
00828 }
00829
00830 if (GetPairedValue(group, "WP_FLECHETTE", readbuf))
00831 {
00832 bs->botWeaponWeights[WP_FLECHETTE] = atoi(readbuf);
00833 }
00834
00835 if (GetPairedValue(group, "WP_ROCKET_LAUNCHER", readbuf))
00836 {
00837 bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = atoi(readbuf);
00838 }
00839
00840 if (GetPairedValue(group, "WP_THERMAL", readbuf))
00841 {
00842 bs->botWeaponWeights[WP_THERMAL] = atoi(readbuf);
00843 }
00844
00845 if (GetPairedValue(group, "WP_TRIP_MINE", readbuf))
00846 {
00847 bs->botWeaponWeights[WP_TRIP_MINE] = atoi(readbuf);
00848 }
00849
00850 if (GetPairedValue(group, "WP_DET_PACK", readbuf))
00851 {
00852 bs->botWeaponWeights[WP_DET_PACK] = atoi(readbuf);
00853 }
00854 }
00855
00856 bs->lovednum = 0;
00857
00858 if (GetValueGroup(buf, "EmotionalAttachments", group))
00859 {
00860 ParseEmotionalAttachments(bs, group);
00861 }
00862
00863 B_TempFree(131072); //buf
00864 B_TempFree(1024); //readbuf
00865 B_TempFree(65536); //group
00866 trap_FS_FCloseFile(f);
00867 }
|
|
|
Definition at line 224 of file ai_wpnav.c. References B_TempFree(), bot_wp_info, gentity_s::client, EV_SCOREPLUM, wpneighbor_s::forceJumpTo, g_entities, G_Printf(), G_TempEntity(), G_TestLine(), gBotEdit, gentity_t, GetFlagStr(), gLastPrintedIndex, gWPArray, gWPNum, gWPRenderedFrame, gWPRenderTime, wpobject_s::inuse, level, wpobject_s::neighbornum, wpobject_s::neighbors, wpneighbor_s::num, playerState_s::origin, wpobject_s::origin, gclient_s::ps, gentity_s::r, gentity_s::s, S_COLOR_YELLOW, SVF_BROADCAST, entityShared_t::svFlags, level_locals_t::time, entityState_s::time, vmCvar_t::value, vec3_t, and VectorSubtract. Referenced by BotAIStartFrame().
00225 {
00226 int i, n;
00227 int inc_checker;
00228 int bestindex;
00229 int gotbestindex;
00230 float bestdist;
00231 float checkdist;
00232 gentity_t *plum;
00233 gentity_t *viewent;
00234 char *flagstr;
00235 vec3_t a;
00236
00237 if (!gBotEdit)
00238 {
00239 return;
00240 }
00241
00242 bestindex = 0;
00243
00244 if (gWPRenderTime > level.time)
00245 {
00246 goto checkprint;
00247 }
00248
00249 gWPRenderTime = level.time + 100;
00250
00251 i = gWPRenderedFrame;
00252 inc_checker = gWPRenderedFrame;
00253
00254 while (i < gWPNum)
00255 {
00256 if (gWPArray[i] && gWPArray[i]->inuse)
00257 {
00258 plum = G_TempEntity( gWPArray[i]->origin, EV_SCOREPLUM );
00259 plum->r.svFlags |= SVF_BROADCAST;
00260 plum->s.time = i;
00261
00262 n = 0;
00263
00264 while (n < gWPArray[i]->neighbornum)
00265 {
00266 if (gWPArray[i]->neighbors[n].forceJumpTo && gWPArray[gWPArray[i]->neighbors[n].num])
00267 {
00268 G_TestLine(gWPArray[i]->origin, gWPArray[gWPArray[i]->neighbors[n].num]->origin, 0x0000ff, 5000);
00269 }
00270 n++;
00271 }
00272
00273 gWPRenderedFrame++;
00274 }
00275 else
00276 {
00277 gWPRenderedFrame = 0;
00278 break;
00279 }
00280
00281 if ((i - inc_checker) > 4)
00282 {
00283 break; //don't render too many at once
00284 }
00285 i++;
00286 }
00287
00288 if (i >= gWPNum)
00289 {
00290 gWPRenderTime = level.time + 1500; //wait a bit after we finish doing the whole trail
00291 gWPRenderedFrame = 0;
00292 }
00293
00294 checkprint:
00295
00296 if (!bot_wp_info.value)
00297 {
00298 return;
00299 }
00300
00301 viewent = &g_entities[0]; //only show info to the first client
00302
00303 if (!viewent || !viewent->client)
00304 { //client isn't in the game yet?
00305 return;
00306 }
00307
00308 bestdist = 256; //max distance for showing point info
00309 gotbestindex = 0;
00310
00311 i = 0;
00312
00313 while (i < gWPNum)
00314 {
00315 if (gWPArray[i] && gWPArray[i]->inuse)
00316 {
00317 VectorSubtract(viewent->client->ps.origin, gWPArray[i]->origin, a);
00318
00319 checkdist = VectorLength(a);
00320
00321 if (checkdist < bestdist)
00322 {
00323 bestdist = checkdist;
00324 bestindex = i;
00325 gotbestindex = 1;
00326 }
00327 }
00328 i++;
00329 }
00330
00331 if (gotbestindex && bestindex != gLastPrintedIndex)
00332 {
00333 flagstr = GetFlagStr(gWPArray[bestindex]->flags);
00334 gLastPrintedIndex = bestindex;
00335 G_Printf(S_COLOR_YELLOW "Waypoint %i\nFlags - %i (%s) (w%f)\nOrigin - (%i %i %i)\n", (int)(gWPArray[bestindex]->index), (int)(gWPArray[bestindex]->flags), flagstr, gWPArray[bestindex]->weight, (int)(gWPArray[bestindex]->origin[0]), (int)(gWPArray[bestindex]->origin[1]), (int)(gWPArray[bestindex]->origin[2]));
00336 //GetFlagStr allocates 128 bytes for this, if it's changed then obviously this must be as well
00337 B_TempFree(128); //flagstr
00338
00339 plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM );
00340 plum->r.svFlags |= SVF_BROADCAST;
00341 plum->s.time = bestindex; //render it once
00342 }
00343 else if (!gotbestindex)
00344 {
00345 gLastPrintedIndex = -1;
00346 }
00347 }
|
|
|
Definition at line 127 of file g_cmds.c.
00127 {
00128 int i, c, tlen;
00129 static char line[MAX_STRING_CHARS];
00130 int len;
00131 char arg[MAX_STRING_CHARS];
00132
00133 len = 0;
00134 c = trap_Argc();
00135 for ( i = start ; i < c ; i++ ) {
00136 trap_Argv( i, arg, sizeof( arg ) );
00137 tlen = strlen( arg );
00138 if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
00139 break;
00140 }
00141 memcpy( line + len, arg, tlen );
00142 len += tlen;
00143 if ( i != c - 1 ) {
00144 line[len] = ' ';
00145 len++;
00146 }
00147 }
00148
00149 line[len] = 0;
00150
00151 return line;
00152 }
|
|
|
Definition at line 3559 of file ai_main.c. References bot_state_t, BotHasAssociated(), wpobject_s::flags, gWPArray, gWPNum, wpobject_s::index, wpobject_s::inuse, bot_state_s::isCamper, level, Q_irand(), bot_state_s::randomNav, bot_state_s::randomNavTime, level_locals_t::time, TotalTrailDistance(), wpobject_s::weight, bot_state_s::wpCurrent, and WPFLAG_GOALPOINT. Referenced by CTFTakesPriority(), GetIdealDestination(), and SiegeTakesPriority().
03560 {
03561 int i = 0;
03562 int highestweight = 0;
03563 int desiredindex = -1;
03564 int dist_to_weight = 0;
03565 int traildist;
03566
03567 if (!bs->wpCurrent)
03568 {
03569 return -1;
03570 }
03571
03572 if (bs->isCamper != 2)
03573 {
03574 if (bs->randomNavTime < level.time)
03575 {
03576 if (Q_irand(1, 10) < 5)
03577 {
03578 bs->randomNav = 1;
03579 }
03580 else
03581 {
03582 bs->randomNav = 0;
03583 }
03584
03585 bs->randomNavTime = level.time + Q_irand(5000, 15000);
03586 }
03587 }
03588
03589 if (bs->randomNav)
03590 { //stop looking for items and/or camping on them
03591 return -1;
03592 }
03593
03594 while (i < gWPNum)
03595 {
03596 if (gWPArray[i] &&
03597 gWPArray[i]->inuse &&
03598 (gWPArray[i]->flags & WPFLAG_GOALPOINT) &&
03599 gWPArray[i]->weight > highestweight &&
03600 !BotHasAssociated(bs, gWPArray[i]))
03601 {
03602 traildist = TotalTrailDistance(bs->wpCurrent->index, i, bs);
03603
03604 if (traildist != -1)
03605 {
03606 dist_to_weight = (int)traildist/10000;
03607 dist_to_weight = (gWPArray[i]->weight)-dist_to_weight;
03608
03609 if (dist_to_weight > highestweight)
03610 {
03611 highestweight = dist_to_weight;
03612 desiredindex = i;
03613 }
03614 }
03615 }
03616
03617 i++;
03618 }
03619
03620 return desiredindex;
03621 }
|
|
||||||||||||
|
Definition at line 1104 of file ai_main.c. References BotPVSCheck(), g_RMG, gWPArray, gWPNum, vmCvar_t::integer, wpobject_s::inuse, OrgVisibleBox(), vec3_t, and VectorSubtract. Referenced by BotGetFlagBack(), BotGuardFlagCarrier(), CalculateSiegeGoals(), GetIdealDestination(), JMTakesPriority(), Siege_DefendFromAttackers(), and StandardBotAI().
01105 {
01106 int i;
01107 float bestdist;
01108 float flLen;
01109 int bestindex;
01110 vec3_t a, mins, maxs;
01111
01112 i = 0;
01113 if (g_RMG.integer)
01114 {
01115 bestdist = 300;
01116 }
01117 else
01118 {
01119 bestdist = 800;//99999;
01120 //don't trace over 800 units away to avoid GIANT HORRIBLE SPEED HITS ^_^
01121 }
01122 bestindex = -1;
01123
01124 mins[0] = -15;
01125 mins[1] = -15;
01126 mins[2] = -1;
01127 maxs[0] = 15;
01128 maxs[1] = 15;
01129 maxs[2] = 1;
01130
01131 while (i < gWPNum)
01132 {
01133 if (gWPArray[i] && gWPArray[i]->inuse)
01134 {
01135 VectorSubtract(org, gWPArray[i]->origin, a);
01136 flLen = VectorLength(a);
01137
01138 if (flLen < bestdist && (g_RMG.integer || BotPVSCheck(org, gWPArray[i]->origin)) && OrgVisibleBox(org, mins, maxs, gWPArray[i]->origin, ignore))
01139 {
01140 bestdist = flLen;
01141 bestindex = i;
01142 }
01143 }
01144
01145 i++;
01146 }
01147
01148 return bestindex;
01149 }
|
|
|
Definition at line 416 of file ai_main.c. References numbots.
00416 {
00417 return numbots;
00418 }
|
|
||||||||||||||||||||||||
|
Definition at line 1029 of file ai_main.c. References trace_t::allsolid, trace_t::fraction, g_RMG, vmCvar_t::integer, MASK_SOLID, NULL, trace_t::startsolid, trap_Trace(), and vec3_t. Referenced by CalculatePaths(), GetNearestVisibleWP(), and GetNearestVisibleWPToItem().
01030 {
01031 trace_t tr;
01032
01033 if (g_RMG.integer)
01034 {
01035 trap_Trace(&tr, org1, NULL, NULL, org2, ignore, MASK_SOLID);
01036 }
01037 else
01038 {
01039 trap_Trace(&tr, org1, mins, maxs, org2, ignore, MASK_SOLID);
01040 }
01041
01042 if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
01043 {
01044 return 1;
01045 }
01046
01047 return 0;
01048 }
|
|
||||||||||||
|
Definition at line 5931 of file ai_main.c. References entityShared_t::absmax, entityShared_t::absmin, botskills_s::accuracy, AltFiring(), playerState_s::ammo, bot_state_s::beStill, bot_forcepowers, bot_forgimmick, bot_getinthecarrr, bot_honorableduelacceptance, BOT_PLANT_DISTANCE, BOT_PLANT_INTERVAL, BOT_SABER_THROW_RANGE, bot_state_t, BOT_WPTOUCH_DISTANCE, BotAimLeading(), BotAimOffsetGoalAngles(), bot_state_s::botChallengingTime, BotCheckDetPacks(), BotDeathNotify(), BotDoChat(), BotDoTeamplayAI(), BotFallbackNavigation(), BotGetWeaponRange(), BotMindTricked(), BotReplyGreetings(), BotScanForLeader(), BotSelectChoiceWeapon(), BotSelectIdealWeapon(), botstates, BotSurfaceNear(), BotTrace_Duck(), BotTrace_Jump(), BotTrace_Strafe(), BotTryAnotherWeapon(), BotUseInventoryItem(), BotWeaponBlockable(), BotWeaponCanLead(), BWEAPONRANGE_LONG, BWEAPONRANGE_MELEE, BWEAPONRANGE_MID, BWEAPONRANGE_SABER, CA_ACTIVE, CA_AUTHORIZING, bot_state_s::campStanding, bot_state_s::chatAltObject, bot_state_s::chatObject, bot_state_s::chatTeam, bot_state_s::chatTime, CheckForFriendInLOF(), CheckForFunc(), CLASS_VEHICLE, client, gentity_s::client, bot_state_s::client, level_locals_t::clients, Cmd_EngageDuel_f(), Cmd_SaberAttackCycle_f(), Cmd_ToggleSaber_f(), CombatBotAI(), CommanderBotAI(), clientPersistant_t::connected, CTFFlagMovement(), bot_state_s::cur_ps, bot_state_s::currentChat, bot_state_s::currentEnemy, entityShared_t::currentOrigin, bot_state_s::dangerousObject, bot_state_s::deathActivitiesDone, bot_state_s::destinationGrabTime, bot_state_s::doAltAttack, bot_state_s::doAttack, bot_state_s::doChat, bot_state_s::doForcePush, bot_state_s::doingFallback, bot_state_s::duckTime, playerState_s::duelIndex, playerState_s::duelInProgress, playerState_s::duelTime, playerState_s::electrifyTime, ENEMY_FORGET_MS, bot_state_s::enemySeenTime, ENTITYNUM_NONE, EntityVisibleBox(), ET_NPC, entityState_s::eType, bot_state_s::eye, playerState_s::fd, wpobject_s::flags, FORCE_DARKSIDE, FORCE_LEVEL_1, FORCE_LIGHTNING_RADIUS, FORCE_LIGHTSIDE, forcedata_s::forceGripBeingGripped, forcedata_s::forceGripCripple, bot_state_s::forceJumpChargeTime, bot_state_s::forceJumping, bot_state_s::forceMove_Forward, bot_state_s::forceMove_Right, bot_state_s::forceMove_Up, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcePowerNeeded, forcedata_s::forcePowersActive, forcedata_s::forcePowersKnown, ForcePowerUsableOn(), forcedata_s::forceSide, bot_state_s::forceWeaponSelect, FP_ABSORB, FP_DRAIN, FP_GRIP, FP_HEAL, FP_LEVITATION, FP_LIGHTNING, FP_PROTECT, FP_PULL, FP_PUSH, FP_RAGE, FP_SABER_OFFENSE, FP_SABERTHROW, FP_SEE, FP_SPEED, FP_TEAM_FORCE, FP_TEAM_HEAL, FP_TELEPATHY, bot_state_s::frame_Enemy_Len, bot_state_s::frame_Enemy_Vis, bot_state_s::frame_Waypoint_Len, bot_state_s::frame_Waypoint_Vis, g_entities, g_forcePowerDisable, g_gametype, g_privateDuel, g_RMG, gDeactivated, gentity_t, GetIdealDestination(), GetNearestVisibleWP(), gJMSaberEnt, gLevelFlags, bot_state_s::goalAngles, bot_state_s::goalMovedir, bot_state_s::goalPosition, GT_JEDIMASTER, GT_SINGLE_PLAYER, GT_TEAM, gWPArray, gWPNum, playerState_s::hasDetPackPlanted, gentity_s::health, bot_state_s::hereWhenSpotted, bot_state_s::hitSpotted, bot_state_s::iHaveNoIdeaWhereIAmGoing, wpobject_s::index, InFieldOfVision(), vmCvar_t::integer, wpobject_s::inuse, gentity_s::inuse, bot_state_s::isCamping, playerState_s::isJediMaster, bot_state_s::isSquadLeader, bot_state_s::jDelay, bot_state_s::jmState, bot_state_s::jumpHoldTime, bot_state_s::jumpPrep, bot_state_s::jumpTime, KeepAltFromFiring(), KeepPrimFromFiring(), bot_state_s::lastAttacked, bot_state_s::lastDeadTime, bot_state_s::lastEnemySpotted, bot_state_s::lastHurt, bot_state_s::lastSignificantAreaChange, bot_state_s::lastSignificantChangeTime, bot_state_s::lastVisibleEnemyIndex, level, LEVELFLAG_NOPOINTPREDICTION, playerState_s::m_iVehicleNum, gentity_s::m_pVehicle, MAX_DRAIN_DISTANCE, MAX_GENTITIES, MAX_GRIP_DISTANCE, MAX_TRICK_DISTANCE, MELEE_ATTACK_RANGE, MeleeCombatHandling(), bot_state_s::meleeStrafeDir, bot_state_s::meleeStrafeDisable, MoveTowardIdealAngles(), bot_state_s::noUseTime, entityState_s::NPC_class, NULL, entityState_s::number, OrgVisible(), entityState_s::origin, wpobject_s::origin, bot_state_s::origin, playerState_s::origin, PassLovedOneCheck(), PassStandardEnemyChecks(), PassWayCheck(), gclient_s::pers, PITCH, bot_state_s::plantContinue, bot_state_s::plantDecided, bot_state_s::plantKillEmAll, bot_state_s::plantTime, playerState_s::pm_flags, PMF_JUMP_HELD, PrimFiring(), gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, rand(), botskills_s::reflex, bot_state_s::revengeEnemy, bot_state_s::revengeHateLevel, gentity_s::s, SABER_ATTACK_RANGE, forcedata_s::saberAnimLevel, SaberCombatHandling(), bot_state_s::saberDefending, playerState_s::saberEntityNum, playerState_s::saberHolstered, playerState_s::saberInFlight, playerState_s::saberLockTime, bot_state_s::saberPower, bot_state_s::saberPowerTime, bot_state_s::saberThrowTime, ScanForEnemies(), bot_state_s::settings, bot_state_s::shootGoal, bot_settings_s::skill, bot_state_s::skills, bot_state_s::squadCannotLead, bot_state_s::squadLeader, SS_DUAL, SS_FAST, SS_MEDIUM, SS_STAFF, SS_STRONG, STRAFEAROUND_LEFT, STRAFEAROUND_RIGHT, StrafeTracing(), gentity_s::takedamage, TEAM_SPECTATOR, level_locals_t::time, bot_state_s::timeToReact, TotalTrailDistance(), trap_EA_Alt_Attack(), trap_EA_Attack(), trap_EA_Crouch(), trap_EA_ForcePower(), trap_EA_Jump(), trap_EA_Move(), trap_EA_MoveBack(), trap_EA_MoveForward(), trap_EA_MoveLeft(), trap_EA_MoveRight(), trap_EA_Say(), trap_EA_SayTeam(), trap_EA_Use(), vec3_origin, vec3_t, vectoangles(), VectorCopy, VectorNormalize(), VectorSubtract, bot_state_s::viewangles, playerState_s::viewheight, WaitingForNow(), playerState_s::weapon, WEAPON_CHARGING, WEAPON_CHARGING_ALT, WEAPON_READY, weaponData, playerState_s::weaponstate, WP_DET_PACK, WP_FLECHETTE, WP_SABER, WP_TRIP_MINE, bot_state_s::wpCamping, bot_state_s::wpCampingTo, WPConstantRoutine(), bot_state_s::wpCurrent, bot_state_s::wpDestIgnoreTime, bot_state_s::wpDestination, bot_state_s::wpDestSwitchTime, bot_state_s::wpDirection, WPFLAG_BLUE_FLAG, WPFLAG_NOMOVEFUNC, WPFLAG_NOVIS, WPFLAG_RED_FLAG, WPFLAG_WAITFORFUNC, WPOrgVisible(), bot_state_s::wpSeenTime, bot_state_s::wpStoreDest, bot_state_s::wpSwitchTime, WPTouchRoutine(), bot_state_s::wpTravelTime, and YAW. Referenced by BotAI().
05932 {
05933 int wp, enemy;
05934 int desiredIndex;
05935 int goalWPIndex;
05936 int doingFallback = 0;
05937 int fjHalt;
05938 vec3_t a, ang, headlevel, eorg, noz_x, noz_y, dif, a_fo;
05939 float reaction;
05940 float bLeadAmount;
05941 int meleestrafe = 0;
05942 int useTheForce = 0;
05943 int forceHostile = 0;
05944 int cBAI = 0;
05945 gentity_t *friendInLOF = 0;
05946 float mLen;
05947 int visResult = 0;
05948 int selResult = 0;
05949 int mineSelect = 0;
05950 int detSelect = 0;
05951 vec3_t preFrameGAngles;
05952
05953 if (gDeactivated)
05954 {
05955 bs->wpCurrent = NULL;
05956 bs->currentEnemy = NULL;
05957 bs->wpDestination = NULL;
05958 bs->wpDirection = 0;
05959 return;
05960 }
05961
05962 if (g_entities[bs->client].inuse &&
05963 g_entities[bs->client].client &&
05964 g_entities[bs->client].client->sess.sessionTeam == TEAM_SPECTATOR)
05965 {
05966 bs->wpCurrent = NULL;
05967 bs->currentEnemy = NULL;
05968 bs->wpDestination = NULL;
05969 bs->wpDirection = 0;
05970 return;
05971 }
05972
05973
05974 #ifndef FINAL_BUILD
05975 if (bot_getinthecarrr.integer)
05976 { //stupid vehicle debug, I tire of having to connect another client to test passengers.
05977 gentity_t *botEnt = &g_entities[bs->client];
05978
05979 if (botEnt->inuse && botEnt->client && botEnt->client->ps.m_iVehicleNum)
05980 { //in a vehicle, so...
05981 bs->noUseTime = level.time + 5000;
05982
05983 if (bot_getinthecarrr.integer != 2)
05984 {
05985 trap_EA_MoveForward(bs->client);
05986
05987 if (bot_getinthecarrr.integer == 3)
05988 { //use alt fire
05989 trap_EA_Alt_Attack(bs->client);
05990 }
05991 }
05992 }
05993 else
05994 { //find one, get in
05995 int i = 0;
05996 gentity_t *vehicle = NULL;
05997 //find the nearest, manned vehicle
05998 while (i < MAX_GENTITIES)
05999 {
06000 vehicle = &g_entities[i];
06001
06002 if (vehicle->inuse && vehicle->client && vehicle->s.eType == ET_NPC &&
06003 vehicle->s.NPC_class == CLASS_VEHICLE && vehicle->m_pVehicle &&
06004 (vehicle->client->ps.m_iVehicleNum || bot_getinthecarrr.integer == 2))
06005 { //ok, this is a vehicle, and it has a pilot/passengers
06006 break;
06007 }
06008 i++;
06009 }
06010 if (i != MAX_GENTITIES && vehicle)
06011 { //broke before end so we must've found something
06012 vec3_t v;
06013
06014 VectorSubtract(vehicle->client->ps.origin, bs->origin, v);
06015 VectorNormalize(v);
06016 vectoangles(v, bs->goalAngles);
06017 MoveTowardIdealAngles(bs);
06018 trap_EA_Move(bs->client, v, 5000.0f);
06019
06020 if (bs->noUseTime < (level.time-400))
06021 {
06022 bs->noUseTime = level.time + 500;
06023 }
06024 }
06025 }
06026
06027 return;
06028 }
06029 #endif
06030
06031 if (bot_forgimmick.integer)
06032 {
06033 bs->wpCurrent = NULL;
06034 bs->currentEnemy = NULL;
06035 bs->wpDestination = NULL;
06036 bs->wpDirection = 0;
06037
06038 if (bot_forgimmick.integer == 2)
06039 { //for debugging saber stuff, this is handy
06040 trap_EA_Attack(bs->client);
06041 }
06042
06043 if (bot_forgimmick.integer == 3)
06044 { //for testing cpu usage moving around rmg terrain without AI
06045 vec3_t mdir;
06046
06047 VectorSubtract(bs->origin, vec3_origin, mdir);
06048 VectorNormalize(mdir);
06049 trap_EA_Attack(bs->client);
06050 trap_EA_Move(bs->client, mdir, 5000);
06051 }
06052
06053 if (bot_forgimmick.integer == 4)
06054 { //constantly move toward client 0
06055 if (g_entities[0].client && g_entities[0].inuse)
06056 {
06057 vec3_t mdir;
06058
06059 VectorSubtract(g_entities[0].client->ps.origin, bs->origin, mdir);
06060 VectorNormalize(mdir);
06061 trap_EA_Move(bs->client, mdir, 5000);
06062 }
06063 }
06064
06065 if (bs->forceMove_Forward)
06066 {
06067 if (bs->forceMove_Forward > 0)
06068 {
06069 trap_EA_MoveForward(bs->client);
06070 }
06071 else
06072 {
06073 trap_EA_MoveBack(bs->client);
06074 }
06075 }
06076 if (bs->forceMove_Right)
06077 {
06078 if (bs->forceMove_Right > 0)
06079 {
06080 trap_EA_MoveRight(bs->client);
06081 }
06082 else
06083 {
06084 trap_EA_MoveLeft(bs->client);
06085 }
06086 }
06087 if (bs->forceMove_Up)
06088 {
06089 trap_EA_Jump(bs->client);
06090 }
06091 return;
06092 }
06093
06094 if (!bs->lastDeadTime)
06095 { //just spawned in?
06096 bs->lastDeadTime = level.time;
06097 }
06098
06099 if (g_entities[bs->client].health < 1)
06100 {
06101 bs->lastDeadTime = level.time;
06102
06103 if (!bs->deathActivitiesDone && bs->lastHurt && bs->lastHurt->client && bs->lastHurt->s.number != bs->client)
06104 {
06105 BotDeathNotify(bs);
06106 if (PassLovedOneCheck(bs, bs->lastHurt))
06107 {
06108 //CHAT: Died
06109 bs->chatObject = bs->lastHurt;
06110 bs->chatAltObject = NULL;
06111 BotDoChat(bs, "Died", 0);
06112 }
06113 else if (!PassLovedOneCheck(bs, bs->lastHurt) &&
06114 botstates[bs->lastHurt->s.number] &&
06115 PassLovedOneCheck(botstates[bs->lastHurt->s.number], &g_entities[bs->client]))
06116 { //killed by a bot that I love, but that does not love me
06117 bs->chatObject = bs->lastHurt;
06118 bs->chatAltObject = NULL;
06119 BotDoChat(bs, "KilledOnPurposeByLove", 0);
06120 }
06121
06122 bs->deathActivitiesDone = 1;
06123 }
06124
06125 bs->wpCurrent = NULL;
06126 bs->currentEnemy = NULL;
06127 bs->wpDestination = NULL;
06128 bs->wpCamping = NULL;
06129 bs->wpCampingTo = NULL;
06130 bs->wpStoreDest = NULL;
06131 bs->wpDestIgnoreTime = 0;
06132 bs->wpDestSwitchTime = 0;
06133 bs->wpSeenTime = 0;
06134 bs->wpDirection = 0;
06135
06136 if (rand()%10 < 5 &&
06137 (!bs->doChat || bs->chatTime < level.time))
06138 {
06139 trap_EA_Attack(bs->client);
06140 }
06141
06142 return;
06143 }
06144
06145 VectorCopy(bs->goalAngles, preFrameGAngles);
06146
06147 bs->doAttack = 0;
06148 bs->doAltAttack = 0;
06149 //reset the attack states
06150
06151 if (bs->isSquadLeader)
06152 {
06153 CommanderBotAI(bs);
06154 }
06155 else
06156 {
06157 BotDoTeamplayAI(bs);
06158 }
06159
06160 if (!bs->currentEnemy)
06161 {
06162 bs->frame_Enemy_Vis = 0;
06163 }
06164
06165 if (bs->revengeEnemy && bs->revengeEnemy->client &&
06166 bs->revengeEnemy->client->pers.connected != CA_ACTIVE && bs->revengeEnemy->client->pers.connected != CA_AUTHORIZING)
06167 {
06168 bs->revengeEnemy = NULL;
06169 bs->revengeHateLevel = 0;
06170 }
06171
06172 if (bs->currentEnemy && bs->currentEnemy->client &&
06173 bs->currentEnemy->client->pers.connected != CA_ACTIVE && bs->currentEnemy->client->pers.connected != CA_AUTHORIZING)
06174 {
06175 bs->currentEnemy = NULL;
06176 }
06177
06178 fjHalt = 0;
06179
06180 #ifndef FORCEJUMP_INSTANTMETHOD
06181 if (bs->forceJumpChargeTime > level.time)
06182 {
06183 useTheForce = 1;
06184 forceHostile = 0;
06185 }
06186
06187 if (bs->currentEnemy && bs->currentEnemy->client && bs->frame_Enemy_Vis && bs->forceJumpChargeTime < level.time)
06188 #else
06189 if (bs->currentEnemy && bs->currentEnemy->client && bs->frame_Enemy_Vis)
06190 #endif
06191 {
06192 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, a_fo);
06193 vectoangles(a_fo, a_fo);
06194
06195 //do this above all things
06196 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PUSH)) && (bs->doForcePush > level.time || bs->cur_ps.fd.forceGripBeingGripped > level.time) && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PUSH]][FP_PUSH] /*&& InFieldOfVision(bs->viewangles, 50, a_fo)*/)
06197 {
06198 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PUSH;
06199 useTheForce = 1;
06200 forceHostile = 1;
06201 }
06202 else if (bs->cur_ps.fd.forceSide == FORCE_DARKSIDE)
06203 { //try dark side powers
06204 //in order of priority top to bottom
06205 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_GRIP)) && (bs->cur_ps.fd.forcePowersActive & (1 << FP_GRIP)) && InFieldOfVision(bs->viewangles, 50, a_fo))
06206 { //already gripping someone, so hold it
06207 level.clients[bs->client].ps.fd.forcePowerSelected = FP_GRIP;
06208 useTheForce = 1;
06209 forceHostile = 1;
06210 }
06211 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_LIGHTNING)) && bs->frame_Enemy_Len < FORCE_LIGHTNING_RADIUS && level.clients[bs->client].ps.fd.forcePower > 50 && InFieldOfVision(bs->viewangles, 50, a_fo))
06212 {
06213 level.clients[bs->client].ps.fd.forcePowerSelected = FP_LIGHTNING;
06214 useTheForce = 1;
06215 forceHostile = 1;
06216 }
06217 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_GRIP)) && bs->frame_Enemy_Len < MAX_GRIP_DISTANCE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_GRIP]][FP_GRIP] && InFieldOfVision(bs->viewangles, 50, a_fo))
06218 {
06219 level.clients[bs->client].ps.fd.forcePowerSelected = FP_GRIP;
06220 useTheForce = 1;
06221 forceHostile = 1;
06222 }
06223 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_RAGE)) && g_entities[bs->client].health < 25 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_RAGE]][FP_RAGE])
06224 {
06225 level.clients[bs->client].ps.fd.forcePowerSelected = FP_RAGE;
06226 useTheForce = 1;
06227 forceHostile = 0;
06228 }
06229 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_DRAIN)) && bs->frame_Enemy_Len < MAX_DRAIN_DISTANCE && level.clients[bs->client].ps.fd.forcePower > 50 && InFieldOfVision(bs->viewangles, 50, a_fo) && bs->currentEnemy->client->ps.fd.forcePower > 10 && bs->currentEnemy->client->ps.fd.forceSide == FORCE_LIGHTSIDE)
06230 {
06231 level.clients[bs->client].ps.fd.forcePowerSelected = FP_DRAIN;
06232 useTheForce = 1;
06233 forceHostile = 1;
06234 }
06235 }
06236 else if (bs->cur_ps.fd.forceSide == FORCE_LIGHTSIDE)
06237 { //try light side powers
06238 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && bs->cur_ps.fd.forceGripCripple &&
06239 level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06240 { //absorb to get out
06241 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06242 useTheForce = 1;
06243 forceHostile = 0;
06244 }
06245 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && bs->cur_ps.electrifyTime >= level.time &&
06246 level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06247 { //absorb lightning
06248 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06249 useTheForce = 1;
06250 forceHostile = 0;
06251 }
06252 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_TELEPATHY)) && bs->frame_Enemy_Len < MAX_TRICK_DISTANCE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TELEPATHY]][FP_TELEPATHY] && InFieldOfVision(bs->viewangles, 50, a_fo) && !(bs->currentEnemy->client->ps.fd.forcePowersActive & (1 << FP_SEE)))
06253 {
06254 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TELEPATHY;
06255 useTheForce = 1;
06256 forceHostile = 1;
06257 }
06258 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && g_entities[bs->client].health < 75 && bs->currentEnemy->client->ps.fd.forceSide == FORCE_DARKSIDE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06259 {
06260 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06261 useTheForce = 1;
06262 forceHostile = 0;
06263 }
06264 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PROTECT)) && g_entities[bs->client].health < 35 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PROTECT]][FP_PROTECT])
06265 {
06266 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PROTECT;
06267 useTheForce = 1;
06268 forceHostile = 0;
06269 }
06270 }
06271
06272 if (!useTheForce)
06273 { //try neutral powers
06274 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PUSH)) && bs->cur_ps.fd.forceGripBeingGripped > level.time && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PUSH]][FP_PUSH] && InFieldOfVision(bs->viewangles, 50, a_fo))
06275 {
06276 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PUSH;
06277 useTheForce = 1;
06278 forceHostile = 1;
06279 }
06280 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_SPEED)) && g_entities[bs->client].health < 25 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_SPEED]][FP_SPEED])
06281 {
06282 level.clients[bs->client].ps.fd.forcePowerSelected = FP_SPEED;
06283 useTheForce = 1;
06284 forceHostile = 0;
06285 }
06286 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_SEE)) && BotMindTricked(bs->client, bs->currentEnemy->s.number) && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_SEE]][FP_SEE])
06287 {
06288 level.clients[bs->client].ps.fd.forcePowerSelected = FP_SEE;
06289 useTheForce = 1;
06290 forceHostile = 0;
06291 }
06292 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PULL)) && bs->frame_Enemy_Len < 256 && level.clients[bs->client].ps.fd.forcePower > 75 && InFieldOfVision(bs->viewangles, 50, a_fo))
06293 {
06294 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PULL;
06295 useTheForce = 1;
06296 forceHostile = 1;
06297 }
06298 }
06299 }
06300
06301 if (!useTheForce)
06302 { //try powers that we don't care if we have an enemy for
06303 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_HEAL)) && g_entities[bs->client].health < 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_HEAL]][FP_HEAL] && bs->cur_ps.fd.forcePowerLevel[FP_HEAL] > FORCE_LEVEL_1)
06304 {
06305 level.clients[bs->client].ps.fd.forcePowerSelected = FP_HEAL;
06306 useTheForce = 1;
06307 forceHostile = 0;
06308 }
06309 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_HEAL)) && g_entities[bs->client].health < 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_HEAL]][FP_HEAL] && !bs->currentEnemy && bs->isCamping > level.time)
06310 { //only meditate and heal if we're camping
06311 level.clients[bs->client].ps.fd.forcePowerSelected = FP_HEAL;
06312 useTheForce = 1;
06313 forceHostile = 0;
06314 }
06315 }
06316
06317 if (useTheForce && forceHostile)
06318 {
06319 if (bs->currentEnemy && bs->currentEnemy->client &&
06320 !ForcePowerUsableOn(&g_entities[bs->client], bs->currentEnemy, level.clients[bs->client].ps.fd.forcePowerSelected))
06321 {
06322 useTheForce = 0;
06323 forceHostile = 0;
06324 }
06325 }
06326
06327 doingFallback = 0;
06328
06329 bs->deathActivitiesDone = 0;
06330
06331 if (BotUseInventoryItem(bs))
06332 {
06333 if (rand()%10 < 5)
06334 {
06335 trap_EA_Use(bs->client);
06336 }
06337 }
06338
06339 if (bs->cur_ps.ammo[weaponData[bs->cur_ps.weapon].ammoIndex] < weaponData[bs->cur_ps.weapon].energyPerShot)
06340 {
06341 if (BotTryAnotherWeapon(bs))
06342 {
06343 return;
06344 }
06345 }
06346 else
06347 {
06348 if (bs->currentEnemy && bs->lastVisibleEnemyIndex == bs->currentEnemy->s.number &&
06349 bs->frame_Enemy_Vis && bs->forceWeaponSelect /*&& bs->plantContinue < level.time*/)
06350 {
06351 bs->forceWeaponSelect = 0;
06352 }
06353
06354 if (bs->plantContinue > level.time)
06355 {
06356 bs->doAttack = 1;
06357 bs->destinationGrabTime = 0;
06358 }
06359
06360 if (!bs->forceWeaponSelect && bs->cur_ps.hasDetPackPlanted && bs->plantKillEmAll > level.time)
06361 {
06362 bs->forceWeaponSelect = WP_DET_PACK;
06363 }
06364
06365 if (bs->forceWeaponSelect)
06366 {
06367 selResult = BotSelectChoiceWeapon(bs, bs->forceWeaponSelect, 1);
06368 }
06369
06370 if (selResult)
06371 {
06372 if (selResult == 2)
06373 { //newly selected
06374 return;
06375 }
06376 }
06377 else if (BotSelectIdealWeapon(bs))
06378 {
06379 return;
06380 }
06381 }
06382 /*if (BotSelectMelee(bs))
06383 {
06384 return;
06385 }*/
06386
06387 reaction = bs->skills.reflex/bs->settings.skill;
06388
06389 if (reaction < 0)
06390 {
06391 reaction = 0;
06392 }
06393 if (reaction > 2000)
06394 {
06395 reaction = 2000;
06396 }
06397
06398 if (!bs->currentEnemy)
06399 {
06400 bs->timeToReact = level.time + reaction;
06401 }
06402
06403 if (bs->cur_ps.weapon == WP_DET_PACK && bs->cur_ps.hasDetPackPlanted && bs->plantKillEmAll > level.time)
06404 {
06405 bs->doAltAttack = 1;
06406 }
06407
06408 if (bs->wpCamping)
06409 {
06410 if (bs->isCamping < level.time)
06411 {
06412 bs->wpCamping = NULL;
06413 bs->isCamping = 0;
06414 }
06415
06416 if (bs->currentEnemy && bs->frame_Enemy_Vis)
06417 {
06418 bs->wpCamping = NULL;
06419 bs->isCamping = 0;
06420 }
06421 }
06422
06423 if (bs->wpCurrent &&
06424 (bs->wpSeenTime < level.time || bs->wpTravelTime < level.time))
06425 {
06426 bs->wpCurrent = NULL;
06427 }
06428
06429 if (bs->currentEnemy)
06430 {
06431 if (bs->enemySeenTime < level.time ||
06432 !PassStandardEnemyChecks(bs, bs->currentEnemy))
06433 {
06434 if (bs->revengeEnemy == bs->currentEnemy &&
06435 bs->currentEnemy->health < 1 &&
06436 bs->lastAttacked && bs->lastAttacked == bs->currentEnemy)
06437 {
06438 //CHAT: Destroyed hated one [KilledHatedOne section]
06439 bs->chatObject = bs->revengeEnemy;
06440 bs->chatAltObject = NULL;
06441 BotDoChat(bs, "KilledHatedOne", 1);
06442 bs->revengeEnemy = NULL;
06443 bs->revengeHateLevel = 0;
06444 }
06445 else if (bs->currentEnemy->health < 1 && PassLovedOneCheck(bs, bs->currentEnemy) &&
06446 bs->lastAttacked && bs->lastAttacked == bs->currentEnemy)
06447 {
06448 //CHAT: Killed
06449 bs->chatObject = bs->currentEnemy;
06450 bs->chatAltObject = NULL;
06451 BotDoChat(bs, "Killed", 0);
06452 }
06453
06454 bs->currentEnemy = NULL;
06455 }
06456 }
06457
06458 if (bot_honorableduelacceptance.integer)
06459 {
06460 if (bs->currentEnemy && bs->currentEnemy->client &&
06461 bs->cur_ps.weapon == WP_SABER &&
06462 g_privateDuel.integer &&
06463 bs->frame_Enemy_Vis &&
06464 bs->frame_Enemy_Len < 400 &&
06465 bs->currentEnemy->client->ps.weapon == WP_SABER &&
06466 bs->currentEnemy->client->ps.saberHolstered)
06467 {
06468 vec3_t e_ang_vec;
06469
06470 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, e_ang_vec);
06471
06472 if (InFieldOfVision(bs->viewangles, 100, e_ang_vec))
06473 { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back
06474 if (!bs->cur_ps.saberHolstered)
06475 {
06476 Cmd_ToggleSaber_f(&g_entities[bs->client]);
06477 }
06478 else
06479 {
06480 if (bs->currentEnemy->client->ps.duelIndex == bs->client &&
06481 bs->currentEnemy->client->ps.duelTime > level.time &&
06482 !bs->cur_ps.duelInProgress)
06483 {
06484 Cmd_EngageDuel_f(&g_entities[bs->client]);
06485 }
06486 }
06487
06488 bs->doAttack = 0;
06489 bs->doAltAttack = 0;
06490 bs->botChallengingTime = level.time + 100;
06491 bs->beStill = level.time + 100;
06492 }
06493 }
06494 }
06495 //Apparently this "allows you to cheese" when fighting against bots. I'm not sure why you'd want to con bots
06496 //into an easy kill, since they're bots and all. But whatever.
06497
06498 if (!bs->wpCurrent)
06499 {
06500 wp = GetNearestVisibleWP(bs->origin, bs->client);
06501
06502 if (wp != -1)
06503 {
06504 bs->wpCurrent = gWPArray[wp];
06505 bs->wpSeenTime = level.time + 1500;
06506 bs->wpTravelTime = level.time + 10000; //never take more than 10 seconds to travel to a waypoint
06507 }
06508 }
06509
06510 if (bs->enemySeenTime < level.time || !bs->frame_Enemy_Vis || !bs->currentEnemy ||
06511 (bs->currentEnemy /*&& bs->cur_ps.weapon == WP_SABER && bs->frame_Enemy_Len > 300*/))
06512 {
06513 enemy = ScanForEnemies(bs);
06514
06515 if (enemy != -1)
06516 {
06517 bs->currentEnemy = &g_entities[enemy];
06518 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
06519 }
06520 }
06521
06522 if (!bs->squadLeader && !bs->isSquadLeader)
06523 {
06524 BotScanForLeader(bs);
06525 }
06526
06527 if (!bs->squadLeader && bs->squadCannotLead < level.time)
06528 { //if still no leader after scanning, then become a squad leader
06529 bs->isSquadLeader = 1;
06530 }
06531
06532 if (bs->isSquadLeader && bs->squadLeader)
06533 { //we don't follow anyone if we are a leader
06534 bs->squadLeader = NULL;
06535 }
06536
06537 //ESTABLISH VISIBILITIES AND DISTANCES FOR THE WHOLE FRAME HERE
06538 if (bs->wpCurrent)
06539 {
06540 if (g_RMG.integer)
06541 { //this is somewhat hacky, but in RMG we don't really care about vertical placement because points are scattered across only the terrain.
06542 vec3_t vecB, vecC;
06543
06544 vecB[0] = bs->origin[0];
06545 vecB[1] = bs->origin[1];
06546 vecB[2] = bs->origin[2];
06547
06548 vecC[0] = bs->wpCurrent->origin[0];
06549 vecC[1] = bs->wpCurrent->origin[1];
06550 vecC[2] = vecB[2];
06551
06552
06553 VectorSubtract(vecC, vecB, a);
06554 }
06555 else
06556 {
06557 VectorSubtract(bs->wpCurrent->origin, bs->origin, a);
06558 }
06559 bs->frame_Waypoint_Len = VectorLength(a);
06560
06561 visResult = WPOrgVisible(&g_entities[bs->client], bs->origin, bs->wpCurrent->origin, bs->client);
06562
06563 if (visResult == 2)
06564 {
06565 bs->frame_Waypoint_Vis = 0;
06566 bs->wpSeenTime = 0;
06567 bs->wpDestination = NULL;
06568 bs->wpDestIgnoreTime = level.time + 5000;
06569
06570 if (bs->wpDirection)
06571 {
06572 bs->wpDirection = 0;
06573 }
06574 else
06575 {
06576 bs->wpDirection = 1;
06577 }
06578 }
06579 else if (visResult)
06580 {
06581 bs->frame_Waypoint_Vis = 1;
06582 }
06583 else
06584 {
06585 bs->frame_Waypoint_Vis = 0;
06586 }
06587 }
06588
06589 if (bs->currentEnemy)
06590 {
06591 if (bs->currentEnemy->client)
06592 {
06593 VectorCopy(bs->currentEnemy->client->ps.origin, eorg);
06594 eorg[2] += bs->currentEnemy->client->ps.viewheight;
06595 }
06596 else
06597 {
06598 VectorCopy(bs->currentEnemy->s.origin, eorg);
06599 }
06600
06601 VectorSubtract(eorg, bs->eye, a);
06602 bs->frame_Enemy_Len = VectorLength(a);
06603
06604 if (OrgVisible(bs->eye, eorg, bs->client))
06605 {
06606 bs->frame_Enemy_Vis = 1;
06607 VectorCopy(eorg, bs->lastEnemySpotted);
06608 VectorCopy(bs->origin, bs->hereWhenSpotted);
06609 bs->lastVisibleEnemyIndex = bs->currentEnemy->s.number;
06610 //VectorCopy(bs->eye, bs->lastEnemySpotted);
06611 bs->hitSpotted = 0;
06612 }
06613 else
06614 {
06615 bs->frame_Enemy_Vis = 0;
06616 }
06617 }
06618 else
06619 {
06620 bs->lastVisibleEnemyIndex = ENTITYNUM_NONE;
06621 }
06622 //END
06623
06624 if (bs->frame_Enemy_Vis)
06625 {
06626 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
06627 }
06628
06629 if (bs->wpCurrent)
06630 {
06631 int wpTouchDist = BOT_WPTOUCH_DISTANCE;
06632 WPConstantRoutine(bs);
06633
06634 if (!bs->wpCurrent)
06635 { //WPConstantRoutine has the ability to nullify the waypoint if it fails certain checks, so..
06636 return;
06637 }
06638
06639 if (bs->wpCurrent->flags & WPFLAG_WAITFORFUNC)
06640 {
06641 if (!CheckForFunc(bs->wpCurrent->origin, -1))
06642 {
06643 bs->beStill = level.time + 500; //no func brush under.. wait
06644 }
06645 }
06646 if (bs->wpCurrent->flags & WPFLAG_NOMOVEFUNC)
06647 {
06648 if (CheckForFunc(bs->wpCurrent->origin, -1))
06649 {
06650 bs->beStill = level.time + 500; //func brush under.. wait
06651 }
06652 }
06653
06654 if (bs->frame_Waypoint_Vis || (bs->wpCurrent->flags & WPFLAG_NOVIS))
06655 {
06656 if (g_RMG.integer)
06657 {
06658 bs->wpSeenTime = level.time + 5000; //if we lose sight of the point, we have 1.5 seconds to regain it before we drop it
06659 }
06660 else
06661 {
06662 bs->wpSeenTime = level.time + 1500; //if we lose sight of the point, we have 1.5 seconds to regain it before we drop it
06663 }
06664 }
06665 VectorCopy(bs->wpCurrent->origin, bs->goalPosition);
06666 if (bs->wpDirection)
06667 {
06668 goalWPIndex = bs->wpCurrent->index-1;
06669 }
06670 else
06671 {
06672 goalWPIndex = bs->wpCurrent->index+1;
06673 }
06674
06675 if (bs->wpCamping)
06676 {
06677 VectorSubtract(bs->wpCampingTo->origin, bs->origin, a);
06678 vectoangles(a, ang);
06679 VectorCopy(ang, bs->goalAngles);
06680
06681 VectorSubtract(bs->origin, bs->wpCamping->origin, a);
06682 if (VectorLength(a) < 64)
06683 {
06684 VectorCopy(bs->wpCamping->origin, bs->goalPosition);
06685 bs->beStill = level.time + 1000;
06686
06687 if (!bs->campStanding)
06688 {
06689 bs->duckTime = level.time + 1000;
06690 }
06691 }
06692 }
06693 else if (gWPArray[goalWPIndex] && gWPArray[goalWPIndex]->inuse &&
06694 !(gLevelFlags & LEVELFLAG_NOPOINTPREDICTION))
06695 {
06696 VectorSubtract(gWPArray[goalWPIndex]->origin, bs->origin, a);
06697 vectoangles(a, ang);
06698 VectorCopy(ang, bs->goalAngles);
06699 }
06700 else
06701 {
06702 VectorSubtract(bs->wpCurrent->origin, bs->origin, a);
06703 vectoangles(a, ang);
06704 VectorCopy(ang, bs->goalAngles);
06705 }
06706
06707 if (bs->destinationGrabTime < level.time /*&& (!bs->wpDestination || (bs->currentEnemy && bs->frame_Enemy_Vis))*/)
06708 {
06709 GetIdealDestination(bs);
06710 }
06711
06712 if (bs->wpCurrent && bs->wpDestination)
06713 {
06714 if (TotalTrailDistance(bs->wpCurrent->index, bs->wpDestination->index, bs) == -1)
06715 {
06716 bs->wpDestination = NULL;
06717 bs->destinationGrabTime = level.time + 10000;
06718 }
06719 }
06720
06721 if (g_RMG.integer)
06722 {
06723 if (bs->frame_Waypoint_Vis)
06724 {
06725 if (bs->wpCurrent && !bs->wpCurrent->flags)
06726 {
06727 wpTouchDist *= 3;
06728 }
06729 }
06730 }
06731
06732 if (bs->frame_Waypoint_Len < wpTouchDist || (g_RMG.integer && bs->frame_Waypoint_Len < wpTouchDist*2))
06733 {
06734 WPTouchRoutine(bs);
06735
06736 if (!bs->wpDirection)
06737 {
06738 desiredIndex = bs->wpCurrent->index+1;
06739 }
06740 else
06741 {
06742 desiredIndex = bs->wpCurrent->index-1;
06743 }
06744
06745 if (gWPArray[desiredIndex] &&
06746 gWPArray[desiredIndex]->inuse &&
06747 desiredIndex < gWPNum &&
06748 desiredIndex >= 0 &&
06749 PassWayCheck(bs, desiredIndex))
06750 {
06751 bs->wpCurrent = gWPArray[desiredIndex];
06752 }
06753 else
06754 {
06755 if (bs->wpDestination)
06756 {
06757 bs->wpDestination = NULL;
06758 bs->destinationGrabTime = level.time + 10000;
06759 }
06760
06761 if (bs->wpDirection)
06762 {
06763 bs->wpDirection = 0;
06764 }
06765 else
06766 {
06767 bs->wpDirection = 1;
06768 }
06769 }
06770 }
06771 }
06772 else //We can't find a waypoint, going to need a fallback routine.
06773 {
06774 /*if (g_gametype.integer == GT_DUEL)*/
06775 { //helps them get out of messy situations
06776 /*if ((level.time - bs->forceJumpChargeTime) > 3500)
06777 {
06778 bs->forceJumpChargeTime = level.time + 2000;
06779 trap_EA_MoveForward(bs->client);
06780 }
06781 */
06782 bs->jumpTime = level.time + 1500;
06783 bs->jumpHoldTime = level.time + 1500;
06784 bs->jDelay = 0;
06785 }
06786 doingFallback = BotFallbackNavigation(bs);
06787 }
06788
06789 if (g_RMG.integer)
06790 { //for RMG if the bot sticks around an area too long, jump around randomly some to spread to a new area (horrible hacky method)
06791 vec3_t vSubDif;
06792
06793 VectorSubtract(bs->origin, bs->lastSignificantAreaChange, vSubDif);
06794 if (VectorLength(vSubDif) > 1500)
06795 {
06796 VectorCopy(bs->origin, bs->lastSignificantAreaChange);
06797 bs->lastSignificantChangeTime = level.time + 20000;
06798 }
06799
06800 if (bs->lastSignificantChangeTime < level.time)
06801 {
06802 bs->iHaveNoIdeaWhereIAmGoing = level.time + 17000;
06803 }
06804 }
06805
06806 if (bs->iHaveNoIdeaWhereIAmGoing > level.time && !bs->currentEnemy)
06807 {
06808 VectorCopy(preFrameGAngles, bs->goalAngles);
06809 bs->wpCurrent = NULL;
06810 bs->wpSwitchTime = level.time + 150;
06811 doingFallback = BotFallbackNavigation(bs);
06812 bs->jumpTime = level.time + 150;
06813 bs->jumpHoldTime = level.time + 150;
06814 bs->jDelay = 0;
06815 bs->lastSignificantChangeTime = level.time + 25000;
06816 }
06817
06818 if (bs->wpCurrent && g_RMG.integer)
06819 {
06820 qboolean doJ = qfalse;
06821
06822 if (bs->wpCurrent->origin[2]-192 > bs->origin[2])
06823 {
06824 doJ = qtrue;
06825 }
06826 else if ((bs->wpTravelTime - level.time) < 5000 && bs->wpCurrent->origin[2]-64 > bs->origin[2])
06827 {
06828 doJ = qtrue;
06829 }
06830 else if ((bs->wpTravelTime - level.time) < 7000 && (bs->wpCurrent->flags & WPFLAG_RED_FLAG))
06831 {
06832 if ((level.time - bs->jumpTime) > 200)
06833 {
06834 bs->jumpTime = level.time + 100;
06835 bs->jumpHoldTime = level.time + 100;
06836 bs->jDelay = 0;
06837 }
06838 }
06839 else if ((bs->wpTravelTime - level.time) < 7000 && (bs->wpCurrent->flags & WPFLAG_BLUE_FLAG))
06840 {
06841 if ((level.time - bs->jumpTime) > 200)
06842 {
06843 bs->jumpTime = level.time + 100;
06844 bs->jumpHoldTime = level.time + 100;
06845 bs->jDelay = 0;
06846 }
06847 }
06848 else if (bs->wpCurrent->index > 0)
06849 {
06850 if ((bs->wpTravelTime - level.time) < 7000)
06851 {
06852 if ((gWPArray[bs->wpCurrent->index-1]->flags & WPFLAG_RED_FLAG) ||
06853 (gWPArray[bs->wpCurrent->index-1]->flags & WPFLAG_BLUE_FLAG))
06854 {
06855 if ((level.time - bs->jumpTime) > 200)
06856 {
06857 bs->jumpTime = level.time + 100;
06858 bs->jumpHoldTime = level.time + 100;
06859 bs->jDelay = 0;
06860 }
06861 }
06862 }
06863 }
06864
06865 if (doJ)
06866 {
06867 bs->jumpTime = level.time + 1500;
06868 bs->jumpHoldTime = level.time + 1500;
06869 bs->jDelay = 0;
06870 }
06871 }
06872
06873 if (doingFallback)
06874 {
06875 bs->doingFallback = qtrue;
06876 }
06877 else
06878 {
06879 bs->doingFallback = qfalse;
06880 }
06881
06882 if (bs->timeToReact < level.time && bs->currentEnemy && bs->enemySeenTime > level.time + (ENEMY_FORGET_MS - (ENEMY_FORGET_MS*0.2)))
06883 {
06884 if (bs->frame_Enemy_Vis)
06885 {
06886 cBAI = CombatBotAI(bs, thinktime);
06887 }
06888 else if (bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT)
06889 { //keep charging in case we see him again before we lose track of him
06890 bs->doAltAttack = 1;
06891 }
06892 else if (bs->cur_ps.weaponstate == WEAPON_CHARGING)
06893 { //keep charging in case we see him again before we lose track of him
06894 bs->doAttack = 1;
06895 }
06896
06897 if (bs->destinationGrabTime > level.time + 100)
06898 {
06899 bs->destinationGrabTime = level.time + 100; //assures that we will continue staying within a general area of where we want to be in a combat situation
06900 }
06901
06902 if (bs->currentEnemy->client)
06903 {
06904 VectorCopy(bs->currentEnemy->client->ps.origin, headlevel);
06905 headlevel[2] += bs->currentEnemy->client->ps.viewheight;
06906 }
06907 else
06908 {
06909 VectorCopy(bs->currentEnemy->client->ps.origin, headlevel);
06910 }
06911
06912 if (!bs->frame_Enemy_Vis)
06913 {
06914 //if (!bs->hitSpotted && VectorLength(a) > 256)
06915 if (OrgVisible(bs->eye, bs->lastEnemySpotted, -1))
06916 {
06917 VectorCopy(bs->lastEnemySpotted, headlevel);
06918 VectorSubtract(headlevel, bs->eye, a);
06919 vectoangles(a, ang);
06920 VectorCopy(ang, bs->goalAngles);
06921
06922 if (bs->cur_ps.weapon == WP_FLECHETTE &&
06923 bs->cur_ps.weaponstate == WEAPON_READY &&
06924 bs->currentEnemy && bs->currentEnemy->client)
06925 {
06926 mLen = VectorLength(a) > 128;
06927 if (mLen > 128 && mLen < 1024)
06928 {
06929 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->lastEnemySpotted, a);
06930
06931 if (VectorLength(a) < 300)
06932 {
06933 bs->doAltAttack = 1;
06934 }
06935 }
06936 }
06937 }
06938 }
06939 else
06940 {
06941 bLeadAmount = BotWeaponCanLead(bs);
06942 if ((bs->skills.accuracy/bs->settings.skill) <= 8 &&
06943 bLeadAmount)
06944 {
06945 BotAimLeading(bs, headlevel, bLeadAmount);
06946 }
06947 else
06948 {
06949 VectorSubtract(headlevel, bs->eye, a);
06950 vectoangles(a, ang);
06951 VectorCopy(ang, bs->goalAngles);
06952 }
06953
06954 BotAimOffsetGoalAngles(bs);
06955 }
06956 }
06957
06958 if (bs->cur_ps.saberInFlight)
06959 {
06960 bs->saberThrowTime = level.time + Q_irand(4000, 10000);
06961 }
06962
06963 if (bs->currentEnemy)
06964 {
06965 if (BotGetWeaponRange(bs) == BWEAPONRANGE_SABER)
06966 {
06967 int saberRange = SABER_ATTACK_RANGE;
06968
06969 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, a_fo);
06970 vectoangles(a_fo, a_fo);
06971
06972 if (bs->saberPowerTime < level.time)
06973 { //Don't just use strong attacks constantly, switch around a bit
06974 if (Q_irand(1, 10) <= 5)
06975 {
06976 bs->saberPower = qtrue;
06977 }
06978 else
06979 {
06980 bs->saberPower = qfalse;
06981 }
06982
06983 bs->saberPowerTime = level.time + Q_irand(3000, 15000);
06984 }
06985
06986 if ( g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_STAFF
06987 && g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_DUAL )
06988 {
06989 if (bs->currentEnemy->health > 75
06990 && g_entities[bs->client].client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] > 2)
06991 {
06992 if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_STRONG
06993 && bs->saberPower)
06994 { //if we are up against someone with a lot of health and we have a strong attack available, then h4q them
06995 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
06996 }
06997 }
06998 else if (bs->currentEnemy->health > 40
06999 && g_entities[bs->client].client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] > 1)
07000 {
07001 if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_MEDIUM)
07002 { //they're down on health a little, use level 2 if we can
07003 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
07004 }
07005 }
07006 else
07007 {
07008 if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_FAST)
07009 { //they've gone below 40 health, go at them with quick attacks
07010 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
07011 }
07012 }
07013 }
07014
07015 if (g_gametype.integer == GT_SINGLE_PLAYER)
07016 {
07017 saberRange *= 3;
07018 }
07019
07020 if (bs->frame_Enemy_Len <= saberRange)
07021 {
07022 SaberCombatHandling(bs);
07023
07024 if (bs->frame_Enemy_Len < 80)
07025 {
07026 meleestrafe = 1;
07027 }
07028 }
07029 else if (bs->saberThrowTime < level.time && !bs->cur_ps.saberInFlight &&
07030 (bs->cur_ps.fd.forcePowersKnown & (1 << FP_SABERTHROW)) &&
07031 InFieldOfVision(bs->viewangles, 30, a_fo) &&
07032 bs->frame_Enemy_Len < BOT_SABER_THROW_RANGE &&
07033 bs->cur_ps.fd.saberAnimLevel != SS_STAFF)
07034 {
07035 bs->doAltAttack = 1;
07036 bs->doAttack = 0;
07037 }
07038 else if (bs->cur_ps.saberInFlight && bs->frame_Enemy_Len > 300 && bs->frame_Enemy_Len < BOT_SABER_THROW_RANGE)
07039 {
07040 bs->doAltAttack = 1;
07041 bs->doAttack = 0;
07042 }
07043 }
07044 else if (BotGetWeaponRange(bs) == BWEAPONRANGE_MELEE)
07045 {
07046 if (bs->frame_Enemy_Len <= MELEE_ATTACK_RANGE)
07047 {
07048 MeleeCombatHandling(bs);
07049 meleestrafe = 1;
07050 }
07051 }
07052 }
07053
07054 if (doingFallback && bs->currentEnemy) //just stand and fire if we have no idea where we are
07055 {
07056 VectorCopy(bs->origin, bs->goalPosition);
07057 }
07058
07059 if (bs->forceJumping > level.time)
07060 {
07061 VectorCopy(bs->origin, noz_x);
07062 VectorCopy(bs->goalPosition, noz_y);
07063
07064 noz_x[2] = noz_y[2];
07065
07066 VectorSubtract(noz_x, noz_y, noz_x);
07067
07068 if (VectorLength(noz_x) < 32)
07069 {
07070 fjHalt = 1;
07071 }
07072 }
07073
07074 if (bs->doChat && bs->chatTime > level.time && (!bs->currentEnemy || !bs->frame_Enemy_Vis))
07075 {
07076 return;
07077 }
07078 else if (bs->doChat && bs->currentEnemy && bs->frame_Enemy_Vis)
07079 {
07080 //bs->chatTime = level.time + bs->chatTime_stored;
07081 bs->doChat = 0; //do we want to keep the bot waiting to chat until after the enemy is gone?
07082 bs->chatTeam = 0;
07083 }
07084 else if (bs->doChat && bs->chatTime <= level.time)
07085 {
07086 if (bs->chatTeam)
07087 {
07088 trap_EA_SayTeam(bs->client, bs->currentChat);
07089 bs->chatTeam = 0;
07090 }
07091 else
07092 {
07093 trap_EA_Say(bs->client, bs->currentChat);
07094 }
07095 if (bs->doChat == 2)
07096 {
07097 BotReplyGreetings(bs);
07098 }
07099 bs->doChat = 0;
07100 }
07101
07102 CTFFlagMovement(bs);
07103
07104 if (/*bs->wpDestination &&*/ bs->shootGoal &&
07105 /*bs->wpDestination->associated_entity == bs->shootGoal->s.number &&*/
07106 bs->shootGoal->health > 0 && bs->shootGoal->takedamage)
07107 {
07108 dif[0] = (bs->shootGoal->r.absmax[0]+bs->shootGoal->r.absmin[0])/2;
07109 dif[1] = (bs->shootGoal->r.absmax[1]+bs->shootGoal->r.absmin[1])/2;
07110 dif[2] = (bs->shootGoal->r.absmax[2]+bs->shootGoal->r.absmin[2])/2;
07111
07112 if (!bs->currentEnemy || bs->frame_Enemy_Len > 256)
07113 { //if someone is close then don't stop shooting them for this
07114 VectorSubtract(dif, bs->eye, a);
07115 vectoangles(a, a);
07116 VectorCopy(a, bs->goalAngles);
07117
07118 if (InFieldOfVision(bs->viewangles, 30, a) &&
07119 EntityVisibleBox(bs->origin, NULL, NULL, dif, bs->client, bs->shootGoal->s.number))
07120 {
07121 bs->doAttack = 1;
07122 }
07123 }
07124 }
07125
07126 if (bs->cur_ps.hasDetPackPlanted)
07127 { //check if our enemy gets near it and detonate if he does
07128 BotCheckDetPacks(bs);
07129 }
07130 else if (bs->currentEnemy && bs->lastVisibleEnemyIndex == bs->currentEnemy->s.number && !bs->frame_Enemy_Vis && bs->plantTime < level.time &&
07131 !bs->doAttack && !bs->doAltAttack)
07132 {
07133 VectorSubtract(bs->origin, bs->hereWhenSpotted, a);
07134
07135 if (bs->plantDecided > level.time || (bs->frame_Enemy_Len < BOT_PLANT_DISTANCE*2 && VectorLength(a) < BOT_PLANT_DISTANCE))
07136 {
07137 mineSelect = BotSelectChoiceWeapon(bs, WP_TRIP_MINE, 0);
07138 detSelect = BotSelectChoiceWeapon(bs, WP_DET_PACK, 0);
07139 if (bs->cur_ps.hasDetPackPlanted)
07140 {
07141 detSelect = 0;
07142 }
07143
07144 if (bs->plantDecided > level.time && bs->forceWeaponSelect &&
07145 bs->cur_ps.weapon == bs->forceWeaponSelect)
07146 {
07147 bs->doAttack = 1;
07148 bs->plantDecided = 0;
07149 bs->plantTime = level.time + BOT_PLANT_INTERVAL;
07150 bs->plantContinue = level.time + 500;
07151 bs->beStill = level.time + 500;
07152 }
07153 else if (mineSelect || detSelect)
07154 {
07155 if (BotSurfaceNear(bs))
07156 {
07157 if (!mineSelect)
07158 { //if no mines use detpacks, otherwise use mines
07159 mineSelect = WP_DET_PACK;
07160 }
07161 else
07162 {
07163 mineSelect = WP_TRIP_MINE;
07164 }
07165
07166 detSelect = BotSelectChoiceWeapon(bs, mineSelect, 1);
07167
07168 if (detSelect && detSelect != 2)
07169 { //We have it and it is now our weapon
07170 bs->plantDecided = level.time + 1000;
07171 bs->forceWeaponSelect = mineSelect;
07172 return;
07173 }
07174 else if (detSelect == 2)
07175 {
07176 bs->forceWeaponSelect = mineSelect;
07177 return;
07178 }
07179 }
07180 }
07181 }
07182 }
07183 else if (bs->plantContinue < level.time)
07184 {
07185 bs->forceWeaponSelect = 0;
07186 }
07187
07188 if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster && bs->jmState == -1 && gJMSaberEnt && gJMSaberEnt->inuse)
07189 {
07190 vec3_t saberLen;
07191 float fSaberLen = 0;
07192
07193 VectorSubtract(bs->origin, gJMSaberEnt->r.currentOrigin, saberLen);
07194 fSaberLen = VectorLength(saberLen);
07195
07196 if (fSaberLen < 256)
07197 {
07198 if (OrgVisible(bs->origin, gJMSaberEnt->r.currentOrigin, bs->client))
07199 {
07200 VectorCopy(gJMSaberEnt->r.currentOrigin, bs->goalPosition);
07201 }
07202 }
07203 }
07204
07205 if (bs->beStill < level.time && !WaitingForNow(bs, bs->goalPosition) && !fjHalt)
07206 {
07207 VectorSubtract(bs->goalPosition, bs->origin, bs->goalMovedir);
07208 VectorNormalize(bs->goalMovedir);
07209
07210 if (bs->jumpTime > level.time && bs->jDelay < level.time &&
07211 level.clients[bs->client].pers.cmd.upmove > 0)
07212 {
07213 // trap_EA_Move(bs->client, bs->origin, 5000);
07214 bs->beStill = level.time + 200;
07215 }
07216 else
07217 {
07218 trap_EA_Move(bs->client, bs->goalMovedir, 5000);
07219 }
07220
07221 if (meleestrafe)
07222 {
07223 StrafeTracing(bs);
07224 }
07225
07226 if (bs->meleeStrafeDir && meleestrafe && bs->meleeStrafeDisable < level.time)
07227 {
07228 trap_EA_MoveRight(bs->client);
07229 }
07230 else if (meleestrafe && bs->meleeStrafeDisable < level.time)
07231 {
07232 trap_EA_MoveLeft(bs->client);
07233 }
07234
07235 if (BotTrace_Jump(bs, bs->goalPosition))
07236 {
07237 bs->jumpTime = level.time + 100;
07238 }
07239 else if (BotTrace_Duck(bs, bs->goalPosition))
07240 {
07241 bs->duckTime = level.time + 100;
07242 }
07243 #ifdef BOT_STRAFE_AVOIDANCE
07244 else
07245 {
07246 int strafeAround = BotTrace_Strafe(bs, bs->goalPosition);
07247
07248 if (strafeAround == STRAFEAROUND_RIGHT)
07249 {
07250 trap_EA_MoveRight(bs->client);
07251 }
07252 else if (strafeAround == STRAFEAROUND_LEFT)
07253 {
07254 trap_EA_MoveLeft(bs->client);
07255 }
07256 }
07257 #endif
07258 }
07259
07260 #ifndef FORCEJUMP_INSTANTMETHOD
07261 if (bs->forceJumpChargeTime > level.time)
07262 {
07263 bs->jumpTime = 0;
07264 }
07265 #endif
07266
07267 if (bs->jumpPrep > level.time)
07268 {
07269 bs->forceJumpChargeTime = 0;
07270 }
07271
07272 if (bs->forceJumpChargeTime > level.time)
07273 {
07274 bs->jumpHoldTime = ((bs->forceJumpChargeTime - level.time)/2) + level.time;
07275 bs->forceJumpChargeTime = 0;
07276 }
07277
07278 if (bs->jumpHoldTime > level.time)
07279 {
07280 bs->jumpTime = bs->jumpHoldTime;
07281 }
07282
07283 if (bs->jumpTime > level.time && bs->jDelay < level.time)
07284 {
07285 if (bs->jumpHoldTime > level.time)
07286 {
07287 trap_EA_Jump(bs->client);
07288 if (bs->wpCurrent)
07289 {
07290 if ((bs->wpCurrent->origin[2] - bs->origin[2]) < 64)
07291 {
07292 trap_EA_MoveForward(bs->client);
07293 }
07294 }
07295 else
07296 {
07297 trap_EA_MoveForward(bs->client);
07298 }
07299 if (g_entities[bs->client].client->ps.groundEntityNum == ENTITYNUM_NONE)
07300 {
07301 g_entities[bs->client].client->ps.pm_flags |= PMF_JUMP_HELD;
07302 }
07303 }
07304 else if (!(bs->cur_ps.pm_flags & PMF_JUMP_HELD))
07305 {
07306 trap_EA_Jump(bs->client);
07307 }
07308 }
07309
07310 if (bs->duckTime > level.time)
07311 {
07312 trap_EA_Crouch(bs->client);
07313 }
07314
07315 if ( bs->dangerousObject && bs->dangerousObject->inuse && bs->dangerousObject->health > 0 &&
07316 bs->dangerousObject->takedamage && (!bs->frame_Enemy_Vis || !bs->currentEnemy) &&
07317 (BotGetWeaponRange(bs) == BWEAPONRANGE_MID || BotGetWeaponRange(bs) == BWEAPONRANGE_LONG) &&
07318 bs->cur_ps.weapon != WP_DET_PACK && bs->cur_ps.weapon != WP_TRIP_MINE &&
07319 !bs->shootGoal )
07320 {
07321 float danLen;
07322
07323 VectorSubtract(bs->dangerousObject->r.currentOrigin, bs->eye, a);
07324
07325 danLen = VectorLength(a);
07326
07327 if (danLen > 256)
07328 {
07329 vectoangles(a, a);
07330 VectorCopy(a, bs->goalAngles);
07331
07332 if (Q_irand(1, 10) < 5)
07333 {
07334 bs->goalAngles[YAW] += Q_irand(0, 3);
07335 bs->goalAngles[PITCH] += Q_irand(0, 3);
07336 }
07337 else
07338 {
07339 bs->goalAngles[YAW] -= Q_irand(0, 3);
07340 bs->goalAngles[PITCH] -= Q_irand(0, 3);
07341 }
07342
07343 if (InFieldOfVision(bs->viewangles, 30, a) &&
07344 EntityVisibleBox(bs->origin, NULL, NULL, bs->dangerousObject->r.currentOrigin, bs->client, bs->dangerousObject->s.number))
07345 {
07346 bs->doAttack = 1;
07347 }
07348 }
07349 }
07350
07351 if (PrimFiring(bs) ||
07352 AltFiring(bs))
07353 {
07354 friendInLOF = CheckForFriendInLOF(bs);
07355
07356 if (friendInLOF)
07357 {
07358 if (PrimFiring(bs))
07359 {
07360 KeepPrimFromFiring(bs);
07361 }
07362 if (AltFiring(bs))
07363 {
07364 KeepAltFromFiring(bs);
07365 }
07366 if (useTheForce && forceHostile)
07367 {
07368 useTheForce = 0;
07369 }
07370
07371 if (!useTheForce && friendInLOF->client)
07372 { //we have a friend here and are not currently using force powers, see if we can help them out
07373 if (friendInLOF->health <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL])
07374 {
07375 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_HEAL;
07376 useTheForce = 1;
07377 forceHostile = 0;
07378 }
07379 else if (friendInLOF->client->ps.fd.forcePower <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_FORCE]][FP_TEAM_FORCE])
07380 {
07381 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_FORCE;
07382 useTheForce = 1;
07383 forceHostile = 0;
07384 }
07385 }
07386 }
07387 }
07388 else if (g_gametype.integer >= GT_TEAM)
07389 { //still check for anyone to help..
07390 friendInLOF = CheckForFriendInLOF(bs);
07391
07392 if (!useTheForce && friendInLOF)
07393 {
07394 if (friendInLOF->health <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL])
07395 {
07396 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_HEAL;
07397 useTheForce = 1;
07398 forceHostile = 0;
07399 }
07400 else if (friendInLOF->client->ps.fd.forcePower <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_FORCE]][FP_TEAM_FORCE])
07401 {
07402 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_FORCE;
07403 useTheForce = 1;
07404 forceHostile = 0;
07405 }
07406 }
07407 }
07408
07409 if (bs->doAttack && bs->cur_ps.weapon == WP_DET_PACK &&
07410 bs->cur_ps.hasDetPackPlanted)
07411 { //maybe a bit hackish, but bots only want to plant one of these at any given time to avoid complications
07412 bs->doAttack = 0;
07413 }
07414
07415 if (bs->doAttack && bs->cur_ps.weapon == WP_SABER &&
07416 bs->saberDefending && bs->currentEnemy && bs->currentEnemy->client &&
07417 BotWeaponBlockable(bs->currentEnemy->client->ps.weapon) )
07418 {
07419 bs->doAttack = 0;
07420 }
07421
07422 if (bs->cur_ps.saberLockTime > level.time)
07423 {
07424 if (rand()%10 < 5)
07425 {
07426 bs->doAttack = 1;
07427 }
07428 else
07429 {
07430 bs->doAttack = 0;
07431 }
07432 }
07433
07434 if (bs->botChallengingTime > level.time)
07435 {
07436 bs->doAttack = 0;
07437 bs->doAltAttack = 0;
07438 }
07439
07440 if (bs->cur_ps.weapon == WP_SABER &&
07441 bs->cur_ps.saberInFlight &&
07442 !bs->cur_ps.saberEntityNum)
07443 { //saber knocked away, keep trying to get it back
07444 bs->doAttack = 1;
07445 bs->doAltAttack = 0;
07446 }
07447
07448 if (bs->doAttack)
07449 {
07450 trap_EA_Attack(bs->client);
07451 }
07452 else if (bs->doAltAttack)
07453 {
07454 trap_EA_Alt_Attack(bs->client);
07455 }
07456
07457 if (useTheForce && forceHostile && bs->botChallengingTime > level.time)
07458 {
07459 useTheForce = qfalse;
07460 }
07461
07462 if (useTheForce)
07463 {
07464 #ifndef FORCEJUMP_INSTANTMETHOD
07465 if (bs->forceJumpChargeTime > level.time)
07466 {
07467 level.clients[bs->client].ps.fd.forcePowerSelected = FP_LEVITATION;
07468 trap_EA_ForcePower(bs->client);
07469 }
07470 else
07471 {
07472 #endif
07473 if (bot_forcepowers.integer && !g_forcePowerDisable.integer)
07474 {
07475 trap_EA_ForcePower(bs->client);
07476 }
07477 #ifndef FORCEJUMP_INSTANTMETHOD
07478 }
07479 #endif
07480 }
07481
07482 MoveTowardIdealAngles(bs);
07483 }
|
|
|
Definition at line 374 of file ai_main.h. Referenced by BotAISetup(), BotAIStartFrame(), BotLovedOneDied(), GetLoveLevel(), and PassLovedOneCheck(). |
|
|
Definition at line 375 of file ai_main.h. Referenced by BotAISetup(), BotAIStartFrame(), and WPTouchRoutine(). |
|
|
Definition at line 366 of file ai_main.h. Referenced by BotAISetup(), and StandardBotAI(). |
|
|
Definition at line 367 of file ai_main.h. Referenced by BotAISetup(), BotAIStartFrame(), and StandardBotAI(). |
|
|
Definition at line 368 of file ai_main.h. Referenced by BotAISetup(), BotAIStartFrame(), and StandardBotAI(). |
|
|
Definition at line 379 of file ai_main.h. Referenced by BotAISetup(), and CalculateWeightGoals(). |
|
|
Definition at line 380 of file ai_main.h. Referenced by BotAISetup(), and RepairPaths(). |
|
|
Definition at line 378 of file ai_main.h. Referenced by BotAISetup(), and LoadPath_ThisLevel(). |
|
|
Definition at line 377 of file ai_main.h. Referenced by BotAISetup(), BotAIStartFrame(), and BotWaypointRender(). |
|
|
Definition at line 381 of file ai_main.h. Referenced by BotAISetup(), and RepairPaths(). |
|
|
Definition at line 389 of file ai_main.h. Referenced by CTFTakesPriority(), FlagObjects(), and LoadPath_ThisLevel(). |
|
|
Definition at line 388 of file ai_main.h. Referenced by CTFTakesPriority(), FlagObjects(), and LoadPath_ThisLevel(). |
|
|
Definition at line 385 of file ai_main.h. Referenced by BotDefendFlag(), BotGetEnemyFlag(), BotGetFlagHome(), CreateNewWP_FromObject(), CTFFlagMovement(), CTFTakesPriority(), FlagObjects(), and GetNewFlagPoint(). |
|
|
Definition at line 383 of file ai_main.h. Referenced by BotDefendFlag(), BotGetEnemyFlag(), BotGetFlagHome(), CreateNewWP_FromObject(), CTFFlagMovement(), CTFTakesPriority(), FlagObjects(), and GetNewFlagPoint(). |
|
|
|
|
|
Definition at line 391 of file ai_main.h. Referenced by BotDoChat(), BotUtilizePersonality(), and ReadChatGroups(). |
|
|
Definition at line 394 of file ai_main.h. Referenced by AcceptBotCommand(), BotAIStartFrame(), BotWaypointRender(), and LoadPath_ThisLevel(). |
|
|
Definition at line 393 of file ai_main.h. Referenced by AcceptBotCommand(), and StandardBotAI(). |
|
|
Definition at line 402 of file ai_main.h. Referenced by BotWaypointRender(). |
|
|
Definition at line 408 of file ai_main.h. Referenced by BotIsAChickenWuss(), LoadPath_ThisLevel(), LoadPathData(), PassStandardEnemyChecks(), and StandardBotAI(). |
|
|
|
|
Definition at line 395 of file ai_main.h. Referenced by BotWaypointRender(). |
|
|
Definition at line 392 of file ai_main.h. Referenced by BotWaypointRender(). |
|
|
Definition at line 406 of file ai_main.h. Referenced by ConnectTrail(), G_NearestNodeToPoint(), G_NodeClearFlags(), G_NodeClearForNext(), G_NodeMatchingXY(), G_NodeMatchingXY_BA(), G_RMGPathing(), and NodeHere(). |
|
|
Definition at line 404 of file ai_main.h. Referenced by ConnectTrail(), G_BackwardAttachment(), G_NearestNodeToPoint(), G_NodeClearFlags(), G_NodeClearForNext(), G_NodeMatchingXY(), G_NodeMatchingXY_BA(), G_RecursiveConnection(), G_RMGPathing(), and NodeHere(). |
|
|
Definition at line 386 of file ai_main.h. Referenced by CreateNewWP_FromObject(), CTFTakesPriority(), and FlagObjects(). |
|
|
Definition at line 384 of file ai_main.h. Referenced by CreateNewWP_FromObject(), CTFTakesPriority(), and FlagObjects(). |