mirror of
https://github.com/ineedbots/t5_bot_warfare.git
synced 2026-05-03 08:39:34 +00:00
Start push update
This commit is contained in:
+7
-3
@@ -19,11 +19,15 @@
|
||||
!/mods/
|
||||
/mods/*
|
||||
!/mods/mp_bots/
|
||||
!/mods/mp_patch/
|
||||
!/mods/patch_mp/
|
||||
!/mods/patch_ui_mp/
|
||||
|
||||
*.log
|
||||
missingasset.csv
|
||||
*.ff
|
||||
*.files
|
||||
/mods/mp_bots/out/*
|
||||
!/mods/mp_bots/out/readme.txt
|
||||
*.iwd
|
||||
!/out/
|
||||
!/out/**/*.ff
|
||||
!/out/**/*.iwd
|
||||
*.zip
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
_bot_utility
|
||||
Author: INeedGames
|
||||
Date: 12/20/2020
|
||||
The shared functions for bots
|
||||
*/
|
||||
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
/*
|
||||
Returns an array of all the bots in the game.
|
||||
*/
|
||||
getBotArray()
|
||||
{
|
||||
result = [];
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(!player is_bot())
|
||||
continue;
|
||||
|
||||
result[result.size] = player;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a good amount of players.
|
||||
*/
|
||||
getGoodMapAmount()
|
||||
{
|
||||
switch(getdvar("mapname"))
|
||||
{
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Rounds to the nearest whole number.
|
||||
*/
|
||||
Round(x)
|
||||
{
|
||||
y = int(x);
|
||||
|
||||
if(abs(x) - abs(y) > 0.5)
|
||||
{
|
||||
if(x < 0)
|
||||
return y - 1;
|
||||
else
|
||||
return y + 1;
|
||||
}
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
/*
|
||||
Picks a random thing
|
||||
*/
|
||||
PickRandom(arr)
|
||||
{
|
||||
if (!arr.size)
|
||||
return undefined;
|
||||
|
||||
return arr[randomInt(arr.size)];
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
isDefusing()
|
||||
{
|
||||
return (isDefined(self.isDefusing) && self.isDefusing);
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
isPlanting()
|
||||
{
|
||||
return (isDefined(self.isPlanting) && self.isPlanting);
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
inLastStand()
|
||||
{
|
||||
return (isDefined(self.laststand) && self.laststand);
|
||||
}
|
||||
|
||||
/*
|
||||
Is they the flag carrier men?
|
||||
*/
|
||||
isFlagCarrier()
|
||||
{
|
||||
return (isDefined(self.isFlagCarrier) && self.isFlagCarrier);
|
||||
}
|
||||
|
||||
/*
|
||||
If the site is in use
|
||||
*/
|
||||
isInUse()
|
||||
{
|
||||
return (isDefined(self.inUse) && self.inUse);
|
||||
}
|
||||
|
||||
/*
|
||||
If the player is carrying a bomb
|
||||
*/
|
||||
isBombCarrier()
|
||||
{
|
||||
return (isDefined(self.isBombCarrier) && self.isBombCarrier);
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the bot's difficulty number
|
||||
*/
|
||||
GetBotDiffNum()
|
||||
{
|
||||
num = 0;
|
||||
|
||||
switch (getDvar("bot_difficulty"))
|
||||
{
|
||||
case "fu":
|
||||
num = 3;
|
||||
break;
|
||||
case "hard":
|
||||
num = 2;
|
||||
break;
|
||||
case "normal":
|
||||
num = 1;
|
||||
break;
|
||||
case "easy":
|
||||
default:
|
||||
num = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
Taken from iw4 script
|
||||
*/
|
||||
waittill_any_timeout( timeOut, string1, string2, string3, string4, string5 )
|
||||
{
|
||||
if ( ( !isdefined( string1 ) || string1 != "death" ) &&
|
||||
( !isdefined( string2 ) || string2 != "death" ) &&
|
||||
( !isdefined( string3 ) || string3 != "death" ) &&
|
||||
( !isdefined( string4 ) || string4 != "death" ) &&
|
||||
( !isdefined( string5 ) || string5 != "death" ) )
|
||||
self endon( "death" );
|
||||
|
||||
ent = spawnstruct();
|
||||
|
||||
if ( isdefined( string1 ) )
|
||||
self thread waittill_string( string1, ent );
|
||||
|
||||
if ( isdefined( string2 ) )
|
||||
self thread waittill_string( string2, ent );
|
||||
|
||||
if ( isdefined( string3 ) )
|
||||
self thread waittill_string( string3, ent );
|
||||
|
||||
if ( isdefined( string4 ) )
|
||||
self thread waittill_string( string4, ent );
|
||||
|
||||
if ( isdefined( string5 ) )
|
||||
self thread waittill_string( string5, ent );
|
||||
|
||||
ent thread _timeout( timeOut );
|
||||
|
||||
ent waittill( "returned", msg );
|
||||
ent notify( "die" );
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
Used for waittill_any_timeout
|
||||
*/
|
||||
_timeout( delay )
|
||||
{
|
||||
self endon( "die" );
|
||||
|
||||
wait( delay );
|
||||
self notify( "returned", "timeout" );
|
||||
}
|
||||
|
||||
/*
|
||||
Waits for a host player
|
||||
*/
|
||||
bot_wait_for_host()
|
||||
{
|
||||
host = undefined;
|
||||
|
||||
while (!isDefined(level) || !isDefined(level.players))
|
||||
wait 0.05;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
host = GetHostPlayer();
|
||||
|
||||
if(isDefined(host))
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
|
||||
if(!isDefined(host))
|
||||
return;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
if(IsDefined( host.pers[ "team" ] ))
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
|
||||
if(!IsDefined( host.pers[ "team" ] ))
|
||||
return;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
if(host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis")
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Wrapper for setgoal
|
||||
*/
|
||||
SetBotGoal(where, dist)
|
||||
{
|
||||
self SetScriptGoal(where, dist);
|
||||
waittillframeend;
|
||||
self notify("new_goal");
|
||||
}
|
||||
|
||||
/*
|
||||
Weapper for cleargoal
|
||||
*/
|
||||
ClearBotGoal()
|
||||
{
|
||||
self ClearScriptGoal();
|
||||
waittillframeend;
|
||||
self notify("new_goal");
|
||||
}
|
||||
|
||||
/*
|
||||
Freezes bot in place
|
||||
*/
|
||||
botStopMove(what)
|
||||
{
|
||||
self endon("disconnect");
|
||||
self endon("death");
|
||||
level endon("game_ended");
|
||||
|
||||
self notify("botStopMove");
|
||||
self endon("botStopMove");
|
||||
|
||||
if (!what)
|
||||
return;
|
||||
|
||||
og = self.origin;
|
||||
for (;;)
|
||||
{
|
||||
self setVelocity((0,0,0));
|
||||
self setOrigin(og);
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Matches a num to a char
|
||||
*/
|
||||
keyCodeToString(a)
|
||||
{
|
||||
b="";
|
||||
switch(a)
|
||||
{
|
||||
case 0: b= "a"; break;
|
||||
case 1: b= "b"; break;
|
||||
case 2: b= "c"; break;
|
||||
case 3: b= "d"; break;
|
||||
case 4: b= "e"; break;
|
||||
case 5: b= "f"; break;
|
||||
case 6: b= "g"; break;
|
||||
case 7: b= "h"; break;
|
||||
case 8: b= "i"; break;
|
||||
case 9: b= "j"; break;
|
||||
case 10: b= "k"; break;
|
||||
case 11: b= "l"; break;
|
||||
case 12: b= "m"; break;
|
||||
case 13: b= "n"; break;
|
||||
case 14: b= "o"; break;
|
||||
case 15: b= "p"; break;
|
||||
case 16: b= "q"; break;
|
||||
case 17: b= "r"; break;
|
||||
case 18: b= "s"; break;
|
||||
case 19: b= "t"; break;
|
||||
case 20: b= "u"; break;
|
||||
case 21: b= "v"; break;
|
||||
case 22: b= "w"; break;
|
||||
case 23: b= "x"; break;
|
||||
case 24: b= "y"; break;
|
||||
case 25: b= "z"; break;
|
||||
case 26: b= "."; break;
|
||||
case 27: b= " "; break;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
Does the extra check when adding bots
|
||||
*/
|
||||
doExtraCheck()
|
||||
{
|
||||
maps\mp\bots\_bot_script::checkTheBots();
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the cone dot (like fov, or distance from the center of our screen).
|
||||
*/
|
||||
getConeDot(to, from, dir)
|
||||
{
|
||||
dirToTarget = VectorNormalize(to-from);
|
||||
forward = AnglesToForward(dir);
|
||||
return vectordot(dirToTarget, forward);
|
||||
}
|
||||
|
||||
/*
|
||||
Fixes sd bomb planting
|
||||
*/
|
||||
bot_onUsePlantObjectFix( player )
|
||||
{
|
||||
// planted the bomb
|
||||
if ( !self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
|
||||
{
|
||||
level thread bot_bombPlanted( self, player );
|
||||
player logString( "bomb planted: " + self.label );
|
||||
|
||||
// disable all bomb zones except this one
|
||||
for ( index = 0; index < level.bombZones.size; index++ )
|
||||
{
|
||||
if ( level.bombZones[index] == self )
|
||||
continue;
|
||||
|
||||
level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
|
||||
}
|
||||
thread playSoundOnPlayers( "mus_sd_planted"+"_"+level.teamPostfix[player.pers["team"]] );
|
||||
// removed plant audio until finalization of assest TODO : new plant sounds when assests are online
|
||||
// player playSound( "mpl_sd_bomb_plant" );
|
||||
player notify ( "bomb_planted" );
|
||||
|
||||
level thread maps\mp\_popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_PLANTED_BY", player );
|
||||
|
||||
if( isdefined(player.pers["plants"]) )
|
||||
{
|
||||
player.pers["plants"]++;
|
||||
player.plants = player.pers["plants"];
|
||||
}
|
||||
|
||||
player maps\mp\_medals::saboteur();
|
||||
player maps\mp\gametypes\_persistence::statAddWithGameType( "PLANTS", 1 );
|
||||
|
||||
maps\mp\gametypes\_globallogic_audio::leaderDialog( "bomb_planted" );
|
||||
|
||||
maps\mp\gametypes\_globallogic_score::givePlayerScore( "plant", player );
|
||||
//player thread [[level.onXPEvent]]( "plant" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fixes sd bomb planting
|
||||
*/
|
||||
bot_bombPlanted( destroyedObj, player )
|
||||
{
|
||||
maps\mp\gametypes\_globallogic_utils::pauseTimer();
|
||||
level.bombPlanted = true;
|
||||
|
||||
destroyedObj.visuals[0] thread maps\mp\gametypes\_globallogic_utils::playTickingSound( "mpl_sab_ui_suitcasebomb_timer" );
|
||||
//Play suspense music
|
||||
level thread maps\mp\gametypes\sd::bombPlantedMusicDelay();
|
||||
|
||||
//thread maps\mp\gametypes\_globallogic_audio::actionMusicSet();
|
||||
|
||||
level.tickingObject = destroyedObj.visuals[0];
|
||||
|
||||
level.timeLimitOverride = true;
|
||||
setGameEndTime( int( gettime() + (level.bombTimer * 1000) ) );
|
||||
setMatchFlag( "bomb_timer", 1 );
|
||||
|
||||
if ( !level.multiBomb )
|
||||
{
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" );
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::setDropped();
|
||||
level.sdBombModel = level.sdBomb.visuals[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for ( index = 0; index < level.players.size; index++ )
|
||||
{
|
||||
if ( isDefined( level.players[index].carryIcon ) )
|
||||
level.players[index].carryIcon destroyElem();
|
||||
}
|
||||
|
||||
trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
|
||||
|
||||
tempAngle = randomfloat( 360 );
|
||||
forward = (cos( tempAngle ), sin( tempAngle ), 0);
|
||||
forward = vectornormalize( forward - vector_scale( trace["normal"], vectordot( forward, trace["normal"] ) ) );
|
||||
dropAngles = vectortoangles( forward );
|
||||
|
||||
level.sdBombModel = spawn( "script_model", trace["position"] );
|
||||
level.sdBombModel.angles = dropAngles;
|
||||
level.sdBombModel setModel( "prop_suitcase_bomb" );
|
||||
}
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::allowUse( "none" );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
|
||||
/*
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined );
|
||||
*/
|
||||
label = destroyedObj maps\mp\gametypes\_gameobjects::getLabel();
|
||||
|
||||
// create a new object to defuse with.
|
||||
trigger = destroyedObj.bombDefuseTrig;
|
||||
trigger.origin = level.sdBombModel.origin;
|
||||
visuals = [];
|
||||
defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,32) );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "compass_waypoint_defuse" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "compass_waypoint_defend" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defuse" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_defend" + label );
|
||||
defuseObject.label = label;
|
||||
defuseObject.onBeginUse = maps\mp\gametypes\sd::onBeginUse;
|
||||
defuseObject.onEndUse = maps\mp\gametypes\sd::onEndUse;
|
||||
defuseObject.onUse = maps\mp\gametypes\sd::onUseDefuseObject;
|
||||
defuseObject.useWeapon = "briefcase_bomb_defuse_mp";
|
||||
|
||||
level.defuseObject = defuseObject;//every cod...
|
||||
|
||||
player.isBombCarrier = false;
|
||||
|
||||
maps\mp\gametypes\sd::BombTimerWait();
|
||||
setMatchFlag( "bomb_timer", 0 );
|
||||
|
||||
destroyedObj.visuals[0] maps\mp\gametypes\_globallogic_utils::stopTickingSound();
|
||||
|
||||
if ( level.gameEnded || level.bombDefused )
|
||||
return;
|
||||
|
||||
level.bombExploded = true;
|
||||
|
||||
|
||||
|
||||
explosionOrigin = level.sdBombModel.origin+(0,0,12);
|
||||
level.sdBombModel hide();
|
||||
|
||||
if ( isdefined( player ) )
|
||||
{
|
||||
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player, "MOD_EXPLOSIVE", "briefcase_bomb_mp" );
|
||||
level thread maps\mp\_popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_BLOWUP_BY", player );
|
||||
player maps\mp\_medals::bomber();
|
||||
player maps\mp\gametypes\_persistence::statAddWithGameType( "DESTRUCTIONS", 1 );
|
||||
}
|
||||
else
|
||||
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, undefined, "MOD_EXPLOSIVE", "briefcase_bomb_mp" );
|
||||
|
||||
rot = randomfloat(360);
|
||||
explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) );
|
||||
triggerFx( explosionEffect );
|
||||
|
||||
thread playSoundinSpace( "mpl_sd_exp_suitcase_bomb_main", explosionOrigin );
|
||||
//thread maps\mp\gametypes\_globallogic_audio::set_music_on_team( "SILENT", "both" );
|
||||
|
||||
if ( isDefined( destroyedObj.exploderIndex ) )
|
||||
exploder( destroyedObj.exploderIndex );
|
||||
|
||||
for ( index = 0; index < level.bombZones.size; index++ )
|
||||
level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
|
||||
defuseObject maps\mp\gametypes\_gameobjects::disableObject();
|
||||
|
||||
setGameEndTime( 0 );
|
||||
|
||||
wait 3;
|
||||
|
||||
maps\mp\gametypes\sd::sd_endGame( game["attackers"], game["strings"]["target_destroyed"] );
|
||||
}
|
||||
+546
-6923
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
_bot_utility
|
||||
Author: INeedGames
|
||||
Date: 12/20/2020
|
||||
The shared functions for bots
|
||||
*/
|
||||
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
|
||||
/*
|
||||
Returns an array of all the bots in the game.
|
||||
*/
|
||||
getBotArray()
|
||||
{
|
||||
result = [];
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(!player is_bot())
|
||||
continue;
|
||||
|
||||
result[result.size] = player;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a good amount of players.
|
||||
*/
|
||||
getGoodMapAmount()
|
||||
{
|
||||
switch(getdvar("mapname"))
|
||||
{
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Rounds to the nearest whole number.
|
||||
*/
|
||||
Round(x)
|
||||
{
|
||||
y = int(x);
|
||||
|
||||
if(abs(x) - abs(y) > 0.5)
|
||||
{
|
||||
if(x < 0)
|
||||
return y - 1;
|
||||
else
|
||||
return y + 1;
|
||||
}
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
/*
|
||||
Picks a random thing
|
||||
*/
|
||||
PickRandom(arr)
|
||||
{
|
||||
if (!arr.size)
|
||||
return undefined;
|
||||
|
||||
return arr[randomInt(arr.size)];
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
isDefusing()
|
||||
{
|
||||
return (isDefined(self.isDefusing) && self.isDefusing);
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
isPlanting()
|
||||
{
|
||||
return (isDefined(self.isPlanting) && self.isPlanting);
|
||||
}
|
||||
|
||||
/*
|
||||
If is defusing
|
||||
*/
|
||||
inLastStand()
|
||||
{
|
||||
return (isDefined(self.laststand) && self.laststand);
|
||||
}
|
||||
|
||||
/*
|
||||
Is they the flag carrier men?
|
||||
*/
|
||||
isFlagCarrier()
|
||||
{
|
||||
return (isDefined(self.isFlagCarrier) && self.isFlagCarrier);
|
||||
}
|
||||
|
||||
/*
|
||||
If the site is in use
|
||||
*/
|
||||
isInUse()
|
||||
{
|
||||
return (isDefined(self.inUse) && self.inUse);
|
||||
}
|
||||
|
||||
/*
|
||||
If the player is carrying a bomb
|
||||
*/
|
||||
isBombCarrier()
|
||||
{
|
||||
return (isDefined(self.isBombCarrier) && self.isBombCarrier);
|
||||
}
|
||||
|
||||
/*
|
||||
Gets the bot's difficulty number
|
||||
*/
|
||||
GetBotDiffNum()
|
||||
{
|
||||
num = 0;
|
||||
|
||||
switch (getDvar("bot_difficulty"))
|
||||
{
|
||||
case "fu":
|
||||
num = 3;
|
||||
break;
|
||||
case "hard":
|
||||
num = 2;
|
||||
break;
|
||||
case "normal":
|
||||
num = 1;
|
||||
break;
|
||||
case "easy":
|
||||
default:
|
||||
num = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
Taken from iw4 script
|
||||
*/
|
||||
waittill_any_timeout( timeOut, string1, string2, string3, string4, string5 )
|
||||
{
|
||||
if ( ( !isdefined( string1 ) || string1 != "death" ) &&
|
||||
( !isdefined( string2 ) || string2 != "death" ) &&
|
||||
( !isdefined( string3 ) || string3 != "death" ) &&
|
||||
( !isdefined( string4 ) || string4 != "death" ) &&
|
||||
( !isdefined( string5 ) || string5 != "death" ) )
|
||||
self endon( "death" );
|
||||
|
||||
ent = spawnstruct();
|
||||
|
||||
if ( isdefined( string1 ) )
|
||||
self thread waittill_string( string1, ent );
|
||||
|
||||
if ( isdefined( string2 ) )
|
||||
self thread waittill_string( string2, ent );
|
||||
|
||||
if ( isdefined( string3 ) )
|
||||
self thread waittill_string( string3, ent );
|
||||
|
||||
if ( isdefined( string4 ) )
|
||||
self thread waittill_string( string4, ent );
|
||||
|
||||
if ( isdefined( string5 ) )
|
||||
self thread waittill_string( string5, ent );
|
||||
|
||||
ent thread _timeout( timeOut );
|
||||
|
||||
ent waittill( "returned", msg );
|
||||
ent notify( "die" );
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
Used for waittill_any_timeout
|
||||
*/
|
||||
_timeout( delay )
|
||||
{
|
||||
self endon( "die" );
|
||||
|
||||
wait( delay );
|
||||
self notify( "returned", "timeout" );
|
||||
}
|
||||
|
||||
/*
|
||||
Waits for a host player
|
||||
*/
|
||||
bot_wait_for_host()
|
||||
{
|
||||
host = undefined;
|
||||
|
||||
while (!isDefined(level) || !isDefined(level.players))
|
||||
wait 0.05;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
host = GetHostPlayer();
|
||||
|
||||
if(isDefined(host))
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
|
||||
if(!isDefined(host))
|
||||
return;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
if(IsDefined( host.pers[ "team" ] ))
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
|
||||
if(!IsDefined( host.pers[ "team" ] ))
|
||||
return;
|
||||
|
||||
for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05)
|
||||
{
|
||||
if(host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis")
|
||||
break;
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Wrapper for setgoal
|
||||
*/
|
||||
SetBotGoal(where, dist)
|
||||
{
|
||||
self SetScriptGoal(where, dist);
|
||||
waittillframeend;
|
||||
self notify("new_goal");
|
||||
}
|
||||
|
||||
/*
|
||||
Weapper for cleargoal
|
||||
*/
|
||||
ClearBotGoal()
|
||||
{
|
||||
self ClearScriptGoal();
|
||||
waittillframeend;
|
||||
self notify("new_goal");
|
||||
}
|
||||
|
||||
/*
|
||||
Freezes bot in place
|
||||
*/
|
||||
botStopMove(what)
|
||||
{
|
||||
self endon("disconnect");
|
||||
self endon("death");
|
||||
level endon("game_ended");
|
||||
|
||||
self notify("botStopMove");
|
||||
self endon("botStopMove");
|
||||
|
||||
if (!what)
|
||||
return;
|
||||
|
||||
og = self.origin;
|
||||
for (;;)
|
||||
{
|
||||
self setVelocity((0,0,0));
|
||||
self setOrigin(og);
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Matches a num to a char
|
||||
*/
|
||||
keyCodeToString(a)
|
||||
{
|
||||
b="";
|
||||
switch(a)
|
||||
{
|
||||
case 0: b= "a"; break;
|
||||
case 1: b= "b"; break;
|
||||
case 2: b= "c"; break;
|
||||
case 3: b= "d"; break;
|
||||
case 4: b= "e"; break;
|
||||
case 5: b= "f"; break;
|
||||
case 6: b= "g"; break;
|
||||
case 7: b= "h"; break;
|
||||
case 8: b= "i"; break;
|
||||
case 9: b= "j"; break;
|
||||
case 10: b= "k"; break;
|
||||
case 11: b= "l"; break;
|
||||
case 12: b= "m"; break;
|
||||
case 13: b= "n"; break;
|
||||
case 14: b= "o"; break;
|
||||
case 15: b= "p"; break;
|
||||
case 16: b= "q"; break;
|
||||
case 17: b= "r"; break;
|
||||
case 18: b= "s"; break;
|
||||
case 19: b= "t"; break;
|
||||
case 20: b= "u"; break;
|
||||
case 21: b= "v"; break;
|
||||
case 22: b= "w"; break;
|
||||
case 23: b= "x"; break;
|
||||
case 24: b= "y"; break;
|
||||
case 25: b= "z"; break;
|
||||
case 26: b= "."; break;
|
||||
case 27: b= " "; break;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
Does the extra check when adding bots
|
||||
*/
|
||||
doExtraCheck()
|
||||
{
|
||||
maps\mp\bots\_bot_script::checkTheBots();
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the cone dot (like fov, or distance from the center of our screen).
|
||||
*/
|
||||
getConeDot(to, from, dir)
|
||||
{
|
||||
dirToTarget = VectorNormalize(to-from);
|
||||
forward = AnglesToForward(dir);
|
||||
return vectordot(dirToTarget, forward);
|
||||
}
|
||||
|
||||
/*
|
||||
Fixes sd bomb planting
|
||||
*/
|
||||
bot_onUsePlantObjectFix( player )
|
||||
{
|
||||
// planted the bomb
|
||||
if ( !self maps\mp\gametypes\_gameobjects::isFriendlyTeam( player.pers["team"] ) )
|
||||
{
|
||||
level thread bot_bombPlanted( self, player );
|
||||
player logString( "bomb planted: " + self.label );
|
||||
|
||||
// disable all bomb zones except this one
|
||||
for ( index = 0; index < level.bombZones.size; index++ )
|
||||
{
|
||||
if ( level.bombZones[index] == self )
|
||||
continue;
|
||||
|
||||
level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
|
||||
}
|
||||
thread playSoundOnPlayers( "mus_sd_planted"+"_"+level.teamPostfix[player.pers["team"]] );
|
||||
// removed plant audio until finalization of assest TODO : new plant sounds when assests are online
|
||||
// player playSound( "mpl_sd_bomb_plant" );
|
||||
player notify ( "bomb_planted" );
|
||||
|
||||
level thread maps\mp\_popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_PLANTED_BY", player );
|
||||
|
||||
if( isdefined(player.pers["plants"]) )
|
||||
{
|
||||
player.pers["plants"]++;
|
||||
player.plants = player.pers["plants"];
|
||||
}
|
||||
|
||||
player maps\mp\_medals::saboteur();
|
||||
player maps\mp\gametypes\_persistence::statAddWithGameType( "PLANTS", 1 );
|
||||
|
||||
maps\mp\gametypes\_globallogic_audio::leaderDialog( "bomb_planted" );
|
||||
|
||||
maps\mp\gametypes\_globallogic_score::givePlayerScore( "plant", player );
|
||||
//player thread [[level.onXPEvent]]( "plant" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fixes sd bomb planting
|
||||
*/
|
||||
bot_bombPlanted( destroyedObj, player )
|
||||
{
|
||||
maps\mp\gametypes\_globallogic_utils::pauseTimer();
|
||||
level.bombPlanted = true;
|
||||
|
||||
destroyedObj.visuals[0] thread maps\mp\gametypes\_globallogic_utils::playTickingSound( "mpl_sab_ui_suitcasebomb_timer" );
|
||||
//Play suspense music
|
||||
level thread maps\mp\gametypes\sd::bombPlantedMusicDelay();
|
||||
|
||||
//thread maps\mp\gametypes\_globallogic_audio::actionMusicSet();
|
||||
|
||||
level.tickingObject = destroyedObj.visuals[0];
|
||||
|
||||
level.timeLimitOverride = true;
|
||||
setGameEndTime( int( gettime() + (level.bombTimer * 1000) ) );
|
||||
setMatchFlag( "bomb_timer", 1 );
|
||||
|
||||
if ( !level.multiBomb )
|
||||
{
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" );
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
|
||||
level.sdBomb maps\mp\gametypes\_gameobjects::setDropped();
|
||||
level.sdBombModel = level.sdBomb.visuals[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for ( index = 0; index < level.players.size; index++ )
|
||||
{
|
||||
if ( isDefined( level.players[index].carryIcon ) )
|
||||
level.players[index].carryIcon destroyElem();
|
||||
}
|
||||
|
||||
trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
|
||||
|
||||
tempAngle = randomfloat( 360 );
|
||||
forward = (cos( tempAngle ), sin( tempAngle ), 0);
|
||||
forward = vectornormalize( forward - vector_scale( trace["normal"], vectordot( forward, trace["normal"] ) ) );
|
||||
dropAngles = vectortoangles( forward );
|
||||
|
||||
level.sdBombModel = spawn( "script_model", trace["position"] );
|
||||
level.sdBombModel.angles = dropAngles;
|
||||
level.sdBombModel setModel( "prop_suitcase_bomb" );
|
||||
}
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::allowUse( "none" );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" );
|
||||
/*
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined );
|
||||
destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined );
|
||||
*/
|
||||
label = destroyedObj maps\mp\gametypes\_gameobjects::getLabel();
|
||||
|
||||
// create a new object to defuse with.
|
||||
trigger = destroyedObj.bombDefuseTrig;
|
||||
trigger.origin = level.sdBombModel.origin;
|
||||
visuals = [];
|
||||
defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,32) );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", "compass_waypoint_defuse" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", "compass_waypoint_defend" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defuse" + label );
|
||||
defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_defend" + label );
|
||||
defuseObject.label = label;
|
||||
defuseObject.onBeginUse = maps\mp\gametypes\sd::onBeginUse;
|
||||
defuseObject.onEndUse = maps\mp\gametypes\sd::onEndUse;
|
||||
defuseObject.onUse = maps\mp\gametypes\sd::onUseDefuseObject;
|
||||
defuseObject.useWeapon = "briefcase_bomb_defuse_mp";
|
||||
|
||||
level.defuseObject = defuseObject;//every cod...
|
||||
|
||||
player.isBombCarrier = false;
|
||||
|
||||
maps\mp\gametypes\sd::BombTimerWait();
|
||||
setMatchFlag( "bomb_timer", 0 );
|
||||
|
||||
destroyedObj.visuals[0] maps\mp\gametypes\_globallogic_utils::stopTickingSound();
|
||||
|
||||
if ( level.gameEnded || level.bombDefused )
|
||||
return;
|
||||
|
||||
level.bombExploded = true;
|
||||
|
||||
|
||||
|
||||
explosionOrigin = level.sdBombModel.origin+(0,0,12);
|
||||
level.sdBombModel hide();
|
||||
|
||||
if ( isdefined( player ) )
|
||||
{
|
||||
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player, "MOD_EXPLOSIVE", "briefcase_bomb_mp" );
|
||||
level thread maps\mp\_popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_BLOWUP_BY", player );
|
||||
player maps\mp\_medals::bomber();
|
||||
player maps\mp\gametypes\_persistence::statAddWithGameType( "DESTRUCTIONS", 1 );
|
||||
}
|
||||
else
|
||||
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, undefined, "MOD_EXPLOSIVE", "briefcase_bomb_mp" );
|
||||
|
||||
rot = randomfloat(360);
|
||||
explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) );
|
||||
triggerFx( explosionEffect );
|
||||
|
||||
thread playSoundinSpace( "mpl_sd_exp_suitcase_bomb_main", explosionOrigin );
|
||||
//thread maps\mp\gametypes\_globallogic_audio::set_music_on_team( "SILENT", "both" );
|
||||
|
||||
if ( isDefined( destroyedObj.exploderIndex ) )
|
||||
exploder( destroyedObj.exploderIndex );
|
||||
|
||||
for ( index = 0; index < level.bombZones.size; index++ )
|
||||
level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject();
|
||||
defuseObject maps\mp\gametypes\_gameobjects::disableObject();
|
||||
|
||||
setGameEndTime( 0 );
|
||||
|
||||
wait 3;
|
||||
|
||||
maps\mp\gametypes\sd::sd_endGame( game["attackers"], game["strings"]["target_destroyed"] );
|
||||
}
|
||||
@@ -0,0 +1,924 @@
|
||||
/*
|
||||
_bot
|
||||
Author: INeedGames
|
||||
Date: 12/20/2020
|
||||
The entry point and manager of the bots.
|
||||
*/
|
||||
|
||||
#include common_scripts\utility;
|
||||
#include maps\mp\_utility;
|
||||
#include maps\mp\gametypes\_hud_util;
|
||||
#include maps\mp\bots\_bot_utility;
|
||||
|
||||
/*
|
||||
Entry point to the bots
|
||||
*/
|
||||
init()
|
||||
{
|
||||
level.bw_VERSION = "1.1.0";
|
||||
|
||||
level.bot_offline = false;
|
||||
|
||||
if(getDvar("bots_main") == "")
|
||||
setDvar("bots_main", true);
|
||||
|
||||
if (!getDvarInt("bots_main"))
|
||||
return;
|
||||
|
||||
if(getDvar("bots_main_waitForHostTime") == "")
|
||||
setDvar("bots_main_waitForHostTime", 10.0);//how long to wait to wait for the host player
|
||||
|
||||
if(getDvar("bots_manage_add") == "")
|
||||
setDvar("bots_manage_add", 0);//amount of bots to add to the game
|
||||
if(getDvar("bots_manage_fill") == "")
|
||||
setDvar("bots_manage_fill", 0);//amount of bots to maintain
|
||||
if(getDvar("bots_manage_fill_spec") == "")
|
||||
setDvar("bots_manage_fill_spec", true);//to count for fill if player is on spec team
|
||||
if(getDvar("bots_manage_fill_mode") == "")
|
||||
setDvar("bots_manage_fill_mode", 0);//fill mode, 0 adds everyone, 1 just bots, 2 maintains at maps, 3 is 2 with 1
|
||||
if(getDvar("bots_manage_fill_kick") == "")
|
||||
setDvar("bots_manage_fill_kick", false);//kick bots if too many
|
||||
|
||||
if(getDvar("bots_team") == "")
|
||||
setDvar("bots_team", "autoassign");//which team for bots to join
|
||||
if(getDvar("bots_team_amount") == "")
|
||||
setDvar("bots_team_amount", 0);//amount of bots on axis team
|
||||
if(getDvar("bots_team_force") == "")
|
||||
setDvar("bots_team_force", false);//force bots on team
|
||||
if(getDvar("bots_team_mode") == "")
|
||||
setDvar("bots_team_mode", 0);//counts just bots when 1
|
||||
|
||||
if(getDvar("bots_loadout_reasonable") == "")//filter out the bad 'guns' and perks
|
||||
setDvar("bots_loadout_reasonable", false);
|
||||
if(getDvar("bots_loadout_allow_op") == "")//allows jug, marty and laststand
|
||||
setDvar("bots_loadout_allow_op", true);
|
||||
if(getDvar("bots_loadout_rank") == "")// what rank the bots should be around, -1 is around the players, 0 is all random
|
||||
setDvar("bots_loadout_rank", -1);
|
||||
if(getDvar("bots_loadout_codpoints") == "")// how much cod points a bot should have, -1 is around the players, 0 is all random
|
||||
setDvar("bots_loadout_codpoints", -1);
|
||||
if(getDvar("bots_loadout_prestige") == "")// what pretige the bots will be, -1 is the players, -2 is random
|
||||
setDvar("bots_loadout_prestige", -1);
|
||||
|
||||
if(getDvar("bots_play_target_other") == "")//bot target non play ents (vehicles)
|
||||
setDvar("bots_play_target_other", true);
|
||||
if(getDvar("bots_play_killstreak") == "")//bot use killstreaks
|
||||
setDvar("bots_play_killstreak", true);
|
||||
if(getDvar("bots_play_nade") == "")//bots grenade
|
||||
setDvar("bots_play_nade", true);
|
||||
if(getDvar("bots_play_knife") == "")//bots knife
|
||||
setDvar("bots_play_knife", true);
|
||||
if(getDvar("bots_play_fire") == "")//bots fire
|
||||
setDvar("bots_play_fire", true);
|
||||
if(getDvar("bots_play_move") == "")//bots move
|
||||
setDvar("bots_play_move", true);
|
||||
if(getDvar("bots_play_take_carepackages") == "")//bots take carepackages
|
||||
setDvar("bots_play_take_carepackages", true);
|
||||
if(getDvar("bots_play_obj") == "")//bots play the obj
|
||||
setDvar("bots_play_obj", true);
|
||||
if(getDvar("bots_play_camp") == "")//bots camp and follow
|
||||
setDvar("bots_play_camp", true);
|
||||
|
||||
level.bots = [];
|
||||
level.bot_decoys = [];
|
||||
level.bot_planes = [];
|
||||
|
||||
if(!isDefined(game["botWarfare"]))
|
||||
game["botWarfare"] = true;
|
||||
|
||||
thread fixGamemodes();
|
||||
thread onPlayerConnect();
|
||||
thread bot_watch_planes();
|
||||
|
||||
thread handleBots();
|
||||
|
||||
thread doNonDediBots();
|
||||
}
|
||||
|
||||
/*
|
||||
Thread when any player connects. Starts the threads needed.
|
||||
*/
|
||||
onPlayerConnect()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
level waittill("connected", player);
|
||||
|
||||
player thread watch_shoot();
|
||||
player thread watch_grenade();
|
||||
player thread connected();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Starts the threads for bots.
|
||||
*/
|
||||
handleBots()
|
||||
{
|
||||
thread diffBots();
|
||||
thread teamBots();
|
||||
addBots();
|
||||
|
||||
while(!level.intermission)
|
||||
wait 0.05;
|
||||
|
||||
setDvar("bots_manage_add", getBotArray().size);
|
||||
}
|
||||
|
||||
/*
|
||||
When a bot disconnects.
|
||||
*/
|
||||
onDisconnect()
|
||||
{
|
||||
self waittill("disconnect");
|
||||
|
||||
level.bots = array_remove(level.bots, self);
|
||||
}
|
||||
|
||||
/*
|
||||
Whena player connects
|
||||
*/
|
||||
connected()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
if (!self is_bot())
|
||||
return;
|
||||
|
||||
self thread maps\mp\bots\_bot_script::connected();
|
||||
|
||||
level.bots[level.bots.size] = self;
|
||||
self thread onDisconnect();
|
||||
|
||||
level notify("bot_connected", self);
|
||||
}
|
||||
|
||||
/*
|
||||
Handles the diff of the bots
|
||||
*/
|
||||
diffBots()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
wait 1.5;
|
||||
|
||||
bot_set_difficulty(GetDvar( #"bot_difficulty" ));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Setup bot dvars for non dedicated clients
|
||||
*/
|
||||
doNonDediBots()
|
||||
{
|
||||
if (!GetDvarInt( #"xblive_basictraining" ))
|
||||
return;
|
||||
|
||||
if (isDefined(game[ "bots_spawned" ]))
|
||||
return;
|
||||
|
||||
game[ "bots_spawned" ] = true;
|
||||
|
||||
if(getDvar("bot_enemies_extra") == "")
|
||||
setDvar("bot_enemies_extra", 0);
|
||||
if(getDvar("bot_friends_extra") == "")
|
||||
setDvar("bot_friends_extra", 0);
|
||||
|
||||
bot_friends = GetDvarInt( #"bot_friends" );
|
||||
bot_enemies = GetDvarInt( #"bot_enemies" );
|
||||
|
||||
bot_enemies += GetDvarInt("bot_enemies_extra");
|
||||
bot_friends += GetDvarInt("bot_friends_extra");
|
||||
|
||||
bot_wait_for_host();
|
||||
host = GetHostPlayer();
|
||||
|
||||
team = "allies";
|
||||
if(isDefined(host) && isDefined(host.pers[ "team" ]) && (host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis"))
|
||||
team = host.pers[ "team" ];
|
||||
|
||||
setDvar("bots_manage_add", bot_enemies + bot_friends - 1);
|
||||
setDvar("bots_manage_fill", bot_enemies + bot_friends);
|
||||
setDvar("bots_manage_fill_mode", 0);
|
||||
setDvar("bots_manage_fill_kick", true);
|
||||
setDvar("bots_manage_fill_spec", false);
|
||||
|
||||
setDvar("bots_team", "custom");
|
||||
|
||||
if (team == "axis")
|
||||
setDvar("bots_team_amount", bot_friends);
|
||||
else
|
||||
setDvar("bots_team_amount", bot_enemies);
|
||||
|
||||
setDvar("bots_team_force", true);
|
||||
setDvar("bots_team_mode", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Sets the difficulty of the bots
|
||||
*/
|
||||
bot_set_difficulty( difficulty )
|
||||
{
|
||||
if ( difficulty == "fu" )
|
||||
{
|
||||
SetDvar( "sv_botMinDeathTime", "250" );
|
||||
SetDvar( "sv_botMaxDeathTime", "500" );
|
||||
SetDvar( "sv_botMinFireTime", "100" );
|
||||
SetDvar( "sv_botMaxFireTime", "300" );
|
||||
SetDvar( "sv_botYawSpeed", "14" );
|
||||
SetDvar( "sv_botYawSpeedAds", "14" );
|
||||
SetDvar( "sv_botPitchUp", "-5" );
|
||||
SetDvar( "sv_botPitchDown", "10" );
|
||||
SetDvar( "sv_botFov", "160" );
|
||||
SetDvar( "sv_botMinAdsTime", "3000" );
|
||||
SetDvar( "sv_botMaxAdsTime", "5000" );
|
||||
SetDvar( "sv_botMinCrouchTime", "100" );
|
||||
SetDvar( "sv_botMaxCrouchTime", "400" );
|
||||
SetDvar( "sv_botTargetLeadBias", "2" );
|
||||
SetDvar( "sv_botMinReactionTime", "30" );
|
||||
SetDvar( "sv_botMaxReactionTime", "100" );
|
||||
SetDvar( "sv_botStrafeChance", "1" );
|
||||
SetDvar( "sv_botMinStrafeTime", "3000" );
|
||||
SetDvar( "sv_botMaxStrafeTime", "6000" );
|
||||
SetDvar( "scr_help_dist", "512" );
|
||||
SetDvar( "sv_botAllowGrenades", "1" );
|
||||
SetDvar( "sv_botMinGrenadeTime", "1500" );
|
||||
SetDvar( "sv_botMaxGrenadeTime", "4000" );
|
||||
SetDvar( "sv_botSprintDistance", "512" );
|
||||
SetDvar( "sv_botMeleeDist", "80" );
|
||||
}
|
||||
else if ( difficulty == "hard" )
|
||||
{
|
||||
SetDvar( "sv_botMinDeathTime", "250" );
|
||||
SetDvar( "sv_botMaxDeathTime", "500" );
|
||||
SetDvar( "sv_botMinFireTime", "400" );
|
||||
SetDvar( "sv_botMaxFireTime", "600" );
|
||||
SetDvar( "sv_botYawSpeed", "8" );
|
||||
SetDvar( "sv_botYawSpeedAds", "10" );
|
||||
SetDvar( "sv_botPitchUp", "-5" );
|
||||
SetDvar( "sv_botPitchDown", "10" );
|
||||
SetDvar( "sv_botFov", "100" );
|
||||
SetDvar( "sv_botMinAdsTime", "3000" );
|
||||
SetDvar( "sv_botMaxAdsTime", "5000" );
|
||||
SetDvar( "sv_botMinCrouchTime", "100" );
|
||||
SetDvar( "sv_botMaxCrouchTime", "400" );
|
||||
SetDvar( "sv_botTargetLeadBias", "2" );
|
||||
SetDvar( "sv_botMinReactionTime", "400" );
|
||||
SetDvar( "sv_botMaxReactionTime", "700" );
|
||||
SetDvar( "sv_botStrafeChance", "0.9" );
|
||||
SetDvar( "sv_botMinStrafeTime", "3000" );
|
||||
SetDvar( "sv_botMaxStrafeTime", "6000" );
|
||||
SetDvar( "scr_help_dist", "384" );
|
||||
SetDvar( "sv_botAllowGrenades", "1" );
|
||||
SetDvar( "sv_botMinGrenadeTime", "1500" );
|
||||
SetDvar( "sv_botMaxGrenadeTime", "4000" );
|
||||
SetDvar( "sv_botSprintDistance", "512" );
|
||||
SetDvar( "sv_botMeleeDist", "80" );
|
||||
}
|
||||
else if ( difficulty == "easy" )
|
||||
{
|
||||
SetDvar( "sv_botMinDeathTime", "1000" );
|
||||
SetDvar( "sv_botMaxDeathTime", "2000" );
|
||||
SetDvar( "sv_botMinFireTime", "900" );
|
||||
SetDvar( "sv_botMaxFireTime", "1000" );
|
||||
SetDvar( "sv_botYawSpeed", "2" );
|
||||
SetDvar( "sv_botYawSpeedAds", "2.5" );
|
||||
SetDvar( "sv_botPitchUp", "-20" );
|
||||
SetDvar( "sv_botPitchDown", "40" );
|
||||
SetDvar( "sv_botFov", "50" );
|
||||
SetDvar( "sv_botMinAdsTime", "3000" );
|
||||
SetDvar( "sv_botMaxAdsTime", "5000" );
|
||||
SetDvar( "sv_botMinCrouchTime", "4000" );
|
||||
SetDvar( "sv_botMaxCrouchTime", "6000" );
|
||||
SetDvar( "sv_botTargetLeadBias", "8" );
|
||||
SetDvar( "sv_botMinReactionTime", "1200" );
|
||||
SetDvar( "sv_botMaxReactionTime", "1600" );
|
||||
SetDvar( "sv_botStrafeChance", "0.1" );
|
||||
SetDvar( "sv_botMinStrafeTime", "3000" );
|
||||
SetDvar( "sv_botMaxStrafeTime", "6000" );
|
||||
SetDvar( "scr_help_dist", "256" );
|
||||
SetDvar( "sv_botAllowGrenades", "0" );
|
||||
SetDvar( "sv_botSprintDistance", "1024" );
|
||||
SetDvar( "sv_botMeleeDist", "40" );
|
||||
}
|
||||
else // 'normal' difficulty
|
||||
{
|
||||
SetDvar( "sv_botMinDeathTime", "500" );
|
||||
SetDvar( "sv_botMaxDeathTime", "1000" );
|
||||
SetDvar( "sv_botMinFireTime", "600" );
|
||||
SetDvar( "sv_botMaxFireTime", "800" );
|
||||
SetDvar( "sv_botYawSpeed", "4" );
|
||||
SetDvar( "sv_botYawSpeedAds", "5" );
|
||||
SetDvar( "sv_botPitchUp", "-10" );
|
||||
SetDvar( "sv_botPitchDown", "20" );
|
||||
SetDvar( "sv_botFov", "70" );
|
||||
SetDvar( "sv_botMinAdsTime", "3000" );
|
||||
SetDvar( "sv_botMaxAdsTime", "5000" );
|
||||
SetDvar( "sv_botMinCrouchTime", "2000" );
|
||||
SetDvar( "sv_botMaxCrouchTime", "4000" );
|
||||
SetDvar( "sv_botTargetLeadBias", "4" );
|
||||
SetDvar( "sv_botMinReactionTime", "800" );
|
||||
SetDvar( "sv_botMaxReactionTime", "1200" );
|
||||
SetDvar( "sv_botStrafeChance", "0.6" );
|
||||
SetDvar( "sv_botMinStrafeTime", "3000" );
|
||||
SetDvar( "sv_botMaxStrafeTime", "6000" );
|
||||
SetDvar( "scr_help_dist", "256" );
|
||||
SetDvar( "sv_botAllowGrenades", "1" );
|
||||
SetDvar( "sv_botMinGrenadeTime", "1500" );
|
||||
SetDvar( "sv_botMaxGrenadeTime", "4000" );
|
||||
SetDvar( "sv_botSprintDistance", "512" );
|
||||
SetDvar( "sv_botMeleeDist", "80" );
|
||||
difficulty = "normal";
|
||||
}
|
||||
|
||||
if ( level.gameType == "oic" && difficulty == "fu" )
|
||||
{
|
||||
SetDvar( "sv_botMinReactionTime", "400" );
|
||||
SetDvar( "sv_botMaxReactionTime", "500" );
|
||||
SetDvar( "sv_botMinAdsTime", "1000" );
|
||||
SetDvar( "sv_botMaxAdsTime", "2000" );
|
||||
}
|
||||
|
||||
if ( level.gameType == "oic" && ( difficulty == "hard" || difficulty == "fu" ) )
|
||||
{
|
||||
SetDvar( "sv_botSprintDistance", "256" );
|
||||
}
|
||||
|
||||
if (!getDvarInt("bots_play_nade"))
|
||||
SetDvar( "sv_botAllowGrenades", "0" );
|
||||
|
||||
SetDvar( "bot_difficulty", difficulty );
|
||||
SetDvar( "scr_bot_difficulty", difficulty );
|
||||
SetDvar( "splitscreen_botDifficulty", difficulty );
|
||||
}
|
||||
|
||||
/*
|
||||
A server thread for monitoring all bot's teams for custom server settings.
|
||||
*/
|
||||
teamBots()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
wait 1.5;
|
||||
teamAmount = getDvarInt("bots_team_amount");
|
||||
toTeam = getDvar("bots_team");
|
||||
|
||||
alliesbots = 0;
|
||||
alliesplayers = 0;
|
||||
axisbots = 0;
|
||||
axisplayers = 0;
|
||||
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(!isDefined(player.pers["team"]))
|
||||
continue;
|
||||
|
||||
if(player is_bot())
|
||||
{
|
||||
if(player.pers["team"] == "allies")
|
||||
alliesbots++;
|
||||
else if(player.pers["team"] == "axis")
|
||||
axisbots++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(player.pers["team"] == "allies")
|
||||
alliesplayers++;
|
||||
else if(player.pers["team"] == "axis")
|
||||
axisplayers++;
|
||||
}
|
||||
}
|
||||
|
||||
allies = alliesbots;
|
||||
axis = axisbots;
|
||||
|
||||
if(!getDvarInt("bots_team_mode"))
|
||||
{
|
||||
allies += alliesplayers;
|
||||
axis += axisplayers;
|
||||
}
|
||||
|
||||
if(toTeam != "custom")
|
||||
{
|
||||
if(getDvarInt("bots_team_force"))
|
||||
{
|
||||
if(toTeam == "autoassign")
|
||||
{
|
||||
if(abs(axis - allies) > 1)
|
||||
{
|
||||
toTeam = "axis";
|
||||
if(axis > allies)
|
||||
toTeam = "allies";
|
||||
}
|
||||
}
|
||||
|
||||
if(toTeam != "autoassign")
|
||||
{
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(!isDefined(player.pers["team"]))
|
||||
continue;
|
||||
|
||||
if(!player is_bot())
|
||||
continue;
|
||||
|
||||
if(player.pers["team"] == toTeam)
|
||||
continue;
|
||||
|
||||
if (toTeam == "allies")
|
||||
player thread [[level.allies]]();
|
||||
else if (toTeam == "axis")
|
||||
player thread [[level.axis]]();
|
||||
else
|
||||
player thread [[level.spectator]]();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(!isDefined(player.pers["team"]))
|
||||
continue;
|
||||
|
||||
if(!player is_bot())
|
||||
continue;
|
||||
|
||||
if(player.pers["team"] == "axis")
|
||||
{
|
||||
if(axis > teamAmount)
|
||||
{
|
||||
player thread [[level.allies]]();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(axis < teamAmount)
|
||||
{
|
||||
player thread [[level.axis]]();
|
||||
break;
|
||||
}
|
||||
else if(player.pers["team"] != "allies")
|
||||
{
|
||||
player thread [[level.allies]]();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
A server thread for monitoring all bot's in game. Will add and kick bots according to server settings.
|
||||
|
||||
Dedis only spawn bots when developer is not 0
|
||||
This makes the dedi unstable and can crash
|
||||
|
||||
Patch the executable to skip the pregame and make it so bots can spawn
|
||||
|
||||
pregame:
|
||||
in the ShouldDoPregame sub:
|
||||
B8 01 00 00 00: mov eax, 1
|
||||
change to: B8 00 00 00 00: mov eax, 0
|
||||
0x4F6C77 in rektmp
|
||||
0x4598A7 in bg
|
||||
|
||||
|
||||
spawnbots:
|
||||
in the SV_AddTestClient sub:
|
||||
0F 85 A4 00 00 00: jnz
|
||||
change to: 0F 84 A4 00 00 00: jz
|
||||
0x6B6180 in rektmp
|
||||
0x4682F0 in bg
|
||||
|
||||
|
||||
allow changing g_antilag dvar:
|
||||
set the byte from 0x40 to 0x00
|
||||
|
||||
0x53B1B2 in rekt
|
||||
0x59B6F2 in bg
|
||||
*/
|
||||
addBots()
|
||||
{
|
||||
level endon ( "game_ended" );
|
||||
|
||||
bot_wait_for_host();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
wait 1.5;
|
||||
|
||||
botsToAdd = GetDvarInt("bots_manage_add");
|
||||
|
||||
if(botsToAdd > 0)
|
||||
{
|
||||
SetDvar("bots_manage_add", 0);
|
||||
|
||||
if(botsToAdd > 64)
|
||||
botsToAdd = 64;
|
||||
|
||||
for(; botsToAdd > 0; botsToAdd--)
|
||||
{
|
||||
level add_bot();
|
||||
wait 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
fillMode = getDVarInt("bots_manage_fill_mode");
|
||||
|
||||
if(fillMode == 2 || fillMode == 3)
|
||||
setDvar("bots_manage_fill", getGoodMapAmount());
|
||||
|
||||
fillAmount = getDvarInt("bots_manage_fill");
|
||||
|
||||
players = 0;
|
||||
bots = 0;
|
||||
spec = 0;
|
||||
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if (player isdemoclient())
|
||||
continue;
|
||||
|
||||
if(player is_bot())
|
||||
bots++;
|
||||
else if(!isDefined(player.pers["team"]) || (player.pers["team"] != "axis" && player.pers["team"] != "allies"))
|
||||
spec++;
|
||||
else
|
||||
players++;
|
||||
}
|
||||
|
||||
if(fillMode == 4)
|
||||
{
|
||||
axisplayers = 0;
|
||||
alliesplayers = 0;
|
||||
|
||||
playercount = level.players.size;
|
||||
for(i = 0; i < playercount; i++)
|
||||
{
|
||||
player = level.players[i];
|
||||
|
||||
if(player is_bot())
|
||||
continue;
|
||||
|
||||
if(!isDefined(player.pers["team"]))
|
||||
continue;
|
||||
|
||||
if(player.pers["team"] == "axis")
|
||||
axisplayers++;
|
||||
else if(player.pers["team"] == "allies")
|
||||
alliesplayers++;
|
||||
}
|
||||
|
||||
result = fillAmount - abs(axisplayers - alliesplayers) + bots;
|
||||
|
||||
if (players == 0)
|
||||
{
|
||||
if(bots < fillAmount)
|
||||
result = fillAmount-1;
|
||||
else if (bots > fillAmount)
|
||||
result = fillAmount+1;
|
||||
else
|
||||
result = fillAmount;
|
||||
}
|
||||
|
||||
bots = result;
|
||||
}
|
||||
|
||||
if (!randomInt(999))
|
||||
{
|
||||
setDvar("testclients_doreload", true);
|
||||
wait 0.1;
|
||||
setDvar("testclients_doreload", false);
|
||||
doExtraCheck();
|
||||
}
|
||||
|
||||
amount = bots;
|
||||
if(fillMode == 0 || fillMode == 2)
|
||||
amount += players;
|
||||
if(getDVarInt("bots_manage_fill_spec"))
|
||||
amount += spec;
|
||||
|
||||
if(amount < fillAmount)
|
||||
setDvar("bots_manage_add", 1);
|
||||
else if(amount > fillAmount && getDvarInt("bots_manage_fill_kick"))
|
||||
{
|
||||
tempBot = PickRandom(getBotArray());
|
||||
if (isDefined(tempBot))
|
||||
kick( tempBot getEntityNumber(), "EXE_PLAYERKICKED" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Adds a bot to the game.
|
||||
*/
|
||||
add_bot()
|
||||
{
|
||||
bot = addtestclient();
|
||||
|
||||
if (isdefined(bot))
|
||||
{
|
||||
bot.pers["isBot"] = true;
|
||||
bot.equipment_enabled = true;
|
||||
bot.pers[ "bot_perk" ] = true;
|
||||
bot.pers["isBotWarfare"] = true;
|
||||
bot thread maps\mp\bots\_bot_script::added();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Gives the bot loadout
|
||||
*/
|
||||
bot_give_loadout()
|
||||
{
|
||||
self maps\mp\bots\_bot_loadout::bot_give_loadout();
|
||||
}
|
||||
|
||||
/*
|
||||
Fired when the bot is damaged
|
||||
*/
|
||||
bot_damage_callback( eAttacker, iDamage, sMeansOfDeath, sWeapon, eInflictor, sHitLoc )
|
||||
{
|
||||
self maps\mp\bots\_bot_script::bot_damage_callback( eAttacker, iDamage, sMeansOfDeath, sWeapon, eInflictor, sHitLoc );
|
||||
}
|
||||
|
||||
/*
|
||||
Bot is idle
|
||||
*/
|
||||
bot_is_idle()
|
||||
{
|
||||
if ( !IsDefined( self ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !IsAlive( self ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !self is_bot() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self inLastStand() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self HasScriptGoal() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( IsDefined( self GetThreat() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self IsRemoteControlling() || self.bot_lock_goal )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(self UseButtonPressed())
|
||||
return false;
|
||||
|
||||
if(self isPlanting())
|
||||
return false;
|
||||
|
||||
if(self isDefusing())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Watch all players grenades
|
||||
*/
|
||||
watch_grenade()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
self.bot_scrambled = false;
|
||||
for(;;)
|
||||
{
|
||||
self waittill("grenade_fire", g, name);
|
||||
if(name == "scrambler_mp")
|
||||
{
|
||||
g thread watch_scrambler();
|
||||
}
|
||||
else if(name == "nightingale_mp")
|
||||
{
|
||||
self thread watch_decoy(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Watch the decoy grenade
|
||||
*/
|
||||
watch_decoy(g)
|
||||
{
|
||||
g.team = self.team;
|
||||
|
||||
level.bot_decoys[level.bot_decoys.size] = g;
|
||||
|
||||
g waittill("death");
|
||||
|
||||
for ( entry = 0; entry < level.bot_decoys.size; entry++ )
|
||||
{
|
||||
if ( level.bot_decoys[entry] == g )
|
||||
{
|
||||
while ( entry < level.bot_decoys.size-1 )
|
||||
{
|
||||
level.bot_decoys[entry] = level.bot_decoys[entry+1];
|
||||
entry++;
|
||||
}
|
||||
level.bot_decoys[entry] = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Attach a trigger to the scrambler
|
||||
*/
|
||||
watch_scrambler()
|
||||
{
|
||||
trig = spawn( "trigger_radius", self.origin + (0, 0, -1000), 0, 1000, 2000 );
|
||||
|
||||
self scramble_nearby(trig);
|
||||
|
||||
trig delete();
|
||||
}
|
||||
|
||||
/*
|
||||
Watch when players enter the scrambler trigger
|
||||
*/
|
||||
scramble_nearby(trig)
|
||||
{
|
||||
self endon("death");
|
||||
self endon("hacked");
|
||||
|
||||
while(!isDefined(self.owner) || !isDefined(self.owner.team))
|
||||
wait 0.05;
|
||||
|
||||
self.team = self.owner.team;
|
||||
for(;;)
|
||||
{
|
||||
trig waittill("trigger", player);
|
||||
|
||||
if (!isDefined(player) || !isDefined(player.team))
|
||||
continue;
|
||||
|
||||
if(self maps\mp\gametypes\_weaponobjects::isStunned())
|
||||
continue;
|
||||
|
||||
if(isDefined(self.owner) && player == self.owner)
|
||||
continue;
|
||||
|
||||
if(level.teamBased && self.team == player.team)
|
||||
continue;
|
||||
|
||||
player thread scramble_player();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Scramble this player
|
||||
*/
|
||||
scramble_player()
|
||||
{
|
||||
self notify("scramble_nearby");
|
||||
self endon("scramble_nearby");
|
||||
|
||||
self.bot_scrambled = true;
|
||||
wait 0.1;
|
||||
|
||||
if(isDefined(self))
|
||||
self.bot_scrambled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Watch when a player shoots
|
||||
*/
|
||||
watch_shoot()
|
||||
{
|
||||
self endon("disconnect");
|
||||
|
||||
self.bot_firing = false;
|
||||
for(;;)
|
||||
{
|
||||
self waittill( "weapon_fired" );
|
||||
self thread doFiringThread();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
When a player fires
|
||||
*/
|
||||
doFiringThread()
|
||||
{
|
||||
self endon("disconnect");
|
||||
self endon("weapon_fired");
|
||||
|
||||
self.bot_firing = true;
|
||||
wait 1;
|
||||
self.bot_firing = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Watches the planes
|
||||
*/
|
||||
bot_watch_planes()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
level waittill("uav_update");
|
||||
|
||||
ents = GetEntArray("script_model", "classname");
|
||||
for(i = 0; i < ents.size; i++)
|
||||
{
|
||||
ent = ents[i];
|
||||
|
||||
if(isDefined(ent.bot_plane))
|
||||
continue;
|
||||
|
||||
if(ent.model != level.spyplanemodel)
|
||||
continue;
|
||||
|
||||
thread watch_plane(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Watches the plane
|
||||
*/
|
||||
watch_plane(ent)
|
||||
{
|
||||
ent.bot_plane = true;
|
||||
|
||||
level.bot_planes[level.bot_planes.size] = ent;
|
||||
|
||||
ent waittill_any("death", "delete", "leaving");
|
||||
|
||||
for ( entry = 0; entry < level.bot_planes.size; entry++ )
|
||||
{
|
||||
if ( level.bot_planes[entry] == ent )
|
||||
{
|
||||
while ( entry < level.bot_planes.size-1 )
|
||||
{
|
||||
level.bot_planes[entry] = level.bot_planes[entry+1];
|
||||
entry++;
|
||||
}
|
||||
level.bot_planes[entry] = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fix xp in sd
|
||||
*/
|
||||
bot_killBoost()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Fixes sd
|
||||
*/
|
||||
fixGamemodes()
|
||||
{
|
||||
for(i=0;i<19;i++)
|
||||
{
|
||||
if(isDefined(level.bombZones) && level.gametype == "sd")
|
||||
{
|
||||
level.isKillBoosting = ::bot_killBoost;
|
||||
for(i = 0; i < level.bombZones.size; i++)
|
||||
level.bombZones[i].onUse = ::bot_onUsePlantObjectFix;
|
||||
break;
|
||||
}
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
@@ -73,5 +73,8 @@ stringtable,mp/mapsTable.csv
|
||||
stringtable,mp/attachmentTable.csv
|
||||
|
||||
rawfile,maps/mp/gametypes/_bot.gsc
|
||||
rawfile,maps/mp/bots/_bot_loadout.gsc
|
||||
rawfile,maps/mp/bots/_bot_script.gsc
|
||||
rawfile,maps/mp/bots/_bot_utility.gsc
|
||||
|
||||
menufile,ui_mp/playercards.menu
|
||||
|
@@ -0,0 +1 @@
|
||||
Extends functionality of Combat Training.
|
||||
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Reference in New Issue
Block a user