Compare commits

...

13 Commits

Author SHA1 Message Date
23a64c5e1c Clean up code, and add prototypes for objectives. 2023-04-29 17:18:24 -07:00
1990b8c79d Fix compile errors. Add bot pathing and movement. 2023-04-28 23:43:40 -07:00
558805de77 Improve target code. 2023-04-27 02:28:35 -07:00
bdf933b907 Add target handling code. 2023-04-26 03:12:45 -07:00
a6ce1e1923 Simplify combat action functions.
Add look action functions.
2023-04-23 02:13:49 -07:00
a230151228 WIP objective code for powerup and revive type objectives. 2023-03-28 04:01:09 -07:00
ae7cfb991a Add missing return values to check_complete functions.
Fix mistakes in scripts. Create bot objective glob and add objectives on map to the glob. Don't create 3 separate threads for bot think.
2023-03-27 21:38:25 -07:00
872630b7e2 Fix some compile errors.
Add base scripts for personality and difficulty presets. Add canceling, and postponing thinks.
2023-03-27 16:44:32 -07:00
c23fd0fd2d Add 2 new functions to handle getting and setting action completion.
Move action code to bot_actions_common.gsc and remake how it works.
2023-03-25 23:34:31 -07:00
f75726147c Split bot actions script into 3 different scripts. 2023-03-25 21:35:57 -07:00
31c885a396 Remove limit on how many actions can be queued.
Add support for affecting the process order of an action aka the order the should do action function is executed for each action. Add bot actions for each bot think thread.
2023-03-25 20:32:14 -07:00
7614efcec3 Import code from another repo(by me). 2023-03-25 19:16:32 -07:00
7d01471760 New base. 2023-03-25 19:10:22 -07:00
13 changed files with 3715 additions and 2927 deletions

View File

@ -1,82 +1,96 @@
#include common_scripts\utility; #include common_scripts\utility;
#include maps\_utility; #include maps\_utility;
#include scripts\sp\bots\_bot_utility; #include maps\so\zm_common\_zm_utility;
/* #include scripts\sp\bots\_bot_internal;
Initiates the whole bot scripts.
*/ #include scripts\sp\bots\bot_actions_common;
init() #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()
{ {
level.bw_VERSION = "2.1.0"; //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 );
if ( getDvar( "bots_main" ) == "" ) //Combat actions
setDvar( "bots_main", true ); //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 );
if ( !getDvarInt( "bots_main" ) ) //Movement actions
return; //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" )
//thread load_waypoints(); //Don't call for now 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 );
thread hook_callbacks(); 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 );
if ( getDvar( "bots_main_GUIDs" ) == "" ) register_bot_personality_type( "aggressive" );
setDvar( "bots_main_GUIDs", "" ); //guids of players who will be given host powers, comma seperated register_bot_personality_type( "passive" );
register_bot_personality_type( "supportive" );
register_bot_personality_type( "mixed" );
register_bot_personality_type( "default" );
if ( getDvar( "bots_main_firstIsHost" ) == "" ) register_bot_difficulty( "bone" );
setDvar( "bots_main_firstIsHost", true ); //first player to connect is a host register_bot_difficulty( "crossbones" );
register_bot_difficulty( "skull" );
register_bot_difficulty( "knife" );
register_bot_difficulty( "shotguns" );
if ( getDvar( "bots_main_waitForHostTime" ) == "" ) register_bot_objective( "magicbox" );
setDvar( "bots_main_waitForHostTime", 10.0 ); //how long to wait to wait for the host player 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" );
if ( getDvar( "bots_main_kickBotsAtEnd" ) == "" ) register_bot_target_type( "zombie" );
setDvar( "bots_main_kickBotsAtEnd", false ); //kicks the bots at game end register_bot_target_type( "zombie_dog" );
if ( getDvar( "bots_manage_add" ) == "" ) level.bot_weapon_quality_poor = 0;
setDvar( "bots_manage_add", 0 ); //amount of bots to add to the game level.bot_weapon_quality_fair = 1;
level.bot_weapon_quality_good = 2;
if ( getDvar( "bots_manage_fill" ) == "" ) level.bot_weapon_quality_excellent = 3;
setDvar( "bots_manage_fill", 0 ); //amount of bots to maintain level.bot_weapon_quality_best = 4;
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_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 ( !isDefined( game["botWarfare"] ) )
game["botWarfare"] = true;
level.bots_minSprintDistance = 315; level.bots_minSprintDistance = 315;
level.bots_minSprintDistance *= level.bots_minSprintDistance; level.bots_minSprintDistance *= level.bots_minSprintDistance;
@ -92,332 +106,549 @@ init()
level.bots_noADSDistance *= level.bots_noADSDistance; level.bots_noADSDistance *= level.bots_noADSDistance;
level.bots_maxShotgunDistance = 500; level.bots_maxShotgunDistance = 500;
level.bots_maxShotgunDistance *= level.bots_maxShotgunDistance; level.bots_maxShotgunDistance *= level.bots_maxShotgunDistance;
level.bots_listenDist = 100;
level.players = []; /*
level.bots = []; 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.bots_fullautoguns = []; level thread spawn_bots_for_host();
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 on_player_connect();
level thread handleBots();
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;
} }
/* /*
Starts the threads for bots. We clear all of the script variables and other stuff for the bots.
*/ */
handleBots() resetBotVars()
{ {
level thread diffBots(); self.bot = spawnStruct();
level addBots(); 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;
while ( !level.intermission ) self.bot.script_aimpos = undefined;
wait 0.05;
setDvar( "bots_manage_add", getBotArray().size ); self.bot.script_goal = undefined;
self.bot.script_goal_dist = 0.0;
if ( !getDvarInt( "bots_main_kickBotsAtEnd" ) ) self.bot.next_wp = -1;
return; 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;
bots = getBotArray(); 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;
for ( i = 0; i < bots.size; i++ ) 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++ )
{ {
bots[i] RemoveTestClient(); 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 )
The hook callback for when any player becomes damaged.
*/
onPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, timeOffset )
{ {
if ( self is_bot() ) playable_area = getentarray( "playable_area", "targetname" );
in_playable_area = false;
if ( !isDefined( playable_area ) || playable_area.size < 1 )
{ {
//self scripts\sp\bots\_bot_internal::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, timeOffset ); in_playable_area = true;
self scripts\sp\bots\_bot_script::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, timeOffset );
} }
self [[level.prevCallbackPlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, iModelIndex, timeOffset ); 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()
Starts the callbacks.
*/
hook_callbacks()
{ {
wait 0.05; i = 0;
level.prevCallbackPlayerDamage = level.callbackPlayerDamage; while ( true )
level.callbackPlayerDamage = ::onPlayerDamage;
}
/*
Thread when any player connects. Starts the threads needed.
*/
onPlayerConnect()
{
for ( ;; )
{ {
level waittill( "connected", player ); level waittill( "connected", player );
player thread on_player_spawned();
player thread connected(); 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()
When a bot disconnects.
*/
onDisconnectAll()
{
self waittill( "disconnect" );
level.players = array_remove( level.players, self );
}
/*
When a bot disconnects.
*/
onDisconnect()
{
self waittill( "disconnect" );
level.bots = array_remove( level.bots, self );
}
/*
Called when a player connects.
*/
connected()
{ {
self endon( "disconnect" ); 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" );
}
}
if ( !isDefined( self.pers["bot_host"] ) ) clear_script_on_event()
self thread doHostCheck(); {
self endon( "disconnect" );
result = self waittill_any_return( "new_goal", "goal", "bad_path" );
if ( result != "new_goal" )
{
self scripts\sp\bots\_bot_utility::ClearScriptGoal();
}
}
level.players[level.players.size] = self; on_player_spawned()
self thread onDisconnectAll(); {
self waittill( "spawned_player" );
self.score = 100000;
}
if ( !self is_bot() ) 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; return;
if ( !isDefined( self.pers["isBot"] ) )
{
// fast restart...
self.pers["isBot"] = true;
} }
add_possible_bot_target( self.targetname, level.zbot_target_glob_ids[ self.targetname ], self );
if ( !isDefined( self.pers["isBotWarfare"] ) ) self.target_id = level.zbot_target_glob_ids[ self.targetname ];
{ level.zbot_target_glob_ids[ self.targetname ]++;
self.pers["isBotWarfare"] = true;
self thread added();
}
self thread scripts\sp\bots\_bot_internal::connected();
self thread scripts\sp\bots\_bot_script::connected();
level.bots[level.bots.size] = self;
self thread onDisconnect();
level notify( "bot_connected", self );
self thread watchBotDebugEvent();
} }
/* zbots_actor_killed( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, iTimeOffset )
DEBUG
*/
watchBotDebugEvent()
{ {
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 endon( "disconnect" );
for ( ;; ) self waittill( "spawned_player" );
while ( true )
{ {
self waittill( "bot_event", msg, str, b, c, d, e, f, g );
if ( msg == "debug" && GetDvarInt( "bots_main_debug" ) )
{
PrintConsole( "Bot Warfare debug: " + self.name + ": " + str + "\n" );
}
}
}
/*
When a bot gets added into the game.
*/
added()
{
self endon( "disconnect" );
self thread scripts\sp\bots\_bot_internal::added();
//self thread scripts\sp\bots\_bot_script::added();
}
/*
Adds a bot to the game.
*/
add_bot()
{
bot = addtestclient();
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; wait 0.25;
} if ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
}
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]; self notify( "stop_action_think" );
self bot_clear_actions_queue();
if ( player is_bot() ) while ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
bots++; {
else wait 1;
players++; }
} }
amount = bots; //group_name = "movement";
if ( fillMode == 0 || fillMode == 2 ) //self bot_action_think( group_name );
amount += players;
if ( amount < fillAmount ) //group_name = "look";
setDvar( "bots_manage_add", 1 );
else if ( amount > fillAmount && getDvarInt( "bots_manage_fill_kick" ) )
{
tempBot = PickRandom( getBotArray() );
if ( isDefined( tempBot ) ) //self bot_action_think( group_name );
tempBot RemoveTestClient();
//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 )
A server thread for monitoring all bot's in game. Will add and kick bots according to server settings.
*/
addBots()
{ {
level endon( "game_ended" ); level endon( "end_game" );
bot_wait_for_host(); for ( doors_opened_count = 0; doors_opened_count < zombie_doors.size; doors_opened_count++ )
for ( ;; )
{ {
wait 1.5; level waittill( "door_opened", door, player );
free_bot_objective( "door", door.id );
addBots_loop();
} }
} }
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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
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

@ -0,0 +1,224 @@
#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

@ -0,0 +1,240 @@
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

@ -0,0 +1,867 @@
#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

@ -0,0 +1,279 @@
/*
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

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

View File

@ -0,0 +1,207 @@
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

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

View File

@ -0,0 +1,194 @@
#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

@ -0,0 +1,625 @@
#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> );
*/