Version 2.1.0

This commit is contained in:
ineed bots 2022-05-08 17:46:25 -06:00
parent 9c20cf621b
commit a64a0cc810
15 changed files with 9340 additions and 5631 deletions

View File

@ -5,7 +5,7 @@ Bot Warfare is a GSC mod for the [CoD4x project](https://github.com/callofduty4x
It aims to add playable AI to the multiplayer games of CoD4. It aims to add playable AI to the multiplayer games of CoD4.
You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfare/downloads/cod4x-bot-warfare-latest) and the CoD4x.me post [here](https://cod4x.me/index.php?/forums/topic/3116-release-bot-warfare/). You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfare/downloads/cod4x-bot-warfare-latest) and the CoD4x forum post [here](https://cod4x.ovh/index.php?/forums/topic/3116-release-bot-warfare/).
## <span style="color:red">Important to public dedicated servers</span> ## <span style="color:red">Important to public dedicated servers</span>
The ```bots_main_firstIsHost``` DVAR is enabled by default! The ```bots_main_firstIsHost``` DVAR is enabled by default!
@ -57,15 +57,15 @@ Make sure to disable this DVAR by adding ```set bots_main_firstIsHost 0``` in yo
- ... And pretty much everything you expect a Combat Training bot to have - ... And pretty much everything you expect a Combat Training bot to have
## Installation ## Installation
Using CoD4x's extended functionality requires to use their Dedicated server, as explained [here](https://cod4x.me/index.php?/forums/topic/2047-add-cod4x-server-gsc-functions-to-the-client/). Using CoD4x's extended functionality requires to use their Dedicated server, as explained [here](https://cod4x.ovh/index.php?/forums/topic/2047-add-cod4x-server-gsc-functions-to-the-client/).
You can easily setup a local LAN dedicated server for you to join and play on. Have a look at [Setting up a CoD4x server](). You can easily setup a local LAN dedicated server for you to join and play on. Have a look at [Setting up a CoD4x server]().
0. Make sure that [CoD4x server + client](https://cod4x.me/) is installed, updated and working properly. 0. Make sure that [CoD4x server + client](https://cod4x.ovh/) is installed, updated and working properly.
- Download the [latest release](https://github.com/ineedbots/cod4x_bot_warfare/releases) of Bot Warfare. - Download the [latest release](https://github.com/ineedbots/cod4x_bot_warfare/releases) of Bot Warfare.
1. Locate your CoD4x server install folder. 1. Locate your CoD4x server install folder.
2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder. 2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder.
- The folder/file structure should follow as '.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc'. - The folder/file structure should follow as `.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc`.
3. The mod is now installed, now start your server, change the DVARs and start a map. 3. The mod is now installed, now start your server, change the DVARs and start a map.
4. Now start your CoD4x client and connect to your server ('connect 127.0.0.1' in the console most likely) and play! 4. Now start your CoD4x client and connect to your server ('connect 127.0.0.1' in the console most likely) and play!
@ -88,6 +88,7 @@ You can easily setup a local LAN dedicated server for you to join and play on. H
| bots_main_menu | Enable the in-game menu for hosts. | true | | bots_main_menu | Enable the in-game menu for hosts. | true |
| bots_main_debug | Enable the in-game waypoint editor. | false | | bots_main_debug | Enable the in-game waypoint editor. | false |
| bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | false | | bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | false |
| bots_main_chat | The rate bots will chat at, set to 0 to disable. | 1.0 |
| bots_manage_add | Amount of bots to add to the game, once bots are added, resets back to `0`. | 0 | | bots_manage_add | Amount of bots to add to the game, once bots are added, resets back to `0`. | 0 |
| bots_manage_fill | Amount of players/bots (look at `bots_manage_fill_mode`) to maintain in the match. | 0 | | bots_manage_fill | Amount of players/bots (look at `bots_manage_fill_mode`) to maintain in the match. | 0 |
| bots_manage_fill_mode | `bots_manage_fill` players/bots counting method.<ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots.</li></ul> | 0 | | bots_manage_fill_mode | `bots_manage_fill` players/bots counting method.<ul><li>`0` - counts both players and bots.</li><li>`1` - only counts bots.</li></ul> | 0 |
@ -121,6 +122,17 @@ You can easily setup a local LAN dedicated server for you to join and play on. H
## Changelog ## Changelog
- v2.1.0
- Bot chatter system, bots_main_chat
- Greatly reduce script variable usage
- Improved bots mantling and stuck
- Fix some runtime errors
- Bots sprint more
- Improved bots sight on enemies
- Bots do random actions while waiting at an objective
- Improved bots from getting stuck
- Better bot difficulty management, bots_skill_min and bots_skill_max
- v2.0.1 - v2.0.1
- Reduced bots crouching - Reduced bots crouching
- Increased bots sprinting - Increased bots sprinting

@ -1 +1 @@
Subproject commit 65a344f95388f6d0f0704f3c4517283670bb2818 Subproject commit c734ac790d590225e613fa3c2b10f411c29885aa

View File

@ -8,7 +8,7 @@
*/ */
init() init()
{ {
level.bw_VERSION = "2.0.1"; level.bw_VERSION = "2.1.0";
if ( getDvar( "bots_main" ) == "" ) if ( getDvar( "bots_main" ) == "" )
setDvar( "bots_main", true ); setDvar( "bots_main", true );

View File

@ -8,7 +8,7 @@
*/ */
init() init()
{ {
level.bw_VERSION = "2.0.1"; level.bw_VERSION = "2.1.0";
if ( getDvar( "bots_main" ) == "" ) if ( getDvar( "bots_main" ) == "" )
setDvar( "bots_main", true ); setDvar( "bots_main", true );
@ -22,78 +22,116 @@ init()
if ( getDvar( "bots_main_GUIDs" ) == "" ) if ( getDvar( "bots_main_GUIDs" ) == "" )
setDvar( "bots_main_GUIDs", "" ); //guids of players who will be given host powers, comma seperated setDvar( "bots_main_GUIDs", "" ); //guids of players who will be given host powers, comma seperated
if ( getDvar( "bots_main_firstIsHost" ) == "" ) if ( getDvar( "bots_main_firstIsHost" ) == "" )
setDvar( "bots_main_firstIsHost", true ); //first player to connect is a host setDvar( "bots_main_firstIsHost", true ); //first player to connect is a host
if ( getDvar( "bots_main_waitForHostTime" ) == "" ) if ( getDvar( "bots_main_waitForHostTime" ) == "" )
setDvar( "bots_main_waitForHostTime", 10.0 ); //how long to wait to wait for the host player setDvar( "bots_main_waitForHostTime", 10.0 ); //how long to wait to wait for the host player
if ( getDvar( "bots_main_kickBotsAtEnd" ) == "" )
setDvar( "bots_main_kickBotsAtEnd", false ); //kicks the bots at game end
if ( getDvar( "bots_manage_add" ) == "" ) if ( getDvar( "bots_manage_add" ) == "" )
setDvar( "bots_manage_add", 0 ); //amount of bots to add to the game setDvar( "bots_manage_add", 0 ); //amount of bots to add to the game
if ( getDvar( "bots_manage_fill" ) == "" ) if ( getDvar( "bots_manage_fill" ) == "" )
setDvar( "bots_manage_fill", 0 ); //amount of bots to maintain setDvar( "bots_manage_fill", 0 ); //amount of bots to maintain
if ( getDvar( "bots_manage_fill_spec" ) == "" ) if ( getDvar( "bots_manage_fill_spec" ) == "" )
setDvar( "bots_manage_fill_spec", true ); //to count for fill if player is on spec team setDvar( "bots_manage_fill_spec", true ); //to count for fill if player is on spec team
if ( getDvar( "bots_manage_fill_mode" ) == "" ) 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 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" ) == "" ) if ( getDvar( "bots_manage_fill_kick" ) == "" )
setDvar( "bots_manage_fill_kick", false ); //kick bots if too many setDvar( "bots_manage_fill_kick", false ); //kick bots if too many
if ( getDvar( "bots_team" ) == "" ) if ( getDvar( "bots_team" ) == "" )
setDvar( "bots_team", "autoassign" ); //which team for bots to join setDvar( "bots_team", "autoassign" ); //which team for bots to join
if ( getDvar( "bots_team_amount" ) == "" ) if ( getDvar( "bots_team_amount" ) == "" )
setDvar( "bots_team_amount", 0 ); //amount of bots on axis team setDvar( "bots_team_amount", 0 ); //amount of bots on axis team
if ( getDvar( "bots_team_force" ) == "" ) if ( getDvar( "bots_team_force" ) == "" )
setDvar( "bots_team_force", false ); //force bots on team setDvar( "bots_team_force", false ); //force bots on team
if ( getDvar( "bots_team_mode" ) == "" ) if ( getDvar( "bots_team_mode" ) == "" )
setDvar( "bots_team_mode", 0 ); //counts just bots when 1 setDvar( "bots_team_mode", 0 ); //counts just bots when 1
if ( getDvar( "bots_skill" ) == "" ) if ( getDvar( "bots_skill" ) == "" )
setDvar( "bots_skill", 0 ); //0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random setDvar( "bots_skill", 0 ); //0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random
if ( getDvar( "bots_skill_axis_hard" ) == "" ) if ( getDvar( "bots_skill_axis_hard" ) == "" )
setDvar( "bots_skill_axis_hard", 0 ); //amount of hard bots on axis team setDvar( "bots_skill_axis_hard", 0 ); //amount of hard bots on axis team
if ( getDvar( "bots_skill_axis_med" ) == "" ) if ( getDvar( "bots_skill_axis_med" ) == "" )
setDvar( "bots_skill_axis_med", 0 ); setDvar( "bots_skill_axis_med", 0 );
if ( getDvar( "bots_skill_allies_hard" ) == "" ) if ( getDvar( "bots_skill_allies_hard" ) == "" )
setDvar( "bots_skill_allies_hard", 0 ); setDvar( "bots_skill_allies_hard", 0 );
if ( getDvar( "bots_skill_allies_med" ) == "" ) if ( getDvar( "bots_skill_allies_med" ) == "" )
setDvar( "bots_skill_allies_med", 0 ); setDvar( "bots_skill_allies_med", 0 );
if ( getDvar( "bots_skill_min" ) == "" )
setDvar( "bots_skill_min", 1 );
if ( getDvar( "bots_skill_max" ) == "" )
setDvar( "bots_skill_max", 7 );
if ( getDvar( "bots_loadout_reasonable" ) == "" ) //filter out the bad 'guns' and perks if ( getDvar( "bots_loadout_reasonable" ) == "" ) //filter out the bad 'guns' and perks
setDvar( "bots_loadout_reasonable", false ); setDvar( "bots_loadout_reasonable", false );
if ( getDvar( "bots_loadout_allow_op" ) == "" ) //allows jug, marty and laststand if ( getDvar( "bots_loadout_allow_op" ) == "" ) //allows jug, marty and laststand
setDvar( "bots_loadout_allow_op", true ); 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 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 ); setDvar( "bots_loadout_rank", -1 );
if ( getDvar( "bots_loadout_prestige" ) == "" ) // what pretige the bots will be, -1 is the players, -2 is random if ( getDvar( "bots_loadout_prestige" ) == "" ) // what pretige the bots will be, -1 is the players, -2 is random
setDvar( "bots_loadout_prestige", -1 ); setDvar( "bots_loadout_prestige", -1 );
if ( getDvar( "bots_play_move" ) == "" ) //bots move if ( getDvar( "bots_play_move" ) == "" ) //bots move
setDvar( "bots_play_move", true ); setDvar( "bots_play_move", true );
if ( getDvar( "bots_play_knife" ) == "" ) //bots knife if ( getDvar( "bots_play_knife" ) == "" ) //bots knife
setDvar( "bots_play_knife", true ); setDvar( "bots_play_knife", true );
if ( getDvar( "bots_play_fire" ) == "" ) //bots fire if ( getDvar( "bots_play_fire" ) == "" ) //bots fire
setDvar( "bots_play_fire", true ); setDvar( "bots_play_fire", true );
if ( getDvar( "bots_play_nade" ) == "" ) //bots grenade if ( getDvar( "bots_play_nade" ) == "" ) //bots grenade
setDvar( "bots_play_nade", true ); setDvar( "bots_play_nade", true );
if ( getDvar( "bots_play_obj" ) == "" ) //bots play the obj if ( getDvar( "bots_play_obj" ) == "" ) //bots play the obj
setDvar( "bots_play_obj", true ); setDvar( "bots_play_obj", true );
if ( getDvar( "bots_play_camp" ) == "" ) //bots camp and follow if ( getDvar( "bots_play_camp" ) == "" ) //bots camp and follow
setDvar( "bots_play_camp", true ); setDvar( "bots_play_camp", true );
if ( getDvar( "bots_play_jumpdrop" ) == "" ) //bots jump and dropshot if ( getDvar( "bots_play_jumpdrop" ) == "" ) //bots jump and dropshot
setDvar( "bots_play_jumpdrop", true ); setDvar( "bots_play_jumpdrop", true );
if ( getDvar( "bots_play_target_other" ) == "" ) //bot target non play ents (vehicles) if ( getDvar( "bots_play_target_other" ) == "" ) //bot target non play ents (vehicles)
setDvar( "bots_play_target_other", true ); setDvar( "bots_play_target_other", true );
if ( getDvar( "bots_play_killstreak" ) == "" ) //bot use killstreaks if ( getDvar( "bots_play_killstreak" ) == "" ) //bot use killstreaks
setDvar( "bots_play_killstreak", true ); setDvar( "bots_play_killstreak", true );
if ( getDvar( "bots_play_ads" ) == "" ) //bot ads if ( getDvar( "bots_play_ads" ) == "" ) //bot ads
setDvar( "bots_play_ads", true ); setDvar( "bots_play_ads", true );
if ( getDvar( "bots_play_aim" ) == "" )
setDvar( "bots_play_aim", true );
if ( !isDefined( game["botWarfare"] ) ) if ( !isDefined( game["botWarfare"] ) )
game["botWarfare"] = true; game["botWarfare"] = true;
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;
for ( h = 1; h < 6; h++ ) for ( h = 1; h < 6; h++ )
for ( i = 0; i < 3; i++ ) for ( i = 0; i < 3; i++ )
level.default_perk["CLASS_CUSTOM" + h][i] = "specialty_null"; level.default_perk["CLASS_CUSTOM" + h][i] = "specialty_null";
@ -156,6 +194,11 @@ handleBots()
wait 0.05; wait 0.05;
setDvar( "bots_manage_add", getBotArray().size ); setDvar( "bots_manage_add", getBotArray().size );
if ( !getDvarInt( "bots_main_kickBotsAtEnd" ) )
return;
removeAllTestClients();
} }
/* /*
@ -183,6 +226,14 @@ onPlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi
self maps\mp\bots\_bot_script::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); self maps\mp\bots\_bot_script::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration );
} }
self.lastAttacker = eAttacker;
if ( isDefined( eAttacker ) )
{
eAttacker.lastKilledPlayer = self;
eAttacker notify( "killed_enemy" );
}
self [[level.prevCallbackPlayerKilled]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); self [[level.prevCallbackPlayerKilled]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration );
} }
@ -240,6 +291,7 @@ fixGamemodes()
{ {
for ( i = 0; i < level.bombZones.size; i++ ) for ( i = 0; i < level.bombZones.size; i++ )
level.bombZones[i].onUse = ::onUsePlantObjectFix; level.bombZones[i].onUse = ::onUsePlantObjectFix;
break; break;
} }
@ -332,6 +384,26 @@ connected()
self thread onDisconnect(); self thread onDisconnect();
level notify( "bot_connected", self ); level notify( "bot_connected", self );
self thread watchBotDebugEvent();
}
/*
DEBUG
*/
watchBotDebugEvent()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "bot_event", msg, str, b, c, d, e, f, g );
if ( msg == "debug" && GetDvarInt( "bots_main_debug" ) )
{
printToConsole( "Bot Warfare debug: " + self.name + ": " + str );
}
}
} }
/* /*
@ -370,12 +442,8 @@ add_bot()
/* /*
A server thread for monitoring all bot's difficulty levels for custom server settings. A server thread for monitoring all bot's difficulty levels for custom server settings.
*/ */
diffBots() diffBots_loop()
{ {
for(;;)
{
wait 1.5;
var_allies_hard = getDVarInt( "bots_skill_allies_hard" ); var_allies_hard = getDVarInt( "bots_skill_allies_hard" );
var_allies_med = getDVarInt( "bots_skill_allies_med" ); var_allies_med = getDVarInt( "bots_skill_allies_med" );
var_axis_hard = getDVarInt( "bots_skill_axis_hard" ); var_axis_hard = getDVarInt( "bots_skill_axis_hard" );
@ -390,6 +458,7 @@ diffBots()
if ( var_skill == 8 ) if ( var_skill == 8 )
{ {
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -435,6 +504,7 @@ diffBots()
else if ( var_skill != 0 && var_skill != 9 ) else if ( var_skill != 0 && var_skill != 9 )
{ {
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -445,17 +515,40 @@ diffBots()
player.pers["bots"]["skill"]["base"] = var_skill; player.pers["bots"]["skill"]["base"] = var_skill;
} }
} }
playercount = level.players.size;
min_diff = GetDvarInt( "bots_skill_min" );
max_diff = GetDvarInt( "bots_skill_max" );
for ( i = 0; i < playercount; i++ )
{
player = level.players[i];
if ( !player is_bot() )
continue;
player.pers["bots"]["skill"]["base"] = int( clamp( player.pers["bots"]["skill"]["base"], min_diff, max_diff ) );
}
}
/*
A server thread for monitoring all bot's difficulty levels for custom server settings.
*/
diffBots()
{
for ( ;; )
{
wait 1.5;
diffBots_loop();
} }
} }
/* /*
A server thread for monitoring all bot's teams for custom server settings. A server thread for monitoring all bot's teams for custom server settings.
*/ */
teamBots() teamBots_loop()
{ {
for(;;)
{
wait 1.5;
teamAmount = getDvarInt( "bots_team_amount" ); teamAmount = getDvarInt( "bots_team_amount" );
toTeam = getDvar( "bots_team" ); toTeam = getDvar( "bots_team" );
@ -465,6 +558,7 @@ teamBots()
axisplayers = 0; axisplayers = 0;
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -506,6 +600,7 @@ teamBots()
if ( abs( axis - allies ) > 1 ) if ( abs( axis - allies ) > 1 )
{ {
toTeam = "axis"; toTeam = "axis";
if ( axis > allies ) if ( axis > allies )
toTeam = "allies"; toTeam = "allies";
} }
@ -514,6 +609,7 @@ teamBots()
if ( toTeam != "autoassign" ) if ( toTeam != "autoassign" )
{ {
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -533,6 +629,7 @@ teamBots()
player thread [[level.axis]](); player thread [[level.axis]]();
else else
player thread [[level.spectator]](); player thread [[level.spectator]]();
break; break;
} }
} }
@ -541,6 +638,7 @@ teamBots()
else else
{ {
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -575,21 +673,25 @@ teamBots()
} }
} }
} }
/*
A server thread for monitoring all bot's teams for custom server settings.
*/
teamBots()
{
for ( ;; )
{
wait 1.5;
teamBots_loop();
}
} }
/* /*
A server thread for monitoring all bot's in game. Will add and kick bots according to server settings. A server thread for monitoring all bot's in game. Will add and kick bots according to server settings.
*/ */
addBots() addBots_loop()
{ {
level endon("game_ended");
bot_wait_for_host();
for(;;)
{
wait 1.5;
botsToAdd = GetDvarInt( "bots_manage_add" ); botsToAdd = GetDvarInt( "bots_manage_add" );
if ( botsToAdd > 0 ) if ( botsToAdd > 0 )
@ -618,6 +720,7 @@ addBots()
spec = 0; spec = 0;
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -644,6 +747,7 @@ addBots()
alliesplayers = 0; alliesplayers = 0;
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -676,8 +780,10 @@ addBots()
} }
amount = bots; amount = bots;
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;
@ -688,6 +794,22 @@ addBots()
RemoveTestClient(); //cod4x RemoveTestClient(); //cod4x
} }
} }
/*
A server thread for monitoring all bot's in game. Will add and kick bots according to server settings.
*/
addBots()
{
level endon( "game_ended" );
bot_wait_for_host();
for ( ;; )
{
wait 1.5;
addBots_loop();
}
} }
/* /*
@ -696,10 +818,16 @@ addBots()
onGrenadeFire() onGrenadeFire()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
for ( ;; ) for ( ;; )
{ {
self waittill ( "grenade_fire", grenade, weaponName ); self waittill ( "grenade_fire", grenade, weaponName );
if ( !isDefined( grenade ) )
continue;
grenade.name = weaponName; grenade.name = weaponName;
if ( weaponName == "smoke_grenade_mp" ) if ( weaponName == "smoke_grenade_mp" )
grenade thread AddToSmokeList(); grenade thread AddToSmokeList();
} }
@ -731,6 +859,7 @@ thinkSmoke()
self.state = "moving"; self.state = "moving";
wait 0.05; wait 0.05;
} }
self.state = "smoking"; self.state = "smoking";
wait 11.5; wait 11.5;
@ -752,6 +881,7 @@ chopperWatch()
if ( level.teamBased && getDvarInt( "doubleHeli" ) ) if ( level.teamBased && getDvarInt( "doubleHeli" ) )
{ {
chopper = level.chopper["allies"]; chopper = level.chopper["allies"];
if ( !isDefined( chopper ) ) if ( !isDefined( chopper ) )
chopper = level.chopper["axis"]; chopper = level.chopper["axis"];
} }
@ -826,6 +956,7 @@ doUAVUpdate(team)
wait level.radarViewTime; wait level.radarViewTime;
playercount = level.players.size; playercount = level.players.size;
for ( i = 0; i < playercount; i++ ) for ( i = 0; i < playercount; i++ )
{ {
player = level.players[i]; player = level.players[i];
@ -858,6 +989,7 @@ onWeaponFired()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
self.bots_firing = false; self.bots_firing = false;
for ( ;; ) for ( ;; )
{ {
self waittill( "weapon_fired" ); self waittill( "weapon_fired" );

File diff suppressed because it is too large Load Diff

View File

@ -103,6 +103,7 @@ getLinesFromUrl(url, filename)
fd = FS_FOpen( filename, "write" ); fd = FS_FOpen( filename, "write" );
line = ""; line = "";
for ( i = 0; i < data.size; i++ ) for ( i = 0; i < data.size; i++ )
{ {
c = data[i]; c = data[i];
@ -126,6 +127,7 @@ getLinesFromUrl(url, filename)
line += c; line += c;
} }
result.lines[result.lines.size] = line; result.lines[result.lines.size] = line;
if ( fd > 0 ) if ( fd > 0 )

View File

@ -129,11 +129,13 @@ watchPlayerOpenMenu()
else else
{ {
self playLocalSound( "mouse_click" ); self playLocalSound( "mouse_click" );
if ( self.SubMenu != "Main" ) if ( self.SubMenu != "Main" )
self ExitSub(); self ExitSub();
else else
{ {
self ExitMenu(); self ExitMenu();
if ( level.inPrematchPeriod || level.gameEnded ) if ( level.inPrematchPeriod || level.gameEnded )
self freezeControls( true ); self freezeControls( true );
else else
@ -159,6 +161,7 @@ MenuSelect()
if ( self.MenuOpen ) if ( self.MenuOpen )
{ {
self playLocalSound( "mouse_click" ); self playLocalSound( "mouse_click" );
if ( self.SubMenu == "Main" ) if ( self.SubMenu == "Main" )
self thread [[self.Option["Function"][self.SubMenu][self.Curs["Main"]["X"]]]]( self.Option["Arg1"][self.SubMenu][self.Curs["Main"]["X"]], self.Option["Arg2"][self.SubMenu][self.Curs["Main"]["X"]] ); self thread [[self.Option["Function"][self.SubMenu][self.Curs["Main"]["X"]]]]( self.Option["Arg1"][self.SubMenu][self.Curs["Main"]["X"]], self.Option["Arg2"][self.SubMenu][self.Curs["Main"]["X"]] );
else else
@ -283,6 +286,7 @@ OpenSub(menu, menu2)
self.MenuText[i] = self createfontstring( "default", 1.6 ); self.MenuText[i] = self createfontstring( "default", 1.6 );
self.MenuText[i] setpoint( "CENTER", "CENTER", -300 + ( i * 100 ), -226 ); self.MenuText[i] setpoint( "CENTER", "CENTER", -300 + ( i * 100 ), -226 );
self.MenuText[i] settext( self.Option["Name"][self.SubMenu][i] ); self.MenuText[i] settext( self.Option["Name"][self.SubMenu][i] );
if ( logOldi ) if ( logOldi )
self.oldi = i; self.oldi = i;
@ -292,6 +296,7 @@ OpenSub(menu, menu2)
x = i - self.oldi; x = i - self.oldi;
self.MenuText[i] setpoint( "CENTER", "CENTER", ( ( ( -300 ) - ( i * 100 ) ) + ( i * 100 ) ) + ( x * 100 ), -196 ); self.MenuText[i] setpoint( "CENTER", "CENTER", ( ( ( -300 ) - ( i * 100 ) ) + ( i * 100 ) ) + ( x * 100 ), -196 );
} }
self.MenuText[i].alpha = 1; self.MenuText[i].alpha = 1;
self.MenuText[i].sort = 999; self.MenuText[i].sort = 999;
} }
@ -332,6 +337,7 @@ OpenSub(menu, menu2)
CursMove( direction ) CursMove( direction )
{ {
self notify( "scrolled" ); self notify( "scrolled" );
if ( self.SubMenu == "Main" ) if ( self.SubMenu == "Main" )
{ {
self.Menu["X"]["Scroller"].x = self.MenuText[self.Curs["Main"]["X"]].x; self.Menu["X"]["Scroller"].x = self.MenuText[self.Curs["Main"]["X"]].x;
@ -409,8 +415,10 @@ ShowOptionOn(variable)
self.MenuText[self.Curs[self.SubMenu][variable]].fontscale = 2.0; self.MenuText[self.Curs[self.SubMenu][variable]].fontscale = 2.0;
//self.MenuText[self.Curs[self.SubMenu][variable]].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); //self.MenuText[self.Curs[self.SubMenu][variable]].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255);
color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 );
if ( int( time * 4 ) % 2 ) if ( int( time * 4 ) % 2 )
color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 );
self.MenuText[self.Curs[self.SubMenu][variable]].color = color; self.MenuText[self.Curs[self.SubMenu][variable]].color = color;
} }
@ -430,8 +438,10 @@ ShowOptionOn(variable)
self.MenuTextY[self.Curs[self.SubMenu][variable]].fontscale = 2.0; self.MenuTextY[self.Curs[self.SubMenu][variable]].fontscale = 2.0;
//self.MenuTextY[self.Curs[self.SubMenu][variable]].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); //self.MenuTextY[self.Curs[self.SubMenu][variable]].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255);
color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 );
if ( int( time * 4 ) % 2 ) if ( int( time * 4 ) % 2 )
color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 );
self.MenuTextY[self.Curs[self.SubMenu][variable]].color = color; self.MenuTextY[self.Curs[self.SubMenu][variable]].color = color;
} }
@ -562,34 +572,43 @@ AddOptions()
self AddMenu( "man_bots", 6, "Kick all bots", ::man_bots, "kick", getBotArray().size ); self AddMenu( "man_bots", 6, "Kick all bots", ::man_bots, "kick", getBotArray().size );
_tempDvar = getDvarInt( "bots_manage_fill_kick" ); _tempDvar = getDvarInt( "bots_manage_fill_kick" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "man_bots", 7, "Toggle auto bot kicking: " + _temp, ::man_bots, "autokick", _tempDvar ); self AddMenu( "man_bots", 7, "Toggle auto bot kicking: " + _temp, ::man_bots, "autokick", _tempDvar );
_tempDvar = getDvarInt( "bots_manage_fill_mode" ); _tempDvar = getDvarInt( "bots_manage_fill_mode" );
switch ( _tempDvar ) switch ( _tempDvar )
{ {
case 0: case 0:
_temp = "everyone"; _temp = "everyone";
break; break;
case 1: case 1:
_temp = "just bots"; _temp = "just bots";
break; break;
case 2: case 2:
_temp = "everyone, adjust to map"; _temp = "everyone, adjust to map";
break; break;
case 3: case 3:
_temp = "just bots, adjust to map"; _temp = "just bots, adjust to map";
break; break;
case 4: case 4:
_temp = "bots used as team balance"; _temp = "bots used as team balance";
break; break;
default: default:
_temp = "out of range"; _temp = "out of range";
break; break;
} }
self AddMenu( "man_bots", 8, "Change bot_fill_mode: " + _temp, ::man_bots, "fillmode", _tempDvar ); self AddMenu( "man_bots", 8, "Change bot_fill_mode: " + _temp, ::man_bots, "fillmode", _tempDvar );
_tempDvar = getDvarInt( "bots_manage_fill" ); _tempDvar = getDvarInt( "bots_manage_fill" );
@ -597,10 +616,12 @@ AddOptions()
self AddMenu( "man_bots", 10, "Decrease bots to keep in-game: " + _tempDvar, ::man_bots, "filldown", _tempDvar ); self AddMenu( "man_bots", 10, "Decrease bots to keep in-game: " + _tempDvar, ::man_bots, "filldown", _tempDvar );
_tempDvar = getDvarInt( "bots_manage_fill_spec" ); _tempDvar = getDvarInt( "bots_manage_fill_spec" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "man_bots", 11, "Count players for fill on spectator: " + _temp, ::man_bots, "fillspec", _tempDvar ); self AddMenu( "man_bots", 11, "Count players for fill on spectator: " + _temp, ::man_bots, "fillspec", _tempDvar );
// //
@ -616,56 +637,72 @@ AddOptions()
self AddMenu( "man_team", 2, "Decrease bots to be on axis team: " + _tempDvar, ::bot_teams, "teamdown", _tempDvar ); self AddMenu( "man_team", 2, "Decrease bots to be on axis team: " + _tempDvar, ::bot_teams, "teamdown", _tempDvar );
_tempDvar = getDvarInt( "bots_team_force" ); _tempDvar = getDvarInt( "bots_team_force" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "man_team", 3, "Toggle forcing bots on team: " + _temp, ::bot_teams, "teamforce", _tempDvar ); self AddMenu( "man_team", 3, "Toggle forcing bots on team: " + _temp, ::bot_teams, "teamforce", _tempDvar );
_tempDvar = getDvarInt( "bots_team_mode" ); _tempDvar = getDvarInt( "bots_team_mode" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "only bots"; _temp = "only bots";
else else
_temp = "everyone"; _temp = "everyone";
self AddMenu( "man_team", 4, "Toggle bot_team_bot: " + _temp, ::bot_teams, "teammode", _tempDvar ); self AddMenu( "man_team", 4, "Toggle bot_team_bot: " + _temp, ::bot_teams, "teammode", _tempDvar );
_tempDvar = getdvarint( "bots_skill" ); _tempDvar = getdvarint( "bots_skill" );
switch ( _tempDvar ) switch ( _tempDvar )
{ {
case 0: case 0:
_temp = "random for all"; _temp = "random for all";
break; break;
case 1: case 1:
_temp = "too easy"; _temp = "too easy";
break; break;
case 2: case 2:
_temp = "easy"; _temp = "easy";
break; break;
case 3: case 3:
_temp = "easy-medium"; _temp = "easy-medium";
break; break;
case 4: case 4:
_temp = "medium"; _temp = "medium";
break; break;
case 5: case 5:
_temp = "hard"; _temp = "hard";
break; break;
case 6: case 6:
_temp = "very hard"; _temp = "very hard";
break; break;
case 7: case 7:
_temp = "hardest"; _temp = "hardest";
break; break;
case 8: case 8:
_temp = "custom"; _temp = "custom";
break; break;
case 9: case 9:
_temp = "complete random"; _temp = "complete random";
break; break;
default: default:
_temp = "out of range"; _temp = "out of range";
break; break;
} }
self AddMenu( "man_team", 5, "Change bot difficulty: " + _temp, ::bot_teams, "skill", _tempDvar ); self AddMenu( "man_team", 5, "Change bot difficulty: " + _temp, ::bot_teams, "skill", _tempDvar );
_tempDvar = getDvarInt( "bots_skill_axis_hard" ); _tempDvar = getDvarInt( "bots_skill_axis_hard" );
@ -690,87 +727,111 @@ AddOptions()
self AddBack( "set1", "Main" ); self AddBack( "set1", "Main" );
_tempDvar = getDvarInt( "bots_loadout_reasonable" ); _tempDvar = getDvarInt( "bots_loadout_reasonable" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 0, "Bots use only good class setups: " + _temp, ::bot_func, "reasonable", _tempDvar ); self AddMenu( "set1", 0, "Bots use only good class setups: " + _temp, ::bot_func, "reasonable", _tempDvar );
_tempDvar = getDvarInt( "bots_loadout_allow_op" ); _tempDvar = getDvarInt( "bots_loadout_allow_op" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 1, "Bots can use op and annoying class setups: " + _temp, ::bot_func, "op", _tempDvar ); self AddMenu( "set1", 1, "Bots can use op and annoying class setups: " + _temp, ::bot_func, "op", _tempDvar );
_tempDvar = getDvarInt( "bots_play_move" ); _tempDvar = getDvarInt( "bots_play_move" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 2, "Bots can move: " + _temp, ::bot_func, "move", _tempDvar ); self AddMenu( "set1", 2, "Bots can move: " + _temp, ::bot_func, "move", _tempDvar );
_tempDvar = getDvarInt( "bots_play_knife" ); _tempDvar = getDvarInt( "bots_play_knife" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 3, "Bots can knife: " + _temp, ::bot_func, "knife", _tempDvar ); self AddMenu( "set1", 3, "Bots can knife: " + _temp, ::bot_func, "knife", _tempDvar );
_tempDvar = getDvarInt( "bots_play_fire" ); _tempDvar = getDvarInt( "bots_play_fire" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 4, "Bots can fire: " + _temp, ::bot_func, "fire", _tempDvar ); self AddMenu( "set1", 4, "Bots can fire: " + _temp, ::bot_func, "fire", _tempDvar );
_tempDvar = getDvarInt( "bots_play_nade" ); _tempDvar = getDvarInt( "bots_play_nade" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 5, "Bots can nade: " + _temp, ::bot_func, "nade", _tempDvar ); self AddMenu( "set1", 5, "Bots can nade: " + _temp, ::bot_func, "nade", _tempDvar );
_tempDvar = getDvarInt( "bots_play_obj" ); _tempDvar = getDvarInt( "bots_play_obj" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 6, "Bots play the objective: " + _temp, ::bot_func, "obj", _tempDvar ); self AddMenu( "set1", 6, "Bots play the objective: " + _temp, ::bot_func, "obj", _tempDvar );
_tempDvar = getDvarInt( "bots_play_camp" ); _tempDvar = getDvarInt( "bots_play_camp" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 7, "Bots can camp: " + _temp, ::bot_func, "camp", _tempDvar ); self AddMenu( "set1", 7, "Bots can camp: " + _temp, ::bot_func, "camp", _tempDvar );
_tempDvar = getDvarInt( "bots_play_jumpdrop" ); _tempDvar = getDvarInt( "bots_play_jumpdrop" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 8, "Bots can jump and dropshot: " + _temp, ::bot_func, "jump", _tempDvar ); self AddMenu( "set1", 8, "Bots can jump and dropshot: " + _temp, ::bot_func, "jump", _tempDvar );
_tempDvar = getDvarInt( "bots_play_target_other" ); _tempDvar = getDvarInt( "bots_play_target_other" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 9, "Bots can target other script objects: " + _temp, ::bot_func, "targetother", _tempDvar ); self AddMenu( "set1", 9, "Bots can target other script objects: " + _temp, ::bot_func, "targetother", _tempDvar );
_tempDvar = getDvarInt( "bots_play_killstreak" ); _tempDvar = getDvarInt( "bots_play_killstreak" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 10, "Bots can use killstreaks: " + _temp, ::bot_func, "killstreak", _tempDvar ); self AddMenu( "set1", 10, "Bots can use killstreaks: " + _temp, ::bot_func, "killstreak", _tempDvar );
_tempDvar = getDvarInt( "bots_play_ads" ); _tempDvar = getDvarInt( "bots_play_ads" );
if ( _tempDvar ) if ( _tempDvar )
_temp = "true"; _temp = "true";
else else
_temp = "false"; _temp = "false";
self AddMenu( "set1", 11, "Bots can ads: " + _temp, ::bot_func, "ads", _tempDvar ); self AddMenu( "set1", 11, "Bots can ads: " + _temp, ::bot_func, "ads", _tempDvar );
} }
@ -782,46 +843,57 @@ bot_func(a, b)
setDvar( "bots_loadout_reasonable", !b ); setDvar( "bots_loadout_reasonable", !b );
self iPrintln( "Bots using reasonable setups: " + !b ); self iPrintln( "Bots using reasonable setups: " + !b );
break; break;
case "op": case "op":
setDvar( "bots_loadout_allow_op", !b ); setDvar( "bots_loadout_allow_op", !b );
self iPrintln( "Bots using op setups: " + !b ); self iPrintln( "Bots using op setups: " + !b );
break; break;
case "move": case "move":
setDvar( "bots_play_move", !b ); setDvar( "bots_play_move", !b );
self iPrintln( "Bots move: " + !b ); self iPrintln( "Bots move: " + !b );
break; break;
case "knife": case "knife":
setDvar( "bots_play_knife", !b ); setDvar( "bots_play_knife", !b );
self iPrintln( "Bots knife: " + !b ); self iPrintln( "Bots knife: " + !b );
break; break;
case "fire": case "fire":
setDvar( "bots_play_fire", !b ); setDvar( "bots_play_fire", !b );
self iPrintln( "Bots fire: " + !b ); self iPrintln( "Bots fire: " + !b );
break; break;
case "nade": case "nade":
setDvar( "bots_play_nade", !b ); setDvar( "bots_play_nade", !b );
self iPrintln( "Bots nade: " + !b ); self iPrintln( "Bots nade: " + !b );
break; break;
case "obj": case "obj":
setDvar( "bots_play_obj", !b ); setDvar( "bots_play_obj", !b );
self iPrintln( "Bots play the obj: " + !b ); self iPrintln( "Bots play the obj: " + !b );
break; break;
case "camp": case "camp":
setDvar( "bots_play_camp", !b ); setDvar( "bots_play_camp", !b );
self iPrintln( "Bots camp: " + !b ); self iPrintln( "Bots camp: " + !b );
break; break;
case "jump": case "jump":
setDvar( "bots_play_jumpdrop", !b ); setDvar( "bots_play_jumpdrop", !b );
self iPrintln( "Bots jump: " + !b ); self iPrintln( "Bots jump: " + !b );
break; break;
case "targetother": case "targetother":
setDvar( "bots_play_target_other", !b ); setDvar( "bots_play_target_other", !b );
self iPrintln( "Bots target other: " + !b ); self iPrintln( "Bots target other: " + !b );
break; break;
case "killstreak": case "killstreak":
setDvar( "bots_play_killstreak", !b ); setDvar( "bots_play_killstreak", !b );
self iPrintln( "Bots use killstreaks: " + !b ); self iPrintln( "Bots use killstreaks: " + !b );
break; break;
case "ads": case "ads":
setDvar( "bots_play_ads", !b ); setDvar( "bots_play_ads", !b );
self iPrintln( "Bots ads: " + !b ); self iPrintln( "Bots ads: " + !b );
@ -840,36 +912,45 @@ bot_teams(a, b)
setdvar( "bots_team", "allies" ); setdvar( "bots_team", "allies" );
self iPrintlnBold( "Changed bot team to allies." ); self iPrintlnBold( "Changed bot team to allies." );
break; break;
case "allies": case "allies":
setdvar( "bots_team", "axis" ); setdvar( "bots_team", "axis" );
self iPrintlnBold( "Changed bot team to axis." ); self iPrintlnBold( "Changed bot team to axis." );
break; break;
case "axis": case "axis":
setdvar( "bots_team", "custom" ); setdvar( "bots_team", "custom" );
self iPrintlnBold( "Changed bot team to custom." ); self iPrintlnBold( "Changed bot team to custom." );
break; break;
default: default:
setdvar( "bots_team", "autoassign" ); setdvar( "bots_team", "autoassign" );
self iPrintlnBold( "Changed bot team to autoassign." ); self iPrintlnBold( "Changed bot team to autoassign." );
break; break;
} }
break; break;
case "teamup": case "teamup":
setdvar( "bots_team_amount", b + 1 ); setdvar( "bots_team_amount", b + 1 );
self iPrintln( ( b + 1 ) + " bot(s) will try to be on axis team." ); self iPrintln( ( b + 1 ) + " bot(s) will try to be on axis team." );
break; break;
case "teamdown": case "teamdown":
setdvar( "bots_team_amount", b - 1 ); setdvar( "bots_team_amount", b - 1 );
self iPrintln( ( b - 1 ) + " bot(s) will try to be on axis team." ); self iPrintln( ( b - 1 ) + " bot(s) will try to be on axis team." );
break; break;
case "teamforce": case "teamforce":
setDvar( "bots_team_force", !b ); setDvar( "bots_team_force", !b );
self iPrintln( "Forcing bots to team: " + !b ); self iPrintln( "Forcing bots to team: " + !b );
break; break;
case "teammode": case "teammode":
setDvar( "bots_team_mode", !b ); setDvar( "bots_team_mode", !b );
self iPrintln( "Only count bots on team: " + !b ); self iPrintln( "Only count bots on team: " + !b );
break; break;
case "skill": case "skill":
switch ( b ) switch ( b )
{ {
@ -877,72 +958,90 @@ bot_teams(a, b)
self iPrintlnBold( "Changed bot skill to easy." ); self iPrintlnBold( "Changed bot skill to easy." );
setDvar( "bots_skill", 1 ); setDvar( "bots_skill", 1 );
break; break;
case 1: case 1:
self iPrintlnBold( "Changed bot skill to easy-med." ); self iPrintlnBold( "Changed bot skill to easy-med." );
setDvar( "bots_skill", 2 ); setDvar( "bots_skill", 2 );
break; break;
case 2: case 2:
self iPrintlnBold( "Changed bot skill to medium." ); self iPrintlnBold( "Changed bot skill to medium." );
setDvar( "bots_skill", 3 ); setDvar( "bots_skill", 3 );
break; break;
case 3: case 3:
self iPrintlnBold( "Changed bot skill to med-hard." ); self iPrintlnBold( "Changed bot skill to med-hard." );
setDvar( "bots_skill", 4 ); setDvar( "bots_skill", 4 );
break; break;
case 4: case 4:
self iPrintlnBold( "Changed bot skill to hard." ); self iPrintlnBold( "Changed bot skill to hard." );
setDvar( "bots_skill", 5 ); setDvar( "bots_skill", 5 );
break; break;
case 5: case 5:
self iPrintlnBold( "Changed bot skill to very hard." ); self iPrintlnBold( "Changed bot skill to very hard." );
setDvar( "bots_skill", 6 ); setDvar( "bots_skill", 6 );
break; break;
case 6: case 6:
self iPrintlnBold( "Changed bot skill to hardest." ); self iPrintlnBold( "Changed bot skill to hardest." );
setDvar( "bots_skill", 7 ); setDvar( "bots_skill", 7 );
break; break;
case 7: case 7:
self iPrintlnBold( "Changed bot skill to custom. Base is easy." ); self iPrintlnBold( "Changed bot skill to custom. Base is easy." );
setDvar( "bots_skill", 8 ); setDvar( "bots_skill", 8 );
break; break;
case 8: case 8:
self iPrintlnBold( "Changed bot skill to complete random. Takes effect at restart." ); self iPrintlnBold( "Changed bot skill to complete random. Takes effect at restart." );
setDvar( "bots_skill", 9 ); setDvar( "bots_skill", 9 );
break; break;
default: default:
self iPrintlnBold( "Changed bot skill to random. Takes effect at restart." ); self iPrintlnBold( "Changed bot skill to random. Takes effect at restart." );
setDvar( "bots_skill", 0 ); setDvar( "bots_skill", 0 );
break; break;
} }
break; break;
case "axishardup": case "axishardup":
setdvar( "bots_skill_axis_hard", ( b + 1 ) ); setdvar( "bots_skill_axis_hard", ( b + 1 ) );
self iPrintln( ( ( b + 1 ) ) + " hard bots will be on axis team." ); self iPrintln( ( ( b + 1 ) ) + " hard bots will be on axis team." );
break; break;
case "axisharddown": case "axisharddown":
setdvar( "bots_skill_axis_hard", ( b - 1 ) ); setdvar( "bots_skill_axis_hard", ( b - 1 ) );
self iPrintln( ( ( b - 1 ) ) + " hard bots will be on axis team." ); self iPrintln( ( ( b - 1 ) ) + " hard bots will be on axis team." );
break; break;
case "axismedup": case "axismedup":
setdvar( "bots_skill_axis_med", ( b + 1 ) ); setdvar( "bots_skill_axis_med", ( b + 1 ) );
self iPrintln( ( ( b + 1 ) ) + " med bots will be on axis team." ); self iPrintln( ( ( b + 1 ) ) + " med bots will be on axis team." );
break; break;
case "axismeddown": case "axismeddown":
setdvar( "bots_skill_axis_med", ( b - 1 ) ); setdvar( "bots_skill_axis_med", ( b - 1 ) );
self iPrintln( ( ( b - 1 ) ) + " med bots will be on axis team." ); self iPrintln( ( ( b - 1 ) ) + " med bots will be on axis team." );
break; break;
case "allieshardup": case "allieshardup":
setdvar( "bots_skill_allies_hard", ( b + 1 ) ); setdvar( "bots_skill_allies_hard", ( b + 1 ) );
self iPrintln( ( ( b + 1 ) ) + " hard bots will be on allies team." ); self iPrintln( ( ( b + 1 ) ) + " hard bots will be on allies team." );
break; break;
case "alliesharddown": case "alliesharddown":
setdvar( "bots_skill_allies_hard", ( b - 1 ) ); setdvar( "bots_skill_allies_hard", ( b - 1 ) );
self iPrintln( ( ( b - 1 ) ) + " hard bots will be on allies team." ); self iPrintln( ( ( b - 1 ) ) + " hard bots will be on allies team." );
break; break;
case "alliesmedup": case "alliesmedup":
setdvar( "bots_skill_allies_med", ( b + 1 ) ); setdvar( "bots_skill_allies_med", ( b + 1 ) );
self iPrintln( ( ( b + 1 ) ) + " med bots will be on allies team." ); self iPrintln( ( ( b + 1 ) ) + " med bots will be on allies team." );
break; break;
case "alliesmeddown": case "alliesmeddown":
setdvar( "bots_skill_allies_med", ( b - 1 ) ); setdvar( "bots_skill_allies_med", ( b - 1 ) );
self iPrintln( ( ( b - 1 ) ) + " med bots will be on allies team." ); self iPrintln( ( ( b - 1 ) ) + " med bots will be on allies team." );
@ -956,6 +1055,7 @@ man_bots(a, b)
{ {
case "add": case "add":
setdvar( "bots_manage_add", b ); setdvar( "bots_manage_add", b );
if ( b == 1 ) if ( b == 1 )
{ {
self iPrintln( "Adding " + b + " bot." ); self iPrintln( "Adding " + b + " bot." );
@ -964,7 +1064,9 @@ man_bots(a, b)
{ {
self iPrintln( "Adding " + b + " bots." ); self iPrintln( "Adding " + b + " bots." );
} }
break; break;
case "kick": case "kick":
for ( i = 0; i < b; i++ ) for ( i = 0; i < b; i++ )
{ {
@ -972,11 +1074,14 @@ man_bots(a, b)
wait 0.25; wait 0.25;
} }
break; break;
case "autokick": case "autokick":
setDvar( "bots_manage_fill_kick", !b ); setDvar( "bots_manage_fill_kick", !b );
self iPrintln( "Kicking bots when bots_fill is exceeded: " + !b ); self iPrintln( "Kicking bots when bots_fill is exceeded: " + !b );
break; break;
case "fillmode": case "fillmode":
switch ( b ) switch ( b )
{ {
@ -984,32 +1089,40 @@ man_bots(a, b)
setdvar( "bots_manage_fill_mode", 1 ); setdvar( "bots_manage_fill_mode", 1 );
self iPrintln( "bot_fill will now count only bots." ); self iPrintln( "bot_fill will now count only bots." );
break; break;
case 1: case 1:
setdvar( "bots_manage_fill_mode", 2 ); setdvar( "bots_manage_fill_mode", 2 );
self iPrintln( "bot_fill will now count everyone, adjusting to map." ); self iPrintln( "bot_fill will now count everyone, adjusting to map." );
break; break;
case 2: case 2:
setdvar( "bots_manage_fill_mode", 3 ); setdvar( "bots_manage_fill_mode", 3 );
self iPrintln( "bot_fill will now count only bots, adjusting to map." ); self iPrintln( "bot_fill will now count only bots, adjusting to map." );
break; break;
case 3: case 3:
setdvar( "bots_manage_fill_mode", 4 ); setdvar( "bots_manage_fill_mode", 4 );
self iPrintln( "bot_fill will now use bots as team balance." ); self iPrintln( "bot_fill will now use bots as team balance." );
break; break;
default: default:
setdvar( "bots_manage_fill_mode", 0 ); setdvar( "bots_manage_fill_mode", 0 );
self iPrintln( "bot_fill will now count everyone." ); self iPrintln( "bot_fill will now count everyone." );
break; break;
} }
break; break;
case "fillup": case "fillup":
setdvar( "bots_manage_fill", b + 1 ); setdvar( "bots_manage_fill", b + 1 );
self iPrintln( "Increased to maintain " + ( b + 1 ) + " bot(s)." ); self iPrintln( "Increased to maintain " + ( b + 1 ) + " bot(s)." );
break; break;
case "filldown": case "filldown":
setdvar( "bots_manage_fill", b - 1 ); setdvar( "bots_manage_fill", b - 1 );
self iPrintln( "Decreased to maintain " + ( b - 1 ) + " bot(s)." ); self iPrintln( "Decreased to maintain " + ( b - 1 ) + " bot(s)." );
break; break;
case "fillspec": case "fillspec":
setDvar( "bots_manage_fill_spec", !b ); setDvar( "bots_manage_fill_spec", !b );
self iPrintln( "Count players on spectator for bots_fill: " + !b ); self iPrintln( "Count players on spectator for bots_fill: " + !b );

View File

@ -75,6 +75,7 @@ init()
onPlayerSpawned() onPlayerSpawned()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
for ( ;; ) for ( ;; )
{ {
self waittill( "spawned_player" ); self waittill( "spawned_player" );
@ -145,7 +146,7 @@ debug()
if ( distance( level.waypoints[i].origin, self.origin ) < getDvarFloat( "bots_main_debug_distance" ) && ( bulletTracePassed( myEye, wpOrg, false, self ) || getDVarint( "bots_main_debug_drawThrough" ) ) ) if ( distance( level.waypoints[i].origin, self.origin ) < getDvarFloat( "bots_main_debug_distance" ) && ( bulletTracePassed( myEye, wpOrg, false, self ) || getDVarint( "bots_main_debug_drawThrough" ) ) )
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
line( wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + ( 0, 0, 25 ), ( 1, 0, 1 ), 1, 1, getDvarInt( "bots_main_debug_lineDuration" ) ); line( wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + ( 0, 0, 25 ), ( 1, 0, 1 ), 1, 1, getDvarInt( "bots_main_debug_lineDuration" ) );
if ( getConeDot( wpOrg, myEye, myAngles ) > getDvarFloat( "bots_main_debug_cone" ) ) if ( getConeDot( wpOrg, myEye, myAngles ) > getDvarFloat( "bots_main_debug_cone" ) )
@ -161,13 +162,15 @@ debug()
if ( closest != -1 ) if ( closest != -1 )
{ {
stringChildren = ""; stringChildren = "";
for(i = 0; i < level.waypoints[closest].childCount; i++)
for ( i = 0; i < level.waypoints[closest].children.size; i++ )
{ {
if ( i != 0 ) if ( i != 0 )
stringChildren = stringChildren + "," + level.waypoints[closest].children[i]; stringChildren = stringChildren + "," + level.waypoints[closest].children[i];
else else
stringChildren = stringChildren + level.waypoints[closest].children[i]; stringChildren = stringChildren + level.waypoints[closest].children[i];
} }
print3d( level.waypoints[closest].origin + ( 0, 0, 35 ), stringChildren, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) ); print3d( level.waypoints[closest].origin + ( 0, 0, 35 ), stringChildren, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) );
print3d( level.waypoints[closest].origin + ( 0, 0, 15 ), level.waypoints[closest].type, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) ); print3d( level.waypoints[closest].origin + ( 0, 0, 15 ), level.waypoints[closest].type, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) );
@ -179,6 +182,7 @@ AddWaypoints()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
self endon( "death" ); self endon( "death" );
for ( ;; ) for ( ;; )
{ {
while ( !self SecondaryOffhandButtonPressed() || isDefined( self.command ) ) while ( !self SecondaryOffhandButtonPressed() || isDefined( self.command ) )
@ -207,6 +211,7 @@ linkWaypoints()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
self endon( "death" ); self endon( "death" );
for ( ;; ) for ( ;; )
{ {
while ( !self MeleeButtonPressed() || isDefined( self.command ) ) while ( !self MeleeButtonPressed() || isDefined( self.command ) )
@ -234,6 +239,7 @@ deleteWaypoints()
{ {
self endon( "disconnect" ); self endon( "disconnect" );
self endon( "death" ); self endon( "death" );
for ( ;; ) for ( ;; )
{ {
while ( !self fragButtonPressed() || isDefined( self.command ) ) while ( !self fragButtonPressed() || isDefined( self.command ) )
@ -286,19 +292,22 @@ watchSaveWaypointsCommand()
mpnm = getMapName( getdvar( "mapname" ) ); mpnm = getMapName( getdvar( "mapname" ) );
logprint( "\n\n" + mpnm + "()\n{\n/*" ); logprint( "\n\n" + mpnm + "()\n{\n/*" );
logprint( "*/waypoints = [];\n/*" ); logprint( "*/waypoints = [];\n/*" );
for ( i = 0; i < level.waypointCount; i++ ) for ( i = 0; i < level.waypointCount; i++ )
{ {
logprint( "*/waypoints[" + i + "] = spawnstruct();\n/*" ); logprint( "*/waypoints[" + i + "] = spawnstruct();\n/*" );
logprint( "*/waypoints[" + i + "].origin = " + level.waypoints[i].origin + ";\n/*" ); logprint( "*/waypoints[" + i + "].origin = " + level.waypoints[i].origin + ";\n/*" );
logprint( "*/waypoints[" + i + "].type = \"" + level.waypoints[i].type + "\";\n/*" ); logprint( "*/waypoints[" + i + "].type = \"" + level.waypoints[i].type + "\";\n/*" );
logprint("*/waypoints["+i+"].childCount = "+level.waypoints[i].childCount+";\n/*");
for(c = 0; c < level.waypoints[i].childCount; c++) for ( c = 0; c < level.waypoints[i].children.size; c++ )
{ {
logprint( "*/waypoints[" + i + "].children[" + c + "] = " + level.waypoints[i].children[c] + ";\n/*" ); logprint( "*/waypoints[" + i + "].children[" + c + "] = " + level.waypoints[i].children[c] + ";\n/*" );
} }
if(isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade"))
if ( isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) )
logprint( "*/waypoints[" + i + "].angles = " + level.waypoints[i].angles + ";\n/*" ); logprint( "*/waypoints[" + i + "].angles = " + level.waypoints[i].angles + ";\n/*" );
} }
logprint( "*/return waypoints;\n}\n\n\n\n" ); logprint( "*/return waypoints;\n}\n\n\n\n" );
filename = "waypoints/" + getdvar( "mapname" ) + "_wp.csv"; filename = "waypoints/" + getdvar( "mapname" ) + "_wp.csv";
@ -315,6 +324,7 @@ watchSaveWaypointsCommand()
fd = 0; fd = 0;
} }
} }
for ( i = 0; i < level.waypointCount; i++ ) for ( i = 0; i < level.waypointCount; i++ )
{ {
str = ""; str = "";
@ -322,13 +332,14 @@ watchSaveWaypointsCommand()
str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ","; str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ",";
for(h = 0; h < wp.childCount; h++) for ( h = 0; h < wp.children.size; h++ )
{ {
str += wp.children[h]; str += wp.children[h];
if (h < wp.childCount - 1) if ( h < wp.children.size - 1 )
str += " "; str += " ";
} }
str += "," + wp.type + ","; str += "," + wp.type + ",";
if ( isDefined( wp.angles ) ) if ( isDefined( wp.angles ) )
@ -349,6 +360,7 @@ watchSaveWaypointsCommand()
} }
} }
} }
PrintLn( "\n\n\n\n\n\n" ); PrintLn( "\n\n\n\n\n\n" );
self iprintln( "Saved!!! to " + filename ); self iprintln( "Saved!!! to " + filename );
@ -406,8 +418,8 @@ checkForWarnings()
continue; continue;
} }
if(level.waypoints[i].childCount <= 0) if ( level.waypoints[i].children.size <= 0 )
self iprintln("WARNING: waypoint "+i+" childCount is "+level.waypoints[i].childCount); self iprintln( "WARNING: waypoint " + i + " childCount is " + level.waypoints[i].children.size );
else else
{ {
if ( !isDefined( level.waypoints[i].children ) || !isDefined( level.waypoints[i].children.size ) ) if ( !isDefined( level.waypoints[i].children ) || !isDefined( level.waypoints[i].children.size ) )
@ -416,10 +428,7 @@ checkForWarnings()
} }
else else
{ {
if(level.waypoints[i].childCount != level.waypoints[i].children.size) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
self iprintln("WARNING: waypoint "+i+" childCount is not "+level.waypoints[i].children.size);
for (h = 0; h < level.waypoints[i].childCount; h++)
{ {
child = level.waypoints[i].children[h]; child = level.waypoints[i].children[h];
@ -437,7 +446,7 @@ checkForWarnings()
continue; continue;
} }
if(!isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) if ( !isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) )
self iprintln( "WARNING: waypoint " + i + " angles is undefined" ); self iprintln( "WARNING: waypoint " + i + " angles is undefined" );
} }
} }
@ -446,12 +455,6 @@ DeleteAllWaypoints()
{ {
level.waypoints = []; level.waypoints = [];
level.waypointCount = 0; level.waypointCount = 0;
level.waypointsKDTree = WaypointsToKDTree();
level.waypointsCamp = [];
level.waypointsTube = [];
level.waypointsGren = [];
level.waypointsClay = [];
self iprintln( "DelAllWps" ); self iprintln( "DelAllWps" );
} }
@ -466,18 +469,16 @@ DeleteWaypoint(nwp)
level.wpToLink = -1; level.wpToLink = -1;
for(i = 0; i < level.waypoints[nwp].childCount; i++) for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- )
{ {
child = level.waypoints[nwp].children[i]; child = level.waypoints[nwp].children[i];
level.waypoints[child].children = array_remove( level.waypoints[child].children, nwp ); level.waypoints[child].children = array_remove( level.waypoints[child].children, nwp );
level.waypoints[child].childCount = level.waypoints[child].children.size;
} }
for ( i = 0; i < level.waypointCount; i++ ) for ( i = 0; i < level.waypointCount; i++ )
{ {
for(h = 0; h < level.waypoints[i].childCount; h++) for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- )
{ {
if ( level.waypoints[i].children[h] > nwp ) if ( level.waypoints[i].children[h] > nwp )
level.waypoints[i].children[h]--; level.waypoints[i].children[h]--;
@ -493,10 +494,12 @@ DeleteWaypoint(nwp)
level.waypoints[entry] = level.waypoints[entry + 1]; level.waypoints[entry] = level.waypoints[entry + 1];
entry++; entry++;
} }
level.waypoints[entry] = undefined; level.waypoints[entry] = undefined;
break; break;
} }
} }
level.waypointCount--; level.waypointCount--;
self iprintln( "DelWp " + nwp ); self iprintln( "DelWp " + nwp );
@ -522,7 +525,6 @@ addWaypoint(pos)
level.waypoints[level.waypointCount].angles = self getPlayerAngles(); level.waypoints[level.waypointCount].angles = self getPlayerAngles();
level.waypoints[level.waypointCount].children = []; level.waypoints[level.waypointCount].children = [];
level.waypoints[level.waypointCount].childCount = 0;
self iprintln( level.waypoints[level.waypointCount].type + " Waypoint " + level.waypointCount + " Added at " + pos ); self iprintln( level.waypoints[level.waypointCount].type + " Waypoint " + level.waypointCount + " Added at " + pos );
@ -559,9 +561,6 @@ UnLinkWaypoint(nwp)
level.waypoints[nwp].children = array_remove( level.waypoints[nwp].children, level.wpToLink ); level.waypoints[nwp].children = array_remove( level.waypoints[nwp].children, level.wpToLink );
level.waypoints[level.wpToLink].children = array_remove( level.waypoints[level.wpToLink].children, nwp ); level.waypoints[level.wpToLink].children = array_remove( level.waypoints[level.wpToLink].children, nwp );
level.waypoints[nwp].childCount = level.waypoints[nwp].children.size;
level.waypoints[level.wpToLink].childCount = level.waypoints[level.wpToLink].children.size;
self iprintln( "Waypoint " + nwp + " Broken to " + level.wpToLink ); self iprintln( "Waypoint " + nwp + " Broken to " + level.wpToLink );
level.wpToLink = -1; level.wpToLink = -1;
} }
@ -583,7 +582,8 @@ LinkWaypoint(nwp)
} }
weGood = true; weGood = true;
for(i = 0; i < level.waypoints[level.wpToLink].childCount; i++)
for ( i = level.waypoints[level.wpToLink].children.size - 1; i >= 0; i-- )
{ {
if ( level.waypoints[level.wpToLink].children[i] == nwp ) if ( level.waypoints[level.wpToLink].children[i] == nwp )
{ {
@ -591,9 +591,10 @@ LinkWaypoint(nwp)
break; break;
} }
} }
if ( weGood ) if ( weGood )
{ {
for(i = 0; i < level.waypoints[nwp].childCount; i++) for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- )
{ {
if ( level.waypoints[nwp].children[i] == level.wpToLink ) if ( level.waypoints[nwp].children[i] == level.wpToLink )
{ {
@ -610,10 +611,8 @@ LinkWaypoint(nwp)
return; return;
} }
level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].childcount] = nwp; level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].children.size] = nwp;
level.waypoints[level.wpToLink].childcount++; level.waypoints[nwp].children[level.waypoints[nwp].children.size] = level.wpToLink;
level.waypoints[nwp].children[level.waypoints[nwp].childcount] = level.wpToLink;
level.waypoints[nwp].childcount++;
self iprintln( "Waypoint " + nwp + " Linked to " + level.wpToLink ); self iprintln( "Waypoint " + nwp + " Linked to " + level.wpToLink );
level.wpToLink = -1; level.wpToLink = -1;

View File

@ -1,4 +1,4 @@
# CoD4x Bot Warfare # CoD4x Bot Warfare v2.1.0
Bot Warfare is a GSC mod for the CoD4x project. Bot Warfare is a GSC mod for the CoD4x project.
It aims to add playable AI to the multiplayer games of CoD4. It aims to add playable AI to the multiplayer games of CoD4.
@ -12,7 +12,7 @@ Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your s
## Installation ## Installation
0. Make sure that CoD4x server + client is installed, updated and working properly. 0. Make sure that CoD4x server + client is installed, updated and working properly.
- Go to https://cod4x.me/ and download the Windows Server zip file. Move the contents of 'cod4x-windows-server' into your CoD4 game folder. - Go to https://cod4x.ovh/ and download the Windows Server zip file. Move the contents of 'cod4x-windows-server' into your CoD4 game folder.
1. Locate your CoD4x server install folder. 1. Locate your CoD4x server install folder.
2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder. 2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder.
- The folder/file structure should follow as '.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc'. - The folder/file structure should follow as '.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc'.
@ -30,6 +30,17 @@ Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your s
- Pressing the menu button again closes menus. - Pressing the menu button again closes menus.
## Changelog ## Changelog
- v2.1.0
- Bot chatter system, bots_main_chat
- Greatly reduce script variable usage
- Improved bots mantling and stuck
- Fix some runtime errors
- Bots sprint more
- Improved bots sight on enemies
- Bots do random actions while waiting at an objective
- Improved bots from getting stuck
- Better bot difficulty management, bots_skill_min and bots_skill_max
- v2.0.1 - v2.0.1
- Reduced bots crouching - Reduced bots crouching
- Increased bots sprinting - Increased bots sprinting

BIN
out/ss.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 MiB