15 Commits

Author SHA1 Message Date
dc03e0fbb3 update 2024-04-30 13:11:41 -06:00
24c1908c85 some updates 2024-04-30 11:20:18 -06:00
02761a1013 chat event 2024-04-25 15:37:43 -06:00
093dc9cd8c playername 2024-04-25 14:49:26 -06:00
a3266c6de3 init time 2024-04-25 14:16:28 -06:00
0ea6672804 connection events 2024-04-25 14:07:35 -06:00
b3967606f4 small fixes 2024-04-04 16:54:29 -06:00
fcd130a132 update bones 2024-04-04 15:38:50 -06:00
f39a4d008c waittillframeend for event 2024-03-12 14:58:28 -06:00
cff61ab690 modwarfare support 2024-01-20 00:17:29 -06:00
f044af8aea update gsc version 2024-01-18 15:08:18 -06:00
1d464fca49 check for target knife 2024-01-18 14:53:07 -06:00
538269517a Merge branch 'master' of github.com:ineedbots/iw3_bot_warfare 2024-01-18 14:13:04 -06:00
9efda21175 move scripts to mp folder 2024-01-18 14:13:01 -06:00
f536f2b65d Update main.yml 2024-01-15 15:26:03 -06:00
14 changed files with 243 additions and 73 deletions

View File

@ -13,7 +13,9 @@ jobs:
- name: Setup gsc-tool - name: Setup gsc-tool
uses: xensik/setup-gsc-tool@v1 uses: xensik/setup-gsc-tool@v1
with:
version: '1.4.0'
- name: Compile test script - name: Compile test script
run: | run: |
gsc-tool.exe parse iw5 pc . gsc-tool.exe -m parse -g iw5 -s pc .

View File

@ -120,6 +120,10 @@ You can easily setup a local LAN dedicated server for you to join and play on. H
## Changelog ## Changelog
- v2.3.0 (not released yet)
- Smoothed bot aim at range
- Fixed bots_manage_fill_spec players being counted with bots_manage_fill_mode 1 (bot only)
- v2.2.0 - v2.2.0
- Fixed some chat related script runtime errors - Fixed some chat related script runtime errors
- Waypoints only load from csv now - Waypoints only load from csv now

View File

@ -8,7 +8,7 @@
*/ */
init() init()
{ {
level.bw_version = "2.1.0"; level.bw_version = "2.3.0";
if ( getdvar( "bots_main" ) == "" ) if ( getdvar( "bots_main" ) == "" )
{ {
@ -207,8 +207,11 @@ init()
if ( !isdefined( game[ "botWarfare" ] ) ) if ( !isdefined( game[ "botWarfare" ] ) )
{ {
game[ "botWarfare" ] = true; game[ "botWarfare" ] = true;
game[ "botWarfareInitTime" ] = gettime();
} }
level.bot_inittime = gettime();
level.defuseobject = undefined; level.defuseobject = undefined;
level.bots_smokelist = List(); level.bots_smokelist = List();
level.tbl_perkdata[ 0 ][ "reference_full" ] = true; level.tbl_perkdata[ 0 ][ "reference_full" ] = true;
@ -262,6 +265,7 @@ init()
level thread onPlayerConnect(); level thread onPlayerConnect();
level thread handleBots(); level thread handleBots();
level thread onPlayerChat();
} }
/* /*
@ -440,6 +444,23 @@ fixPerksAndScriptKick()
self.pers[ "isBot" ] = true; self.pers[ "isBot" ] = true;
} }
/*
When a bot disconnects.
*/
onDisconnectPlayer()
{
name = self.name;
self waittill( "disconnect" );
waittillframeend;
for ( i = 0; i < level.bots.size; i++ )
{
bot = level.bots[ i ];
bot BotNotifyBotEvent( "connection", "disconnected", self, name );
}
}
/* /*
When a bot disconnects. When a bot disconnects.
*/ */
@ -457,6 +478,14 @@ connected()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
for ( i = 0; i < level.bots.size; i++ )
{
bot = level.bots[ i ];
bot BotNotifyBotEvent( "connection", "connected", self, self.name );
}
self thread onDisconnectPlayer();
if ( !isdefined( self.pers[ "bot_host" ] ) ) if ( !isdefined( self.pers[ "bot_host" ] ) )
{ {
self thread doHostCheck(); self thread doHostCheck();
@ -998,12 +1027,12 @@ addBots_loop()
if ( fillMode == 0 || fillMode == 2 ) if ( fillMode == 0 || fillMode == 2 )
{ {
amount += players; amount += players;
}
if ( getdvarint( "bots_manage_fill_spec" ) ) if ( getdvarint( "bots_manage_fill_spec" ) )
{ {
amount += spec; amount += spec;
} }
}
if ( amount < fillAmount ) if ( amount < fillAmount )
{ {
@ -1247,3 +1276,21 @@ doFiringThread()
wait 1; wait 1;
self.bots_firing = false; self.bots_firing = false;
} }
/*
When a player chats
*/
onPlayerChat()
{
for ( ;; )
{
level waittill( "say", message, player, is_hidden );
for ( i = 0; i < level.bots.size; i++ )
{
bot = level.bots[ i ];
bot BotNotifyBotEvent( "chat", "chat", message, player, is_hidden );
}
}
}

View File

@ -252,10 +252,43 @@ start_chat_watch()
case "sd": case "sd":
self thread bot_chat_sd_watch( a, b, c, d, e, f, g ); self thread bot_chat_sd_watch( a, b, c, d, e, f, g );
break; break;
case "connection":
self thread bot_chat_connection_player_watch( a, b, c, d, e, f, g );
break;
case "chat":
self thread bot_chat_chat_player_watch( a, b, c, d, e, f, g );
break;
} }
} }
} }
/*
When another player chats
*/
bot_chat_chat_player_watch( chatstr, message, player, is_hidden, e, f, g )
{
self endon( "disconnect" );
}
/*
When a player connected
*/
bot_chat_connection_player_watch( conn, player, playername, d, e, f, g )
{
self endon( "disconnect" );
switch ( conn )
{
case "connected":
break;
case "disconnected":
break;
}
}
/* /*
start_startgame_watch start_startgame_watch
*/ */

View File

@ -485,7 +485,7 @@ IsWeapSniper( weap )
return false; return false;
} }
if ( maps\mp\gametypes\_missions::getweaponclass( weap ) != "weapon_sniper" ) if ( getweaponclass( weap ) != "weapon_sniper" )
{ {
return false; return false;
} }
@ -556,6 +556,12 @@ onWeaponChange()
{ {
first = false; first = false;
newWeapon = self getcurrentweapon(); newWeapon = self getcurrentweapon();
// hack fix for botstop overridding weapon
if ( newWeapon != "none" )
{
self switchtoweapon( newWeapon );
}
} }
else else
{ {
@ -903,12 +909,14 @@ updateBones()
self endon( "disconnect" ); self endon( "disconnect" );
self endon( "death" ); self endon( "death" );
bones = strtok( self.pers[ "bots" ][ "skill" ][ "bones" ], "," );
waittime = self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ];
for ( ;; ) for ( ;; )
{ {
self waittill_notify_or_timeout( "new_enemy", waittime ); oldbones = self.pers[ "bots" ][ "skill" ][ "bones" ];
bones = strtok( oldbones, "," );
while ( oldbones == self.pers[ "bots" ][ "skill" ][ "bones" ] )
{
self waittill_notify_or_timeout( "new_enemy", self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] );
if ( !isdefined( self.bot.target ) ) if ( !isdefined( self.bot.target ) )
{ {
@ -918,6 +926,7 @@ updateBones()
self.bot.target.bone = random( bones ); self.bot.target.bone = random( bones );
} }
} }
}
/* /*
Creates the base target obj Creates the base target obj
@ -1024,6 +1033,23 @@ targetObjUpdateNoTrace( obj )
obj.didlook = false; obj.didlook = false;
} }
/*
Returns true if myEye can see the bone of self
*/
checkTraceForBone( myEye, bone )
{
boneLoc = self gettagorigin( bone );
if ( !isdefined( boneLoc ) )
{
return false;
}
trace = bullettrace( myEye, boneLoc, false, undefined );
return ( sighttracepassed( myEye, boneLoc, false, undefined ) && ( trace[ "fraction" ] >= 1.0 || trace[ "surfacetype" ] == "glass" ) );
}
/* /*
The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets.
*/ */
@ -1135,21 +1161,9 @@ target_loop()
continue; continue;
} }
targetHead = player gettagorigin( "j_head" ); canTargetPlayer = ( ( player checkTraceForBone( myEye, "j_head" ) ||
targetAnkleLeft = player gettagorigin( "j_ankle_le" ); player checkTraceForBone( myEye, "j_ankle_le" ) ||
targetAnkleRight = player gettagorigin( "j_ankle_ri" ); player checkTraceForBone( myEye, "j_ankle_ri" ) )
traceHead = bullettrace( myEye, targetHead, false, undefined );
traceAnkleLeft = bullettrace( myEye, targetAnkleLeft, false, undefined );
traceAnkleRight = bullettrace( myEye, targetAnkleRight, false, undefined );
canTargetPlayer = ( ( sighttracepassed( myEye, targetHead, false, undefined ) ||
sighttracepassed( myEye, targetAnkleLeft, false, undefined ) ||
sighttracepassed( myEye, targetAnkleRight, false, undefined ) )
&& ( ( traceHead[ "fraction" ] >= 1.0 || traceHead[ "surfacetype" ] == "glass" ) ||
( traceAnkleLeft[ "fraction" ] >= 1.0 || traceAnkleLeft[ "surfacetype" ] == "glass" ) ||
( traceAnkleRight[ "fraction" ] >= 1.0 || traceAnkleRight[ "surfacetype" ] == "glass" ) )
&& ( SmokeTrace( myEye, player.origin, level.smokeradius ) || && ( SmokeTrace( myEye, player.origin, level.smokeradius ) ||
daDist < level.bots_maxknifedistance * 4 ) daDist < level.bots_maxknifedistance * 4 )
@ -1508,7 +1522,7 @@ aim_loop()
} }
else if ( curweap != "none" && weaponclass( curweap ) == "grenade" ) else if ( curweap != "none" && weaponclass( curweap ) == "grenade" )
{ {
if ( maps\mp\gametypes\_missions::getweaponclass( curweap ) == "weapon_projectile" ) if ( getweaponclass( curweap ) == "weapon_projectile" )
{ {
nadeAimOffset = dist / 16000; nadeAimOffset = dist / 16000;
} }
@ -1582,11 +1596,11 @@ aim_loop()
conedot = getConeDot( aimpos, eyePos, angles ); conedot = getConeDot( aimpos, eyePos, angles );
if ( isdefined( self.bot.knifing_target ) ) if ( isdefined( self.bot.knifing_target ) && self.bot.knifing_target == target )
{ {
self thread bot_lookat( target gettagorigin( "j_spine4" ), 0.05 ); self thread bot_lookat( target gettagorigin( "j_spine4" ), 0.05 );
} }
else if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) else if ( !nadeAimOffset && conedot > 0.999995 && lengthsquared( aimoffset ) < 0.05 )
{ {
self thread bot_lookat( aimpos, 0.05 ); self thread bot_lookat( aimpos, 0.05 );
} }
@ -1604,7 +1618,7 @@ aim_loop()
conedot = getConeDot( aimpos, eyePos, angles ); conedot = getConeDot( aimpos, eyePos, angles );
if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) if ( !nadeAimOffset && conedot > 0.999995 && lengthsquared( aimoffset ) < 0.05 )
{ {
self thread bot_lookat( aimpos, 0.05 ); self thread bot_lookat( aimpos, 0.05 );
} }
@ -1680,7 +1694,7 @@ aim_loop()
} }
else if ( curweap != "none" && weaponclass( curweap ) == "grenade" ) else if ( curweap != "none" && weaponclass( curweap ) == "grenade" )
{ {
if ( maps\mp\gametypes\_missions::getweaponclass( curweap ) == "weapon_projectile" ) if ( getweaponclass( curweap ) == "weapon_projectile" )
{ {
nadeAimOffset = dist / 16000; nadeAimOffset = dist / 16000;
} }
@ -1773,6 +1787,7 @@ aim()
for ( ;; ) for ( ;; )
{ {
wait 0.05; wait 0.05;
waittillframeend;
if ( level.inprematchperiod || level.gameended || self.bot.isfrozen || self maps\mp\_flashgrenades::isflashbanged() ) if ( level.inprematchperiod || level.gameended || self.bot.isfrozen || self maps\mp\_flashgrenades::isflashbanged() )
{ {
@ -1954,9 +1969,9 @@ walk_loop()
dist = 16; dist = 16;
if ( level.waypointcount ) if ( level.waypoints.size )
{ {
goal = level.waypoints[ randomint( level.waypointcount ) ].origin; goal = level.waypoints[ randomint( level.waypoints.size ) ].origin;
} }
else else
{ {
@ -2843,7 +2858,7 @@ bot_lookat( pos, time, vel, doAimPredict )
for ( i = 0; i < steps; i++ ) for ( i = 0; i < steps; i++ )
{ {
myAngle = ( angleclamp180( myAngle[ 0 ] + X ), angleclamp180( myAngle[ 1 ] + Y ), 0 ); myAngle = ( angleclamp180( myAngle[ 0 ] + X ), angleclamp180( myAngle[ 1 ] + Y ), 0 );
self setplayerangles( myAngle ); self BotBuiltinBotAngles( myAngle );
wait 0.05; wait 0.05;
} }
} }

View File

@ -347,6 +347,21 @@ classWatch()
if ( !maps\mp\gametypes\_globallogic::isvalidclass( self.class ) || !isdefined( self.bot_change_class ) ) if ( !maps\mp\gametypes\_globallogic::isvalidclass( self.class ) || !isdefined( self.bot_change_class ) )
{ {
// mod warfare shtuff
if ( isdefined( level.serverdvars ) )
{
a = [];
a[ a.size ] = "assault";
a[ a.size ] = "specops";
a[ a.size ] = "heavygunner";
a[ a.size ] = "demolitions";
a[ a.size ] = "sniper";
self notify( "menuresponse", game[ "menu_changeclass_" + self.pers[ "team" ] ], random( a ) );
wait 0.5;
}
self notify( "menuresponse", game[ "menu_changeclass" ], self chooseRandomClass() ); self notify( "menuresponse", game[ "menu_changeclass" ], self chooseRandomClass() );
} }
@ -2841,6 +2856,12 @@ bot_killstreak_think_loop()
{ {
curWeap = self getcurrentweapon(); curWeap = self getcurrentweapon();
if ( curWeap == "radar_mp" || curWeap == "helicopter_mp" || curWeap == "airstrike_mp" )
{
self thread changeToWeapon( self.lastdroppableweapon );
return;
}
if ( curWeap == "none" || !isWeaponDroppable( curWeap ) ) if ( curWeap == "none" || !isWeaponDroppable( curWeap ) )
{ {
curWeap = self.lastdroppableweapon; curWeap = self.lastdroppableweapon;

View File

@ -133,6 +133,17 @@ BotBuiltinBotMeleeParams( yaw, dist )
} }
} }
/*
Sets angles
*/
BotBuiltinBotAngles( angles )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botangles" ] ) )
{
self [[ level.bot_builtins[ "botangles" ] ]]( angles );
}
}
/* /*
Test if is a bot Test if is a bot
*/ */
@ -426,12 +437,22 @@ BotStopMoving( what )
} }
} }
/*
Waits till frame end so that if two notifies happen in the same frame, the other will not be missed.
*/
BotNotifyBotEvent_( msg, a, b, c, d, e, f, g )
{
self endon( "disconnect" );
waittillframeend; // wait for the waittills to setup again
self notify( "bot_event", msg, a, b, c, d, e, f, g );
}
/* /*
Notify the bot chat message Notify the bot chat message
*/ */
BotNotifyBotEvent( msg, a, b, c, d, e, f, g ) BotNotifyBotEvent( msg, a, b, c, d, e, f, g )
{ {
self notify( "bot_event", msg, a, b, c, d, e, f, g ); self thread BotNotifyBotEvent_( msg, a, b, c, d, e, f, g );
} }
/* /*
@ -1029,6 +1050,22 @@ isItemUnlocked( what, lvl )
} }
} }
/*
ModWarfare removes this func from _missions
*/
getweaponclass( weapon )
{
tokens = strtok( weapon, "_" );
weaponClass = tablelookup( "mp/statstable.csv", 4, tokens[ 0 ], 2 );
if ( ismg( weapon ) )
{
weaponClass = "weapon_mg";
}
return weaponClass;
}
/* /*
If the weapon is allowed to be dropped If the weapon is allowed to be dropped
*/ */
@ -1724,7 +1761,6 @@ load_waypoints()
{ {
mapname = getdvar( "mapname" ); mapname = getdvar( "mapname" );
level.waypointcount = 0;
level.waypointusage = []; level.waypointusage = [];
level.waypointusage[ "allies" ] = []; level.waypointusage[ "allies" ] = [];
level.waypointusage[ "axis" ] = []; level.waypointusage[ "axis" ] = [];
@ -1771,9 +1807,7 @@ load_waypoints()
BotBuiltinPrintConsole( "No waypoints loaded!" ); BotBuiltinPrintConsole( "No waypoints loaded!" );
} }
level.waypointcount = level.waypoints.size; for ( i = level.waypoints.size - 1; i >= 0; i-- )
for ( i = 0; i < level.waypointcount; i++ )
{ {
if ( !isdefined( level.waypoints[ i ].children ) || !isdefined( level.waypoints[ i ].children.size ) ) if ( !isdefined( level.waypoints[ i ].children ) || !isdefined( level.waypoints[ i ].children.size ) )
{ {
@ -1872,7 +1906,7 @@ getWaypointsOfType( type )
{ {
answer = []; answer = [];
for ( i = 0; i < level.waypointcount; i++ ) for ( i = level.waypoints.size - 1; i >= 0; i-- )
{ {
wp = level.waypoints[ i ]; wp = level.waypoints[ i ];
@ -2679,16 +2713,18 @@ RemoveWaypointUsage( wp, team )
return; return;
} }
if ( !isdefined( level.waypointusage[ team ][ wp + "" ] ) ) wpstr = wp + "";
if ( !isdefined( level.waypointusage[ team ][ wpstr ] ) )
{ {
return; return;
} }
level.waypointusage[ team ][ wp + "" ]--; level.waypointusage[ team ][ wpstr ]--;
if ( level.waypointusage[ team ][ wp + "" ] <= 0 ) if ( level.waypointusage[ team ][ wpstr ] <= 0 )
{ {
level.waypointusage[ team ][ wp + "" ] = undefined; level.waypointusage[ team ][ wpstr ] = undefined;
} }
} }
@ -2700,7 +2736,7 @@ GetNearestWaypointWithSight( pos )
candidate = undefined; candidate = undefined;
dist = 2147483647; dist = 2147483647;
for ( i = 0; i < level.waypointcount; i++ ) for ( i = level.waypoints.size - 1; i >= 0; i-- )
{ {
if ( !bullettracepassed( pos + ( 0, 0, 15 ), level.waypoints[ i ].origin + ( 0, 0, 15 ), false, undefined ) ) if ( !bullettracepassed( pos + ( 0, 0, 15 ), level.waypoints[ i ].origin + ( 0, 0, 15 ), false, undefined ) )
{ {
@ -2729,7 +2765,7 @@ getNearestWaypoint( pos )
candidate = undefined; candidate = undefined;
dist = 2147483647; dist = 2147483647;
for ( i = 0; i < level.waypointcount; i++ ) for ( i = level.waypoints.size - 1; i >= 0; i-- )
{ {
curdis = distancesquared( level.waypoints[ i ].origin, pos ); curdis = distancesquared( level.waypoints[ i ].origin, pos );
@ -2814,7 +2850,8 @@ AStarSearch( start, goal, team, greedy_path )
// pop bestnode from queue // pop bestnode from queue
bestNode = open.data[ 0 ]; bestNode = open.data[ 0 ];
open HeapRemove(); open HeapRemove();
openset[ bestNode.index + "" ] = undefined; bestNodeStr = bestNode.index + "";
openset[ bestNodeStr ] = undefined;
wp = level.waypoints[ bestNode.index ]; wp = level.waypoints[ bestNode.index ];
// check if we made it to the goal // check if we made it to the goal
@ -2824,14 +2861,16 @@ AStarSearch( start, goal, team, greedy_path )
while ( isdefined( bestNode ) ) while ( isdefined( bestNode ) )
{ {
bestNodeStr = bestNode.index + "";
if ( isdefined( team ) && isdefined( level.waypointusage ) ) if ( isdefined( team ) && isdefined( level.waypointusage ) )
{ {
if ( !isdefined( level.waypointusage[ team ][ bestNode.index + "" ] ) ) if ( !isdefined( level.waypointusage[ team ][ bestNodeStr ] ) )
{ {
level.waypointusage[ team ][ bestNode.index + "" ] = 0; level.waypointusage[ team ][ bestNodeStr ] = 0;
} }
level.waypointusage[ team ][ bestNode.index + "" ]++; level.waypointusage[ team ][ bestNodeStr ]++;
} }
// construct path // construct path
@ -2847,6 +2886,7 @@ AStarSearch( start, goal, team, greedy_path )
for ( i = wp.children.size - 1; i >= 0; i-- ) for ( i = wp.children.size - 1; i >= 0; i-- )
{ {
child = wp.children[ i ]; child = wp.children[ i ];
childStr = child + "";
childWp = level.waypoints[ child ]; childWp = level.waypoints[ child ];
penalty = 1; penalty = 1;
@ -2855,9 +2895,9 @@ AStarSearch( start, goal, team, greedy_path )
{ {
temppen = 1; temppen = 1;
if ( isdefined( level.waypointusage[ team ][ child + "" ] ) ) if ( isdefined( level.waypointusage[ team ][ childStr ] ) )
{ {
temppen = level.waypointusage[ team ][ child + "" ]; // consider how many bots are taking this path temppen = level.waypointusage[ team ][ childStr ]; // consider how many bots are taking this path
} }
if ( temppen > 1 ) if ( temppen > 1 )
@ -2876,16 +2916,16 @@ AStarSearch( start, goal, team, greedy_path )
newg = bestNode.g + distancesquared( wp.origin, childWp.origin ) * penalty; // bots on same team's path are more expensive newg = bestNode.g + distancesquared( wp.origin, childWp.origin ) * penalty; // bots on same team's path are more expensive
// check if this child is in open or close with a g value less than newg // check if this child is in open or close with a g value less than newg
inopen = isdefined( openset[ child + "" ] ); inopen = isdefined( openset[ childStr ] );
if ( inopen && openset[ child + "" ].g <= newg ) if ( inopen && openset[ childStr ].g <= newg )
{ {
continue; continue;
} }
inclosed = isdefined( closed[ child + "" ] ); inclosed = isdefined( closed[ childStr ] );
if ( inclosed && closed[ child + "" ].g <= newg ) if ( inclosed && closed[ childStr ].g <= newg )
{ {
continue; continue;
} }
@ -2894,11 +2934,11 @@ AStarSearch( start, goal, team, greedy_path )
if ( inopen ) if ( inopen )
{ {
node = openset[ child + "" ]; node = openset[ childStr ];
} }
else if ( inclosed ) else if ( inclosed )
{ {
node = closed[ child + "" ]; node = closed[ childStr ];
} }
else else
{ {
@ -2914,19 +2954,19 @@ AStarSearch( start, goal, team, greedy_path )
// check if in closed, remove it // check if in closed, remove it
if ( inclosed ) if ( inclosed )
{ {
closed[ child + "" ] = undefined; closed[ childStr ] = undefined;
} }
// check if not in open, add it // check if not in open, add it
if ( !inopen ) if ( !inopen )
{ {
open HeapInsert( node ); open HeapInsert( node );
openset[ child + "" ] = node; openset[ childStr ] = node;
} }
} }
// done with children, push onto closed // done with children, push onto closed
closed[ bestNode.index + "" ] = bestNode; closed[ bestNodeStr ] = bestNode;
} }
return []; return [];

View File

@ -461,6 +461,7 @@ LoadWaypoints()
self deleteAllWaypoints(); self deleteAllWaypoints();
self iprintlnbold( "Loading WPS..." ); self iprintlnbold( "Loading WPS..." );
load_waypoints(); load_waypoints();
level.waypointcount = level.waypoints.size;
wait 1; wait 1;

View File

@ -17,11 +17,11 @@ CodeCallback_StartGameType()
level.gametypestarted = true; // so we know that the gametype has been started up level.gametypestarted = true; // so we know that the gametype has been started up
level thread scripts\bots_adapter_cod4x::init(); level thread scripts\mp\bots_adapter_cod4x::init();
level thread scripts\bots_chat::init(); level thread scripts\mp\bots_chat::init();
level thread scripts\bots_menu::init(); level thread scripts\mp\bots_menu::init();
level thread scripts\bots_wp_editor::init(); level thread scripts\mp\bots_wp_editor::init();
level thread scripts\bots::init(); level thread scripts\mp\bots::init();
} }
} }

View File

@ -7,6 +7,7 @@ init()
level.bot_builtins[ "botmovement" ] = ::do_botmovement; level.bot_builtins[ "botmovement" ] = ::do_botmovement;
level.bot_builtins[ "botmoveto" ] = ::do_botmoveto; level.bot_builtins[ "botmoveto" ] = ::do_botmoveto;
level.bot_builtins[ "botmeleeparams" ] = ::do_botmeleeparams; level.bot_builtins[ "botmeleeparams" ] = ::do_botmeleeparams;
level.bot_builtins[ "botangles" ] = ::do_botangles;
level.bot_builtins[ "isbot" ] = ::do_isbot; level.bot_builtins[ "isbot" ] = ::do_isbot;
level.bot_builtins[ "fs_fopen" ] = ::do_fs_fopen; level.bot_builtins[ "fs_fopen" ] = ::do_fs_fopen;
level.bot_builtins[ "fs_fclose" ] = ::do_fs_fclose; level.bot_builtins[ "fs_fclose" ] = ::do_fs_fclose;
@ -49,6 +50,12 @@ do_botmeleeparams( yaw, dist )
// cod4x removed lunging due to movement exploits // cod4x removed lunging due to movement exploits
} }
do_botangles( angles )
{
self setplayerangles( angles );
// self botangles( angles[ 0 ], angles[ 1 ], angles[ 2 ] );
}
do_isbot() do_isbot()
{ {
return self.isbot; return self.isbot;