Compare commits

102 Commits

Author SHA1 Message Date
d22af0209a wait for notifies 2024-10-22 10:01:40 -06:00
5ea5f77213 we are not released 2024-09-21 20:52:41 -06:00
3ee5453c87 add bots_manage_fill_watchplayers 2024-05-16 19:29:08 -06:00
9c0e3e26cd update 2024-04-30 13:12:18 -06:00
764a12dc7f small update 2024-04-30 12:43:16 -06:00
7acc701c04 chat event 2024-04-26 13:33:29 -06:00
b05344f0d7 playername 2024-04-25 14:42:45 -06:00
7fb2906d62 init time 2024-04-25 14:14:48 -06:00
1272026e97 connection events 2024-04-25 14:11:27 -06:00
96e8fb36b6 no teams in sp 2024-04-05 11:46:02 -06:00
73141eddf4 small fix 2024-04-04 16:55:03 -06:00
7a19d85393 fix 2024-04-04 15:21:11 -06:00
4adaab9841 update bones 2024-04-04 14:55:04 -06:00
772259aa13 update bones 2024-04-04 14:39:54 -06:00
5020458595 some cleanup 2024-04-04 14:18:25 -06:00
680440946f ver 2024-03-12 14:51:52 -06:00
484eedd4a2 waittillframeend for event 2024-03-12 14:51:30 -06:00
6a49312538 its time 2024-01-30 13:32:00 -06:00
4748f0e8ce checkf or target 2024-01-18 14:58:38 -06:00
9ac08f9d15 Update main.yml 2024-01-15 17:39:37 -06:00
3aad2db86d ci 2024-01-07 21:22:28 -06:00
dd1ea5ca07 fmt 2024-01-04 16:02:38 -06:00
18abf5e007 register 2023-12-31 14:05:58 -06:00
daeed3e27d register 2023-12-31 13:55:06 -06:00
9c663186aa fix these 2023-12-22 00:29:14 -06:00
2492ffc97b fix comment formatting 2023-12-20 15:19:08 -06:00
4aba1289f2 always use curly braces 2023-12-19 19:24:07 -06:00
9e2025e86a spacing 2023-12-19 16:58:31 -06:00
271ea76c3e casing fixes 2023-12-18 23:42:48 -06:00
b85f5af73a add check 2023-12-13 19:14:54 -06:00
532eb70a47 better bot kick logic 2023-12-13 12:43:34 -06:00
7458491ac1 fixes 2023-12-11 17:11:08 -06:00
f95e0ac9fb cleanup 2023-12-11 16:07:27 -06:00
95d7947d54 isai 2023-12-10 05:29:52 -06:00
6737000c72 small fix 2023-12-10 05:20:34 -06:00
0af3e4ca90 lunge 2023-12-10 05:09:48 -06:00
a7a72cb85f change 2023-12-09 23:00:55 -06:00
43608a1b67 doesnt need 2023-12-03 18:24:08 -06:00
a92a5798d6 ishost builtin 2023-12-03 18:21:54 -06:00
9114d20f73 Add todo 2023-12-01 13:53:31 -06:00
f342a64ca2 nothin used this 2023-11-30 03:23:16 -06:00
977dc41f18 cleanup 2023-11-30 03:15:34 -06:00
12c74cc6f4 no more meme 2023-07-22 18:36:08 -06:00
a91d8a769e update 2023-07-20 16:24:45 -06:00
40edab1671 fixed shinonuma links 2023-07-20 13:43:02 -06:00
cc91952f4d cleanup 2023-07-18 21:04:04 -06:00
b9bf6e4d7b some stuff 2023-07-18 20:50:16 -06:00
93829034d7 added debug 2023-07-18 20:29:09 -06:00
91d1728e41 cleanup 2023-07-17 23:18:52 -06:00
8a9aa8fdb4 fix meme map 2023-07-17 02:39:36 -06:00
50cc792fd4 added perk machine 2023-07-17 00:23:43 -06:00
68ab7dad3b they do the box 2023-07-16 18:12:05 -06:00
120b3edec6 better debug 2023-07-15 16:01:35 -06:00
2d719726dc use dyn prio 2023-07-15 14:58:58 -06:00
b7254c0131 skip 2023-07-15 13:20:49 -06:00
3f41b61b8f iprove prio 2023-07-15 13:03:28 -06:00
edb0004fd8 prio 2023-07-14 21:08:57 -06:00
f035a2badd smallish fix 2023-07-14 20:22:41 -06:00
e25adccf15 small fixes 2023-07-14 20:18:54 -06:00
411a1a047a fixed wallweapons 2023-07-13 22:52:27 -06:00
2fad2787a0 small fix 2023-07-13 15:30:20 -06:00
84e0677420 update ignore 2023-07-13 15:20:36 -06:00
81e65a3adb cleanup 2023-07-13 14:58:54 -06:00
65ad154eb6 remove prioity func ptr 2023-07-13 02:23:50 -06:00
1302a40869 add processrate to objs 2023-07-13 02:21:14 -06:00
7c9f6fca11 new objective system 2023-07-13 01:52:35 -06:00
2f5a21fd8c Progress 4. 2023-07-12 21:04:35 -07:00
3d3c7e7fa4 some stuff 2023-07-11 23:01:06 -06:00
aae462fb95 nvm 2023-07-11 22:33:10 -06:00
2bd494c8d7 fix 2023-07-11 22:30:06 -06:00
01dcaaff95 wont knife when reloading 2023-07-11 22:18:08 -06:00
f5753789db some cleanup 2023-07-11 22:15:11 -06:00
280ec4c318 Progress 3. 2023-07-11 21:00:28 -07:00
81094096cb Add untested code for every remaining objective(except trap). 2023-07-10 02:14:19 -07:00
8343d597c7 Progress 2. 2023-07-09 17:57:55 -07:00
845b377eff Progress. 2023-07-03 20:12:04 -07:00
6994631128 Bug fixes and optimizations for objective system. 2023-06-25 02:13:39 -07:00
09780b4ea0 Change how function works. 2023-06-24 21:51:17 -07:00
0e68c20fcd Bug fix. 2023-06-24 21:49:51 -07:00
cf77a0237e Add dependency for bots. 2023-06-24 21:49:11 -07:00
07a10e74f3 Add bots_t8_mode dvar, and fix bug with bot debug prints. 2023-06-20 17:55:37 -07:00
b117cdb1fa temp disable 2023-06-20 14:00:27 -06:00
5b5133a629 some organization 2023-06-20 13:57:20 -06:00
5a3f920155 Merge branch 'main' of https://github.com/JezuzLizard/T4ZM-Zombie-Bots 2023-06-20 13:40:21 -06:00
a906e6f34e update this 2023-06-20 13:40:20 -06:00
5faf834803 Add better logging for bot objectives. 2023-06-19 14:32:31 -07:00
a209af39b8 Add debug prints. Move objective related code into separate scripts.
Add the ability to prioritize objectives over targets.
2023-05-03 21:42:59 -07:00
b9fe21d15f Fix multiple script errors.
Bot objective and action improvements.
2023-05-02 04:29:34 -07:00
1c835bd77b Improve action system.
Fix objective system to use entity numbers instead of infinitely increasing ids. Fix all known script errors. Add the ability for bots to revive players and pickup powerups automatically.
2023-05-01 08:09:33 -07:00
da170b8f9e Prototype for bot objective behavior. 2023-05-01 04:45:26 -07:00
caa27fcfc2 bot internal has everything now 2023-04-30 12:58:36 -06:00
52ebe9961f Hack fix for targets not being cleared. 2023-04-30 02:31:15 -07:00
c7558faa47 Handle different bones for dogs and gibbed zombies.
Readd difficulty settings.
2023-04-30 01:52:00 -07:00
dbf6ce6f3e some testing 2023-04-30 00:15:59 -06:00
c730347c25 Add aim code. 2023-04-29 22:38:54 -07:00
e4254b5fcb Add targeting code. 2023-04-29 22:10:09 -07:00
9a8df716bb Fix script errors related to player damage callback. 2023-04-29 21:51:17 -07:00
aea546f469 Remove oof moment. 2023-04-29 21:45:11 -07:00
87f57db2dc debug dvar 2023-04-29 22:23:13 -06:00
19d7be701a fix debug 2023-04-29 22:17:53 -06:00
111e81efa1 some debugging 2023-04-29 22:09:19 -06:00
c0b19f00c7 They walk bro. 2023-04-29 18:11:49 -07:00
34 changed files with 7474 additions and 5675 deletions

27
.astylerc Normal file
View File

@ -0,0 +1,27 @@
# try to mimic the original gsc provided
# mode=ghc
mode=c
style=allman
indent=force-tab=2
lineend=windows
pad-oper
pad-paren-in
pad-header
# pad-brackets-in
fill-empty-lines
squeeze-lines=2
squeeze-ws
break-one-line-headers
add-braces
remove-comment-prefix
break-blocks
indent-switches
indent-cases
indent-after-parens
indent-col1-comments
remove-comment-prefix

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
root = true
[*]
indent_style = tab
indent_size = 2
charset = latin1
trim_trailing_whitespace = false
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

21
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: main
on: [push]
jobs:
main-win:
name: Test on Windows
runs-on: windows-latest
steps:
- name: Check out files
uses: actions/checkout@main
- name: Setup gsc-tool
uses: xensik/setup-gsc-tool@v1
with:
version: '1.4.0'
- name: Compile test script
run: |
gsc-tool.exe -m parse -g iw5 -s pc .

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.log
missingasset.csv
console.log*

15
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"astyle.astylerc": "${workspaceRoot}/.astylerc",
"astyle.additional_languages": [
"gsc"
],
"[gsc]": {
"editor.defaultFormatter": "chiehyu.vscode-astyle",
},
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"vscode-codscript.use_builtin_completionItems": false
}

View File

@ -1,5 +1,20 @@
# T4ZM-Zombie-Bots # T4SP-Bots
Bots for T4ZM. Bots for T4SP.
Coby basted code from https://github.com/ineedbots/t4m_bot_warfare ## TODO:
- Bots need to open doors
- Bots need to turn on power
- Bots need better decisions for buying weapons
- Add following a player around
- Add boarding up windows
- Activate traps
- Pack a punch
- Do pack a punch quest
- Do EEs
- Use teleporters
- Use zipline
- Bot menu
- Bot chat (needs sayall)
Coby basted code from https://github.com/ineedbots/t4_bot_warfare
Credit to ineedbots for his bot warfare mods for various games. Credit to ineedbots for his bot warfare mods for various games.

671
maps/bots/_bot.gsc Normal file
View File

@ -0,0 +1,671 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
/*
Initiates the whole bot scripts.
*/
init()
{
level.bw_version = "2.3.0 PR 1";
if ( getdvar( "bots_main" ) == "" )
{
setdvar( "bots_main", true );
}
if ( !getdvarint( "bots_main" ) )
{
return;
}
if ( !wait_for_builtins() )
{
println( "FATAL: NO BUILT-INS FOR BOTS" );
}
thread load_waypoints();
thread hook_callbacks();
if ( getdvar( "bots_main_GUIDs" ) == "" )
{
setdvar( "bots_main_GUIDs", "" ); // guids of players who will be given host powers, comma seperated
}
if ( getdvar( "bots_main_firstIsHost" ) == "" )
{
setdvar( "bots_main_firstIsHost", false ); // first player to connect is a host
}
if ( getdvar( "bots_main_waitForHostTime" ) == "" )
{
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" ) == "" )
{
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_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_manage_fill_watchplayers" ) == "" )
{
setdvar( "bots_manage_fill_watchplayers", false ); // add bots when player exists, kick if not
}
if ( getdvar( "bots_skill" ) == "" )
{
setdvar( "bots_skill", 0 ); // 0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random
}
if ( getdvar( "bots_skill_hard" ) == "" )
{
setdvar( "bots_skill_hard", 0 ); // amount of hard bots on axis team
}
if ( getdvar( "bots_skill_med" ) == "" )
{
setdvar( "bots_skill_med", 0 );
}
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_prestige" ) == "" ) // what pretige the bots will be, -1 is the players, -2 is random
{
setdvar( "bots_loadout_prestige", -1 );
}
if ( getdvar( "bots_play_move" ) == "" ) // bots move
{
setdvar( "bots_play_move", 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_nade" ) == "" ) // bots grenade
{
setdvar( "bots_play_nade", true );
}
if ( getdvar( "bots_play_ads" ) == "" ) // bot ads
{
setdvar( "bots_play_ads", true );
}
if ( getdvar( "bots_play_aim" ) == "" )
{
setdvar( "bots_play_aim", true );
}
if ( getdvar( "bots_t8_mode" ) == "" )
{
setdvar( "bots_t8_mode", false );
}
if ( getdvar( "bots_play_opendoors" ) == "" )
{
setdvar( "bots_play_opendoors", true );
}
if ( !isdefined( game[ "botWarfare" ] ) )
{
game[ "botWarfare" ] = true;
game[ "botWarfareInitTime" ] = gettime();
}
level.bot_inittime = gettime();
level.bots_minsprintdistance = 315;
level.bots_minsprintdistance *= level.bots_minsprintdistance;
level.bots_mingrenadedistance = 256;
level.bots_mingrenadedistance *= level.bots_mingrenadedistance;
level.bots_maxgrenadedistance = 1024;
level.bots_maxgrenadedistance *= level.bots_maxgrenadedistance;
level.bots_maxknifedistance = 128;
level.bots_maxknifedistance *= level.bots_maxknifedistance;
level.bots_goaldistance = 27.5;
level.bots_goaldistance *= level.bots_goaldistance;
level.bots_noadsdistance = 200;
level.bots_noadsdistance *= level.bots_noadsdistance;
level.bots_maxshotgundistance = 500;
level.bots_maxshotgundistance *= level.bots_maxshotgundistance;
level.players = [];
level.bots = [];
level.bots_fullautoguns = [];
level.bots_fullautoguns[ "thompson" ] = true;
level.bots_fullautoguns[ "mp40" ] = true;
level.bots_fullautoguns[ "type100smg" ] = true;
level.bots_fullautoguns[ "ppsh" ] = true;
level.bots_fullautoguns[ "stg44" ] = true;
level.bots_fullautoguns[ "30cal" ] = true;
level.bots_fullautoguns[ "mg42" ] = true;
level.bots_fullautoguns[ "dp28" ] = true;
level.bots_fullautoguns[ "bar" ] = true;
level.bots_fullautoguns[ "fg42" ] = true;
level.bots_fullautoguns[ "type99lmg" ] = true;
level thread onPlayerConnect();
level thread handleBots();
level thread onPlayerChat();
level thread maps\bots\_bot_script::bot_script_init();
}
/*
Starts the threads for bots.
*/
handleBots()
{
level thread diffBots();
level addBots();
while ( !isdefined( level.intermission ) || !level.intermission )
{
wait 0.05;
}
setdvar( "bots_manage_add", getBotArray().size );
if ( !getdvarint( "bots_main_kickBotsAtEnd" ) )
{
return;
}
bots = getBotArray();
for ( i = 0; i < bots.size; i++ )
{
BotBuiltinCmdExec( "clientkick " + bots[ i ] getentitynumber() );
}
}
/*
The hook callback for when any player becomes damaged.
*/
onPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, modelIndex, psOffsetTime )
{
if ( self is_bot() && getdvarint( "bots_t8_mode" ) )
{
if ( ( level.script == "nazi_zombie_asylum" || level.script == "nazi_zombie_sumpf" ) && self hasperk( "specialty_armorvest" ) )
{
iDamage = int( iDamage * 0.333 );
}
else
{
iDamage = int( iDamage * 0.1 );
}
}
if ( self is_bot() )
{
self maps\bots\_bot_internal::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, modelIndex, psOffsetTime );
self maps\bots\_bot_script::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, modelIndex, psOffsetTime );
}
self [[ level.prevcallbackplayerdamage ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, modelIndex, psOffsetTime );
}
onActorDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, iTimeOffset )
{
if ( isdefined( eAttacker ) && isplayer( eAttacker ) && eAttacker is_bot() && getdvarint( "bots_t8_mode" ) && ( !isdefined( self.magic_bullet_shield ) || !self.magic_bullet_shield ) )
{
iDamage += int( self.maxhealth * randomfloatrange( 0.25, 1.25 ) );
}
self [[ level.prevcallbackactordamage ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, iTimeOffset );
}
/*
Starts the callbacks.
*/
hook_callbacks()
{
wait 0.05;
level.prevcallbackplayerdamage = level.callbackplayerdamage;
level.callbackplayerdamage = ::onPlayerDamage;
level.prevcallbackactordamage = level.callbackactordamage;
level.callbackactordamage = ::onActorDamage;
}
/*
Thread when any player connects. Starts the threads needed.
*/
onPlayerConnect()
{
for ( ;; )
{
level waittill( "connected", player );
player thread connected();
}
}
/*
When a bot disconnects.
*/
onDisconnectAll()
{
name = self.playername;
self waittill( "disconnect" );
level.players = array_remove( level.players, self );
waittillframeend;
for ( i = 0; i < level.bots.size; i++ )
{
bot = level.bots[ i ];
bot BotNotifyBotEvent( "connection", "disconnected", self, name );
}
}
/*
When any client spawns
*/
onSpawnedAll()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "spawned_player" );
self.lastspawntime = gettime();
if ( getdvarint( "bots_main_debug" ) )
{
self.score = 100000;
}
}
}
/*
When a bot disconnects.
*/
onDisconnect()
{
self waittill( "disconnect" );
level.bots = array_remove( level.bots, self );
}
/*
Called when a player connects.
*/
connected()
{
self endon( "disconnect" );
if ( !isdefined( self.pers[ "bot_host" ] ) )
{
self thread doHostCheck();
}
level.players[ level.players.size ] = self;
for ( i = 0; i < level.bots.size; i++ )
{
bot = level.bots[ i ];
bot BotNotifyBotEvent( "connection", "connected", self, self.playername );
}
self thread onDisconnectAll();
self thread onSpawnedAll();
if ( !self is_bot() )
{
return;
}
if ( !isdefined( self.pers[ "isBot" ] ) )
{
// fast restart...
self.pers[ "isBot" ] = true;
}
if ( !isdefined( self.pers[ "isBotWarfare" ] ) )
{
self.pers[ "isBotWarfare" ] = true;
self thread added();
}
self thread maps\bots\_bot_internal::connected();
self thread maps\bots\_bot_script::connected();
level.bots[ level.bots.size ] = self;
self thread onDisconnect();
self thread watchBotDebugEvent();
waittillframeend; // wait for waittills to process
level notify( "bot_connected", self );
}
/*
DEBUG
*/
watchBotDebugEvent()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "bot_event", msg, str, b, c, d, e, f, g );
if ( getdvarint( "bots_main_debug" ) >= 2 )
{
big_str = "Bot Warfare debug: " + self.playername + ": " + msg;
if ( isdefined( str ) && isstring( str ) )
{
big_str += ", " + str;
}
if ( isdefined( b ) && isstring( b ) )
{
big_str += ", " + b;
}
if ( isdefined( c ) && isstring( c ) )
{
big_str += ", " + c;
}
if ( isdefined( d ) && isstring( d ) )
{
big_str += ", " + d;
}
if ( isdefined( e ) && isstring( e ) )
{
big_str += ", " + e;
}
if ( isdefined( f ) && isstring( f ) )
{
big_str += ", " + f;
}
if ( isdefined( g ) && isstring( g ) )
{
big_str += ", " + g;
}
BotBuiltinPrintConsole( big_str );
}
else if ( msg == "debug" && getdvarint( "bots_main_debug" ) )
{
BotBuiltinPrintConsole( "Bot Warfare debug: " + self.playername + ": " + str );
}
}
}
/*
When a bot gets added into the game.
*/
added()
{
self endon( "disconnect" );
self thread maps\bots\_bot_internal::added();
self thread maps\bots\_bot_script::added();
}
/*
Adds a bot to the game.
*/
add_bot()
{
bot = BotBuiltinAddTestClient();
if ( isdefined( bot ) )
{
bot.pers[ "isBot" ] = true;
bot.pers[ "isBotWarfare" ] = true;
bot thread added();
}
}
/*
A server thread for monitoring all bot's difficulty levels for custom server settings.
*/
diffBots_loop()
{
var_hard = getdvarint( "bots_skill_hard" );
var_med = getdvarint( "bots_skill_med" );
var_skill = getdvarint( "bots_skill" );
hard = 0;
med = 0;
if ( var_skill == 8 )
{
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 ( hard < var_hard )
{
hard++;
player.pers[ "bots" ][ "skill" ][ "base" ] = 7;
}
else if ( med < var_med )
{
med++;
player.pers[ "bots" ][ "skill" ][ "base" ] = 4;
}
else
{
player.pers[ "bots" ][ "skill" ][ "base" ] = 1;
}
}
}
else if ( var_skill != 0 && var_skill != 9 )
{
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( !player is_bot() )
{
continue;
}
player.pers[ "bots" ][ "skill" ][ "base" ] = var_skill;
}
}
}
/*
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 in game. Will add and kick bots according to server settings.
*/
addBots_loop()
{
botsToAdd = getdvarint( "bots_manage_add" );
if ( botsToAdd > 0 )
{
setdvar( "bots_manage_add", 0 );
if ( botsToAdd > 4 )
{
botsToAdd = 4;
}
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;
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( player is_bot() )
{
bots++;
}
else
{
players++;
}
}
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 ( players <= 0 && getdvarint( "bots_manage_fill_watchplayers" ) )
{
amount = fillAmount + bots;
}
if ( amount < fillAmount )
{
setdvar( "bots_manage_add", fillAmount - amount );
}
else if ( amount > fillAmount && getdvarint( "bots_manage_fill_kick" ) )
{
botsToKick = amount - fillAmount;
if ( botsToKick > 64 )
{
botsToKick = 64;
}
for ( i = 0; i < botsToKick; i++ )
{
tempBot = getBotToKick();
if ( isdefined( tempBot ) )
{
BotBuiltinCmdExec( "clientkick " + tempBot getentitynumber() + " EXE_PLAYERKICKED" );
wait 0.25;
}
}
}
}
/*
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();
while ( !isdefined( level.intermission ) || !level.intermission )
{
wait 1.5;
addBots_loop();
}
}
/*
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 );
}
}
}

303
maps/bots/_bot_debug.gsc Normal file
View File

@ -0,0 +1,303 @@
/*
_bot_debug
Author: INeedGames
Date: 07/09/2023
The ingame waypoint visualizer. Designed to be ran on the client (not the server)
*/
#include maps\_utility;
#include common_scripts\utility;
#include maps\_hud_util;
#include maps\bots\_bot_utility;
init()
{
if ( getdvar( "bots_main_debug" ) == "" )
{
setdvar( "bots_main_debug", 0 );
}
if ( !getdvarint( "bots_main_debug" ) || !getdvarint( "bots_main_debug_wp_vis" ) )
{
return;
}
if ( !getdvarint( "developer" ) )
{
setdvar( "developer_script", 1 );
setdvar( "developer", 2 );
setdvar( "sv_mapRotation", "map " + getdvar( "mapname" ) );
exitlevel( false );
return;
}
setdvar( "bots_main", false );
setdvar( "bots_main_menu", false );
setdvar( "bots_manage_fill_mode", 0 );
setdvar( "bots_manage_fill", 0 );
setdvar( "bots_manage_add", 0 );
setdvar( "bots_manage_fill_kick", true );
setdvar( "bots_manage_fill_spec", true );
if ( getdvar( "bots_main_debug_distance" ) == "" )
{
setdvar( "bots_main_debug_distance", 512.0 );
}
if ( getdvar( "bots_main_debug_cone" ) == "" )
{
setdvar( "bots_main_debug_cone", 0.65 );
}
if ( getdvar( "bots_main_debug_minDist" ) == "" )
{
setdvar( "bots_main_debug_minDist", 32.0 );
}
if ( getdvar( "bots_main_debug_drawThrough" ) == "" )
{
setdvar( "bots_main_debug_drawThrough", false );
}
thread load_waypoints();
level waittill( "connected", player );
player thread onPlayerSpawned();
}
onPlayerSpawned()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "spawned_player" );
self thread beginDebug();
}
}
beginDebug()
{
self endon( "disconnect" );
self endon( "zombified" );
self thread debug();
self thread watch_for_unlink();
self thread textScroll( "^1xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" );
}
watch_for_unlink()
{
self endon( "disconnect" );
self endon( "zombified" );
self BotBuiltinNotifyOnPlayerCommand( "+smoke", "toggle_unlink" );
for ( ;; )
{
self waittill( "toggle_unlink" );
if ( self.closest == -1 )
{
self iprintln( "not close to node" );
continue;
}
firstwp = level.waypoints[ self.closest ];
self iprintln( "wp selected for unlink: " + firstwp BotBuiltinGetNodeNumber() );
self waittill( "toggle_unlink" );
if ( self.closest == -1 )
{
self iprintln( "not close to node" );
continue;
}
self toggle_link( firstwp, level.waypoints[ self.closest ] );
}
}
array_contains( arr, it )
{
for ( i = 0; i < arr.size; i++ )
{
if ( arr[ i ] == it )
{
return true;
}
}
return false;
}
toggle_link( firstwp, secondwp )
{
// check if it exists
key = firstwp BotBuiltinGetNodeNumber() + "";
secnum = secondwp BotBuiltinGetNodeNumber();
links = firstwp BotBuiltinGetLinkedNodes();
linked = false;
for ( i = 0; i < links.size; i++ )
{
if ( links[ i ] BotBuiltinGetNodeNumber() == secnum )
{
linked = true;
break;
}
}
if ( !linked )
{
self iprintln( "no link: " + key + " " + secnum );
return;
}
if ( key == secnum + "" )
{
self iprintln( "same unlink: " + key + " " + secnum );
return;
}
if ( isdefined( level.bot_ignore_links[ key ] ) && array_contains( level.bot_ignore_links[ key ], secnum ) )
{
a = level.bot_ignore_links[ key ];
a = array_remove( a, secnum );
if ( a.size <= 0 )
{
level.bot_ignore_links[ key ] = undefined;
}
else
{
level.bot_ignore_links[ key ] = a;
}
self iprintln( "removed unlink: " + key + " " + secnum );
BotBuiltinPrintConsole( "toggle_link: add: " + key + " " + secnum );
}
else
{
if ( !isdefined( level.bot_ignore_links[ key ] ) )
{
level.bot_ignore_links[ key ] = [];
}
a = level.bot_ignore_links[ key ];
a[ a.size ] = secnum;
level.bot_ignore_links[ key ] = a;
self iprintln( "added unlink: " + key + " " + secnum );
BotBuiltinPrintConsole( "toggle_link: del: " + key + " " + secnum );
}
}
debug()
{
self endon( "disconnect" );
self endon( "zombified" );
self.closest = -1;
for ( ;; )
{
wait 0.05;
closest = -1;
myEye = self gettagorigin( "j_head" );
myAngles = self getplayerangles();
for ( i = level.waypoints.size - 1; i >= 0; i-- )
{
if ( closest == -1 || closer( self.origin, level.waypoints[ i ].origin, level.waypoints[ closest ].origin ) )
{
closest = i;
}
wpOrg = level.waypoints[ i ].origin + ( 0, 0, 25 );
if ( distance( level.waypoints[ i ].origin, self.origin ) < getdvarfloat( "bots_main_debug_distance" ) && ( sighttracepassed( myEye, wpOrg, false, self ) || getdvarint( "bots_main_debug_drawThrough" ) ) && getConeDot( wpOrg, myEye, myAngles ) > getdvarfloat( "bots_main_debug_cone" ) )
{
linked = level.waypoints[ i ] BotBuiltinGetLinkedNodes();
node_num_str = level.waypoints[ i ] BotBuiltinGetNodeNumber() + "";
for ( h = linked.size - 1; h >= 0; h-- )
{
if ( isdefined( level.bot_ignore_links[ node_num_str ] ) )
{
found = false;
this_node_num = linked[ h ] BotBuiltinGetNodeNumber();
for ( j = 0; j < level.bot_ignore_links[ node_num_str ].size; j++ )
{
if ( level.bot_ignore_links[ node_num_str ][ j ] == this_node_num )
{
found = true;
break;
}
}
if ( found )
{
continue;
}
}
line( wpOrg, linked[ h ].origin + ( 0, 0, 25 ), ( 1, 0, 1 ) );
}
print3d( wpOrg, node_num_str, ( 1, 0, 0 ), 2 );
if ( isdefined( level.waypoints[ i ].animscript ) )
{
line( wpOrg, wpOrg + anglestoforward( level.waypoints[ i ].angles ) * 64, ( 1, 1, 1 ) );
print3d( wpOrg + ( 0, 0, 15 ), level.waypoints[ i ].animscript, ( 1, 0, 0 ), 2 );
}
}
}
if ( distance( self.origin, level.waypoints[ closest ].origin ) < 64 )
{
self.closest = closest;
}
else
{
self.closest = -1;
}
}
}
destroyOnDeath( hud )
{
hud endon( "death" );
self waittill_either( "zombified", "disconnect" );
hud destroy();
}
textScroll( string )
{
self endon( "zombified" );
self endon( "disconnect" );
// thanks ActionScript
back = createbar( ( 0, 0, 0 ), 1000, 30 );
back setpoint( "CENTER", undefined, 0, 220 );
self thread destroyOnDeath( back );
text = createfontstring( "default", 1.5 );
text settext( string );
self thread destroyOnDeath( text );
for ( ;; )
{
text setpoint( "CENTER", undefined, 1200, 220 );
text setpoint( "CENTER", undefined, -1200, 220, 20 );
wait 20;
}
}

2494
maps/bots/_bot_internal.gsc Normal file

File diff suppressed because it is too large Load Diff

534
maps/bots/_bot_script.gsc Normal file
View File

@ -0,0 +1,534 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
/*
Initialize bot script level functions
*/
bot_script_init()
{
level thread maps\bots\objectives\_manager::init();
}
/*
When the bot gets added into the game.
*/
added()
{
self endon( "disconnect" );
self set_diff();
}
/*
When the bot connects to the game.
*/
connected()
{
self endon( "disconnect" );
self thread difficulty();
self thread onBotSpawned();
self thread onSpawned();
self thread maps\bots\objectives\_manager::connected();
}
/*
The callback for when the bot gets damaged.
*/
onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, modelIndex, psOffsetTime )
{
if ( !isdefined( self ) || !isdefined( self.team ) )
{
return;
}
if ( !isalive( self ) )
{
return;
}
if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" )
{
return;
}
if ( iDamage <= 0 )
{
return;
}
if ( !isdefined( eAttacker ) || !isdefined( eAttacker.team ) )
{
return;
}
if ( eAttacker == self )
{
return;
}
if ( !isalive( eAttacker ) )
{
return;
}
self SetAttacker( eAttacker );
}
/*
Updates the bot's difficulty variables.
*/
difficulty()
{
self endon( "disconnect" );
for ( ;; )
{
if ( getdvarint( "bots_skill" ) != 9 )
{
switch ( self.pers[ "bots" ][ "skill" ][ "base" ] )
{
case 1:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.6;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 500;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 600;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 750;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.7;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 2500;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.75;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 0;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.9;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 1;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1.5;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 4;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 2;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 0;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 30;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 20;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 0;
break;
case 2:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.55;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 800;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1250;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.65;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 3000;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.65;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 500;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.75;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.75;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 3;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1.5;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri,j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 15;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 45;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 15;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 10;
break;
case 3:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.4;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 750;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 500;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 2000;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.6;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 4000;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 2250;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 750;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.65;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.65;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.75;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2.5;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 20;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 20;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 50;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 25;
break;
case 4:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.3;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 600;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 400;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 3000;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.55;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 5000;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 3350;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.35;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1000;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.75;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head,j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 30;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 25;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 55;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 35;
break;
case 5:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 500;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 300;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 2000;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 4000;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 7500;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 5000;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1500;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.4;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.35;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.35;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1.5;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 40;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 35;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 60;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 50;
break;
case 6:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.2;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 250;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 150;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2000;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 3000;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 5000;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.45;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 10000;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 7500;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.2;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 2000;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.25;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head,j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 50;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 45;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 65;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 75;
break;
case 7:
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.1;
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 100;
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50;
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500;
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 4000;
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 7500;
self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.4;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 15000;
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 10000;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05;
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 3000;
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.1;
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0;
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0;
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 0;
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.05;
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head";
self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5;
self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5;
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 65;
self.pers[ "bots" ][ "behavior" ][ "nade" ] = 65;
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 70;
self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 5;
self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2;
self.pers[ "bots" ][ "behavior" ][ "jump" ] = 90;
break;
}
}
wait 5;
}
}
/*
Sets the bot difficulty.
*/
set_diff()
{
rankVar = getdvarint( "bots_skill" );
switch ( rankVar )
{
case 0:
self.pers[ "bots" ][ "skill" ][ "base" ] = Round( random_normal_distribution( 3.5, 1.75, 1, 7 ) );
break;
case 8:
break;
case 9:
self.pers[ "bots" ][ "skill" ][ "base" ] = randomintrange( 1, 7 );
self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.05 * randomintrange( 1, 20 );
self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 50 * randomint( 100 );
self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50 * randomint( 100 );
self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 50 * randomint( 100 );
self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 50 * randomint( 100 );
self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 50 * randomint( 100 );
self.pers[ "bots" ][ "skill" ][ "fov" ] = randomfloatrange( -1, 1 );
randomNum = randomintrange( 500, 25000 );
self.pers[ "bots" ][ "skill" ][ "dist_start" ] = randomNum;
self.pers[ "bots" ][ "skill" ][ "dist_max" ] = randomNum * 2;
self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05 * randomint( 20 );
self.pers[ "bots" ][ "skill" ][ "help_dist" ] = randomintrange( 500, 25000 );
self.pers[ "bots" ][ "skill" ][ "semi_time" ] = randomfloatrange( 0.05, 1 );
self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = randomfloatrange( 0.05, 1 );
self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = randomfloatrange( 0.05, 1 );
self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = randomfloatrange( 0.05, 1 );
self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = randomfloatrange( 0.05, 1 );
self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head,j_spineupper,j_ankle_ri,j_ankle_le";
self.pers[ "bots" ][ "behavior" ][ "strafe" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "nade" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "sprint" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "camp" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "follow" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "crouch" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "switch" ] = randomint( 100 );
self.pers[ "bots" ][ "behavior" ][ "jump" ] = randomint( 100 );
break;
default:
self.pers[ "bots" ][ "skill" ][ "base" ] = rankVar;
break;
}
}
/*
When the bot spawned, after the difficulty wait. Start the logic for the bot.
*/
onBotSpawned()
{
self endon( "disconnect" );
level endon( "intermission" );
for ( ;; )
{
self waittill( "bot_spawned" );
self thread start_bot_threads();
}
}
/*
When the bot spawns.
*/
onSpawned()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "spawned_player" );
self thread maps\bots\objectives\_manager::spawned();
}
}
/*
Starts all the bot thinking
*/
start_bot_threads()
{
self endon( "disconnect" );
level endon( "intermission" );
self endon( "zombified" );
self thread doReloadCancel();
self thread maps\bots\objectives\_manager::start_bot_threads();
}
/*
Changes to the weap
*/
changeToWeapon( weap )
{
self endon( "disconnect" );
self endon( "zombified" );
level endon( "game_ended" );
if ( !self hasweapon( weap ) )
{
return false;
}
self switchtoweapon( weap );
if ( self getcurrentweapon() == weap )
{
return true;
}
self waittill_any_timeout( 5, "weapon_change" );
return ( self getcurrentweapon() == weap );
}
/*
Reload cancels
*/
doReloadCancel_loop()
{
ret = self waittill_any_return( "reload", "weapon_change" );
if ( self BotIsFrozen() )
{
return;
}
if ( self usebuttonpressed() )
{
return;
}
if ( self inLastStand() )
{
return;
}
curWeap = self getcurrentweapon();
if ( !self isWeaponPrimary( curWeap ) )
{
return;
}
if ( ret == "reload" )
{
// check single reloads
if ( self getweaponammoclip( curWeap ) < weaponclipsize( curWeap ) )
{
return;
}
}
// check difficulty
if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 3 )
{
return;
}
// check if got another weapon
weaponslist = self getweaponslistprimaries();
weap = "";
while ( weaponslist.size )
{
weapon = weaponslist[ randomint( weaponslist.size ) ];
weaponslist = array_remove( weaponslist, weapon );
if ( !self isWeaponPrimary( weapon ) )
{
continue;
}
if ( curWeap == weapon || weapon == "none" || weapon == "" )
{
continue;
}
weap = weapon;
break;
}
if ( weap == "" )
{
return;
}
// do the cancel
wait 0.1;
self thread changeToWeapon( weap );
wait 0.25;
self thread changeToWeapon( curWeap );
wait 2;
}
/*
Reload cancels
*/
doReloadCancel()
{
self endon( "disconnect" );
self endon( "zombified" );
for ( ;; )
{
self doReloadCancel_loop();
}
}

1804
maps/bots/_bot_utility.gsc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
init()
{
level.bot_objectives = [];
level.bot_objectives[ level.bot_objectives.size ] = CreateObjectiveForManger( "revive", maps\bots\objectives\_revive::Finder, maps\bots\objectives\_revive::Priority, maps\bots\objectives\_revive::Executer, 1000 );
level.bot_objectives[ level.bot_objectives.size ] = CreateObjectiveForManger( "powerup", maps\bots\objectives\_powerup::Finder, maps\bots\objectives\_powerup::Priority, maps\bots\objectives\_powerup::Executer, 2500 );
level.bot_objectives[ level.bot_objectives.size ] = CreateObjectiveForManger( "wallweapon", maps\bots\objectives\_wallweapon::Finder, maps\bots\objectives\_wallweapon::Priority, maps\bots\objectives\_wallweapon::Executer, 7500 );
level.bot_objectives[ level.bot_objectives.size ] = CreateObjectiveForManger( "treasurechest", maps\bots\objectives\_treasurechest::Finder, maps\bots\objectives\_treasurechest::Priority, maps\bots\objectives\_treasurechest::Executer, 7000 );
maps\bots\objectives\_perkmachine::init();
level.bot_objectives[ level.bot_objectives.size ] = CreateObjectiveForManger( "perkmachine", maps\bots\objectives\_perkmachine::Finder, maps\bots\objectives\_perkmachine::Priority, maps\bots\objectives\_perkmachine::Executer, 10000 );
}
connected()
{
self.bot_current_objective = undefined;
}
spawned()
{
self.bot_current_objective = undefined;
self thread clean_objective_on_completion();
self thread watch_for_objective_canceled();
}
watch_for_objective_canceled()
{
self endon( "disconnect" );
level endon( "intermission" );
self endon( "zombified" );
for ( ;; )
{
self waittill( "cancel_bot_objective", reason );
obj_name = "undefined";
if ( isdefined( self.bot_current_objective ) )
{
obj_name = self.bot_current_objective.sname;
}
self BotNotifyBotEvent( "debug", "watch_for_objective_canceled: " + obj_name + ": " + reason );
}
}
clean_objective_on_completion()
{
self endon( "disconnect" );
level endon( "intermission" );
self endon( "zombified" );
for ( ;; )
{
self waittill( "completed_bot_objective", successful, reason );
obj_name = "undefined";
if ( isdefined( self.bot_current_objective ) )
{
obj_name = self.bot_current_objective.sname;
self.bot_current_objective.eparentobj.abotprocesstimes[ self getentitynumber() + "" ] = gettime();
}
self BotNotifyBotEvent( "debug", "clean_objective_on_completion: " + obj_name + ": " + successful + ": " + reason );
waittillframeend;
self.bot_current_objective = undefined;
}
}
start_bot_threads()
{
self endon( "disconnect" );
level endon( "intermission" );
self endon( "zombified" );
self thread bot_objective_think();
}
bot_objective_think()
{
self endon( "disconnect" );
level endon( "intermission" );
self endon( "zombified" );
for ( ;; )
{
wait 1;
// find all avail objectives
objectives = [];
now = gettime();
our_key = self getentitynumber() + "";
for ( i = 0; i < level.bot_objectives.size; i++ )
{
objective = level.bot_objectives[ i ];
// check the process rate
if ( isdefined( objective.abotprocesstimes[ our_key ] ) && now - objective.abotprocesstimes[ our_key ] < objective.iprocessrate )
{
continue;
}
objectives = array_merge( objectives, self [[ objective.fpfinder ]]( objective ) );
objective.abotprocesstimes[ our_key ] = now;
}
if ( objectives.size <= 0 )
{
continue;
}
// sort according to priority
heap = NewHeap( ::HeapPriority );
for ( i = 0; i < objectives.size; i++ )
{
if ( objectives[ i ].fpriority <= -100 )
{
continue;
}
heap HeapInsert( objectives[ i ] );
}
// pop the top!
best_prio = heap.data[ 0 ];
if ( !isdefined( best_prio ) )
{
continue;
}
// already on a better obj
if ( isdefined( self.bot_current_objective ) && ( best_prio.guid == self.bot_current_objective.guid || best_prio.fpriority < self [[ self.bot_current_objective.eparentobj.fppriorty ]]( self.bot_current_objective.eparentobj, self.bot_current_objective.eent ) ) )
{
continue;
}
// DO THE OBJ
// cancel the old obj
if ( isdefined( self.bot_current_objective ) )
{
// cancel it
self CancelObjective( "new obj: " + best_prio.sname );
// wait for it to clean up
self waittill( "completed_bot_objective" );
// redo the loop, should do the obj next iteration
best_prio.eparentobj.abotprocesstimes[ our_key ] = undefined;
continue;
}
// ready to execute
self BotNotifyBotEvent( "debug", "bot_objective_think: " + best_prio.sname );
self.bot_current_objective = best_prio;
self thread [[ best_prio.eparentobj.fpexecuter ]]( best_prio );
}
}

View File

@ -0,0 +1,287 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
init()
{
vending_triggers = getentarray( "zombie_vending", "targetname" );
if ( !isdefined( vending_triggers ) || vending_triggers.size < 1 )
{
vending_triggers = getentarray( "harrybo21_perk_trigger", "targetname" );
if ( !isdefined( vending_triggers ) || vending_triggers.size < 1 )
{
return;
}
}
for ( i = 0 ; i < vending_triggers.size; i++ )
{
vending_triggers[ i ] thread init_vending_trigger();
}
}
init_vending_trigger()
{
self endon( "death" );
if ( self.targetname == "harrybo21_perk_trigger" )
{
machine = self getMachine();
machine waittill( "activate_machine" );
self.bot_powered_on = true;
}
else
{
perk = self getVendingPerk();
notify_name = perk + "_power_on";
level waittill( notify_name );
self.bot_powered_on = true;
}
}
Finder( eObj )
{
answer = [];
if ( self inLastStand() )
{
return answer;
}
vending_triggers = getentarray( "zombie_vending", "targetname" );
if ( !isdefined( vending_triggers ) || vending_triggers.size < 1 )
{
vending_triggers = getentarray( "harrybo21_perk_trigger", "targetname" );
if ( !isdefined( vending_triggers ) || vending_triggers.size < 1 )
{
return answer;
}
}
for ( i = 0 ; i < vending_triggers.size; i++ )
{
vending = vending_triggers[ i ];
if ( !isdefined( vending.bot_powered_on ) || !vending.bot_powered_on )
{
continue;
}
perk = vending getVendingPerk();
cost = vending getPerkCost();
if ( self.score < cost )
{
continue;
}
// perk limit??
if ( self hasperk( perk ) )
{
continue;
}
machine = vending getMachine();
if ( !isdefined( machine ) )
{
continue;
}
org = self getOffset( machine );
if ( GetPathIsInaccessible( self.origin, org ) )
{
continue;
}
answer[ answer.size ] = self CreateFinderObjectiveEZ( eObj, vending );
}
return answer;
}
getMachine()
{
return getent( self.target, "targetname" );
}
getVendingPerk()
{
if ( self.targetname == "harrybo21_perk_trigger" )
{
machine = self getMachine();
return machine.script_string;
}
return self.script_noteworthy;
}
getPerkCost()
{
if ( self.targetname == "harrybo21_perk_trigger" )
{
return level.zombie_perks[ self getVendingPerk() ].perk_cost;
}
cost = level.zombie_vars[ "zombie_perk_cost" ];
switch ( self getVendingPerk() )
{
case "specialty_armorvest":
cost = 2500;
break;
case "specialty_quickrevive":
cost = 1500;
break;
case "specialty_fastreload":
cost = 3000;
break;
case "specialty_rof":
cost = 2000;
break;
default:
cost = 10000;
break;
}
return cost;
}
getOffset( model )
{
org = model get_angle_offset_node( 40, ( 0, -90, 0 ), ( 0, 0, 1 ) );
return org;
}
Priority( eObj, eEnt )
{
// TODO rank perks
base_priority = 2;
base_priority += ClampLerp( get_path_dist( self.origin, eEnt.origin ), 500, 1600, 3, 0 );
if ( self HasBotObjective() && self GetBotObjectiveEnt() != eEnt )
{
base_priority -= 1;
}
return base_priority;
}
Executer( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
vending = eObj.eent;
self thread WatchForCancel( vending );
self GoDoPerkMachine( eObj );
self WatchForCancelCleanup();
self ClearScriptAimPos();
self ClearScriptGoal();
self CompletedObjective( eObj.bwassuccessful, eObj.sreason );
}
WatchForCancelCleanup()
{
self notify( "WatchForCancelPerkmachine" );
}
WatchForCancel( vending )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "WatchForCancelPerkmachine" );
for ( ;; )
{
wait 0.05;
if ( self inLastStand() )
{
self CancelObjective( "self inLastStand()" );
break;
}
}
}
WatchToGoToMachine( vending )
{
self endon( "cancel_bot_objective" );
self endon( "disconnect" );
self endon( "zombified" );
self endon( "goal" );
self endon( "bad_path" );
self endon( "new_goal" );
for ( ;; )
{
wait 0.05;
if ( self istouching( vending ) || vending PointInsideUseTrigger( self.origin ) )
{
self notify( "goal" );
break; // is this needed?
}
}
}
GoDoPerkMachine( eObj )
{
self endon( "cancel_bot_objective" );
vending = eObj.eent;
machine = vending getMachine();
perk = vending getVendingPerk();
org = self getOffset( machine );
// go to machine
self thread WatchToGoToMachine( vending );
self SetScriptGoal( org, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to machine";
return;
}
if ( !self istouching( vending ) && !vending PointInsideUseTrigger( self.origin ) )
{
eObj.sreason = "not touching machine";
return;
}
// ok we are touching machine, lets look at it
self SetScriptAimPos( vending.origin );
// wait to look at it
wait 1;
// press use
self thread BotPressUse( 0.15 );
wait 0.1;
// ok we pressed use, DONE
eObj.sreason = "completed " + perk;
eObj.bwassuccessful = true;
}

View File

@ -0,0 +1,142 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
Finder( eObj )
{
answer = [];
if ( self inLastStand() )
{
return answer;
}
ents = getentarray( "script_model", "classname" );
for ( i = 0; i < ents.size; i++ )
{
// not a powerup script_model
if ( !isdefined( ents[ i ].powerup_name ) )
{
continue;
}
// can we path to it?
if ( GetPathIsInaccessible( self.origin, ents[ i ].origin ) )
{
continue;
}
// make sure we are the only one going for it
if ( self GetBotsAmountForEntity( ents[ i ] ) >= 1 )
{
continue;
}
answer[ answer.size ] = self CreateFinderObjectiveEZ( eObj, ents[ i ] );
}
return answer;
}
Priority( eObj, eEnt )
{
// TODO: check powerup type
base_priority = 0;
base_priority += ClampLerp( get_path_dist( self.origin, eEnt.origin ), 300, 700, 2, -2 );
if ( self HasBotObjective() && self GetBotObjectiveEnt() != eEnt )
{
base_priority -= 1;
}
return base_priority;
}
Executer( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
powerup = eObj.eent;
org = powerup.origin;
self thread IncrementBotsForEntity( powerup );
self thread WatchForCancel( powerup );
self GoDoPowerup( eObj );
self WatchForCancelCleanup();
self DecrementBotsForEntity( powerup );
self ClearScriptGoal();
if ( distance( org, self.origin ) <= 64 )
{
eObj.sreason = "completed";
eObj.bwassuccessful = true;
}
self CompletedObjective( eObj.bwassuccessful, eObj.sreason );
}
WatchForCancelCleanup()
{
self notify( "WatchForCancelPowerup" );
}
WatchForCancel( powerup )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "WatchForCancelPowerup" );
for ( ;; )
{
wait 0.05;
if ( self inLastStand() )
{
self CancelObjective( "self inLastStand()" );
break;
}
if ( !isdefined( powerup ) )
{
self CancelObjective( "!isdefined( powerup )" );
break;
}
}
}
GoDoPowerup( eObj )
{
self endon( "cancel_bot_objective" );
powerup = eObj.eent;
// go to it
self SetScriptGoal( powerup.origin, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to powerup";
return;
}
if ( !isdefined( powerup ) || !isdefined( powerup.origin ) )
{
return;
}
if ( distance( powerup.origin, self.origin ) > 64 )
{
eObj.sreason = "not touching it";
return;
}
eObj.sreason = "completed";
eObj.bwassuccessful = true;
}

View File

@ -0,0 +1,209 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
Finder( eObj )
{
Players = get_players();
Answer = [];
if ( self inLastStand() )
{
return Answer;
}
for ( i = 0; i < Players.size; i++ )
{
Player = Players[ i ];
if ( !isdefined( Player ) || !isdefined( Player.team ) )
{
continue;
}
if ( Player == self )
{
continue;
}
if ( Player.sessionstate != "playing" )
{
continue;
}
if ( !Player inLastStand() || Player.revivetrigger.beingrevived )
{
continue;
}
if ( GetPathIsInaccessible( self.origin, Player.origin ) )
{
continue;
}
if ( self GetBotsAmountForEntity( Player ) >= 1 )
{
continue;
}
Answer[ Answer.size ] = self CreateFinderObjectiveEZ( eObj, Player );
}
return Answer;
}
Priority( eObj, eEnt )
{
base_priority = 3;
base_priority += ClampLerp( get_path_dist( self.origin, eEnt.origin ), 500, 1200, 2, 0 );
if ( self HasBotObjective() && self GetBotObjectiveEnt() != eEnt )
{
base_priority -= 1;
}
return base_priority;
}
Executer( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
revivee = eObj.eent;
self thread IncrementBotsForEntity( revivee );
self thread WatchForCancelRevive( revivee );
self GoDoRevive( eObj );
self WatchForCancelReviveCleanup();
self DecrementBotsForEntity( revivee );
self ClearScriptAimPos();
self ClearScriptGoal();
self ClearPriorityObjective();
self CompletedObjective( eObj.bwassuccessful, eObj.sreason );
}
WatchForCancelReviveCleanup()
{
self notify( "WatchForCancelRevive" );
}
WatchForCancelRevive( revivee )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "WatchForCancelRevive" );
org = revivee.origin;
for ( ;; )
{
wait 0.05;
if ( self inLastStand() )
{
self CancelObjective( "self inLastStand()" );
break;
}
if ( !isdefined( revivee ) || !revivee inLastStand() )
{
self CancelObjective( "!isdefined( revivee ) || !revivee inLastStand()" );
break;
}
if ( revivee.revivetrigger.beingrevived && !self isReviving( revivee ) )
{
self CancelObjective( "revivee.revivetrigger.beingrevived && !self isReviving( revivee )" );
break;
}
if ( distance( revivee.origin, org ) > 16 )
{
self CancelObjective( "distance( revivee.origin, org ) > 16" );
break;
}
}
}
WatchToGoToGuy( revivee )
{
self endon( "cancel_bot_objective" );
self endon( "disconnect" );
self endon( "zombified" );
self endon( "goal" );
self endon( "bad_path" );
self endon( "new_goal" );
for ( ;; )
{
wait 1;
if ( self istouching( revivee.revivetrigger ) )
{
self notify( "goal" );
break; // is this needed?
}
}
}
WatchForSuccessRevive( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
revivee = eObj.eent;
ret = self waittill_either_return( "cancel_bot_objective", "completed_bot_objective" );
if ( ret == "cancel_bot_objective" && isdefined( revivee ) && !revivee inLastStand() )
{
eObj.bwassuccessful = true;
eObj.sreason = "revived him!";
}
}
GoDoRevive( eObj )
{
self endon( "cancel_bot_objective" );
revivee = eObj.eent;
// go to guy
self thread WatchToGoToGuy( revivee );
self SetPriorityObjective();
self SetScriptGoal( revivee.origin, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to guy";
return;
}
if ( !self istouching( revivee.revivetrigger ) )
{
eObj.sreason = "not touching guy";
return;
}
// ok we are touching guy, lets look at him
self SetScriptAimPos( revivee.origin );
// now lets hold use until he is up or otherwise
self thread WatchForSuccessRevive( eObj );
while ( self istouching( revivee.revivetrigger ) )
{
self thread BotPressUse( 0.15 );
wait 0.1;
}
eObj.sreason = "not touching guy";
}

View File

@ -0,0 +1,284 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
Finder( eObj )
{
answer = [];
if ( self inLastStand() )
{
return answer;
}
weapons = self getweaponslist();
// TODO check if need a new weapon, rate weapons too is better then current etc
chests = level.chests;
if ( !isdefined( chests ) )
{
chests = getentarray( "treasure_chest_use", "targetname" );
}
if ( !isdefined( chests ) || chests.size <= 0 )
{
return answer;
}
for ( i = 0; i < chests.size; i ++ )
{
chest = chests[ i ];
// not active chest
if ( isdefined( chest.disabled ) && chest.disabled )
{
continue;
}
// box is waiting for someone to grab weapon
if ( isdefined( chest.grab_weapon_hint ) && chest.grab_weapon_hint )
{
continue;
}
cost = 950;
if ( isdefined( level.zombie_treasure_chest_cost ) )
{
cost = level.zombie_treasure_chest_cost;
}
else if ( isdefined( chest.zombie_cost ) )
{
cost = chest.zombie_cost;
}
// check cost
if ( self.score < cost )
{
continue;
}
lid = getent( chest.target, "targetname" );
if ( !isdefined( lid ) )
{
continue;
}
weapon_spawn_org = getent( lid.target, "targetname" );
if ( !isdefined( weapon_spawn_org ) )
{
continue;
}
org = self getOffset( lid );
if ( GetPathIsInaccessible( self.origin, org ) )
{
continue;
}
answer[ answer.size ] = self CreateFinderObjectiveEZ( eObj, chest );
}
return answer;
}
getOffset( model )
{
org = model get_angle_offset_node( 52, ( 0, 90, 0 ), ( 0, 0, 1 ) );
return org;
}
Priority( eObj, eEnt )
{
base_priority = 1;
base_priority += ClampLerp( get_path_dist( self.origin, eEnt.origin ), 600, 1800, 2, 0 );
if ( self HasBotObjective() && self GetBotObjectiveEnt() != eEnt )
{
base_priority -= 1;
}
return base_priority;
}
Executer( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
chest = eObj.eent;
self thread WatchForCancel( chest );
self GoDoTreasureChest( eObj );
self WatchForCancelCleanup();
self ClearScriptAimPos();
self ClearScriptGoal();
self ClearPriorityObjective();
self CompletedObjective( eObj.bwassuccessful, eObj.sreason );
}
WatchForCancelCleanup()
{
self notify( "WatchForCancelTreasurechest" );
}
WatchForCancel( chest )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "WatchForCancelTreasurechest" );
for ( ;; )
{
wait 0.05;
if ( self inLastStand() )
{
self CancelObjective( "self inLastStand()" );
break;
}
}
}
WatchToGoToChest( chest )
{
self endon( "cancel_bot_objective" );
self endon( "disconnect" );
self endon( "zombified" );
self endon( "goal" );
self endon( "bad_path" );
self endon( "new_goal" );
for ( ;; )
{
wait 0.05;
if ( self istouching( chest ) || chest PointInsideUseTrigger( self.origin ) )
{
self notify( "goal" );
break; // is this needed?
}
if ( isdefined( chest.disabled ) && chest.disabled )
{
self notify( "bad_path" );
break; // is this needed?
}
}
}
GoDoTreasureChest( eObj )
{
self endon( "cancel_bot_objective" );
chest = eObj.eent;
lid = getent( chest.target, "targetname" );
weapon_spawn_org = getent( lid.target, "targetname" );
org = self getOffset( lid );
weap = self getcurrentweapon();
if ( weap == "none" || !self getammocount( weap ) )
{
self SetPriorityObjective();
}
// go to box
self thread WatchToGoToChest( chest );
self SetScriptGoal( org, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to chest";
return;
}
if ( !self istouching( chest ) && !chest PointInsideUseTrigger( self.origin ) )
{
eObj.sreason = "not touching chest";
return;
}
// ok we are touching weapon, lets look at it
self SetScriptAimPos( chest.origin );
// wait to look at it
wait 1;
// press use
self thread BotPressUse( 0.15 );
wait 0.25;
// ok we pressed use, wait for randomization to complete
self ClearScriptAimPos();
self ClearPriorityObjective();
// randomization isnt happening...
if ( !isdefined( chest.disabled ) || !chest.disabled )
{
eObj.sreason = "chest isnt randomizing";
return;
}
ret = weapon_spawn_org waittill_any_timeout( 5, "randomization_done" );
if ( ret == "timeout" )
{
eObj.sreason = "randomization_done timed out";
return;
}
if ( isdefined( level.flag[ "moving_chest_now" ] ) && flag( "moving_chest_now" ) )
{
eObj.sreason = "chest is moving!";
return;
}
waittillframeend;
weap = weapon_spawn_org.weapon_string;
// weapon is done cooking, grabit!
self SetPriorityObjective();
// go to box
self thread WatchToGoToChest( chest );
self SetScriptGoal( org, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to chest";
return;
}
if ( !self istouching( chest ) && !chest PointInsideUseTrigger( self.origin ) )
{
eObj.sreason = "not touching chest";
return;
}
// ok we are touching weapon, lets look at it
self SetScriptAimPos( chest.origin );
// wait to look at it
wait 1;
// press use
self thread BotPressUse( 0.15 );
wait 0.1;
// complete!
eObj.sreason = "completed " + weap;
eObj.bwassuccessful = true;
}

View File

@ -0,0 +1,114 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
CreateObjectiveForManger( sName, fpFinder, fpPriorty, fpExecuter, iProcessRate )
{
Answer = spawnstruct();
Answer.sname = sName;
Answer.fpfinder = fpFinder;
Answer.fpexecuter = fpExecuter;
Answer.fppriorty = fpPriorty;
Answer.abotprocesstimes = [];
Answer.iprocessrate = iProcessRate;
return Answer;
}
CreateFinderObjectiveEZ( eObj, eEnt )
{
return self CreateFinderObjective( eObj, eObj.sname + "_" + eEnt getentitynumber(), eEnt, self [[ eObj.fppriorty ]]( eObj, eEnt ) );
}
CreateFinderObjective( eObj, sName, eEnt, fPriority )
{
Answer = spawnstruct();
Answer.eparentobj = eObj;
Answer.sname = sName;
Answer.eent = eEnt;
Answer.fpriority = fPriority;
Answer.guid = eEnt getentitynumber();
Answer.bwassuccessful = false;
Answer.sreason = "canceled";
return Answer;
}
GetBotsAmountForEntity( eEnt )
{
if ( !isdefined( eEnt.bots ) )
{
eEnt.bots = 0;
}
return eEnt.bots;
}
IncrementBotsForEntity( eEnt )
{
self endon( "bots_for_entity_cleanup" );
eEnt.bots++;
self waittill_either( "disconnect", "zombified" );
if ( isdefined( eEnt ) )
{
eEnt.bots--;
}
}
DecrementBotsForEntity( eEnt )
{
self notify( "bots_for_entity_cleanup" );
if ( isdefined( eEnt ) )
{
eEnt.bots--;
}
}
CleanupBotsForEntity( eEnt )
{
self notify( "bots_for_entity_cleanup" );
}
CancelObjective( reason )
{
self notify( "cancel_bot_objective", reason );
}
CompletedObjective( successful, reason )
{
self notify( "completed_bot_objective", successful, reason );
}
GetBotObjectiveEnt()
{
if ( !self HasBotObjective() )
{
return undefined;
}
return self GetBotObjective().eent;
}
/*
Gets bot objective
*/
GetBotObjective()
{
return self.bot_current_objective;
}
/*
Does the bot have an objective?
*/
HasBotObjective()
{
return isdefined( self GetBotObjective() );
}

View File

@ -0,0 +1,237 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\bots\_bot_utility;
#include maps\bots\objectives\_utility;
Finder( eObj )
{
answer = [];
if ( self inLastStand() )
{
return answer;
}
weapon_spawns = getentarray( "weapon_upgrade", "targetname" );
if ( !isdefined( weapon_spawns ) || weapon_spawns.size <= 0 )
{
return answer;
}
weapons = self getweaponslist();
// TODO check if need a new weapon, rate weapons too is better then current etc
for ( i = 0; i < weapon_spawns.size; i++ )
{
player_has_weapon = false;
if ( !isdefined( weapon_spawns[ i ].zombie_weapon_upgrade ) )
{
continue;
}
for ( h = 0; h < weapons.size; h++ )
{
if ( weapons[ h ] == weapon_spawns[ i ].zombie_weapon_upgrade )
{
player_has_weapon = true;
}
}
is_grenade = ( weapontype( weapon_spawns[ i ].zombie_weapon_upgrade ) == "grenade" );
if ( !player_has_weapon || is_grenade )
{
func = BotBuiltinGetFunction( "maps/_zombiemode_weapons", "get_weapon_cost" );
if ( self.score < [[ func ]]( weapon_spawns[ i ].zombie_weapon_upgrade ) )
{
continue;
}
}
else
{
func = BotBuiltinGetFunction( "maps/_zombiemode_weapons", "get_ammo_cost" );
if ( self.score < [[ func ]]( weapon_spawns[ i ].zombie_weapon_upgrade ) )
{
continue;
}
}
model = weapon_spawns[ i ];
if ( isdefined( weapon_spawns[ i ].target ) )
{
model = getent( weapon_spawns[ i ].target, "targetname" );
}
if ( !isdefined( model ) )
{
continue;
}
org = self getOffset( model, weapon_spawns[ i ] );
if ( GetPathIsInaccessible( self.origin, org ) )
{
continue;
}
answer[ answer.size ] = self CreateFinderObjectiveEZ( eObj, weapon_spawns[ i ] );
}
return answer;
}
getOffset( model, weapon )
{
org = model get_angle_offset_node( 40, ( 0, -90, 0 ), ( 0, 0, 1 ) );
test_org = ( org[ 0 ], org[ 1 ], weapon.origin[ 2 ] );
if ( !weapon PointInsideUseTrigger( test_org ) )
{
org = model get_angle_offset_node( 40, ( 0, 90, 0 ), ( 0, 0, 1 ) );
}
return org;
}
Priority( eObj, eEnt )
{
// TODO: check weallweapon type
base_priority = 0;
base_priority += ClampLerp( get_path_dist( self.origin, eEnt.origin ), 0, 800, 1, -2 );
if ( self HasBotObjective() && self GetBotObjectiveEnt() != eEnt )
{
base_priority -= 1;
}
if ( issubstr( eEnt.zombie_weapon_upgrade, "kar98k" ) || issubstr( eEnt.zombie_weapon_upgrade, "type99" ) )
{
base_priority -= 999;
}
return base_priority;
}
Executer( eObj )
{
self endon( "disconnect" );
self endon( "zombified" );
weapon = eObj.eent;
self thread WatchForCancel( weapon );
self GoDoWallweapon( eObj );
self WatchForCancelCleanup();
self ClearScriptAimPos();
self ClearScriptGoal();
self ClearPriorityObjective();
self CompletedObjective( eObj.bwassuccessful, eObj.sreason );
}
WatchForCancelCleanup()
{
self notify( "WatchForCancelWallweapon" );
}
WatchForCancel( weapon )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "WatchForCancelWallweapon" );
for ( ;; )
{
wait 0.05;
if ( self inLastStand() )
{
self CancelObjective( "self inLastStand()" );
break;
}
}
}
WatchToGoToWeapon( weapon )
{
self endon( "cancel_bot_objective" );
self endon( "disconnect" );
self endon( "zombified" );
self endon( "goal" );
self endon( "bad_path" );
self endon( "new_goal" );
for ( ;; )
{
wait 0.05;
if ( self istouching( weapon ) || weapon PointInsideUseTrigger( self.origin ) )
{
self notify( "goal" );
break; // is this needed?
}
}
}
GoDoWallweapon( eObj )
{
self endon( "cancel_bot_objective" );
weapon = eObj.eent;
model = weapon;
if ( isdefined( weapon.target ) )
{
model = getent( weapon.target, "targetname" );
}
org = self getOffset( model, weapon );
weap = self getcurrentweapon();
if ( weap == "none" || !self getammocount( weap ) )
{
self SetPriorityObjective();
}
// go to weapon
self thread WatchToGoToWeapon( weapon );
self SetScriptGoal( org, 32 );
result = self waittill_any_return( "goal", "bad_path", "new_goal" );
if ( result != "goal" )
{
eObj.sreason = "didn't go to weapon";
return;
}
if ( !self istouching( weapon ) && !weapon PointInsideUseTrigger( self.origin ) )
{
eObj.sreason = "not touching weapon";
return;
}
// ok we are touching weapon, lets look at it
self SetScriptAimPos( weapon.origin );
// wait to look at it
wait 1;
// press use
self thread BotPressUse( 0.15 );
wait 0.1;
eObj.sreason = "completed";
eObj.bwassuccessful = true;
}

View File

@ -1,654 +0,0 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\so\zm_common\_zm_utility;
#include scripts\sp\bots\_bot_internal;
#include scripts\sp\bots\bot_actions_common;
#include scripts\sp\bots\bot_objective_common;
#include scripts\sp\bots\bot_difficulty_presets_common;
#include scripts\sp\bots\bot_personality_presets_common;
#include scripts\sp\bots\bot_target_common;
#include scripts\sp\bots\actions\combat;
#include scripts\sp\bots\actions\movement;
#include scripts\sp\bots\actions\objective;
#include scripts\sp\bots\actions\look;
#include scripts\sp\bots\bot_utility;
main()
{
//Objective group is for things to go to usually allowing the bot to kill zombies on the way and survive as normal
//Objectives can be canceled/postponed by combat, movement or by other objectives
register_bot_action( "objective", "magicbox", ::bot_magicbox_purchase, ::bot_magicbox_process_order, ::bot_should_purchase_magicbox, ::bot_check_complete_magicbox, ::bot_set_complete_magicbox, ::bot_magicbox_purchase_on_completion, ::bot_magicbox_purchase_should_cancel, ::bot_magicbox_purchase_on_cancel, ::bot_magicbox_purchase_should_postpone, ::bot_magicbox_purchase_on_postpone, ::bot_magicbox_purchase_priority );
register_bot_action( "objective", "wallbuy", ::bot_wallbuy_purchase, ::bot_wallbuy_process_order, ::bot_should_purchase_wallbuy, ::bot_check_complete_wallbuy, ::bot_set_complete_wallbuy, ::bot_wallbuy_purchase_on_completion, ::bot_wallbuy_purchase_should_cancel, ::bot_wallbuy_purchase_on_cancel, ::bot_wallbuy_purchase_should_postpone, ::bot_wallbuy_purchase_on_postpone, ::bot_wallbuy_purchase_priority );
register_bot_action( "objective", "wallbuyammo", ::bot_wallbuy_ammo_purchase, ::bot_wallbuyammo_process_order, ::bot_should_purchase_wallbuy_ammo, ::bot_check_complete_wallbuy_ammo, ::bot_set_complete_wallbuy_ammo, ::bot_wallbuy_ammo_purchase_on_completion, ::bot_wallbuy_ammo_purchase_should_cancel, ::bot_wallbuy_ammo_purchase_on_cancel, ::bot_wallbuy_ammo_purchase_should_postpone, ::bot_wallbuy_ammo_purchase_on_postpone, ::bot_wallbuy_ammo_purchase_priority );
register_bot_action( "objective", "perk", ::bot_perk_purchase, ::bot_perk_process_order, ::bot_should_purchase_perk, ::bot_check_complete_perk_purchase, ::bot_set_complete_perk_purchase, ::bot_perk_purchase_on_completion, ::bot_perk_purchase_should_cancel, ::bot_perk_purchase_on_cancel, ::bot_perk_purchase_should_postpone, ::bot_perk_purchase_on_postpone, ::bot_perk_purchase_priority );
register_bot_action( "objective", "door", ::bot_door_purchase, ::bot_door_process_order, ::bot_should_purchase_door, ::bot_check_complete_door_purchase, ::bot_set_complete_door_purchase, ::bot_door_purchase_on_completion, ::bot_door_purchase_should_cancel, ::bot_door_purchase_on_cancel, ::bot_door_purchase_should_postpone, ::bot_door_purchase_on_postpone, ::bot_door_purchase_priority );
register_bot_action( "objective", "debris", ::bot_debris_purchase, ::bot_debris_process_order, ::bot_should_purchase_debris, ::bot_check_complete_debris_purchase, ::bot_set_complete_debris_purchase, ::bot_debris_purchase_on_completion, ::bot_debris_purchase_should_cancel, ::bot_debris_purchase_on_cancel, ::bot_debris_purchase_should_postpone, ::bot_debris_purchase_on_postpone, ::bot_debris_purchase_priority );
register_bot_action( "objective", "trap", ::bot_trap_purchase, ::bot_trap_process_order, ::bot_should_purchase_trap, ::bot_check_complete_trap_purchase, ::bot_set_complete_trap_purchase, ::bot_trap_purchase_on_completion, ::bot_trap_purchase_should_cancel, ::bot_trap_purchase_on_cancel, ::bot_trap_purchase_should_postpone, ::bot_trap_purchase_on_postpone, ::bot_trap_purchase_priority );
register_bot_action( "objective", "packapunch", ::bot_packapunch_purchase, ::bot_packapunch_process_order, ::bot_should_purchase_packapunch, ::bot_check_complete_packapunch_purchase, ::bot_set_complete_packapunch_purchase, ::bot_packapunch_purchase_on_completion, ::bot_packapunch_purchase_should_cancel, ::bot_packapunch_purchase_on_cancel, ::bot_packapunch_purchase_should_postpone, ::bot_packapunch_purchase_on_postpone, ::bot_packapunch_purchase_priority );
register_bot_action( "objective", "revive", ::bot_revive_player, ::bot_revive_process_order, ::bot_should_revive_player, ::bot_check_complete_revive_player, ::bot_set_complete_revive_player, ::bot_revive_player_on_completion, ::bot_revive_player_should_cancel, ::bot_revive_player_on_cancel, ::bot_revive_player_should_postpone, ::bot_revive_player_on_postpone, ::bot_revive_player_priority );
//register_bot_action( "objective", "grabbuildable", ::bot_grab_buildable, ::bot_grab_buildable_process_order, ::bot_should_grab_buildable, ::bot_check_complete_grab_buildable, ::bot_set_complete_grab_buildable, ::bot_grab_buildable_on_completion, ::bot_grab_buildable_should_cancel, ::bot_grabbuild_buildable_on_cancel, ::bot_grab_buildable_should_postpone, ::bot_grab_buildable_on_postpone, ::bot_grab_buildable_priority );
//register_bot_action( "objective", "buildbuildable", ::bot_build_buildable, ::bot_build_buildable_process_order, ::bot_should_build_buildable, ::bot_check_complete_build_buildable, ::bot_set_complete_build_buildable, ::bot_build_buildable_on_completion, ::bot_build_buildable_should_cancel, ::bot_build_buildable_on_cancel, ::bot_build_buildable_should_postpone, ::bot_build_buildable_on_postpone, ::bot_build_buildable_priority );
//register_bot_action( "objective", "part", ::bot_grab_part, ::bot_part_process_order, ::bot_should_grab_part, ::bot_check_complete_grab_part, ::bot_set_complete_grab_part, ::bot_part_on_completion, ::bot_part_should_cancel, ::bot_part_on_cancel, ::bot_part_should_postpone, ::bot_part_on_postpone, ::bot_part_priority );
register_bot_action( "objective", "powerup", ::bot_grab_powerup, ::bot_powerup_process_order, ::bot_should_grab_powerup, ::bot_check_complete_grab_powerup, ::bot_set_complete_grab_powerup, ::bot_powerup_on_completion, ::bot_powerup_should_cancel, ::bot_powerup_on_cancel, ::bot_powerup_should_postpone, ::bot_powerup_on_postpone, ::bot_powerup_priority );
//Combat actions
//These all need definitions
register_bot_action( "combat", "shoot", ::bot_shoot, ::bot_shoot_process_order, ::bot_should_shoot, ::bot_check_complete_shoot, ::bot_set_complete_shoot, ::bot_shoot_on_completion, ::bot_shoot_should_cancel, ::bot_shoot_on_cancel, ::bot_shoot_should_postpone, ::bot_shoot_on_postpone, ::bot_shoot_priority );
register_bot_action( "combat", "reload", ::bot_reload, ::bot_reload_process_order, ::bot_should_reload, ::bot_check_complete_reload, ::bot_set_complete_reload, ::bot_reload_on_completion, ::bot_reload_should_cancel, ::bot_reload_on_cancel, ::bot_reload_should_postpone, ::bot_reload_on_postpone, ::bot_reload_priority );
register_bot_action( "combat", "frag", ::bot_frag, ::bot_frag_process_order, ::bot_should_frag, ::bot_check_complete_frag, ::bot_set_complete_frag, ::bot_frag_on_completion, ::bot_frag_should_cancel, ::bot_frag_on_cancel, ::bot_frag_should_postpone, ::bot_frag_on_postpone, ::bot_frag_priority );
register_bot_action( "combat", "tactical", ::bot_tactical, ::bot_tactical_process_order, ::bot_should_tactical, ::bot_check_complete_tactical, ::bot_set_complete_tactical, ::bot_tactical_on_completion, ::bot_tactical_should_cancel, ::bot_tactical_on_cancel, ::bot_tactical_should_postpone, ::bot_tactical_on_postpone, ::bot_tactical_priority );
//register_bot_action( "combat", "combatoverride", ::bot_combatoverride, ::bot_combatoverride_process_order ::bot_should_combatoverride, ::bot_check_complete_combatoverride, ::bot_set_complete_combatoverride, ::bot_combatoverride_on_completion, ::bot_combatoverride_should_cancel, ::bot_combatoverride_on_cancel, ::bot_combatoverride_should_postpone, ::bot_combatoverride_on_postpone, ::bot_combatoverride_priority );
//Movement actions
//These all need definitions
register_bot_action( "movement", "movetoobjective", ::bot_movetoobjective, ::bot_movetoobjective_process_order, ::bot_should_movetoobjective, ::bot_check_complete_movetoobjective, ::bot_set_complete_movetoobjective, ::bot_movetoobjective_on_completion, ::bot_movetoobjective_should_cancel, ::bot_movetoobjective_on_cancel, ::bot_movetoobjective_should_postpone, ::bot_movetoobjective_on_postpone, ::bot_movetoobjective_priority );
//register_bot_action( "movement", "moveoverride", ::bot_moveoverride, ::bot_moveoverride_process_order, ::bot_should_moveoverride, ::bot_check_complete_moveoverride, ::bot_set_complete_moveoverride, ::bot_moveoverride_on_completion, ::bot_moveoverride_should_cancel, ::bot_moveoverride_on_cancel, ::bot_moveoverride_should_postpone, ::bot_moveoverride_on_postpone, ::bot_moveoverride_priority );
register_bot_action( "movement", "train", ::bot_train, ::bot_train_process_order, ::bot_should_train, ::bot_check_complete_train, ::bot_set_complete_train, ::bot_train_on_completion, ::bot_train_should_cancel, ::bot_train_on_cancel, ::bot_train_should_postpone, ::bot_train_on_postpone, ::bot_train_priority );
register_bot_action( "movement", "camp", ::bot_camp, ::bot_camp_process_order, ::bot_should_camp, ::bot_check_complete_camp, ::bot_set_complete_camp, ::bot_camp_on_completion, ::bot_camp_should_cancel, ::bot_camp_on_cancel, ::bot_camp_should_postpone, ::bot_camp_on_postpone, ::bot_camp_priority );
register_bot_action( "movement", "flee", ::bot_flee, ::bot_flee_process_order, ::bot_should_flee, ::bot_check_complete_flee, ::bot_set_complete_flee, ::bot_flee_on_completion, ::bot_flee_should_cancel, ::bot_flee_on_cancel, ::bot_flee_should_postpone, ::bot_flee_on_postpone, ::bot_flee_priority );
//register_bot_action( "follow" )
register_bot_action( "look", "lookatobjective", ::bot_lookatobjective, ::bot_lookatobjective_process_order, ::bot_should_lookatobjective, ::bot_check_complete_lookatobjective, ::bot_set_complete_lookatobjective, ::bot_lookatobjective_on_completion, ::bot_lookatobjective_should_cancel, ::bot_lookatobjective_on_cancel, ::bot_lookatobjective_should_postpone, ::bot_lookatobjective_on_postpone, ::bot_lookatobjective_priority );
register_bot_action( "look", "lookattarget", ::bot_lookattarget, ::bot_lookattarget_process_order, ::bot_should_lookattarget, ::bot_check_complete_lookattarget, ::bot_set_complete_lookattarget, ::bot_lookattarget_on_completion, ::bot_lookattarget_should_cancel, ::bot_lookattarget_on_cancel, ::bot_lookattarget_should_postpone, ::bot_lookattarget_on_postpone, ::bot_lookattarget_priority );
register_bot_action( "look", "lookatgoal", ::bot_lookatgoal, ::bot_lookatgoal_process_order, ::bot_should_lookatgoal, ::bot_check_complete_lookatgoal, ::bot_set_complete_lookatgoal, ::bot_lookatgoal_on_completion, ::bot_lookatgoal_should_cancel, ::bot_lookatgoal_on_cancel, ::bot_lookatgoal_should_postpone, ::bot_lookatgoal_on_postpone, ::bot_lookatgoal_priority );
//register_bot_action( "look", "ads", ::bot_ads, ::bot_ads_process_order, ::bot_should_ads, ::bot_check_complete_ads, ::bot_set_complete_ads, ::bot_ads_on_completion, ::bot_ads_should_cancel, ::bot_ads_on_cancel, ::bot_ads_should_postpone, ::bot_ads_on_postpone, ::bot_ads_priority );
//register_bot_action( "look", "lookahead", ::bot_lookahead, ::bot_lookahead_process_order, ::bot_should_lookahead, ::bot_check_complete_lookahead, ::bot_set_complete_lookahead, ::bot_lookahead_on_completion, ::bot_lookahead_should_cancel, ::bot_lookahead_on_cancel, ::bot_lookahead_should_postpone, ::bot_lookahead_on_postpone, ::bot_lookahead_priority );
register_bot_personality_type( "aggressive" );
register_bot_personality_type( "passive" );
register_bot_personality_type( "supportive" );
register_bot_personality_type( "mixed" );
register_bot_personality_type( "default" );
register_bot_difficulty( "bone" );
register_bot_difficulty( "crossbones" );
register_bot_difficulty( "skull" );
register_bot_difficulty( "knife" );
register_bot_difficulty( "shotguns" );
register_bot_objective( "magicbox" );
register_bot_objective( "wallbuy" );
register_bot_objective( "wallbuyammo" );
register_bot_objective( "perk" );
register_bot_objective( "door" );
register_bot_objective( "debris" );
register_bot_objective( "trap" );
register_bot_objective( "packapunch" );
register_bot_objective( "revive" );
//register_bot_objective( "grabbuildable" );
//register_bot_objective( "buildbuildable" );
//register_bot_objective( "part" );
register_bot_objective( "powerup" );
register_bot_target_type( "zombie" );
register_bot_target_type( "zombie_dog" );
level.bot_weapon_quality_poor = 0;
level.bot_weapon_quality_fair = 1;
level.bot_weapon_quality_good = 2;
level.bot_weapon_quality_excellent = 3;
level.bot_weapon_quality_best = 4;
level.bots_minSprintDistance = 315;
level.bots_minSprintDistance *= level.bots_minSprintDistance;
level.bots_minGrenadeDistance = 256;
level.bots_minGrenadeDistance *= level.bots_minGrenadeDistance;
level.bots_maxGrenadeDistance = 1024;
level.bots_maxGrenadeDistance *= level.bots_maxGrenadeDistance;
level.bots_maxKnifeDistance = 80;
level.bots_maxKnifeDistance *= level.bots_maxKnifeDistance;
level.bots_goalDistance = 27.5;
level.bots_goalDistance *= level.bots_goalDistance;
level.bots_noADSDistance = 200;
level.bots_noADSDistance *= level.bots_noADSDistance;
level.bots_maxShotgunDistance = 500;
level.bots_maxShotgunDistance *= level.bots_maxShotgunDistance;
level.bots_listenDist = 100;
/*
level.bot_powerup_priority_none = 0;
level.bot_powerup_priority_low = 1;
level.bot_powerup_priority_medium = 2;
level.bot_powerup_priority_high = 3;
level.bot_powerup_priority_urgent = 4;
register_bot_powerup_priority( "nuke", level.bot_powerup_priority_high, level.bot_powerup_priority_urgent );
register_bot_powerup_priority( "insta_kill", level.bot_powerup_priority_high, level.bot_powerup_priority_urgent );
register_bot_powerup_priority( "full_ammo", level.bot_powerup_priority_medium, level.bot_powerup_priority_low );
register_bot_powerup_priority( "double_points", level.bot_powerup_priority_low, level.bot_powerup_priority_none );
register_bot_powerup_priority( "carpenter", level.bot_powerup_priority_low, level.bot_powerup_priority_none );
register_bot_powerup_priority( "fire_sale", level.bot_powerup_priority_low, level.bot_powerup_priority_none );
register_bot_powerup_priority( "free_perk", level.bot_powerup_priority_medium, level.bot_powerup_priority_low );
register_bot_powerup_priority( "zombie_blood", level.bot_powerup_priority_high, level.bot_powerup_priority_urgent);
*/
level thread spawn_bots_for_host();
level thread on_player_connect();
level.waypoints = getAllNodes();
level.waypoints_inside_playable_area = get_nodes_in_playable_area();
level.waypointCount = level.waypoints.size;
level.waypoint_count_inside_playable_area = level.waypoints_inside_playable_area.size;
}
/*
We clear all of the script variables and other stuff for the bots.
*/
resetBotVars()
{
self.bot = spawnStruct();
self.bot.script_target = undefined;
self.bot.script_target_offset = undefined;
self.bot.target = undefined;
self.bot.targets = [];
self.bot.target_this_frame = undefined;
self.bot.after_target = undefined;
self.bot.after_target_pos = undefined;
self.bot.moveTo = self.origin;
self.bot.script_aimpos = undefined;
self.bot.script_goal = undefined;
self.bot.script_goal_dist = 0.0;
self.bot.next_wp = -1;
self.bot.second_next_wp = -1;
self.bot.towards_goal = undefined;
self.bot.astar = [];
self.bot.stop_move = false;
self.bot.greedy_path = false;
self.bot.climbing = false;
self.bot.wantsprint = false;
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self.bot.isfrozen = false;
self.bot.sprintendtime = -1;
self.bot.isreloading = false;
self.bot.issprinting = false;
self.bot.isfragging = false;
self.bot.issmoking = false;
self.bot.isfraggingafter = false;
self.bot.issmokingafter = false;
self.bot.isknifing = false;
self.bot.isknifingafter = false;
self.bot.semi_time = false;
self.bot.jump_time = undefined;
self.bot.last_fire_time = -1;
self.bot.is_cur_full_auto = false;
self.bot.cur_weap_dist_multi = 1;
self.bot.is_cur_sniper = false;
self.bot.rand = randomInt( 100 );
self botStop();
}
get_nodes_in_playable_area()
{
total_nodes = getAllNodes();
filtered_nodes = [];
for ( i = 0; i < total_nodes.size; i++ )
{
if ( !is_point_in_playable_area( total_nodes[ i ].origin ) )
{
continue;
}
filtered_nodes[ filtered_nodes.size ] = total_nodes[ i ];
if ( ( i % 10 ) == 0 )
{
wait 0.05;
}
}
return filtered_nodes;
}
is_point_in_playable_area( point )
{
playable_area = getentarray( "playable_area", "targetname" );
in_playable_area = false;
if ( !isDefined( playable_area ) || playable_area.size < 1 )
{
in_playable_area = true;
}
temp_ent = spawn( "script_origin", point );
if ( !in_playable_area )
{
for ( p = 0; p < playable_area.size; p++ )
{
if ( temp_ent isTouching( playable_area[ p ] ) )
{
in_playable_area = true;
break;
}
}
}
temp_ent delete();
return in_playable_area;
}
on_player_connect()
{
i = 0;
while ( true )
{
level waittill( "connected", player );
player thread on_player_spawned();
player.client_id = i;
if ( player isBot() )
{
player resetBotVars();
player.successfully_grabbed_powerup = false;
player.successfully_revived_player = false;
player.successfully_moved_to_objective = false;
player.can_do_objective_now = false;
player.on_powerup_grab_func = ::bot_on_powerup_grab;
player thread zbot_spawn();
}
else
{
player thread bot_control();
}
i++;
}
}
bot_control()
{
self endon( "disconnect" );
self notifyOnPlayerCommand( "+smoke", "new_script_goal" );
while ( true )
{
self waittill( "new_script_goal" );
players = getPlayers();
for ( i = 0; i < players.size; i++ )
{
if ( players[ i ] isBot() )
{
players[ i ] scripts\sp\bots\_bot_utility::SetScriptGoal( self.origin );
players[ i ] thread clear_script_on_event();
}
}
self iPrintLn( "Set new goal for bots" );
}
}
clear_script_on_event()
{
self endon( "disconnect" );
result = self waittill_any_return( "new_goal", "goal", "bad_path" );
if ( result != "new_goal" )
{
self scripts\sp\bots\_bot_utility::ClearScriptGoal();
}
}
on_player_spawned()
{
self waittill( "spawned_player" );
self.score = 100000;
}
zbot_spawn()
{
level endon( "end_game" );
self endon( "disconnect" );
while ( true )
{
self waittill( "spawned_player" );
self thread doBotMovement();
//self thread grenade_danger();
//self thread check_reload();
//self thread stance();
self thread walk();
//self thread target();
//self thread updateBones();
//self thread aim();
//self thread watchHoldBreath();
//self thread onNewEnemy();
//self thread watchGrenadeFire();
//self thread watchPickupGun();
}
}
//TODO: Make postponing save the settings for the action so when the action is being executed again the bot tries to do/get the same thing
//TODO: Make global canceling and postponing functionality
//TODO: Make shared global objective and normal objective globs work
//TODO: Allow bots to multitask objectives on the way by using the postpone system
//TODO: Cancel most objectives if the bot is invalid
//TODO: Add reset complete functions to reset successfully completed actions variables
//TODO: Ignore objectives if bot is not able fulfill them at the moment, bot can start doing objectives when they are in a good position to do so
//TODO: Add the ability to check if a bot is at an objective to start the action think
//TODO: Add atobjective movement handler to let objectives control movement temporarily
//TODO: Allow bots to still do actions while down if possible
//TODO: Track zombies targetting players
init()
{
if ( isDefined( level.chests ) && level.chests.size > 0 )
{
for ( i = 0; i < level.chests.size; i++ )
{
level.chests[ i ].id = i;
}
//level thread watch_magicbox_objectives();
}
weapon_spawns = GetEntArray( "weapon_upgrade", "targetname" );
if ( isDefined( weapon_spawns ) && weapon_spawns.size > 0 )
{
for( i = 0; i < weapon_spawns.size; i++ )
{
weapon_spawns[ i ].id = i;
add_possible_bot_objective( "wallbuy", i, false, weapon_spawns[ i ] );
add_possible_bot_objective( "wallbuyammo", i, false, weapon_spawns[ i ] );
}
}
vending_triggers = GetEntArray( "zombie_vending", "targetname" );
if ( isDefined( vending_triggers ) && vending_triggers.size > 0 )
{
for ( i = 0; i < vending_triggers.size; i++ )
{
vending_triggers[ i ].id = i;
add_possible_bot_objective( "perk", i, false, vending_triggers[ i ] );
}
}
//TODO: See if its possible to automatically detect if a door is blocking an objective
zombie_doors = GetEntArray( "zombie_door", "targetname" );
if ( isDefined( zombie_doors ) && zombie_doors.size > 0 )
{
for ( i = 0; i < zombie_doors.size; i++ )
{
zombie_doors[ i ].id = i;
add_possible_bot_objective( "door", i, true, zombie_doors[ i ] );
}
level thread watch_door_objectives( zombie_doors );
}
zombie_debris = GetEntArray( "zombie_debris", "targetname" );
if ( isDefined( zombie_debris ) && zombie_debris.size > 0 )
{
for ( i = 0; i < zombie_debris.size; i++ )
{
zombie_debris[ i ].id = i;
add_possible_bot_objective( "debris", i, true, zombie_debris[ i ] );
}
level thread watch_debris_objectives( zombie_debris );
}
vending_upgrade_trigger = GetEntArray("zombie_vending_upgrade", "targetname");
if ( isDefined( vending_upgrade_trigger ) && vending_upgrade_trigger.size > 0 )
{
for ( i = 0; i < vending_upgrade_trigger.size; i++ )
{
vending_upgrade_trigger[ i ].id = i;
add_possible_bot_objective( "packapunch", i, false, vending_upgrade_trigger[ i ] );
}
}
level.callbackActorSpawned = ::zbots_actor_spawned;
level.callbackActorKilled = ::zbots_actor_killed;
level.callbackActorDamage = ::zbots_actor_damage;
level thread watch_for_downed_players();
level thread store_powerups_dropped();
parse_bot_weapon_stats_from_table();
}
zbots_actor_spawned()
{
self.is_actor = true;
self thread add_actor_to_target_glob();
}
add_actor_to_target_glob()
{
wait 1; //Wait long enough for the actor to be initialized in script
assert( isDefined( self.targetname ), "Actor doesn't have a targetname set" );
if ( !isDefined( self.targetname ) )
{
return;
}
add_possible_bot_target( self.targetname, level.zbot_target_glob_ids[ self.targetname ], self );
self.target_id = level.zbot_target_glob_ids[ self.targetname ];
level.zbot_target_glob_ids[ self.targetname ]++;
}
zbots_actor_killed( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, iTimeOffset )
{
free_bot_target( self.targetname, self.target_id );
}
zbots_actor_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, iTimeOffset )
{
if ( isPlayer( eAttacker ) && iDamage > 0 )
{
eAttacker set_target_damaged_by( self.targetname, self.target_id );
eAttacker thread remove_target_damaged_by_after_time( self, self.target_id );
}
self FinishActorDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, iTimeOffset );
}
remove_target_damaged_by_after_time( target_ent, id )
{
player_entnum = self getEntityNumber();
self endon( "disconnect" );
target_ent notify( "damaged_by_player_" + player_entnum );
target_ent endon( "damaged_by_player_" + player_entnum );
target_ent endon( "death" );
wait 6;
self clear_target_damaged_by( target_ent.targetname, id );
}
spawn_bots_for_host()
{
level waittill( "connected", player );
spawn_bots();
}
spawn_bots()
{
required_bots = 3;
bot_count = 0;
while ( bot_count < required_bots )
{
bot = undefined;
while ( !isDefined( bot ) && getPlayers().size < getDvarInt( "sv_maxclients" ) )
{
bot = addTestClient();
}
if ( !isDefined( bot ) )
{
return;
}
bot.pers[ "isBot" ] = true;
bot.action_queue = [];
bot.action_queue[ "objective" ] = [];
bot.action_queue[ "combat" ] = [];
bot.action_queue[ "movement" ] = [];
bot.action_queue[ "look" ] = [];
bot register_action_queue_actions();
bot thread bot_think();
bot_count++;
}
}
bot_think()
{
level endon( "end_game" );
self endon( "disconnect" );
self waittill( "spawned_player" );
while ( true )
{
wait 0.25;
if ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
{
self notify( "stop_action_think" );
self bot_clear_actions_queue();
while ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
{
wait 1;
}
}
//group_name = "movement";
//self bot_action_think( group_name );
//group_name = "look";
//self bot_action_think( group_name );
//group_name = "combat";
//self scripts\sp\bots\bot_target_common::bot_pick_target();
//self bot_action_think( group_name );
group_name = "objective";
self bot_action_think( group_name );
}
}
watch_door_objectives( zombie_doors )
{
level endon( "end_game" );
for ( doors_opened_count = 0; doors_opened_count < zombie_doors.size; doors_opened_count++ )
{
level waittill( "door_opened", door, player );
free_bot_objective( "door", door.id );
}
}
watch_debris_objectives( zombie_debris )
{
level endon( "end_game" );
for ( debris_opened_count = 0; debris_opened_count < zombie_debris.size; debris_opened_count++ )
{
level waittill( "debris_opened", debris, player );
free_bot_objective( "door", debris.id );
}
}
watch_magicbox_objectives()
{
level endon( "end_game" );
level waittill( "connected", player );
prev_magicbox = maps\so\zm_common\_zm_magicbox::get_active_magicbox();
while ( true )
{
cur_magicbox = maps\so\zm_common\_zm_magicbox::get_active_magicbox();
if ( prev_magicbox != cur_magicbox )
{
add_possible_bot_objective( "magicbox", cur_magicbox.id, false, cur_magicbox );
free_bot_objective( "magicbox", prev_magicbox.id );
prev_magicbox = cur_magicbox;
}
wait 1;
}
}
store_powerups_dropped()
{
level endon( "end_game" );
level thread free_powerups_dropped();
level.zbots_powerups = [];
level.zbots_powerups_targeted_for_grab = [];
id = 0;
while ( true )
{
level waittill( "powerup_dropped", powerup );
if ( !isDefined( powerup ) )
{
continue;
}
powerup.id = id;
add_possible_bot_objective( "powerup", id, true, powerup );
level thread objective_think( "powerup", id );
scripts\sp\bots\bot_utility::assign_priority_to_powerup( powerup );
level.zbots_powerups = scripts\sp\bots\bot_utility::sort_array_by_priority_field( level.zbots_powerups, powerup );
id++;
}
}
free_powerups_dropped()
{
level endon( "end_game" );
while ( true )
{
level waittill( "powerup_freed", powerup );
free_bot_objective( "powerup", powerup.id );
}
}
watch_for_downed_players()
{
level endon( "end_game" );
while ( true )
{
level waittill( "player_entered_laststand", player );
if ( !isDefined( player ) )
{
continue;
}
add_possible_bot_objective( "revive", player.client_id, true, player );
player thread free_revive_objective_when_needed();
}
}
free_revive_objective_when_needed()
{
level endon( "end_game" );
id = self.id;
while ( isDefined( self ) && isDefined( self.revivetrigger ) )
{
wait 0.05;
}
free_bot_objective( "revive", id );
}
bot_on_powerup_grab( powerup )
{
self.successfully_grabbed_powerup = true;
}

4
scripts/sp/bots.gsc Normal file
View File

@ -0,0 +1,4 @@
init()
{
level thread maps\bots\_bot::init();
}

View File

@ -1,758 +0,0 @@
#include scripts\sp\bots\_bot_utility;
#include maps\_utility;
#include common_scripts\utility;
/*
Bot moves towards the point
*/
doBotMovement()
{
self endon( "disconnect" );
self endon( "zombified" );
data = spawnStruct();
data.wasMantling = false;
for ( data.i = 0; true; data.i += 0.05 )
{
wait 0.05;
waittillframeend;
self doBotMovement_loop( data );
}
}
/*
Bot moves towards the point
*/
doBotMovement_loop( data )
{
move_To = self.bot.moveTo;
angles = self GetPlayerAngles();
dir = ( 0, 0, 0 );
if ( DistanceSquared( self.origin, move_To ) >= 49 )
{
cosa = cos( 0 - angles[1] );
sina = sin( 0 - angles[1] );
// get the direction
dir = move_To - self.origin;
// rotate our direction according to our angles
dir = ( dir[0] * cosa - dir[1] * sina,
dir[0] * sina + dir[1] * cosa,
0 );
// make the length 127
dir = VectorNormalize( dir ) * 127;
// invert the second component as the engine requires this
dir = ( dir[0], 0 - dir[1], 0 );
}
startPos = self.origin + ( 0, 0, 50 );
startPosForward = startPos + anglesToForward( ( 0, angles[1], 0 ) ) * 25;
bt = bulletTrace( startPos, startPosForward, false, self );
if ( bt["fraction"] >= 1 )
{
// check if need to jump
bt = bulletTrace( startPosForward, startPosForward - ( 0, 0, 40 ), false, self );
if ( bt["fraction"] < 1 && bt["normal"][2] > 0.9 && data.i > 1.5 )
{
data.i = 0;
self thread jump();
}
}
// check if need to knife glass
else if ( bt["surfacetype"] == "glass" )
{
if ( data.i > 1.5 )
{
data.i = 0;
self thread knife();
}
}
else
{
// check if need to crouch
if ( bulletTracePassed( startPos - ( 0, 0, 25 ), startPosForward - ( 0, 0, 25 ), false, self ) && !self.bot.climbing )
self crouch();
}
// move!
if ( self.bot.wantsprint && self.bot.issprinting )
dir = ( 127, dir[1], 0 );
self botMovement( int( dir[0] ), int( dir[1] ) );
}
/*
This is the main walking logic for the bot.
*/
walk()
{
self endon( "disconnect" );
self endon( "zombified" );
for ( ;; )
{
wait 0.05;
self botMoveTo( self.origin );
//if ( !getDvarInt( "bots_play_move" ) )
// continue;
if ( level.intermission || self.bot.isfrozen || self.bot.stop_move )
continue;
self walk_loop();
}
}
/*
This is the main walking logic for the bot.
*/
walk_loop()
{
hasTarget = isDefined( self.bot.target ) && isDefined( self.bot.target.entity );
if ( hasTarget )
{
curweap = self getCurrentWeapon();
if ( self.bot.isfraggingafter || self.bot.issmokingafter )
{
return;
}
if ( self.bot.target.trace_time && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) )
{
if ( self maps\_laststand::player_is_in_laststand() || self GetStance() == "prone" || ( self.bot.is_cur_sniper && self PlayerADS() > 0 ) )
return;
if ( self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"] )
self strafe( self.bot.target.entity );
return;
}
}
dist = 16;
goal = level.waypoints_inside_playable_area[randomInt( level.waypoint_count_inside_playable_area )].origin;
isScriptGoal = false;
if ( isDefined( self.bot.script_goal ) && !hasTarget )
{
goal = self.bot.script_goal;
dist = self.bot.script_goal_dist;
isScriptGoal = true;
}
else
{
if ( hasTarget )
goal = self.bot.target.last_seen_pos;
self notify( "new_goal_internal" );
}
self doWalk( goal, dist, isScriptGoal );
self.bot.towards_goal = undefined;
self.bot.next_wp = -1;
self.bot.second_next_wp = -1;
}
/*
Will walk to the given goal when dist near. Uses AStar path finding with the level's nodes.
*/
doWalk( goal, dist, isScriptGoal )
{
level endon( "end_game" );
self endon( "kill_goal" );
self endon( "goal_internal" ); //so that the watchOnGoal notify can happen same frame, not a frame later
dist *= dist;
if ( isScriptGoal )
self thread doWalkScriptNotify();
self thread killWalkOnEvents();
self thread watchOnGoal( goal, dist );
current = self initAStar( goal );
path_was_truncated = ( current + 1 ) >= 32;
//Couldn't generate path to goal
if ( current <= -1 )
{
self notify( "bad_path_internal" );
return;
}
// skip waypoints we already completed to prevent rubber banding
if ( current > 0 && self.bot.astar[current] == self.bot.last_next_wp && self.bot.astar[current - 1] == self.bot.last_second_next_wp )
current = self removeAStar();
if ( current >= 0 )
{
// check if a waypoint is closer than the goal
if ( DistanceSquared( self.origin, level.waypoints[self.bot.astar[current]].origin ) < DistanceSquared( self.origin, goal ) || DistanceSquared( level.waypoints[self.bot.astar[current]].origin, PlayerPhysicsTrace( self.origin + ( 0, 0, 32 ), level.waypoints[self.bot.astar[current]].origin ) ) > 1.0 )
{
while ( current >= 0 )
{
self.bot.next_wp = self.bot.astar[current];
self.bot.second_next_wp = -1;
if ( current > 0 )
self.bot.second_next_wp = self.bot.astar[current - 1];
self notify( "new_static_waypoint" );
self movetowards( level.waypoints[self.bot.next_wp].origin );
self.bot.last_next_wp = self.bot.next_wp;
self.bot.last_second_next_wp = self.bot.second_next_wp;
current = self removeAStar();
}
}
}
if ( path_was_truncated )
{
self notify( "kill_goal" );
return;
}
self.bot.next_wp = -1;
self.bot.second_next_wp = -1;
self notify( "finished_static_waypoints" );
if ( DistanceSquared( self.origin, goal ) > dist )
{
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self movetowards( goal ); // any better way??
}
self notify( "finished_goal" );
wait 1;
if ( DistanceSquared( self.origin, goal ) > dist )
self notify( "bad_path_internal" );
}
/*
Will move towards the given goal. Will try to not get stuck by crouching, then jumping and then strafing around objects.
*/
movetowards( goal )
{
if ( !isDefined( goal ) )
return;
self.bot.towards_goal = goal;
lastOri = self.origin;
stucks = 0;
timeslow = 0;
time = 0;
if ( self.bot.issprinting )
tempGoalDist = level.bots_goalDistance * 2;
else
tempGoalDist = level.bots_goalDistance;
while ( distanceSquared( self.origin, goal ) > tempGoalDist )
{
self botMoveTo( goal );
if ( time > 3000 )
{
time = 0;
if ( distanceSquared( self.origin, lastOri ) < 32 * 32 )
{
self thread knife();
wait 0.5;
stucks++;
randomDir = self getRandomLargestStafe( stucks );
self BotNotifyBotEvent( "stuck" );
self botMoveTo( randomDir );
wait stucks;
self stand();
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
}
lastOri = self.origin;
}
else if ( timeslow > 0 && ( timeslow % 1000 ) == 0 )
{
self thread doMantle();
}
else if ( time == 2000 )
{
if ( distanceSquared( self.origin, lastOri ) < 32 * 32 )
self crouch();
}
else if ( time == 1750 )
{
if ( distanceSquared( self.origin, lastOri ) < 32 * 32 )
{
// check if directly above or below
if ( abs( goal[2] - self.origin[2] ) > 64 && getConeDot( goal + ( 1, 1, 0 ), self.origin + ( -1, -1, 0 ), VectorToAngles( ( goal[0], goal[1], self.origin[2] ) - self.origin ) ) < 0.64 && DistanceSquared2D( self.origin, goal ) < 32 * 32 )
{
stucks = 2;
}
}
}
wait 0.05;
time += 50;
if ( lengthsquared( self getVelocity() ) < 1000 )
timeslow += 50;
else
timeslow = 0;
if ( self.bot.issprinting )
tempGoalDist = level.bots_goalDistance * 2;
else
tempGoalDist = level.bots_goalDistance;
if ( stucks >= 2 )
self notify( "bad_path_internal" );
}
self.bot.towards_goal = undefined;
self notify( "completed_move_to" );
}
/*
The bot will strafe left or right from their enemy.
*/
strafe( target )
{
self endon( "kill_goal" );
self thread killWalkOnEvents();
angles = VectorToAngles( vectorNormalize( target.origin - self.origin ) );
anglesLeft = ( 0, angles[1] + 90, 0 );
anglesRight = ( 0, angles[1] - 90, 0 );
myOrg = self.origin + ( 0, 0, 16 );
left = myOrg + anglestoforward( anglesLeft ) * 500;
right = myOrg + anglestoforward( anglesRight ) * 500;
traceLeft = BulletTrace( myOrg, left, false, self );
traceRight = BulletTrace( myOrg, right, false, self );
strafe = traceLeft["position"];
if ( traceRight["fraction"] > traceLeft["fraction"] )
strafe = traceRight["position"];
self.bot.last_next_wp = -1;
self.bot.last_second_next_wp = -1;
self botMoveTo( strafe );
wait 2;
self notify( "kill_goal" );
}
/*
Will return the pos of the largest trace from the bot.
*/
getRandomLargestStafe( dist )
{
//find a better algo?
traces = NewHeap( ::HeapTraceFraction );
myOrg = self.origin + ( 0, 0, 16 );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 0, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 0, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, 100 * dist, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, -100 * dist, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, -100 * dist, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 100 * dist, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, -100 * dist, 0 ), false, self ) );
traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 100 * dist, 0 ), false, self ) );
toptraces = [];
top = traces.data[0];
toptraces[toptraces.size] = top;
traces HeapRemove();
while ( traces.data.size && top["fraction"] - traces.data[0]["fraction"] < 0.1 )
{
toptraces[toptraces.size] = traces.data[0];
traces HeapRemove();
}
return toptraces[randomInt( toptraces.size )]["position"];
}
/*
Calls the astar search algorithm for the path to the goal.
*/
initAStar( goal )
{
nodes = generatePath( self.origin, goal, self.team, false );
if ( !isDefined( nodes ) )
{
return -1;
}
node_indexes = [];
for ( i = nodes.size - 1; i >= 0; i-- )
{
node_indexes[ node_indexes.size ] = nodes[ i ] getNodeNumber();
}
self.bot.astar = node_indexes;
return self.bot.astar.size - 1;
}
/*
Cleans up the astar nodes for one node.
*/
removeAStar()
{
remove = self.bot.astar.size - 1;
self.bot.astar[remove] = undefined;
return self.bot.astar.size - 1;
}
/*
Does the notify for goal completion for outside scripts
*/
doWalkScriptNotify()
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "kill_goal" );
if ( self waittill_either_return( "goal_internal", "bad_path_internal" ) == "goal_internal" )
self notify( "goal" );
else
self notify( "bad_path" );
}
/*
Will stop the goal walk when an enemy is found or flashed or a new goal appeared for the bot.
*/
killWalkOnEvents()
{
self endon( "kill_goal" );
self endon( "disconnect" );
self endon( "zombified" );
self waittill_any( "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal" );
waittillframeend;
self notify( "kill_goal" );
}
/*
Will kill the goal when the bot made it to its goal.
*/
watchOnGoal( goal, dis )
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "kill_goal" );
while ( DistanceSquared( self.origin, goal ) > dis )
wait 0.05;
self notify( "goal_internal" );
}
/*
Bot will move towards here
*/
botMoveTo( where )
{
self.bot.moveTo = where;
}
/*
Bot will reload.
*/
reload()
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_reload" );
self endon( "bot_reload" );
self botAction( "+reload" );
wait 0.05;
self botAction( "-reload" );
}
/*
Bot will hold the frag button for a time
*/
frag( time )
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_frag" );
self endon( "bot_frag" );
if ( !isDefined( time ) )
time = 0.05;
self botAction( "+frag" );
self.bot.isfragging = true;
self.bot.isfraggingafter = true;
if ( time )
wait time;
self botAction( "-frag" );
self.bot.isfragging = false;
wait 1.25;
self.bot.isfraggingafter = false;
}
/*
Bot will hold the 'smoke' button for a time.
*/
smoke( time )
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_smoke" );
self endon( "bot_smoke" );
if ( !isDefined( time ) )
time = 0.05;
self botAction( "+smoke" );
self.bot.issmoking = true;
self.bot.issmokingafter = true;
if ( time )
wait time;
self botAction( "-smoke" );
self.bot.issmoking = false;
wait 1.25;
self.bot.issmokingafter = false;
}
/*
Bot will fire if true or not.
*/
fire( what )
{
self notify( "bot_fire" );
if ( what )
self botAction( "+fire" );
else
self botAction( "-fire" );
}
/*
Bot will fire for a time.
*/
pressFire( time )
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_fire" );
self endon( "bot_fire" );
if ( !isDefined( time ) )
time = 0.05;
self botAction( "+fire" );
if ( time )
wait time;
self botAction( "-fire" );
}
/*
Bot will ads if true or not.
*/
ads( what )
{
self notify( "bot_ads" );
if ( what )
self botAction( "+ads" );
else
self botAction( "-ads" );
}
/*
Bot will press ADS for a time.
*/
pressADS( time )
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_ads" );
self endon( "bot_ads" );
if ( !isDefined( time ) )
time = 0.05;
self botAction( "+ads" );
if ( time )
wait time;
self botAction( "-ads" );
}
/*
Bot will press use for a time.
*/
use( time )
{
self endon( "death" );
self endon( "disconnect" );
self notify( "bot_use" );
self endon( "bot_use" );
if ( !isDefined( time ) )
time = 0.05;
self botAction( "+activate" );
if ( time )
wait time;
self botAction( "-activate" );
}
/*
Bot will jump.
*/
jump()
{
self endon( "zombified" );
self endon( "disconnect" );
self notify( "bot_jump" );
self endon( "bot_jump" );
if ( self getStance() != "stand" )
{
self stand();
wait 1;
}
self botAction( "+gostand" );
wait 0.05;
self botAction( "-gostand" );
}
/*
Bots do the mantle
*/
doMantle()
{
self endon( "disconnect" );
self endon( "zombified" );
self endon( "kill_goal" );
self jump();
wait 0.35;
self jump();
}
/*
Bot will stand.
*/
stand()
{
self botAction( "-gocrouch" );
self botAction( "-goprone" );
}
/*
Bot will crouch.
*/
crouch()
{
self botAction( "+gocrouch" );
self botAction( "-goprone" );
}
/*
Bot will knife.
*/
knife()
{
self endon( "zombified" );
self endon( "disconnect" );
self notify( "bot_knife" );
self endon( "bot_knife" );
self.bot.isknifing = true;
self.bot.isknifingafter = true;
self botAction( "+melee" );
wait 0.05;
self botAction( "-melee" );
self.bot.isknifing = false;
wait 1;
self.bot.isknifingafter = false;
}
/*
Returns true if the bot can fire their current weapon.
*/
canFire( curweap )
{
if ( curweap == "none" )
return false;
return self GetWeaponammoclip( curweap );
}
/*
Returns true if the bot is in range of their target.
*/
isInRange( dist, curweap )
{
if ( curweap == "none" )
return false;
weapclass = weaponClass( curweap );
if ( weapclass == "spread" && dist > level.bots_maxShotgunDistance )
return false;
if ( curweap == "m2_flamethrower_mp" && dist > level.bots_maxShotgunDistance )
return false;
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,219 +0,0 @@
bot_shoot()
{
}
bot_shoot_process_order()
{
return 0;
}
bot_should_shoot()
{
return false;
}
bot_check_complete_shoot()
{
return false;
}
bot_set_complete_shoot()
{
}
bot_shoot_on_completion()
{
}
bot_shoot_should_cancel()
{
return false;
}
bot_shoot_on_cancel()
{
}
bot_shoot_should_postpone()
{
return false;
}
bot_shoot_on_postpone()
{
}
bot_shoot_priority()
{
}
bot_reload()
{
}
bot_reload_process_order()
{
return 0;
}
bot_should_reload()
{
return false;
}
bot_check_complete_reload()
{
return false;
}
bot_set_complete_reload()
{
}
bot_reload_on_completion()
{
}
bot_reload_should_cancel()
{
return false;
}
bot_reload_on_cancel()
{
}
bot_reload_should_postpone()
{
return false;
}
bot_reload_on_postpone()
{
}
bot_reload_priority()
{
return 0;
}
bot_frag()
{
}
bot_frag_process_order()
{
return 0;
}
bot_should_frag()
{
return false;
}
bot_check_complete_frag()
{
return false;
}
bot_set_complete_frag()
{
}
bot_frag_on_completion()
{
}
bot_frag_should_cancel()
{
return false;
}
bot_frag_on_cancel()
{
}
bot_frag_should_postpone()
{
}
bot_frag_on_postpone()
{
}
bot_frag_priority()
{
return 0;
}
bot_tactical()
{
}
bot_tactical_process_order()
{
return 0;
}
bot_should_tactical()
{
return false;
}
bot_check_complete_tactical()
{
return false;
}
bot_set_complete_tactical()
{
}
bot_tactical_on_completion()
{
}
bot_tactical_should_cancel()
{
return false;
}
bot_tactical_on_cancel()
{
}
bot_tactical_should_postpone()
{
return false;
}
bot_tactical_on_postpone()
{
}
bot_tactical_priority()
{
return 0;
}

View File

@ -1,224 +0,0 @@
#include scripts\sp\bots\bot_target_common;
bot_lookatobjective()
{
}
bot_lookatobjective_process_order()
{
return 0;
}
bot_should_lookatobjective()
{
return false;
}
bot_check_complete_lookatobjective()
{
return false;
}
bot_set_complete_lookatobjective()
{
}
bot_lookatobjective_on_completion()
{
}
bot_lookatobjective_should_cancel()
{
return false;
}
bot_lookatobjective_on_cancel()
{
}
bot_lookatobjective_should_postpone()
{
return false;
}
bot_lookatobjective_on_postpone()
{
}
bot_lookatobjective_priority()
{
return 0;
}
bot_lookattarget()
{
self endon( "disconnect" );
while ( self bot_has_target() && isAlive( self.zbot_current_target.target_ent ) )
{
target = self.zbot_current_target;
target_ent = target.target_ent;
self bot_lookat( target_ent getTagOrigin( "j_head" ) );
wait 0.05;
}
}
bot_lookattarget_process_order()
{
return 0;
}
bot_should_lookattarget()
{
return self bot_has_target();
}
bot_check_complete_lookattarget()
{
return !self bot_has_target();
}
bot_set_complete_lookattarget()
{
}
bot_lookattarget_on_completion()
{
}
bot_lookattarget_should_cancel()
{
return false;
}
bot_lookattarget_on_cancel()
{
}
bot_lookattarget_should_postpone()
{
return false;
}
bot_lookattarget_on_postpone()
{
}
bot_lookattarget_priority()
{
return 0;
}
bot_lookatgoal()
{
}
bot_lookatgoal_process_order()
{
return 0;
}
bot_should_lookatgoal()
{
return false;
}
bot_check_complete_lookatgoal()
{
return false;
}
bot_set_complete_lookatgoal()
{
}
bot_lookatgoal_on_completion()
{
}
bot_lookatgoal_should_cancel()
{
return false;
}
bot_lookatgoal_on_cancel()
{
}
bot_lookatgoal_should_postpone()
{
return false;
}
bot_lookatgoal_on_postpone()
{
}
bot_lookatgoal_priority()
{
return 0;
}
bot_lookat( pos, time, vel, doAimPredict )
{
self notify( "bots_aim_overlap" );
self endon( "bots_aim_overlap" );
self endon( "disconnect" );
self endon( "player_downed" );
level endon( "end_game" );
if ( !isDefined( pos ) )
return;
if ( !isDefined( doAimPredict ) )
doAimPredict = false;
if ( !isDefined( time ) )
time = 0.05;
if ( !isDefined( vel ) )
vel = ( 0, 0, 0 );
steps = int( time * 20 );
if ( steps < 1 )
steps = 1;
myEye = self scripts\sp\bots\_bot_utility::GetEyePos(); // get our eye pos
if ( doAimPredict )
{
myEye += ( self getVelocity() * 0.05 ) * ( steps - 1 ); // account for our velocity
pos += ( vel * 0.05 ) * ( steps - 1 ); // add the velocity vector
}
myAngle = self getPlayerAngles();
angles = VectorToAngles( ( pos - myEye ) - anglesToForward( myAngle ) );
X = AngleClamp180( angles[0] - myAngle[0] );
X = X / steps;
Y = AngleClamp180( angles[1] - myAngle[1] );
Y = Y / steps;
for ( i = 0; i < steps; i++ )
{
myAngle = ( AngleClamp180(myAngle[0] + X), AngleClamp180(myAngle[1] + Y), 0 );
self setPlayerAngles( myAngle );
wait 0.05;
}
}

View File

@ -1,240 +0,0 @@
bot_movetoobjective()
{
action_id = self.action_queue[ "objective" ][ 0 ].action_id;
at_obj_distance_sq = 48 * 48;
while ( isDefined( self.action_queue[ "objective" ][ 0 ] ) && action_id == self.action_queue[ "objective" ][ 0 ].action_id )
{
if ( distanceSquared( self.origin, self.target_pos ) < at_obj_distance_sq )
{
self bot_set_complete_movetoobjective();
break;
}
wait 0.2;
}
}
bot_movetoobjective_process_order()
{
return 0;
}
bot_should_movetoobjective()
{
if ( isDefined( self.action_queue[ "objective" ][ 0 ] ) )
{
return true;
}
return false;
}
bot_check_complete_movetoobjective()
{
return self.successfully_moved_to_objective;
}
bot_set_complete_movetoobjective()
{
self.successfully_moved_to_objective = true;
}
bot_movetoobjective_on_completion()
{
self.successfully_moved_to_objective = false;
self.can_do_objective_now = true;
}
bot_movetoobjective_should_cancel()
{
return false;
}
bot_movetoobjective_on_cancel()
{
self.successfully_moved_to_objective = false;
self.can_do_objective_now = false;
}
bot_movetoobjective_should_postpone()
{
if ( self bot_should_flee() )
{
return true;
}
return false;
}
bot_movetoobjective_on_postpone()
{
self.successfully_moved_to_objective = false;
self.can_do_objective_now = false;
}
bot_movetoobjective_priority()
{
return 0;
}
bot_train()
{
}
bot_train_process_order()
{
return 0;
}
bot_should_train()
{
return false;
}
bot_check_complete_train()
{
return false;
}
bot_set_complete_train()
{
}
bot_train_on_completion()
{
}
bot_train_should_cancel()
{
return false;
}
bot_train_on_cancel()
{
}
bot_train_should_postpone()
{
return false;
}
bot_train_on_postpone()
{
}
bot_train_priority()
{
return 0;
}
bot_camp()
{
}
bot_camp_process_order()
{
return 0;
}
bot_should_camp()
{
return false;
}
bot_check_complete_camp()
{
return false;
}
bot_set_complete_camp()
{
}
bot_camp_on_completion()
{
}
bot_camp_should_cancel()
{
return false;
}
bot_camp_on_cancel()
{
}
bot_camp_should_postpone()
{
return false;
}
bot_camp_on_postpone()
{
}
bot_camp_priority()
{
return 0;
}
bot_flee()
{
}
bot_flee_process_order()
{
return 0;
}
bot_should_flee()
{
return false;
}
bot_check_complete_flee()
{
return false;
}
bot_set_complete_flee()
{
}
bot_flee_on_completion()
{
}
bot_flee_should_cancel()
{
return false;
}
bot_flee_on_cancel()
{
}
bot_flee_should_postpone()
{
return false;
}
bot_flee_on_postpone()
{
}
bot_flee_priority()
{
return 0;
}

View File

@ -1,867 +0,0 @@
#include scripts\sp\bots\bot_objective_common;
bot_magicbox_purchase()
{
self.target_pos = self.available_chests[ 0 ].origin;
}
bot_magicbox_process_order()
{
}
bot_should_purchase_magicbox()
{
if ( !level.enable_magic )
{
return false;
}
if ( level.chests.size <= 0 )
{
return false;
}
self.available_chests = [];
for ( i = 0; i < level.chests.size; i++ )
{
if ( level.chests[ i ].hidden )
{
continue;
}
if ( self.score < level.chests[ i ].zombie_cost )
{
continue;
}
self.available_chests[ self.available_chests.size ] = level.chests[ i ];
}
if ( self.available_chests.size > 0 )
{
for ( i = 0; i < self.available_chests.size; i++ )
{
if ( isDefined( self.available_chests[ i ].chest_user ) )
{
maps\_utility::array_remove_index( self.available_chests, i );
i--;
}
}
}
return self.available_chests.size > 0;
}
bot_check_complete_magicbox()
{
return false;
}
bot_set_complete_magicbox()
{
}
bot_magicbox_purchase_on_completion()
{
}
bot_magicbox_purchase_should_cancel()
{
return false;
}
bot_magicbox_purchase_on_cancel()
{
}
bot_magicbox_purchase_should_postpone()
{
return false;
}
bot_magicbox_purchase_on_postpone()
{
}
bot_magicbox_purchase_priority()
{
priority = 0;
LOW_AMMO_THRESHOLD = 0.3;
weapons = self getWeaponsListPrimaries();
if ( weapons.size < 2 )
{
priority += 1;
}
for ( j = 0; j < weapons.size; j++ )
{
if ( self getWeaponAmmoStock( weapons[ j ] ) <= int( weaponmaxammo( weapons[ j ] ) * LOW_AMMO_THRESHOLD ) )
{
priority += 1;
}
}
return priority;
}
bot_wallbuy_purchase()
{
}
bot_wallbuy_process_order()
{
return 0;
}
bot_should_purchase_wallbuy()
{
return false;
}
bot_check_complete_wallbuy()
{
return false;
}
bot_set_complete_wallbuy()
{
}
bot_wallbuy_purchase_on_completion()
{
}
bot_wallbuy_purchase_should_cancel()
{
return false;
}
bot_wallbuy_purchase_on_cancel()
{
}
bot_wallbuy_purchase_should_postpone()
{
return false;
}
bot_wallbuy_purchase_on_postpone()
{
}
bot_wallbuy_purchase_priority()
{
return 0;
}
bot_wallbuy_ammo_purchase()
{
}
bot_wallbuyammo_process_order()
{
return 0;
}
bot_should_purchase_wallbuy_ammo()
{
return false;
}
bot_check_complete_wallbuy_ammo()
{
return false;
}
bot_set_complete_wallbuy_ammo()
{
}
bot_wallbuy_ammo_purchase_on_completion()
{
}
bot_wallbuy_ammo_purchase_should_cancel()
{
return false;
}
bot_wallbuy_ammo_purchase_on_cancel()
{
}
bot_wallbuy_ammo_purchase_should_postpone()
{
return false;
}
bot_wallbuy_ammo_purchase_on_postpone()
{
}
bot_wallbuy_ammo_purchase_priority()
{
return 0;
}
bot_perk_purchase()
{
}
bot_perk_process_order()
{
return 0;
}
bot_should_purchase_perk()
{
return false;
}
bot_check_complete_perk_purchase()
{
return false;
}
bot_set_complete_perk_purchase()
{
}
bot_perk_purchase_on_completion()
{
}
bot_perk_purchase_should_cancel()
{
return false;
}
bot_perk_purchase_on_cancel()
{
}
bot_perk_purchase_should_postpone()
{
return false;
}
bot_perk_purchase_on_postpone()
{
}
bot_perk_purchase_priority()
{
return 0;
}
bot_door_purchase()
{
}
bot_door_process_order()
{
return 0;
}
bot_should_purchase_door()
{
return false;
}
bot_check_complete_door_purchase()
{
return false;
}
bot_set_complete_door_purchase()
{
}
bot_door_purchase_on_completion()
{
}
bot_door_purchase_should_cancel()
{
return false;
}
bot_door_purchase_on_cancel()
{
}
bot_door_purchase_should_postpone()
{
return false;
}
bot_door_purchase_on_postpone()
{
}
bot_door_purchase_priority()
{
return 0;
}
bot_debris_purchase()
{
}
bot_debris_process_order()
{
return 0;
}
bot_should_purchase_debris()
{
return false;
}
bot_check_complete_debris_purchase()
{
return false;
}
bot_set_complete_debris_purchase()
{
}
bot_debris_purchase_on_completion()
{
}
bot_debris_purchase_should_cancel()
{
return false;
}
bot_debris_purchase_on_cancel()
{
}
bot_debris_purchase_should_postpone()
{
return false;
}
bot_debris_purchase_on_postpone()
{
}
bot_debris_purchase_priority()
{
return 0;
}
bot_trap_purchase()
{
}
bot_trap_process_order()
{
return 0;
}
bot_should_purchase_trap()
{
return false;
}
bot_check_complete_trap_purchase()
{
return false;
}
bot_set_complete_trap_purchase()
{
}
bot_trap_purchase_on_completion()
{
}
bot_trap_purchase_should_cancel()
{
return false;
}
bot_trap_purchase_on_cancel()
{
}
bot_trap_purchase_should_postpone()
{
return false;
}
bot_trap_purchase_on_postpone()
{
}
bot_trap_purchase_priority()
{
return 0;
}
bot_packapunch_purchase()
{
}
bot_packapunch_process_order()
{
return 0;
}
bot_should_purchase_packapunch()
{
return false;
}
bot_check_complete_packapunch_purchase()
{
return false;
}
bot_set_complete_packapunch_purchase()
{
}
bot_packapunch_purchase_on_completion()
{
}
bot_packapunch_purchase_should_cancel()
{
return false;
}
bot_packapunch_purchase_on_cancel()
{
}
bot_packapunch_purchase_should_postpone()
{
return false;
}
bot_packapunch_purchase_on_postpone()
{
}
bot_packapunch_purchase_priority()
{
return 0;
}
bot_revive_player()
{
if ( !isDefined( self.available_revives ) || self.available_revives.size <= 0 )
{
return;
}
self endon( "disconnect" );
level endon( "end_game" );
player_to_revive_obj = self.available_revives[ 0 ];
set_bot_global_shared_objective_owner_by_reference( "revive", player_to_revive_obj, self );
player_to_revive = player_to_revive_obj.target_ent;
action_id = self.action_queue[ "objective" ][ 0 ].action_id;
//If player is no longer valid to revive stop trying to revive
//If bot doesn't have an objective anymore or the objective has changed stop trying to revive
while ( isDefined( player_to_revive ) && isDefined( player_to_revive_obj ) && isDefined( self.action_queue[ "objective" ][ 0 ] ) && action_id == self.action_queue[ "objective" ][ 0 ].action_id )
{
self.target_pos = player_to_revive.origin;
if ( self.can_do_objective_now )
{
//TODO: Add check to see if another player is reviving target player
//TODO: Add code to revive player, possibly add the ability to circle revive?
}
wait 0.2;
}
}
bot_revive_process_order()
{
return 0;
}
bot_should_revive_player()
{
downed_players_objs = get_all_objectives_for_group( "revive" );
if ( downed_players_objs.size <= 0 )
{
return false;
}
self.available_revives = [];
obj_keys = getArrayKeys( downed_players_objs );
for ( i = 0; i < downed_players_objs.size; i++ )
{
if ( isDefined( downed_players_objs[ obj_keys[ i ] ].owner ) )
{
continue;
}
self.available_revives[ self.available_revives.size ] = downed_players_objs[ obj_keys[ i ] ];
}
return self.available_revives.size > 0;
}
bot_check_complete_revive_player()
{
if ( self.successfully_revived_player )
{
return true;
}
return false;
}
bot_set_complete_revive_player()
{
self.successfully_revived_player = true;
}
bot_revive_player_on_completion()
{
self.successfully_revived_player = false;
}
bot_revive_player_should_cancel()
{
return !isDefined( self.available_revives[ 0 ].target_ent.revivetrigger );
}
bot_revive_player_on_cancel()
{
}
bot_revive_player_should_postpone()
{
return false;
}
bot_revive_player_on_postpone()
{
}
bot_revive_player_priority()
{
return 0;
}
bot_grab_buildable()
{
}
bot_grab_buildable_process_order()
{
return 0;
}
bot_should_grab_buildable()
{
return false;
}
bot_check_complete_grab_buildable()
{
return false;
}
bot_set_complete_grab_buildable()
{
}
bot_grab_buildable_on_completion()
{
}
bot_grab_buildable_should_cancel()
{
return false;
}
bot_grabbuild_buildable_on_cancel()
{
}
bot_grab_buildable_should_postpone()
{
return false;
}
bot_grab_buildable_on_postpone()
{
}
bot_grab_buildable_priority()
{
return 0;
}
bot_build_buildable()
{
}
bot_build_buildable_process_order()
{
return 0;
}
bot_should_build_buildable()
{
return false;
}
bot_check_complete_build_buildable()
{
return false;
}
bot_set_complete_build_buildable()
{
}
bot_build_buildable_on_completion()
{
}
bot_build_buildable_should_cancel()
{
return false;
}
bot_build_buildable_on_cancel()
{
}
bot_build_buildable_should_postpone()
{
return false;
}
bot_build_buildable_on_postpone()
{
}
bot_build_buildable_priority()
{
return 0;
}
bot_grab_part()
{
}
bot_part_process_order()
{
return 0;
}
bot_should_grab_part()
{
return false;
}
bot_part_on_completion()
{
}
bot_part_should_cancel()
{
return false;
}
bot_check_complete_grab_part()
{
return false;
}
bot_set_complete_grab_part()
{
}
bot_part_on_cancel()
{
}
bot_part_should_postpone()
{
return false;
}
bot_part_on_postpone()
{
}
bot_part_priority()
{
return 0;
}
bot_grab_powerup()
{
self endon( "powerup_end_think" );
if ( !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 )
{
return;
}
set_bot_global_shared_objective_owner_by_reference( "powerup", self.available_powerups[ 0 ], self );
while ( true )
{
self SetScriptGoal( self.available_powerups[ 0 ].target_ent.origin );
wait 0.05;
}
}
bot_powerup_process_order()
{
return 0;
}
bot_should_grab_powerup()
{
if ( level.zbot_objective_glob[ "powerup" ].active_objectives.size <= 0 )
{
return false;
}
MAX_DISTANCE_SQ = 10000 * 10000;
BOT_SPEED_WHILE_SPRINTING_SQ = 285 * 285;
self.available_powerups = [];
powerup_objectives = level.zbot_objective_glob[ "powerup" ].active_objectives;
obj_keys = getArrayKeys( powerup_objectives );
for ( i = 0; i < powerup_objectives.size; i++ )
{
obj = powerup_objectives[ obj_keys[ i ] ];
powerup = obj.target_ent;
if ( isDefined( obj.owner ) )
{
continue;
}
time_left = powerup.time_left_until_timeout;
distance_required_to_reach_powerup = distanceSquared( powerup.origin, self.origin );
if ( distance_required_to_reach_powerup > BOT_SPEED_WHILE_SPRINTING_SQ * time_left )
{
continue;
}
if ( distanceSquared( powerup.origin, self.origin ) > MAX_DISTANCE_SQ )
{
continue;
}
if ( !isDefined( generatePath( self.origin, powerup.origin, self.team, false ) ) )
{
continue;
}
self.available_powerups[ self.available_powerups.size ] = obj;
}
//TODO: Sort powerups by priority here
return self.available_powerups.size > 0;
}
bot_check_complete_grab_powerup()
{
if ( self.successfully_grabbed_powerup )
{
return true;
}
return false;
}
bot_set_complete_grab_powerup()
{
}
bot_powerup_on_completion()
{
self.successfully_grabbed_powerup = false;
}
bot_powerup_should_cancel()
{
return ( !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 );
}
bot_powerup_on_cancel()
{
}
bot_powerup_should_postpone()
{
return false;
}
bot_powerup_on_postpone()
{
}
bot_powerup_priority()
{
if ( !isDefined( self.available_powerups ) )
{
return 0;
}
return self.available_powerups[ 0 ].target_ent.priority;
}

View File

@ -1,279 +0,0 @@
/*
Bot actions are in two parts
*/
#include common_scripts\utility;
#include maps\_utility;
#include maps\so\zm_common\_zm_utility;
#include scripts\sp\bots\bot_utility;
register_bot_action( group_name, action_name, action_func, action_process_order_func, should_do_func, check_if_complete_func, set_complete_func, on_completion_func, should_cancel_func, on_cancel_func, should_postpone_func, on_postpone_func, priority_func )
{
if ( !isDefined( level.zbots_actions ) )
{
level.zbots_actions = [];
}
if ( !isDefined( level.zbots_actions[ group_name ] ) )
{
level.zbots_actions[ group_name ] = [];
}
if ( !isDefined( level.zbots_actions[ group_name ][ action_name ] ) )
{
level.zbots_actions[ group_name ][ action_name ] = spawnStruct();
}
level.zbots_actions[ group_name ][ action_name ].action = action_func;
level.zbots_actions[ group_name ][ action_name ].should_do_func = should_do_func;
level.zbots_actions[ group_name ][ action_name ].action_process_order_func = action_process_order_func;
level.zbots_actions[ group_name ][ action_name ].check_if_complete_func = check_if_complete_func;
level.zbots_actions[ group_name ][ action_name ].set_complete_func = set_complete_func;
level.zbots_actions[ group_name ][ action_name ].on_completion_func = on_completion_func;
level.zbots_actions[ group_name ][ action_name ].should_cancel_func = should_cancel_func;
level.zbots_actions[ group_name ][ action_name ].on_cancel_func = on_cancel_func;
level.zbots_actions[ group_name ][ action_name ].should_postpone_func = should_postpone_func;
level.zbots_actions[ group_name ][ action_name ].on_postpone_func = on_postpone_func;
level.zbots_actions[ group_name ][ action_name ].priority_func = priority_func;
}
initialize_bot_actions_queue()
{
group_keys = getArrayKeys( level.zbots_actions );
for ( i = 0; i < group_keys.size; i++ )
{
action_keys = getArrayKeys( level.zbots_actions[ group_keys[ i ] ] );
for ( j = 0; j < action_keys.size; j++ )
{
self register_bot_objective_action_for_queue( group_keys[ i ], action_keys[ j ] );
}
}
}
register_bot_objective_action_for_queue( group_name, action_name )
{
if ( !isDefined( self.zbot_actions_in_queue ) )
{
self.zbot_actions_in_queue = [];
}
if ( !isDefined( self.zbot_actions_in_queue[ group_name ] ) )
{
self.zbot_actions_in_queue[ group_name ] = [];
}
if ( !isDefined( self.zbot_actions_in_queue[ group_name ][ action_name ] ) )
{
self.zbot_actions_in_queue[ group_name ][ action_name ] = spawnStruct();
}
self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].canceled = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].completed = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = false;
}
process_next_queued_action( group_name )
{
if ( self.zbot_actions_in_queue[ group_name ][ self.action_queue[ group_name ][ 0 ].action_name ].queued )
{
return;
}
self.action_queue[ group_name ] = self sort_array_by_priority_field( self.action_queue[ group_name ] );
self thread [[ self.action_queue[ group_name ][ 0 ].action ]]();
self.zbot_actions_in_queue[ group_name ][ self.action_queue[ group_name ][ 0 ].action_name ].is_current = true;
self thread wait_for_action_completion( group_name, self.action_queue[ group_name ][ 0 ].action_name );
}
wait_for_action_completion( group_name, action_name )
{
self endon( "disconnect" );
self endon( "stop_action_think" );
level endon( "end_game" );
result = self waittill_any_return( action_name + "_complete", action_name + "_cancel", action_name + "_postpone" );
if ( ( result == action_name + "_complete" ) )
{
self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].completed = false;
self.action_queue[ group_name ][ 0 ] = undefined;
self thread [[ self.action_queue[ group_name ][ 0 ].on_completion_func ]]();
}
else if ( result == action_name + "_cancel" )
{
self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false;
self.zbot_actions_in_queue[ group_name ][ action_name ].completed = false;
self.action_queue[ group_name ][ 0 ] = undefined;
self thread [[ self.action_queue[ group_name ][ 0 ].on_cancel_func ]]();
}
else if ( result == action_name + "_postpone" )
{
self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = true;
postponed_action = self.action_queue[ group_name ][ 0 ];
self.action_queue[ group_name ][ 0 ] = undefined;
postponed_action.priority = self [[ level.zbots_actions[ group_name ][ action_name ].priority_func ]]();
self.action_queue[ group_name ] = array_insert( self.action_queue[ group_name ], postponed_action, 1 );
self thread [[ self.action_queue[ group_name ][ 0 ].on_postpone_func ]]();
}
self notify( action_name + "_end_think" );
self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = false;
}
copy_default_action_settings_to_queue( group_name, action_name )
{
//self.group = level.zbots_actions[ group_name ][ action_name ].group;
self.action = level.zbots_actions[ group_name ][ action_name ].action;
//self.should_do_func = level.zbots_actions[ group_name ][ action_name ].should_do_func;
self.on_completion_func = level.zbots_actions[ group_name ][ action_name ].on_completion_func;
self.should_cancel_func = level.zbots_actions[ group_name ][ action_name ].should_cancel_func;
self.on_cancel_func = level.zbots_actions[ group_name ][ action_name ].on_cancel_func;
self.should_postpone_func = level.zbots_actions[ group_name ][ action_name ].should_postpone_func;
self.on_postpone_func = level.zbots_actions[ group_name ][ action_name ].on_postpone_func;
self.priority_func = level.zbots_actions[ group_name ][ action_name ].priority_func;
}
pick_actions_to_add_to_queue( group_name )
{
action_keys = getArrayKeys( level.zbots_actions[ group_name ] );
//TODO: Use process order funcs to determine the order of actions being added to the queue
//For now just randomize the order of the keys
/*
for ( i = 0; i < action_keys; i++ )
{
}
*/
if ( !isDefined( self.action_id ) )
{
self.action_id = 0;
}
for ( i = 0; i < action_keys.size; i++ )
{
if ( !self.zbot_actions_in_queue[ group_name ][ action_keys[ i ] ].queued && [[ level.zbots_actions[ group_name ][ action_keys[ i ] ].should_do_func ]]() )
{
self.action_queue[ group_name ][ self.action_queue[ group_name ].size ] = spawnStruct();
self.action_queue[ group_name ][ self.action_queue[ group_name ].size - 1 ].action_name = action_keys[ i ];
self.action_queue[ group_name ][ self.action_queue[ group_name ].size - 1 ].action_id = self.action_id;
self.action_queue[ group_name ][ self.action_queue[ group_name ].size - 1 ].priority = self [[ level.zbots_actions[ group_name ][ action_keys[ i ] ].priority_func ]]();
self.zbot_actions_in_queue[ group_name ][ action_keys[ i ] ].queued = true;
self.action_id++;
}
}
}
bot_clear_actions_queue()
{
group_keys = getArrayKeys( level.zbots_actions );
for ( i = 0; i < group_keys.size; i++ )
{
self.action_queue[ group_keys[ i ] ] = [];
action_keys = getArrayKeys( level.zbots_actions[ group_keys[ i ] ] );
for ( j = 0; j < action_keys.size; j++ )
{
self register_bot_objective_action_for_queue( group_keys[ i ], action_keys[ j ] );
}
}
}
check_if_action_is_completed_in_group( group_name )
{
if ( [[ level.zbots_actions[ group_name ][ self.action_queue[ group_name ][ 0 ].action_name ].check_if_complete_func ]]() )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_complete" );
}
}
check_if_action_should_be_postponed_in_group( group_name )
{
if ( [[ level.zbots_actions[ group_name ][ self.action_queue[ group_name ][ 0 ].action_name ].should_postpone_func ]]() )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_postpone" );
}
}
check_if_action_should_be_canceled_in_group( group_name )
{
if ( [[ level.zbots_actions[ group_name ][ self.action_queue[ group_name ][ 0 ].action_name ].should_cancel_func ]]() )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_cancel" );
}
}
check_if_action_should_be_postponed_globally( group_name )
{
if ( action_should_be_postponed_global( group_name, self.action_queue[ group_name ][ 0 ].action_name ) )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_postpone" );
}
}
check_if_action_should_be_canceled_globally( group_name )
{
if ( action_should_be_canceled_global( group_name, self.action_queue[ group_name ][ 0 ].action_name ) )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_cancel" );
}
}
//TODO: Figure out way of overriding the current action for flee movement action
check_for_forced_action( group_name )
{
action_keys = getArrayKeys( level.zbots_actions[ group_name ] );
action_priorities_array = [];
for ( i = 0; i < action_keys.size; i++ )
{
action_priorities_array[ action_priorities_array.size ] = spawnStruct();
action_priorities_array[ action_priorities_array.size - 1 ].priority = self [[ level.zbots_actions[ group_name ][ action_keys[ i ] ].priority_func ]]();
action_priorities_array[ action_priorities_array.size - 1 ].action_name = action_keys[ i ];
}
action_priorities_array = sort_array_by_priority_field( action_priorities_array );
if ( self.action_queue[ group_name ][ 0 ].priority < action_priorities_array[ 0 ].priority )
{
self notify( self.action_queue[ group_name ][ 0 ].action_name + "_cancel" );
}
}
bot_action_think( group_name )
{
self pick_actions_to_add_to_queue( group_name );
//self check_for_forced_action( group_name );
if ( self.action_queue[ group_name ].size <= 0 )
{
return;
}
self process_next_queued_action( group_name );
self check_if_action_is_completed_in_group( group_name );
self check_if_action_should_be_postponed_in_group( group_name );
self check_if_action_should_be_canceled_in_group( group_name );
self check_if_action_should_be_postponed_globally( group_name );
self check_if_action_should_be_canceled_globally( group_name );
}
action_should_be_postponed_global( primary_group_name, action_name )
{
return false;
}
action_should_be_canceled_global( primary_group_name, action_name )
{
return false;
}
//TODO: Add ability to pause an action so the bot won't be doing it while its paused but when its unpaused they can resume the action with the same settings
//Similar to postpone except instead of selecting a new action the current action is preserved
action_should_be_paused_global( primary_group_name, action_name )
{
return false;
}

View File

@ -1,9 +0,0 @@
register_bot_difficulty( difficulty )
{
if ( !isDefined( level.zbot_difficulties ) )
{
level.zbot_difficulties = [];
}
level.zbot_difficulties[ difficulty ] = true;
}

View File

@ -1,207 +0,0 @@
register_bot_objective( objective_group )
{
if ( !isDefined( level.zbot_objective_glob ) )
{
level.zbot_objective_glob = [];
}
if ( !isDefined( level.zbot_objective_glob[ objective_group ] ) )
{
level.zbot_objective_glob[ objective_group ] = spawnStruct();
level.zbot_objective_glob[ objective_group ].active_objectives = [];
}
}
add_possible_bot_objective( objective_group, id, is_global_shared, target_ent )
{
assert( isDefined( level.zbot_objective_glob ), "Trying to add objective before calling register_bot_objective" );
assert( isDefined( level.zbot_objective_glob[ objective_group ] ), "Trying to add objective to group " + objective_group + " before calling register_bot_objective" );
objective_struct = spawnStruct();
objective_struct.group = objective_group;
objective_struct.id = id;
objective_struct.is_global_shared = is_global_shared;
objective_struct.target_ent = target_ent;
objective_struct.owner = undefined;
objective_struct.is_objective = true;
level.zbot_objective_glob[ objective_group ].active_objectives[ "obj_id_" + id ] = objective_struct;
}
get_bot_objective_by_id( objective_group, id )
{
active_objectives = level.zbot_objective_glob[ objective_group ].active_objectives;
objective = active_objectives[ "obj_id_" + id ];
assert( isDefined( objective ), "Objective with " + id + " id does not point to a objective in group " + objective_group );
return objective;
}
get_all_objectives_for_group( objective_group )
{
return level.zbot_objective_glob[ objective_group ].active_objectives;
}
set_objective_for_bot( objective_group, id )
{
possible_objectives = level.zbot_objective_glob[ objective_group ].active_objectives;
objective = possible_objectives[ "obj_id_" + id ];
objective_exists = isDefined( objective );
assert( objective_exists, "Objective with " + id + " id does not point to a objective in group " + objective_group );
if ( !objective_exists )
{
return;
}
self.zbot_current_objective = objective;
}
clear_objective_for_bot()
{
self.zbot_current_objective = undefined;
}
set_bot_objective_blocked_by_objective( primary_objective_group, primary_id, blocked_by_objective_group, blocked_by_id )
{
primary_active_objectives = level.zbot_objective_glob[ primary_objective_group ].active_objectives;
primary_objective = primary_active_objectives[ "obj_id_" + primary_id ];
primary_objective_exists = isDefined( primary_objective );
assert( primary_objective_exists, "Objective with " + primary_id + " id does not point to a objective in group " + primary_objective_group );
if ( !primary_objective_exists )
{
return;
}
if ( primary_objective_group == blocked_by_objective_group )
{
assert( primary_id != blocked_by_id, "Objective with " + primary_id + " id should not be the same as the blocked_by_id if the objectives are in the same group of " + primary_objective_group );
if ( primary_id == blocked_by_id )
{
return;
}
blocking_objective = primary_active_objectives[ "obj_id_" + blocked_by_id ];
blocking_objective_exists = isDefined( blocking_objective );
assert( blocking_objective_exists, "Objective with " + blocked_by_id + " id does not point to a objective in group " + blocked_by_objective_group );
if ( !blocking_objective_exists )
{
return;
}
primary_objective.blocking_objective = blocking_objective;
}
else
{
secondary_active_objectives = level.zbot_objective_glob[ blocked_by_objective_group ].active_objectives;
blocking_objective = secondary_active_objectives[ "obj_id_" + blocked_by_id ];
blocking_objective_exists = isDefined( blocking_objective );
assert( blocking_objective_exists, "Objective with " + blocked_by_id + " id does not point to a objective in group " + blocked_by_objective_group );
if ( !blocking_objective_exists )
{
return;
}
primary_objective.blocking_objective = blocking_objective;
}
}
set_bot_global_shared_objective_owner_by_id( objective_group, id, new_owner )
{
active_objectives = level.zbot_objective_glob[ objective_group ].active_objectives;
objective = active_objectives[ "obj_id_" + id ];
objective_exists = isDefined( objective );
assert( objective_exists, "Objective with " + id + " id number does not point to a objective in group " + objective_group );
if ( !objective_exists )
{
return;
}
assert( objective.is_global_shared, "Objective with " + id + " id number cannot be set to have an owner because is_global_shared field is false in group " + objective_group );
if ( !objective.is_global_shared )
{
return;
}
objective.owner = new_owner;
}
set_bot_global_shared_objective_owner_by_reference( objective_group, objective, new_owner )
{
is_objective = isDefined( objective.is_objective );
assert( is_objective, "Objective arg is not a valid objective object" );
if ( !is_objective )
{
return;
}
assert( objective.is_global_shared, "Objective with " + objective.id + " id number cannot be set to have an owner because is_global_shared field is false in group " + objective_group );
if ( !objective.is_global_shared )
{
return;
}
objective.owner = new_owner;
}
free_bot_objective( objective_group, id )
{
active_objectives = level.zbot_global_shared_objective_glob[ objective_group ].active_objectives;
objective = active_objectives[ "obj_id_" + id ];
objective_exists = isDefined( objective );
assert( objective_exists, "Objective with " + id + " id number does not point to a objective in group " + objective_group );
if ( !objective_exists )
{
return;
}
players = getPlayers();
for ( i = 0; i < players.size; i++ )
{
if ( players[ i ].pers[ "isBot" ] )
{
if ( players[ i ].zbot_current_objective == objective )
{
players[ i ].zbot_current_objective = undefined;
}
}
}
objective = undefined;
}
objective_think( objective_group, id )
{
active_objectives = level.zbot_global_shared_objective_glob[ objective_group ].active_objectives;
objective = active_objectives[ "obj_id_" + id ];
objective_exists = isDefined( objective );
assert( objective_exists, "Objective with " + id + " id number does not point to a objective in group " + objective_group );
if ( !objective_exists )
{
return;
}
level endon( "end_obj_think_" + objective.target_ent getEntityNumber() );
while ( true )
{
if ( )
wait 0.05;
}
}

View File

@ -1,10 +0,0 @@
register_bot_personality_type( personality )
{
if ( !isDefined( level.zbot_personalities ) )
{
level.zbot_personalities = [];
}
level.zbot_personalities[ personality ] = true;
}

View File

@ -1,194 +0,0 @@
#include common_scripts\utility;
#include scripts\sp\bots\_bot_utility;
register_bot_target_type( target_group )
{
if ( !isDefined( level.zbot_target_glob ) )
{
level.zbot_target_glob = [];
level.zbot_target_glob_ids = [];
}
if ( !isDefined( level.zbot_target_glob[ target_group ] ) )
{
level.zbot_target_glob_ids[ target_group ] = 0;
level.zbot_target_glob[ target_group ] = spawnStruct();
level.zbot_target_glob[ target_group ].active_targets = [];
}
}
add_possible_bot_target( target_group, id, target_ent )
{
assert( isDefined( level.zbot_target_glob ), "Trying to add target before calling register_bot_target_type" );
assert( isDefined( level.zbot_target_glob[ target_group ] ), "Trying to add target to group " + target_group + " before calling register_bot_target_type" );
target_struct = spawnStruct();
target_struct.group = target_group;
target_struct.target_id = id;
target_struct.damaged_by = [];
target_struct.targeted_by = [];
target_struct.target_ent = target_ent;
target_struct.is_target = true;
level.zbot_target_glob[ target_group ].active_targets[ "targ_id_" + id ] = target_struct;
}
get_bot_target_by_id( target_group, id )
{
active_targets = level.zbot_target_glob[ target_group ].active_targets;
target = active_targets[ "targ_id_" + id ];
assert( isDefined( target ), "Target with " + id + " id does not point to a target in group " + target_group );
return target;
}
get_all_targets_for_group( target_group )
{
return level.zbot_target_glob[ target_group ].active_targets;
}
get_all_groups_for_targets()
{
return getArrayKeys( level.zbot_target_glob );
}
bot_has_target()
{
return isDefined( self.zbot_current_target );
}
set_target_for_bot( target_group, id )
{
possible_targets = level.zbot_target_glob[ target_group ].active_targets;
target = possible_targets[ "targ_id_" + id ];
target_exists = isDefined( target );
assert( target_exists, "Target with " + id + " id does not point to a target in group " + target_group );
if ( !target_exists )
{
return;
}
self.zbot_current_target = target;
for ( i = 0; i < target.targeted_by.size; i++ )
{
if ( target.targeted_by[ i ] == self )
{
return;
}
}
target.targeted_by[ target.targeted_by.size ] = self;
}
clear_target_for_bot( target_group, id )
{
possible_targets = level.zbot_target_glob[ target_group ].active_targets;
target = possible_targets[ "targ_id_" + id ];
target_exists = isDefined( target );
assert( target_exists, "Target with " + id + " id does not point to a target in group " + target_group );
if ( !target_exists )
{
return;
}
for ( i = 0; i < target.targeted_by.size; i++ )
{
if ( target.targeted_by[ i ] == self )
{
target.targeted_by[ i ] = undefined;
return;
}
}
self.zbot_current_target = undefined;
}
set_target_damaged_by( target_group, id )
{
possible_targets = level.zbot_target_glob[ target_group ].active_targets;
target = possible_targets[ "targ_id_" + id ];
target_exists = isDefined( target );
assert( target_exists, "Target with " + id + " id does not point to a target in group " + target_group );
if ( !target_exists )
{
return;
}
for ( i = 0; i < target.damaged_by.size; i++ )
{
if ( target.damaged_by[ i ] == self )
{
return;
}
}
target.damaged_by[ target.damaged_by.size ] = self;
}
clear_target_damaged_by( target_group, id )
{
possible_targets = level.zbot_target_glob[ target_group ].active_targets;
target = possible_targets[ "targ_id_" + id ];
target_exists = isDefined( target );
assert( target_exists, "Target with " + id + " id does not point to a target in group " + target_group );
if ( !target_exists )
{
return;
}
for ( i = 0; i < target.damaged_by.size; i++ )
{
if ( target.damaged_by[ i ] == self )
{
target.damaged_by[ i ] = undefined;
return;
}
}
}
free_bot_target( target_group, id )
{
active_targets = level.zbot_global_shared_target_glob[ target_group ].active_targets;
target = active_targets[ "targ_id_" + id ];
target_exists = isDefined( target );
assert( target_exists, "Target with " + id + " id number does not point to a target in group " + target_group );
if ( !target_exists )
{
return;
}
players = getPlayers();
for ( i = 0; i < players.size; i++ )
{
if ( players[ i ].pers[ "isBot" ] )
{
if ( players[ i ].zbot_current_target == target )
{
players[ i ].zbot_current_target = undefined;
}
}
}
target.damaged_by = undefined;
target.targeted_by = undefined;
target = undefined;
}

View File

@ -1,625 +0,0 @@
#include common_scripts\utility;
#include maps\_utility;
#include maps\so\zm_common\_zm_utility;
register_stats_for_bot_weapon( weapon, score )
{
if ( !isDefined( level.bot_weapons_stats ) )
{
level.bot_weapons_stats = [];
}
level.bot_weapons_stats[ weapon ] = score;
}
parse_bot_weapon_stats_from_table()
{
WEAPON_COLUMN = 0;
SCORE_COLUMN = 1;
/*
row = 0;
while ( true )
{
weapon = fs_tablelookupcolumnforrow( "tables\bot_weapon_stats.csv", row, WEAPON_COLUMN );
if ( !isDefined( weapon ) || weapon == "" )
{
break;
}
score = fs_tablelookupcolumnforrow( "tables\bot_weapon_stats.csv", row, SCORE_COLUMN );
if ( !isDefined( score ) || score == "" )
{
row++;
continue;
}
if ( isDefined( level.zombie_include_weapons[ weapon + "_zm" ] ) )
{
register_stats_for_bot_weapon( weapon + "_zm", int( score ) );
if ( isDefined( level.zombie_include_weapons[ weapon + "_upgraded_zm" ] ) )
{
register_stats_for_bot_weapon( weapon + "_upgraded_zm", int( score ) + 1 );
}
}
else if ( isDefined( level.zombie_include_weapons[ weapon ] ) )
{
register_stats_for_bot_weapon( weapon, int( score ) );
}
row++;
}
*/
}
array_add2( array, item )
{
array[ array.size ] = item;
}
swap( array, index1, index2 )
{
temp = array[ index1 ];
array[ index1 ] = array[ index2 ];
array[ index2 ] = temp;
return array;
}
merge_sort( current_list, func_sort, param )
{
if ( current_list.size <= 1 )
{
return current_list;
}
left = [];
right = [];
middle = current_list.size / 2;
for ( x = 0; x < middle; x++ )
{
array_add2( left, current_list[ x ] );
}
for ( ; x < current_list.size; x++ )
{
array_add2( right, current_list[ x ] );
}
left = merge_sort( left, func_sort, param );
right = merge_sort( right, func_sort, param );
//result = merge( left, right, func_sort, param );
//return result;
}
quickSort(array, compare_func)
{
return quickSortMid(array, 0, array.size - 1, compare_func);
}
quickSortMid( array, start, end, compare_func )
{
i = start;
k = end;
if(!IsDefined(compare_func))
compare_func = ::quicksort_compare;
if (end - start >= 1)
{
pivot = array[start];
while (k > i)
{
while ( [[ compare_func ]](array[i], pivot) && i <= end && k > i)
i++;
while ( ![[ compare_func ]](array[k], pivot) && k >= start && k >= i)
k--;
if (k > i)
array = swap(array, i, k);
}
array = swap(array, start, k);
array = quickSortMid(array, start, k - 1, compare_func);
array = quickSortMid(array, k + 1, end, compare_func);
}
else
return array;
return array;
}
quicksort_compare(left, right)
{
return left <= right;
}
get_allies()
{
return getPlayers( self.team );
}
get_zombies()
{
return getAiSpeciesArray( level.zombie_team, "all" );
}
find_gaps()
{
}
are_enemies_horded()
{
MINIMUM_PERCENT_TO_BE_HORDE = 0.9;
DISTANCE_SQ = 120 * 120;
zombies = get_zombies();
amount_in_horde = 0;
if ( isDefined( level.speed_change_round ) )
{
max_eligible_zombies = zombies.size - level.speed_change_num;
}
else
{
max_eligible_zombies = zombies.size;
}
expected_amount_in_horde_min = int( max_eligible_zombies * MINIMUM_PERCENT_TO_BE_HORDE );
if ( isDefined( level.speed_change_round ) )
{
for ( i = 0; i < zombies.size; i++ )
{
if ( zombies[ i ].zombie_move_speed == "walk" )
{
continue;
}
if ( !isDefined( zombies[ i + 1 ] ) )
{
return false;
}
if ( zombies[ i + 1 ].zombie_move_speed != "walk" )
{
if ( distanceSquared( zombies[ i + 1 ].origin, zombies[ i ].origin ) <= DISTANCE_SQ )
{
amount_in_horde++;
}
}
if ( amount_in_horde >= expected_amount_in_horde_min )
{
return true;
}
}
}
else
{
for ( i = 0; i < zombies.size; i++ )
{
if ( !isDefined( zombies[ i + 1 ] ) )
{
return false;
}
if ( distanceSquared( zombies[ i + 1 ].origin, zombies[ i ].origin ) <= DISTANCE_SQ )
{
amount_in_horde++;
}
if ( amount_in_horde >= expected_amount_in_horde_min )
{
return true;
}
}
}
return false;
}
any_enemies_in_direction( dir )
{
}
predict_entity_position_frames( frames )
{
current_velocity = self getVelocity();
predicted_origin = self.origin;
for ( i = 0; i < frames; i++ )
{
predicted_origin += ( current_velocity / 20 );
}
return predicted_origin;
}
predict_entity_position_seconds( seconds )
{
current_velocity = self getVelocity();
predicted_origin = self.origin;
for ( i = 0; i < seconds; i++ )
{
predicted_origin += current_velocity;
}
return predicted_origin;
}
any_zombies_targeting_self()
{
ZOMBIE_TARGETING_DIST_SQ = 10 * 10;
zombies = get_zombies();
if ( !array_validate( zombies ) )
{
return false;
}
for ( i = 0; i < zombies.size; i++ )
{
if ( isDefined( zombies[ i ].favoriteenemy ) && zombies[ i ].favoriteenemy == self )
{
return true;
}
if ( isDefined( zombies[ i ].goal_pos ) && distanceSquared( zombies[ i ].goal_pos, self.origin ) < ZOMBIE_TARGETING_DIST_SQ )
{
return true;
}
}
return false;
}
bot_is_in_danger( player )
{
return false;
}
bot_valid( player )
{
if ( !isdefined( player ) )
return false;
if ( !isalive( player ) )
return false;
if ( !isplayer( player ) )
return false;
if ( !is_true( player.pers[ "isBot" ] ) )
return false;
if ( isdefined( player.is_zombie ) && player.is_zombie == 1 )
return false;
if ( player.sessionstate == "spectator" )
return false;
if ( player.sessionstate == "intermission" )
return false;
if ( isdefined( player.intermission ) && player.intermission )
return false;
if ( isdefined( level.is_player_valid_override ) )
return [[ level.is_player_valid_override ]]( player );
return true;
}
assign_priority_to_powerup( powerup )
{
if ( !isDefined( powerup ) )
{
return;
}
priority = 0;
powerup_is_max_ammo = false;
switch ( powerup.powerup_name )
{
case "zombie_blood":
case "insta_kill":
case "nuke":
priority += 2;
break;
case "full_ammo":
powerup_is_max_ammo = true;
priority += 1;
break;
case "double_points":
case "fire_sale":
case "carpenter":
case "free_perk":
priority += 1;
break;
default:
priority += 0;
break;
}
if ( powerup_is_max_ammo )
{
LOW_AMMO_THRESHOLD = 0.3;
for ( i = 0; i < level.players.size; i++ )
{
weapons = level.players[ i ] getWeaponsListPrimaries();
for ( j = 0; j < weapons.size; j++ )
{
if ( self getWeaponAmmoStock( weapons[ j ] ) <= int( weaponmaxammo( weapons[ j ] ) * LOW_AMMO_THRESHOLD ) )
{
priority += 1;
break;
}
}
if ( priority > 3 )
{
break;
}
}
}
if ( maps\_laststand::player_any_player_in_laststand() )
{
switch ( powerup.powerup_name )
{
case "zombie_blood":
case "insta_kill":
case "nuke":
priority += 1;
break;
case "full_ammo":
priority += 0;
break;
case "double_points":
case "fire_sale":
case "carpenter":
case "free_perk":
priority -= 1;
break;
default:
priority += 0;
break;
}
}
if ( powerup.time_left_until_timeout < 10.0 )
{
priority += 1;
}
if ( priority < 0 )
{
priority = 0;
}
powerup.priority = priority;
}
sort_array_by_priority_field( array, item )
{
if ( isDefined( item ) )
{
array[ array.size ] = item;
}
priority_array = [];
for ( i = 0; i < array.size; i++ )
{
priority_array[ i ] = array[ i ].priority;
}
priority_array = quickSort( priority_array );
sorted_array = [];
for ( i = 0; i < priority_array.size; i++ )
{
for ( j = 0; j < array.size; j++ )
{
if ( array[ j ].priority == priority_array[ i ] )
{
sorted_array[ sorted_array.size ] = array[ j ];
}
}
}
return sorted_array;
}
/*
We need to calculate where the bot should go to next and update their movement constantly here
If the calculations predicts death or teammates death based on current course we need recalculate next move
Updating every frame(0.05) should be sufficient
Key to movement code is determining gaps, and safe lines to follow
Bot should try to find the nearest safe line and follow it
Due to many different variables(primarily resulting from other players) we need to constantly verify if the line is safe to follow
If the bot doesn't detect any danger allow them to stand still far enough away from the zombies to not draw aggro but close enough to shoot at them
Questions:
Can bots move and use the use button at the same time? Necessary to be able to support circle revive
How do we know the bot is safe where they are currently or where they will be moving to?
How do we determine gaps in zombies/terrain to slip through?
*/
movement_think()
{
while ( true )
{
}
}
/*
bot methods docs
enum BotGoalPriority
{
GOAL_PRIORITY_UNUSED = 0x0,
GOAL_PRIORITY_LOW = 0x1,
GOAL_PRIORITY_NORMAL = 0x2,
GOAL_PRIORITY_HIGH = 0x3,
GOAL_PRIORITY_URGENT = 0x4,
GOAL_PRIORITY_MAX = 0x5,
};
success = bot addGoal( <origin|pathnode>, float<goalRadius>, BotGoalPriority<priority>, string<notify> );
bot cancelGoal( string<notify> );
bot atGoal( string[notify] );
bot hasGoal( string<notify> );
origin = bot getGoal( string<notify> );
bot pressUseButton( float<time_in_seconds> );
bot pressAttackButton( float<time_in_seconds> );
bot pressDtpButton();
bot pressAds( <bool> );
bot pressMelee();
bot throwGrenade( string<weapon_name>, vector<destination> );
dist = bot getLookaheadDist();
dir = bot getLookAheadDir();
bot lookAt( vector<origin> );
bot clearLookat();
pos = bot predictPosition( entity<ent>, int<num_frames> );
success = bot sightTracePassed( entity<ent>, vector[point] );
enemies = bot getThreats( float<fov> ); //Fov value can be -1 to find all enemies instead of enemies in fov.
bot botSetFailsafeNode( pathnode[node] );
player methods docs
player allowStand( <bool> );
player allowCrouch( <bool> );
player allowProne( <bool> );
player allowAds( <bool> );
player allowSprint( <bool> );
player allowMelee( <bool> );
player setSpawnWeapon( string<weapon_name> );
player isLookingAt( <entity> );
ads_amount = player playerAds();
stance = player getstance();
player setStance( string<stance> );
dot = player playerSightTrace( vector<item_position>, int<unk>, int<hitnum> );
entity methods docs
mins = entity getMins();
maxes = entity getMaxes();
absmins = entity getAdbMins();
absmaxes = entity getAbsMaxes();
eye = entity getEye();
centroid = entity getCentroid()
velocity = entity getVelocity();
vector = entity getpointinbounds( float<x>, float<y>, float<z> );
is_touching = entity isTouching( entity<ent>, vector[extra_boundary] );
is_touching = entity isTouchingVolume( vector<origin>, vector<mins>, vector<maxes> );
dot = entity damageConeTrace( vector<damage_origin>, entity[ent], vector[damage_angles], float[damage_amount] );
dot = entity sightConeTrace( vector<damage_origin>, entity[ent], vector[damage_angles], float[damage_amount] );
common functions docs
nodeStringTable = {
"Path",
"Cover Stand",
"Cover Crouch",
"Cover Crouch Window",
"Cover Prone",
"Cover Right",
"Cover Left",
"Cover Pillar",
"Ambush",
"Exposed",
"Conceal Stand",
"Conceal Crouch",
"Conceal Prone",
"Reacquire",
"Balcony",
"Scripted",
"Begin",
"End",
"Turret",
"Guard"
}
enum team_t
{
TEAM_FREE = 0x0,
TEAM_BAD = 0x0,
TEAM_ALLIES = 0x1,
TEAM_AXIS = 0x2,
TEAM_THREE = 0x3,
TEAM_FOUR = 0x4,
TEAM_FIVE = 0x5,
TEAM_SIX = 0x6,
TEAM_SEVEN = 0x7,
TEAM_EIGHT = 0x8,
TEAM_NUM_PLAYING_TEAMS = 0x9,
TEAM_SPECTATOR = 0x9,
TEAM_NUM_TEAMS = 0xA,
TEAM_LOCALPLAYERS = 0xB,
TEAM_FIRST_PLAYING_TEAM = 0x1,
TEAM_LAST_PLAYING_TEAM = 0x8,
};
nodespawn_t nodespawns[21]
{
'node_pathnode'
'node_guard'
'node_turret'
'node_negotiation_end'
'node_negotiation_begin'
'node_scripted'
'node_balcony'
'node_reacquire'
'node_concealment_prone'
'node_concealment_crouch'
'node_concealment_stand'
'node_exposed'
'node_ambush'
'node_cover_pillar'
'node_cover_left'
'node_cover_right'
'node_cover_prone'
'node_cover_crouch_window'
'node_cover_crouch'
'node_cover_stand'
}
node = getNode( string<name>, entkey<key> );
nodes = getNodeArray( string<name>, entkey<key );
nodes = getNodeArraySorted( string<name>, entkey<key>, vector[origin], float[max_dist] );
nodes = getAnyNodeArray( vector<origin>, float<max_dist> );
nodes = getCoverNodeArray( vector<origin>, float<max_dist> );
nodes = getAllNodes();
nodes = getNodesInRadius( vector<origin>, float<max_radius>, float<min_radius>, float[max_height], nodeStringTable[type], int<max_nodes> );
nodes = getNodesInRadiusSorted( vector<origin>, float<max_radius>, float<min_radius>, float[max_height], nodeStringTable[type], int<max_nodes> );
node = getNearestNode( vector<origin> );
node = getVisibleNode( vector<start>, vector<end>, entity[ent] );
nodes = getVisibleNodes( node_ent<node> );
visible = nodesVisible( node_ent<node>, node_ent<node> );
canpath = nodesCanPath( node_ent<node>, node_ent<node> );
canclaimnode = canClaimNode( node_ent<node>, team_t<team> );
setEnableNode( node_ent<node>, [bool] );
linkNodes( node_ent<node>, node_ent<node> );
unLinkNodes( node_ent<node>, node_ent<node> );
nodesAreLinked( node_ent<node>, node_ent<node> );
dropnodetofloor( node_ent<node> );
node = spawnPathNode( nodespawn_t<classname>, vector<origin>, vector<angles>, key[key1], value[val1], ... );
deletePathNode( node_ent<node> );
occupied = isNodeOccupied( node_ent<node> );
nodeowner = getNodeOwner( node_ent<node> );
foundpath = findPath( vector<start>, vector<end>, entity[ent], bool[allow_negotiation_links], bool[allow_negotiation_hints] );
vector = vectorFromLineToPoint( vector<<start_pos>, vector<end_pos>, vector<point> );
point = pointOnSegmentNearestToPoint( vector<start_pos>, vector<end_pos>, vector<test_origin> );
pos_a_is_closer = closer( vector<ref_pos>, vector<a>, vector<b> );
dot = vectorDot( vector<a>, vector<b> );
cross = vectorCross( vector<a>, vector<b> );
normalized_vector = vectorNormalize( vector<vec> );
lerped_vector = vectorLerp( vector<from>, vector<to>, float<lerp> );
combined_angles = combineAngles( vector<a>, vector<b> );
angles = vectorToAngles( vector<vec> );
angle = absAngleClamp180( float<angle> );
angle = absAngleClamp360( float<angle> );
point = rotatePoint( vector<point>, vector<angles> );
trace
{
"fraction",
"position",
"entity",
"normal",
"surfacetype"
}
trace = bulletTrace( vector<end_pos>, vector<start_pos>, bool<use_content_mask_flag>, entity<ignore_ent>, bool[modify_contents_flags1], bool[modify_contents_flags2] );
passed = bulletTracePassed( vector<start_pos>, vector<end_pos>, bool<use_clipmask>, entity<ignore_ent>, entity[ignore_ent2?], bool[check_fx_visibility] );
trace = groundTrace( vector<end_pos>, vector<start_pos>, bool<use_content_mask_flag>, entity<ignore_ent>, bool[modify_contents_flags1], bool[modify_contents_flags2] );
passed = sightTracePassed( vector<start_pos>, vector<end_pos>, bool<use_clipmask>, entity<ignore_ent> );
player_physics_trace = playerPhysicsTrace( vector<end_pos>, vector<start_pos> );
trace = physicsTrace( vector<end_pos>, vector<smins>, vector[maxes], vector[end_pos], entity[ignore_ent] );
trace = worldTrace( vector<end_pos>, vector<start_pos> );
? customs functions to add
node = bot getNextNodeInPath( vector<start>, vector<end>, entity[ent], bool[allow_negotiation_links], bool[allow_negotiation_hints] );
bot botMovementOverride( byte<forward>, byte<right> );
self botButtonOverride( string<button>, string<value> );
self botClearMovementOverride();
self botClearButtonOverride( string<value> );
*/

View File

@ -0,0 +1,124 @@
init()
{
level.bot_builtins[ "printconsole" ] = ::do_printconsole;
level.bot_builtins[ "botaction" ] = ::do_botaction;
level.bot_builtins[ "botstop" ] = ::do_botstop;
level.bot_builtins[ "botmovement" ] = ::do_botmovement;
level.bot_builtins[ "botmeleeparams" ] = ::do_botmeleeparams;
level.bot_builtins[ "botangles" ] = ::do_botangles;
level.bot_builtins[ "isbot" ] = ::do_isbot;
level.bot_builtins[ "generatepath" ] = ::do_generatepath;
level.bot_builtins[ "getfunction" ] = ::do_getfunction;
level.bot_builtins[ "getmins" ] = ::do_getmins;
level.bot_builtins[ "getmaxs" ] = ::do_getmaxs;
level.bot_builtins[ "getguid" ] = ::do_getguid;
level.bot_builtins[ "setallowedtraversals" ] = ::do_setallowedtraversals;
level.bot_builtins[ "setignoredlinks" ] = ::do_setignoredlinks;
level.bot_builtins[ "getnodenumber" ] = ::do_getnodenumber;
level.bot_builtins[ "getlinkednodes" ] = ::do_getlinkednodes;
level.bot_builtins[ "addtestclient" ] = ::do_addtestclient;
level.bot_builtins[ "notifyonplayercommand" ] = ::do_notifyonplayercommand;
level.bot_builtins[ "cmdexec" ] = ::do_cmdexec;
level.bot_builtins[ "ishost" ] = ::do_ishost;
}
do_printconsole( s )
{
printconsole( s );
}
do_botaction( action )
{
self botaction( action );
}
do_botstop()
{
self botstop();
}
do_botmovement( left, forward )
{
self botmovement( left, forward );
}
do_botmeleeparams( yaw, dist )
{
self botmeleeparams( yaw, dist );
}
do_botangles( angles )
{
self setplayerangles( angles );
// self botangles( angles[ 0 ], angles[ 1 ], angles[ 2 ] );
}
do_isbot()
{
return self isbot();
}
do_generatepath( from, to, team, best_effort )
{
return generatepath( from, to, team, best_effort );
}
do_getfunction( file, threadname )
{
return getfunction( file, threadname );
}
do_getmins()
{
return self getmins();
}
do_getmaxs()
{
return self getmaxs();
}
do_getguid()
{
return self getguid();
}
do_setallowedtraversals( a )
{
setallowedtraversals( a );
}
do_setignoredlinks( a )
{
setignoredlinks( a );
}
do_getnodenumber()
{
return self getnodenumber();
}
do_getlinkednodes()
{
return self getlinkednodes();
}
do_addtestclient()
{
return addtestclient();
}
do_notifyonplayercommand( a, b )
{
self notifyonplayercommand( a, b );
}
do_cmdexec( a )
{
cmdexec( a );
}
do_ishost()
{
return self ishost();
}

View File

@ -0,0 +1,4 @@
init()
{
level thread maps\bots\_bot_debug::init();
}