mirror of
https://github.com/ineedbots/t5_bot_warfare.git
synced 2025-04-19 16:32:53 +00:00
Start push update
This commit is contained in:
parent
e11e055c68
commit
69bca119d9
10
.gitignore
vendored
10
.gitignore
vendored
@ -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
|
1294
mods/mp_bots/maps/mp/bots/_bot_loadout.gsc
Normal file
1294
mods/mp_bots/maps/mp/bots/_bot_loadout.gsc
Normal file
File diff suppressed because it is too large
Load Diff
4702
mods/mp_bots/maps/mp/bots/_bot_script.gsc
Normal file
4702
mods/mp_bots/maps/mp/bots/_bot_script.gsc
Normal file
File diff suppressed because it is too large
Load Diff
507
mods/mp_bots/maps/mp/bots/_bot_utility.gsc
Normal file
507
mods/mp_bots/maps/mp/bots/_bot_utility.gsc
Normal file
@ -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"] );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1294
mods/patch_mp/maps/mp/bots/_bot_loadout.gsc
Normal file
1294
mods/patch_mp/maps/mp/bots/_bot_loadout.gsc
Normal file
File diff suppressed because it is too large
Load Diff
4702
mods/patch_mp/maps/mp/bots/_bot_script.gsc
Normal file
4702
mods/patch_mp/maps/mp/bots/_bot_script.gsc
Normal file
File diff suppressed because it is too large
Load Diff
507
mods/patch_mp/maps/mp/bots/_bot_utility.gsc
Normal file
507
mods/patch_mp/maps/mp/bots/_bot_utility.gsc
Normal file
@ -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"] );
|
||||
}
|
924
mods/patch_mp/maps/mp/gametypes/_bot.gsc
Normal file
924
mods/patch_mp/maps/mp/gametypes/_bot.gsc
Normal file
@ -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
mods/patch_ui_mp/mod.csv
Normal file
0
mods/patch_ui_mp/mod.csv
Normal file
|
@ -0,0 +1 @@
|
||||
Extends functionality of Combat Training.
|
BIN
out/Others/patch_ui_mp.ff
Normal file
BIN
out/Others/patch_ui_mp.ff
Normal file
Binary file not shown.
BIN
out/ss.png
Normal file
BIN
out/ss.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
Loading…
x
Reference in New Issue
Block a user