X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fbot%2Fdefault%2Fbot.qc;h=f367adab32c538c455a1a12ea8216897de1d2781;hp=2a6164a2826875af507597ba8523bf629bee0403;hb=97177a79357838fa546b5ee0fada274f0a55e12d;hpb=4dcd0138fefe9810c539cc0f5c8f6da5e81d1b06 diff --git a/qcsrc/server/bot/default/bot.qc b/qcsrc/server/bot/default/bot.qc index 2a6164a28..f367adab3 100644 --- a/qcsrc/server/bot/default/bot.qc +++ b/qcsrc/server/bot/default/bot.qc @@ -41,6 +41,8 @@ #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) { @@ -168,6 +170,26 @@ void bot_setnameandstuff(entity this) } else { + entity balance = TeamBalance_CheckAllowedTeams(NULL); + TeamBalance_GetTeamCounts(balance, NULL); + int smallest_team = -1; + int smallest_count = -1; + if (teamplay) + { + for (int i = 1; i <= AvailableTeams(); ++i) + { + // NOTE if (autocvar_g_campaign && autocvar_g_campaign_forceteam == i) + // TeamBalance_GetNumberOfPlayers(balance, i); returns the number of players + 1 + // since it keeps a spot for the real player in the desired team + int count = TeamBalance_GetNumberOfPlayers(balance, i); + if (smallest_count < 0 || count < smallest_count) + { + smallest_team = i; + smallest_count = count; + } + } + } + TeamBalance_Destroy(balance); RandomSelection_Init(); while((readfile = fgets(file))) { @@ -175,18 +197,33 @@ void bot_setnameandstuff(entity this) continue; if(substring(readfile, 0, 1) == "#") continue; + // NOTE if the line is empty tokenizebyseparator(readfile, "\t") + // will create 1 empty token because there's no separator (bug?) + if (readfile == "") + continue; tokens = tokenizebyseparator(readfile, "\t"); if(tokens == 0) continue; s = argv(0); - prio = 1; + prio = 0; + bool conflict = false; FOREACH_CLIENT(IS_BOT_CLIENT(it), { - if(s == it.cleanname) + if (s == it.cleanname) { - prio = 0; + conflict = true; break; } }); + if (!conflict) + prio += 1; + if (teamplay && !(autocvar_bot_vs_human && AvailableTeams() == 2)) + { + int forced_team = stof(argv(5)); + if (!Team_IsValidIndex(forced_team)) + forced_team = 0; + if (!forced_team || forced_team == smallest_team) + prio += 2; + } RandomSelection_AddString(readfile, 1, prio); } readfile = RandomSelection_chosen_string; @@ -209,17 +246,20 @@ void bot_setnameandstuff(entity this) if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4); else bot_pants = ftos(floor(random() * 15)); - this.bot_forced_team = stof(argv(5)); + if (teamplay && !(autocvar_bot_vs_human && AvailableTeams() == 2)) + this.bot_forced_team = stof(argv(5)); + else + this.bot_forced_team = 0; prio = 6; - #define READSKILL(f, w, r) MACRO_BEGIN { \ + #define READSKILL(f, w, r) MACRO_BEGIN \ if(argv(prio) != "") \ this.f = stof(argv(prio)) * w; \ else \ this.f = (!autocvar_g_campaign) * (2 * random() - 1) * r * w; \ prio++; \ - } MACRO_END + MACRO_END //print(bot_name, ": ping=", argv(9), "\n"); READSKILL(havocbot_keyboardskill, 0.5, 0.5); // keyboard skill @@ -239,6 +279,9 @@ void bot_setnameandstuff(entity this) READSKILL(bot_thinkskill, 1, 0.5); // think skill READSKILL(bot_aiskill, 2, 0); // "ai" skill + if (file >= 0 && argv(prio) != "") + LOG_INFOF("^1Warning^7: too many parameters for bot %s, please check format of %s", bot_name, autocvar_bot_config_file); + this.bot_config_loaded = true; // this is really only a default, TeamBalance_JoinBestTeam is called later @@ -280,6 +323,10 @@ void bot_setnameandstuff(entity this) void bot_custom_weapon_priority_setup() { + static string bot_priority_far_prev; + static string bot_priority_mid_prev; + static string bot_priority_close_prev; + static string bot_priority_distances_prev; float tokens, i, w; bot_custom_weapon = false; @@ -287,70 +334,50 @@ void bot_custom_weapon_priority_setup() if( autocvar_bot_ai_custom_weapon_priority_far == "" || autocvar_bot_ai_custom_weapon_priority_mid == "" || autocvar_bot_ai_custom_weapon_priority_close == "" || - autocvar_bot_ai_custom_weapon_priority_distances == "" + autocvar_bot_ai_custom_weapon_priority_distances == "" ) return; - // Parse distances - tokens = tokenizebyseparator(autocvar_bot_ai_custom_weapon_priority_distances," "); - - if (tokens!=2) - return; - - bot_distance_far = stof(argv(0)); - bot_distance_close = stof(argv(1)); - - if(bot_distance_far < bot_distance_close){ - bot_distance_far = stof(argv(1)); - bot_distance_close = stof(argv(0)); - } - - // Initialize list of weapons - bot_weapons_far[0] = -1; - bot_weapons_mid[0] = -1; - bot_weapons_close[0] = -1; - - // Parse far distance weapon priorities - tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_far)," "); + if (bot_priority_distances_prev != autocvar_bot_ai_custom_weapon_priority_distances) + { + strcpy(bot_priority_distances_prev, autocvar_bot_ai_custom_weapon_priority_distances); + tokens = tokenizebyseparator(autocvar_bot_ai_custom_weapon_priority_distances," "); - int c = 0; - for(i=0; i < tokens && c < Weapons_COUNT; ++i){ - w = stof(argv(i)); - if ( w >= WEP_FIRST && w <= WEP_LAST) { - bot_weapons_far[c] = w; - ++c; - } - } - if(c < Weapons_COUNT) - bot_weapons_far[c] = -1; + if (tokens!=2) + return; - // Parse mid distance weapon priorities - tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_mid)," "); + bot_distance_far = stof(argv(0)); + bot_distance_close = stof(argv(1)); - c = 0; - for(i=0; i < tokens && c < Weapons_COUNT; ++i){ - w = stof(argv(i)); - if ( w >= WEP_FIRST && w <= WEP_LAST) { - bot_weapons_mid[c] = w; - ++c; + if(bot_distance_far < bot_distance_close){ + bot_distance_far = stof(argv(1)); + bot_distance_close = stof(argv(0)); } } - if(c < Weapons_COUNT) - bot_weapons_mid[c] = -1; - // Parse close distance weapon priorities - tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_close)," "); - - c = 0; - for(i=0; i < tokens && i < Weapons_COUNT; ++i){ - w = stof(argv(i)); - if ( w >= WEP_FIRST && w <= WEP_LAST) { - bot_weapons_close[c] = w; - ++c; - } - } - if(c < Weapons_COUNT) - bot_weapons_close[c] = -1; + int c; + + #define PARSE_WEAPON_PRIORITIES(dist) MACRO_BEGIN \ + if (bot_priority_##dist##_prev != autocvar_bot_ai_custom_weapon_priority_##dist) { \ + strcpy(bot_priority_##dist##_prev, autocvar_bot_ai_custom_weapon_priority_##dist); \ + tokens = tokenizebyseparator(W_NumberWeaponOrder(autocvar_bot_ai_custom_weapon_priority_##dist)," "); \ + bot_weapons_##dist[0] = -1; \ + c = 0; \ + for(i = 0; i < tokens && c < Weapons_COUNT; ++i) { \ + w = stof(argv(i)); \ + if (w >= WEP_FIRST && w <= WEP_LAST) { \ + bot_weapons_##dist[c] = w; \ + ++c; \ + } \ + } \ + if (c < Weapons_COUNT) \ + bot_weapons_##dist[c] = -1; \ + } \ + MACRO_END + + PARSE_WEAPON_PRIORITIES(far); + PARSE_WEAPON_PRIORITIES(mid); + PARSE_WEAPON_PRIORITIES(close); bot_custom_weapon = true; } @@ -425,16 +452,15 @@ void bot_clientconnect(entity this) bot_setclientfields(this); } - if(this.bot_forced_team==1) - this.team = NUM_TEAM_1; - else if(this.bot_forced_team==2) - this.team = NUM_TEAM_2; - else if(this.bot_forced_team==3) - this.team = NUM_TEAM_3; - else if(this.bot_forced_team==4) - this.team = NUM_TEAM_4; + 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); } @@ -576,9 +602,10 @@ void bot_calculate_stepheightvec() stepheightvec = autocvar_sv_stepheight * '0 0 1'; jumpheight_vec = (autocvar_sv_jumpvelocity ** 2) / (2 * autocvar_sv_gravity) * '0 0 1'; jumpstepheightvec = stepheightvec + jumpheight_vec * 0.85; // reduce it a bit to make the jumps easy + jumpheight_time = autocvar_sv_jumpvelocity / autocvar_sv_gravity; } -float bot_fixcount() +bool bot_fixcount() { int activerealplayers = 0; int realplayers = 0; @@ -602,11 +629,16 @@ float bot_fixcount() 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()); int minbots = max(0, floor(autocvar_bot_number)); // add bots to reach minplayers if needed bots = max(minbots, minplayers - activerealplayers); // cap bots to the max players allowed by the server + int player_limit = GetPlayerLimit(); + if(player_limit) + bots = min(bots, max(player_limit - activerealplayers, 0)); bots = min(bots, maxclients - realplayers); if(bots > minbots) @@ -629,7 +661,7 @@ float bot_fixcount() return false; } } - while (currentbots > bots) + while (currentbots > bots && bots >= 0) bot_removenewest(); } @@ -747,7 +779,7 @@ void bot_serverframe() if(botframe_cachedwaypointlinks) { if(!botframe_loadedforcedlinks) - waypoint_load_links_hardwired(); + waypoint_load_hardwiredlinks(); } else { @@ -812,10 +844,6 @@ void bot_serverframe() if (autocvar_g_waypointeditor_auto) botframe_autowaypoints(); - if(time > bot_cvar_nextthink) - { - if(currentbots>0) - bot_custom_weapon_priority_setup(); - bot_cvar_nextthink = time + 5; - } + if (currentbots > 0) + bot_custom_weapon_priority_setup(); }