Merge pull request #688 from WantedDV/bots

Revised bots script
This commit is contained in:
Maurice Heumann 2023-05-14 08:15:44 +01:00 committed by GitHub
commit db66f60d2d
2 changed files with 629 additions and 421 deletions

Binary file not shown.

View File

@ -1,4 +1,5 @@
#using scripts\codescripts\struct; #using scripts\codescripts\struct;
#using scripts\shared\array_shared; #using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared; #using scripts\shared\callbacks_shared;
#using scripts\shared\killstreaks_shared; #using scripts\shared\killstreaks_shared;
@ -7,12 +8,14 @@
#using scripts\shared\system_shared; #using scripts\shared\system_shared;
#using scripts\shared\util_shared; #using scripts\shared\util_shared;
#using scripts\shared\weapons_shared; #using scripts\shared\weapons_shared;
#using scripts\shared\weapons\_weapons; #using scripts\shared\weapons\_weapons;
#using scripts\shared\bots\_bot; #using scripts\shared\bots\_bot;
#using scripts\shared\bots\_bot_combat; #using scripts\shared\bots\_bot_combat;
#using scripts\shared\bots\bot_traversals;
#using scripts\shared\bots\bot_buttons; #using scripts\shared\bots\bot_buttons;
#using scripts\shared\bots\bot_traversals;
#using scripts\mp\bots\_bot_ball; #using scripts\mp\bots\_bot_ball;
#using scripts\mp\bots\_bot_clean; #using scripts\mp\bots\_bot_clean;
#using scripts\mp\bots\_bot_combat; #using scripts\mp\bots\_bot_combat;
@ -25,8 +28,7 @@
#using scripts\mp\bots\_bot_koth; #using scripts\mp\bots\_bot_koth;
#using scripts\mp\bots\_bot_loadout; #using scripts\mp\bots\_bot_loadout;
#using scripts\mp\bots\_bot_sd; #using scripts\mp\bots\_bot_sd;
#using scripts\mp\killstreaks\_killstreakrules;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_ai_tank; #using scripts\mp\killstreaks\_ai_tank;
#using scripts\mp\killstreaks\_airsupport; #using scripts\mp\killstreaks\_airsupport;
#using scripts\mp\killstreaks\_combat_robot; #using scripts\mp\killstreaks\_combat_robot;
@ -66,11 +68,14 @@
#define MAX_ONLINE_PLAYERS 18 #define MAX_ONLINE_PLAYERS 18
#define MAX_ONLINE_PLAYERS_PER_TEAM 6 #define MAX_ONLINE_PLAYERS_PER_TEAM 6
#define RESPAWN_DELAY 0 #define RESPAWN_DELAY 0.1
#define RESPAWN_INTERVAL 0.2 #define RESPAWN_INTERVAL 0.1
#namespace bot; #namespace bot;
#precache("eventstring", "mpl_killstreak_cruisemissile");
#precache("eventstring", "mpl_killstreak_raps");
REGISTER_SYSTEM("bot_mp", &__init__, undefined) REGISTER_SYSTEM("bot_mp", &__init__, undefined)
function __init__() function __init__()
@ -93,7 +98,13 @@ function __init__()
level.botIgnoreThreat = &bot_combat::bot_ignore_threat; level.botIgnoreThreat = &bot_combat::bot_ignore_threat;
level.enemyEmpActive = &emp::EnemyEmpActive; level.enemyEmpActive = &emp::enemyEmpActive;
/#
level.botDevguiCmd = &bot_devgui_cmd;
level thread system_devgui_gadget_think();
#/
setDvar("bot_enableWallrun", 1);
} }
function init() function init()
@ -101,8 +112,7 @@ function init()
level endon("game_ended"); level endon("game_ended");
level.botSoak = is_bot_soak(); level.botSoak = is_bot_soak();
if (!init_bot_gametype())
if( level.rankedmatch && level.botsoak || !init_bot_gametype() )
{ {
return; return;
} }
@ -117,18 +127,13 @@ function init()
function is_bot_soak() function is_bot_soak()
{ {
return IsDedicated() && GetDvarInt( "sv_botsoak", 0 ); return getDvarInt("sv_botsoak", 0);
} }
function wait_for_host() function wait_for_host()
{ {
level endon("game_ended"); level endon("game_ended");
if ( level.botSoak )
{
return;
}
host = util::getHostPlayerForBots(); host = util::getHostPlayerForBots();
while (!isdefined(host)) while (!isdefined(host))
@ -155,7 +160,6 @@ function is_bot_comp_stomp()
return false; return false;
} }
// Bot Events // Bot Events
//======================================== //========================================
@ -194,6 +198,31 @@ function on_bot_connect()
function on_bot_spawned() function on_bot_spawned()
{ {
self.bot.goalTag = undefined; self.bot.goalTag = undefined;
/#
weapon = undefined;
if (getDvarInt("scr_botsHasPlayerWeapon") != 0)
{
player = util::getHostPlayer();
weapon = player getCurrentWeapon();
}
if (getDvarString("devgui_bot_weapon", "") != "")
{
weapon = getWeapon(getDvarString("devgui_bot_weapon"));
}
if (isdefined(weapon) && level.weaponNone != weapon)
{
self weapons::detach_all_weapons();
self takeAllWeapons();
self giveWeapon(weapon);
self switchToWeapon(weapon);
self setSpawnWeapon(weapon);
self teams::set_player_model(self.team, weapon);
}
#/
} }
function on_bot_killed() function on_bot_killed()
@ -246,7 +275,7 @@ function bot_idle()
function do_supplydrop(maxRange = 1400) // A little under minimap width function do_supplydrop(maxRange = 1400) // A little under minimap width
{ {
crates = GetEntArray( "care_package", "script_noteworthy" ); crates = getEntArray("care_package", "script_noteworthy");
maxRangeSq = maxRange * maxRange; maxRangeSq = maxRange * maxRange;
@ -257,12 +286,12 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width
foreach(crate in crates) foreach(crate in crates)
{ {
if ( !crate IsOnGround() ) if (!crate isOnGround())
{ {
continue; continue;
} }
crateDistSq = Distance2DSquared( self.origin, crate.origin ); crateDistSq = distance2DSquared(self.origin, crate.origin);
if (crateDistSq > maxRangeSq) if (crateDistSq > maxRangeSq)
{ {
@ -282,7 +311,7 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width
return true; return true;
} }
if ( !self has_minimap() && !self BotSightTracePassed( crate ) ) if (!self has_minimap() && !self botSightTracePassed(crate))
{ {
continue; continue;
} }
@ -296,12 +325,12 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width
if (isdefined(closestCrate)) if (isdefined(closestCrate))
{ {
randomAngle = ( 0, RandomInt( 360 ), 0 ); randomAngle = (0, randomInt(360), 0);
randomVec = AnglesToForward(randomAngle); randomVec = AnglesToForward(randomAngle);
point = closestCrate.origin + randomVec * CRATE_GOAL_RADIUS; point = closestCrate.origin + randomVec * CRATE_GOAL_RADIUS;
if ( self BotSetGoal( point ) ) if (self botSetGoal(point))
{ {
self thread watch_crate(closestCrate); self thread watch_crate(closestCrate);
return true; return true;
@ -322,7 +351,7 @@ function watch_crate( crate )
wait level.botSettings.thinkInterval; wait level.botSettings.thinkInterval;
} }
self BotSetGoal( self.origin ); self botSetGoal(self.origin);
} }
// Bot Team Population // Bot Team Population
@ -334,14 +363,14 @@ function populate_bots()
if (level.teambased) if (level.teambased)
{ {
maxAllies = GetDvarInt( "bot_maxAllies", 0 ); maxAllies = getDvarInt("bot_maxAllies", 0);
maxAxis = GetDvarInt( "bot_maxAxis", 0 ); maxAxis = getDvarInt("bot_maxAxis", 0);
level thread monitor_bot_team_population(maxAllies, maxAxis); level thread monitor_bot_team_population(maxAllies, maxAxis);
} }
else else
{ {
maxFree = GetDvarInt( "bot_maxFree", 0 ); maxFree = getDvarInt("bot_maxFree", 0);
level thread monitor_bot_population(maxFree); level thread monitor_bot_population(maxFree);
} }
@ -363,8 +392,8 @@ function monitor_bot_team_population( maxAllies, maxAxis )
wait 3; wait 3;
// TODO: Get a player count that includes 'CON_CONNECTING' players // TODO: Get a player count that includes 'CON_CONNECTING' players
allies = GetPlayers( "allies" ); allies = getPlayers("allies");
axis = GetPlayers( "axis" ); axis = getPlayers("axis");
if (allies.size > maxAllies && if (allies.size > maxAllies &&
remove_best_bot(allies)) remove_best_bot(allies))
@ -387,16 +416,16 @@ function monitor_bot_team_population( maxAllies, maxAxis )
function fill_balanced_teams(maxAllies, maxAxis) function fill_balanced_teams(maxAllies, maxAxis)
{ {
allies = GetPlayers( "allies" ); allies = getPlayers("allies");
axis = GetPlayers( "axis" ); axis = getPlayers("axis");
while ((allies.size < maxAllies || axis.size < maxAxis) && while ((allies.size < maxAllies || axis.size < maxAxis) &&
add_balanced_bot(allies, maxAllies, axis, maxAxis)) add_balanced_bot(allies, maxAllies, axis, maxAxis))
{ {
WAIT_SERVER_FRAME; WAIT_SERVER_FRAME;
allies = GetPlayers( "allies" ); allies = getPlayers("allies");
axis = GetPlayers( "axis" ); axis = getPlayers("axis");
} }
} }
@ -427,12 +456,12 @@ function monitor_bot_population( maxFree )
} }
// Initial Fill // Initial Fill
players = GetPlayers( ); players = getPlayers();
while (players.size < maxFree) while (players.size < maxFree)
{ {
add_bot(); add_bot();
WAIT_SERVER_FRAME; WAIT_SERVER_FRAME;
players = GetPlayers( ); players = getPlayers();
} }
while (1) while (1)
@ -440,7 +469,7 @@ function monitor_bot_population( maxFree )
wait 3; wait 3;
// TODO: Get a player count that includes 'CON_CONNECTING' players // TODO: Get a player count that includes 'CON_CONNECTING' players
players = GetPlayers( ); players = getPlayers();
if (players.size < maxFree) if (players.size < maxFree)
{ {
@ -481,11 +510,11 @@ function remove_best_bot( players )
if (bestBots.size) if (bestBots.size)
{ {
remove_bot( bestBots[RandomInt( bestBots.size )] ); remove_bot(bestBots[randomInt(bestBots.size)]);
} }
else else
{ {
remove_bot( bots[RandomInt( bots.size )] ); remove_bot(bots[randomInt(bots.size)]);
} }
return true; return true;
@ -503,13 +532,13 @@ function choose_class()
currClass = self bot_loadout::get_current_class(); currClass = self bot_loadout::get_current_class();
if ( !isdefined( currClass ) || RandomInt( 100 ) < VAL( level.botSettings.changeClassWeight, 0 ) ) if (!isdefined(currClass) || randomInt(100) < VAL(level.botSettings.changeClassWeight, 0))
{ {
classIndex = RandomInt( self.loadoutClasses.size ); classIndex = randomInt(self.loadoutClasses.size);
className = self.loadoutClasses[classIndex].name; className = self.loadoutClasses[classIndex].name;
} }
if ( !isdefined(className) || className === currClass ) if (!isdefined(className) || className == currClass)
{ {
return false; return false;
} }
@ -525,13 +554,13 @@ function choose_class()
function use_killstreak() function use_killstreak()
{ {
if (!level.loadoutKillstreaksEnabled || if (!level.loadoutKillstreaksEnabled ||
self emp::EnemyEMPActive() ) self emp::enemyEmpActive())
{ {
return; return;
} }
weapons = self GetWeaponsList(); weapons = self getWeaponsList();
inventoryWeapon = self GetInventoryWeapon(); inventoryWeapon = self getInventoryWeapon();
foreach(weapon in weapons) foreach(weapon in weapons)
{ {
@ -542,7 +571,7 @@ function use_killstreak()
continue; continue;
} }
if ( weapon != inventoryWeapon && !self GetWeaponAmmoClip( weapon ) ) if (weapon != inventoryWeapon && !self getWeaponAmmoClip(weapon))
{ {
continue; continue;
} }
@ -565,25 +594,27 @@ function use_killstreak()
{ {
case "killstreak_uav": case "killstreak_uav":
case "killstreak_counteruav": case "killstreak_counteruav":
case "killstreak_remote_missile":
{
self switchtoweapon( weapon );
self waittill( "weapon_change_complete" );
wait 1.5;
self bot::press_attack_button();
}
return;
case "killstreak_satellite": case "killstreak_satellite":
case "killstreak_helicopter_player_gunner": case "killstreak_helicopter_player_gunner":
case "killstreak_ai_tank_drop":
self use_supply_drop( weapon );
break;
case "killstreak_raps": case "killstreak_raps":
case "killstreak_sentinel": case "killstreak_sentinel":
{ {
self switchtoweapon(useweapon); self switchToWeapon(useWeapon);
break; break;
} }
case "killstreak_ai_tank_drop":
{
self use_supply_drop(weapon);
break;
}
case "killstreak_remote_missile":
{
self switchToWeapon(weapon);
self waittill("weapon_change_complete");
wait 1.5;
self bot::press_attack_button();
return;
}
} }
} }
@ -632,16 +663,16 @@ function use_supply_drop( weapon )
wait 0.5; wait 0.5;
if ( self getcurrentweapon() != weapon ) if (self getCurrentWeapon() != weapon)
{ {
self thread weapon_switch_failsafe(); self thread weapon_switch_failsafe();
self switchtoweapon( weapon ); self switchToWeapon(weapon);
self waittill("weapon_change_complete"); self waittill("weapon_change_complete");
} }
use_item(weapon); use_item(weapon);
self switchtoweapon( self.lastnonkillstreakweapon ); self switchToWeapon(self.lastnonkillstreakweapon);
self clearlookat(); self clearlookat();
self cancelgoal("killstreak"); self cancelgoal("killstreak");
} }
@ -653,7 +684,7 @@ function use_item( weapon )
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
{ {
if ( self getcurrentweapon() == weapon || self getcurrentweapon() == "none" ) if (self getCurrentWeapon() == weapon || self getCurrentWeapon() == "none")
self bot::press_attack_button(); self bot::press_attack_button();
else else
return; return;
@ -662,6 +693,52 @@ function use_item( weapon )
} }
} }
function killstreak_location(num, weapon)
{
enemies = get_enemies();
if (!enemies.size)
return;
if (!self switchToWeapon(weapon))
return;
self waittill("weapon_change");
self util::freeze_player_controls(true);
wait_time = 1;
while (!isdefined(self.selectinglocation) || self.selectinglocation == 0)
{
wait 0.05;
wait_time -= 0.05;
if (wait_time <= 0)
{
self util::freeze_player_controls(false);
self switchToWeapon(self.lastnonkillstreakweapon);
return;
}
}
wait 2;
for (i = 0; i < num; i++)
{
enemies = get_enemies();
if (enemies.size)
{
enemy = randomInt(enemies);
self notify("confirm_location", enemy.origin, 0);
}
wait 0.25;
}
self util::freeze_player_controls(false);
}
function weapon_switch_failsafe() function weapon_switch_failsafe()
{ {
self endon("death"); self endon("death");
@ -671,7 +748,6 @@ function weapon_switch_failsafe()
self notify("weapon_change_complete"); self notify("weapon_change_complete");
} }
function has_radar() function has_radar()
{ {
if (level.teambased) if (level.teambased)
@ -706,18 +782,29 @@ function get_enemies( on_radar )
enemies = self GetEnemies(); enemies = self GetEnemies();
/#
for (i = 0; i < enemies.size; i++)
{
if (isplayer(enemies[i]) && enemies[i] isInMoveMode("ufo", "noclip"))
{
arrayRemoveIndex(enemies, i);
i--;
}
}
#/
if (on_radar && !self has_radar()) if (on_radar && !self has_radar())
{ {
for (i = 0; i < enemies.size; i++) for (i = 0; i < enemies.size; i++)
{ {
if (!isdefined(enemies[i].lastFireTime)) if (!isdefined(enemies[i].lastFireTime))
{ {
ArrayRemoveIndex( enemies, i ); arrayRemoveIndex(enemies, i);
i--; i--;
} }
else if (GetTime() - enemies[i].lastFireTime > 2000) else if (GetTime() - enemies[i].lastFireTime > 2000)
{ {
ArrayRemoveIndex( enemies, i ); arrayRemoveIndex(enemies, i);
i--; i--;
} }
} }
@ -728,7 +815,7 @@ function get_enemies( on_radar )
function set_rank() function set_rank()
{ {
players = GetPlayers(); players = getPlayers();
ranks = []; ranks = [];
bot_ranks = []; bot_ranks = [];
@ -760,12 +847,12 @@ function set_rank()
while (bot_ranks.size + human_ranks.size < 5) while (bot_ranks.size + human_ranks.size < 5)
{ {
// add some random ranks for better random number distribution // add some random ranks for better random number distribution
r = human_avg + RandomIntRange( -5, 5 ); r = human_avg + randomIntRange(-5, 5);
rank = math::clamp(r, 0, level.maxRank); rank = math::clamp(r, 0, level.maxRank);
human_ranks[human_ranks.size] = rank; human_ranks[human_ranks.size] = rank;
} }
ranks = ArrayCombine( human_ranks, bot_ranks, true, false ); ranks = arrayCombine(human_ranks, bot_ranks, true, false);
avg = math::array_average(ranks); avg = math::array_average(ranks);
s = math::array_std_deviation(ranks, avg); s = math::array_std_deviation(ranks, avg);
@ -786,69 +873,49 @@ function set_rank()
function init_bot_gametype() function init_bot_gametype()
{ {
switch(level.gametype) switch (level.gameType)
{ {
case "ball": case "ball":
{
bot_ball::init(); bot_ball::init();
return true; return true;
}
case "conf": case "conf":
{
bot_conf::init(); bot_conf::init();
return true; return true;
}
case "ctf": case "ctf":
{
bot_ctf::init(); bot_ctf::init();
return true; return true;
}
case "dem": case "dem":
{
bot_dem::init(); bot_dem::init();
return true; return true;
}
case "dm": case "dm":
{
return true; return true;
}
case "dom": case "dom":
{
bot_dom::init(); bot_dom::init();
return true; return true;
}
case "escort": case "escort":
{
bot_escort::init(); bot_escort::init();
return true; return true;
} // case "infect":
/* case "infect": // return true;
{ case "gun":
return true; return true;
}
*/ case "gun":
{
return true;
}
case "koth": case "koth":
{
bot_koth::init(); bot_koth::init();
return true; return true;
}
case "sd": case "sd":
{
bot_sd::init(); bot_sd::init();
return true; return true;
}
case "clean": case "clean":
{
bot_clean::init(); bot_clean::init();
return true; return true;
}
case "tdm": case "tdm":
{
return true; return true;
} case "sas":
return true;
case "prop":
return true;
case "sniperonly":
return true;
} }
return false; return false;
@ -856,7 +923,7 @@ function init_bot_gametype()
function get_bot_settings() function get_bot_settings()
{ {
switch ( GetDvarInt( "bot_difficulty", 1 ) ) switch (getDvarInt("bot_difficulty", 1))
{ {
case 0: case 0:
bundleName = "bot_mp_easy"; bundleName = "bot_mp_easy";
@ -907,3 +974,144 @@ function dive_to_prone( exit_stance )
} }
/#
// Devgui
//========================================
function bot_devgui_cmd(cmd)
{
cmdTokens = strtok(cmd, " ");
if (cmdTokens.size == 0)
{
return false;
}
host = util::getHostPlayerForBots();
team = get_host_team();
switch (cmdTokens[0])
{
case "spawn_enemy":
team = util::getotherteam(team);
case "spawn_friendly":
count = 1;
if (cmdTokens.size > 1)
{
count = int(cmdTokens[1]);
}
for (i = 0; i < count; i++)
{
add_bot(team);
}
return true;
case "remove_enemy":
team = util::getotherteam(team);
case "remove_friendly":
remove_bots(undefined, team);
return true;
case "fixed_spawn_enemy":
team = util::getotherteam(team);
case "fixed_spawn_friendly":
bot = add_bot_at_eye_trace(team);
if (isdefined(bot))
{
bot thread fixed_spawn_override();
}
return true;
case "player_weapon":
players = getPlayers();
foreach(player in players)
{
if (!player util::is_bot())
{
continue;
}
weapon = host getCurrentWeapon();
player weapons::detach_all_weapons();
player takeAllWeapons();
player giveWeapon(weapon);
player switchToWeapon(weapon);
player setSpawnWeapon(weapon);
player teams::set_player_model(player.team, weapon);
}
return true;
}
return false;
}
function system_devgui_gadget_think()
{
setDvar("devgui_bot_gadget", "");
for (;; )
{
wait(1);
gadget = getDvarString("devgui_bot_gadget");
if (gadget.size == 0)
{
bot_turn_on_gadget(getWeapon(gadget));
setDvar("devgui_bot_gadget", "");
}
}
}
function bot_turn_on_gadget(gadget)
{
players = getPlayers();
foreach(player in players)
{
if (!player util::is_bot())
{
continue;
}
host = util::getHostPlayer();
weapon = host getCurrentWeapon();
if (!isdefined(weapon) || weapon == level.weaponNone || weapon == level.weaponNull)
{
weapon = getWeapon("smg_standard");
}
player weapons::detach_all_weapons();
player takeAllWeapons();
player giveWeapon(weapon);
player switchToWeapon(weapon);
player setSpawnWeapon(weapon);
player teams::set_player_model(player.team, weapon);
player giveWeapon(gadget);
slot = player gadgetGetSlot(gadget);
player gadgetPowerSet(slot, 100.0);
player botPressButtonForGadget(gadget);
}
}
function fixed_spawn_override()
{
self endon("disconnect");
spawnOrigin = self.origin;
spawnAngles = self.angles;
while (1)
{
self waittill("spawned_player");
self setOrigin(spawnOrigin);
self setPlayerAngles(spawnAngles);
}
}
#/