X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fbot%2Fdefault%2Fbot.qc;h=d7cf429d74e150a8324c0c30bfe0245d683658f1;hb=3b5e884b5e67ad05b088c0f0d6af589a6c39be3a;hp=9462339a2b3c92a4d44997f90ca03ec6e99d32b2;hpb=ad48f34a4a109c864ffe01a14f2290821c03dc9d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/bot/default/bot.qc b/qcsrc/server/bot/default/bot.qc index 9462339a2..d7cf429d7 100644 --- a/qcsrc/server/bot/default/bot.qc +++ b/qcsrc/server/bot/default/bot.qc @@ -1,55 +1,43 @@ #include "bot.qh" -#include "cvars.qh" - -#include "aim.qh" -#include "navigation.qh" -#include "scripting.qh" -#include "waypoints.qh" - -#include "havocbot/havocbot.qh" -#include "havocbot/scripting.qh" - -#include "../../teamplay.qh" - -#include "../../antilag.qh" -#include "../../autocvars.qh" -#include "../../campaign.qh" -#include "../../client.qh" -#include "../../constants.qh" -#include "../../defs.qh" -#include -#include -#include "../../race.qh" -#include - -#include - -#include "../../weapons/accuracy.qh" - -#include #include -#include #include +#include +#include +#include #include #include - -#include - #include - #include - #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include STATIC_INIT(bot) { bot_calculate_stepheightvec(); } // TODO: remove this function! its only purpose is to update these fields since bot_setnameandstuff is called before ClientState void bot_setclientfields(entity this) { - CS(this).cvar_cl_accuracy_data_share = 1; // share the bots weapon accuracy data with the world - CS(this).cvar_cl_accuracy_data_receive = 0; // don't receive any weapon accuracy data + CS_CVAR(this).cvar_cl_accuracy_data_share = 1; // share the bots weapon accuracy data with the world + CS_CVAR(this).cvar_cl_accuracy_data_receive = 0; // don't receive any weapon accuracy data } entity bot_spawn() @@ -76,10 +64,16 @@ void bot_think(entity this) if(autocvar_bot_god) this.flags |= FL_GODMODE; - this.bot_nextthink = max(time, this.bot_nextthink) + max(0.01, autocvar_bot_ai_thinkinterval * (0.5 ** this.bot_aiskill) * min(14 / (skill + 14), 1)); + this.bot_nextthink = max(time, this.bot_nextthink) + max(0.01, autocvar_bot_ai_thinkinterval * min(14 / (skill + this.bot_aiskill + 14), 1)); if (!IS_PLAYER(this) || (autocvar_g_campaign && !campaign_bots_may_start)) { + if (IS_PLAYER(this)) + { + .entity weaponentity = weaponentities[0]; + if(this.(weaponentity).m_weapon == WEP_Null) + W_NextWeapon(this, 0, weaponentity); + } CS(this).movement = '0 0 0'; this.bot_nextthink = time + 0.5; return; @@ -119,23 +113,33 @@ void bot_think(entity this) if (time < game_starttime) { + .entity weaponentity = weaponentities[0]; + if(this.(weaponentity).m_weapon == WEP_Null) + W_NextWeapon(this, 0, weaponentity); // block the bot during the countdown to game start CS(this).movement = '0 0 0'; - this.bot_nextthink = game_starttime; return; } // if dead, just wait until we can respawn - if (IS_DEAD(this)) + if (IS_DEAD(this) || IS_OBSERVER(this)) { if (bot_waypoint_queue_owner == this) bot_waypoint_queue_owner = NULL; this.aistatus = 0; CS(this).movement = '0 0 0'; - if (this.deadflag == DEAD_DEAD) + if (IS_OBSERVER(this)) + return; + if (IS_DEAD(this)) { - PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn - navigation_goalrating_timeout_force(this); + if (!navigation_goalrating_timeout(this)) + navigation_goalrating_timeout_force(this); + // jump must not be pressed for at least one frame in order for + // PlayerThink to detect the key down event + if (this.deadflag == DEAD_DYING) + PHYS_INPUT_BUTTON_JUMP(this) = false; + else if (this.deadflag == DEAD_DEAD) + PHYS_INPUT_BUTTON_JUMP(this) = true; // press jump to respawn } } else if(this.aistatus & AI_STATUS_STUCK) @@ -165,7 +169,7 @@ void bot_setnameandstuff(entity this) int smallest_count = -1; if (teamplay) { - for (int i = 1; i <= AvailableTeams(); ++i) + for (int i = 1; i <= AVAILABLE_TEAMS; ++i) { // NOTE if (autocvar_g_campaign && autocvar_g_campaign_forceteam == i) // TeamBalance_GetNumberOfPlayers(balance, i); returns the number of players + 1 @@ -205,7 +209,7 @@ void bot_setnameandstuff(entity this) }); if (!conflict) prio += 1; - if (teamplay && !(autocvar_bot_vs_human && AvailableTeams() == 2)) + if (teamplay && !(autocvar_bot_vs_human && AVAILABLE_TEAMS == 2)) { int forced_team = stof(argv(5)); if (!Team_IsValidIndex(forced_team)) @@ -237,8 +241,12 @@ void bot_setnameandstuff(entity this) if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4); else bot_pants = ftos(floor(random() * 15)); - if (teamplay && !(autocvar_bot_vs_human && AvailableTeams() == 2)) + if (teamplay && !(autocvar_bot_vs_human && AVAILABLE_TEAMS == 2)) + { this.bot_forced_team = stof(argv(5)); + if (!Team_IsValidIndex(this.bot_forced_team)) + this.bot_forced_team = 0; + } else this.bot_forced_team = 0; @@ -396,17 +404,19 @@ void bot_relinkplayerlist() if(IS_BOT_CLIENT(it)) { - if(prevbot) - prevbot.nextbot = it; - else - bot_list = it; - prevbot = it; + if (!IS_OBSERVER(it) && !bot_ispaused(it)) + { + if(prevbot) + prevbot.nextbot = it; + else + bot_list = it; + prevbot = it; + } ++currentbots; } }); if(prevbot) prevbot.nextbot = NULL; - LOG_TRACE("relink: ", ftos(currentbots), " bots seen."); bot_strategytoken = bot_list; bot_strategytoken_taken = true; } @@ -431,7 +441,6 @@ void bot_clientconnect(entity this) if (!IS_BOT_CLIENT(this)) return; this.bot_preferredcolors = this.clientcolors; this.bot_nextthink = time - random(); - this.lag_func = bot_lagfunc; this.isbot = true; this.createdtime = this.bot_nextthink; @@ -441,16 +450,6 @@ void bot_clientconnect(entity this) bot_setclientfields(this); } - if (teamplay && Team_IsValidIndex(this.bot_forced_team)) - { - SetPlayerTeam(this, this.bot_forced_team, TEAM_CHANGE_MANUAL); - } - else - { - this.bot_forced_team = 0; - TeamBalance_JoinBestTeam(this); - } - havocbot_setupbot(this); } @@ -539,11 +538,8 @@ void bot_removenewest() void autoskill(float factor) { - float bestbot; - float bestplayer; - - bestbot = -1; - bestplayer = -1; + int bestbot = -1; + int bestplayer = -1; FOREACH_CLIENT(IS_PLAYER(it), { if(IS_REAL_CLIENT(it)) bestplayer = max(bestplayer, it.totalfrags - it.totalfrags_lastcheck); @@ -551,37 +547,37 @@ void autoskill(float factor) bestbot = max(bestbot, it.totalfrags - it.totalfrags_lastcheck); }); - LOG_DEBUG("autoskill: best player got ", ftos(bestplayer), ", "); - LOG_DEBUG("best bot got ", ftos(bestbot), "; "); + string msg = strcat("autoskill: best player got ", ftos(bestplayer), ", ""best bot got ", ftos(bestbot), "; "); if(bestbot < 0 || bestplayer < 0) { - LOG_DEBUG("not doing anything"); + msg = strcat(msg, "not doing anything"); // don't return, let it reset all counters below } else if(bestbot <= bestplayer * factor - 2) { if(autocvar_skill < 17) { - LOG_DEBUG("2 frags difference, increasing skill"); + msg = strcat(msg, "2 frags difference, increasing skill"); cvar_set("skill", ftos(autocvar_skill + 1)); - bprint("^2SKILL UP!^7 Now at level ", ftos(autocvar_skill), "\n"); + bprint("^2BOT SKILL UP!^7 Now at level ", ftos(autocvar_skill), "\n"); } } else if(bestbot >= bestplayer * factor + 2) { if(autocvar_skill > 0) { - LOG_DEBUG("2 frags difference, decreasing skill"); + msg = strcat(msg, "2 frags difference, decreasing skill"); cvar_set("skill", ftos(autocvar_skill - 1)); - bprint("^1SKILL DOWN!^7 Now at level ", ftos(autocvar_skill), "\n"); + bprint("^1BOT SKILL DOWN!^7 Now at level ", ftos(autocvar_skill), "\n"); } } else { - LOG_DEBUG("not doing anything"); + msg = strcat(msg, "not doing anything"); return; // don't reset counters, wait for them to accumulate } + LOG_DEBUG(msg); FOREACH_CLIENT(IS_PLAYER(it), { it.totalfrags_lastcheck = it.totalfrags; }); } @@ -594,7 +590,7 @@ void bot_calculate_stepheightvec() jumpheight_time = autocvar_sv_jumpvelocity / autocvar_sv_gravity; } -bool bot_fixcount() +bool bot_fixcount(bool multiple_per_frame) { int activerealplayers = 0; int realplayers = 0; @@ -613,13 +609,13 @@ bool bot_fixcount() // But don't remove bots immediately on level change, as the real players // usually haven't rejoined yet bots_would_leave = false; - if (teamplay && autocvar_bot_vs_human && AvailableTeams() == 2) + if (autocvar_bot_vs_human && AVAILABLE_TEAMS == 2) bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers); else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5))) { int minplayers = max(0, floor(autocvar_minplayers)); if (teamplay) - minplayers = max(0, floor(autocvar_minplayers_per_team) * AvailableTeams()); + minplayers = max(0, floor(autocvar_minplayers_per_team) * AVAILABLE_TEAMS); int minbots = max(0, floor(autocvar_bot_number)); // add bots to reach minplayers if needed @@ -642,13 +638,17 @@ bool bot_fixcount() // only add one bot per frame to avoid utter chaos if(time > botframe_nextthink) { - if (currentbots < bots) + while (currentbots < bots) { if (bot_spawn() == NULL) { bprint("Can not add bot, server full.\n"); return false; } + if (!multiple_per_frame) + { + break; + } } while (currentbots > bots && bots >= 0) bot_removenewest(); @@ -657,39 +657,6 @@ bool bot_fixcount() return true; } -void bot_remove_from_bot_list(entity this) -{ - entity e = bot_list; - entity prev_bot = NULL; - while (e) - { - if(e == this) - { - if(!prev_bot) - bot_list = this.nextbot; - else - prev_bot.nextbot = this.nextbot; - if(bot_strategytoken == this) - { - bot_strategytoken = this.nextbot; - bot_strategytoken_taken = true; - } - this.nextbot = NULL; - break; - } - prev_bot = e; - e = e.nextbot; - } -} - -void bot_clear(entity this) -{ - bot_remove_from_bot_list(this); - if(bot_waypoint_queue_owner == this) - bot_waypoint_queue_owner = NULL; - this.aistatus &= ~AI_STATUS_STUCK; // otherwise bot_waypoint_queue_owner will be set again to this by navigation_unstuck -} - void bot_serverframe() { if (intermission_running && currentbots > 0) @@ -712,6 +679,7 @@ void bot_serverframe() // spectators in the scoreboard and never go away. This issue happens at time 2 if map is changed // with the gotomap command, minplayers is > 1 and human clients join as players very soon // either intentionally or automatically (sv_spectate 0) + // A working workaround for this bug was implemented in commit fbd145044, see entcs_attach if (time < 2.5) { currentbots = -1; @@ -752,7 +720,7 @@ void bot_serverframe() if(time > botframe_nextthink) { - if(!bot_fixcount()) + if(!bot_fixcount(false)) botframe_nextthink = time + 10; } @@ -762,7 +730,7 @@ void bot_serverframe() localcmd("quit\n"); } - if (currentbots > 0 || autocvar_g_waypointeditor || autocvar_g_waypointeditor_auto) + if (currentbots > 0 || waypointeditor_enabled || autocvar_g_waypointeditor_auto) if (botframe_spawnedwaypoints) { if(botframe_cachedwaypointlinks) @@ -827,7 +795,7 @@ void bot_serverframe() } } - if (autocvar_g_waypointeditor) + if (waypointeditor_enabled) botframe_showwaypointlinks(); if (autocvar_g_waypointeditor_auto)