From a209af39b80cf07973e2ae6682d2bd422617a967 Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Wed, 3 May 2023 21:42:59 -0700 Subject: [PATCH] Add debug prints. Move objective related code into separate scripts. Add the ability to prioritize objectives over targets. --- maps/bots/_bot.gsc | 25 +- maps/bots/_bot_internal.gsc | 19 +- maps/bots/_bot_script.gsc | 1077 +---------------- maps/bots/_bot_utility.gsc | 35 +- maps/bots/script_objectives/_obj_actions.gsc | 349 ++++++ maps/bots/script_objectives/_obj_common.gsc | 644 ++++++++++ maps/bots/script_objectives/_obj_trackers.gsc | 148 +++ 7 files changed, 1228 insertions(+), 1069 deletions(-) create mode 100644 maps/bots/script_objectives/_obj_actions.gsc create mode 100644 maps/bots/script_objectives/_obj_common.gsc create mode 100644 maps/bots/script_objectives/_obj_trackers.gsc diff --git a/maps/bots/_bot.gsc b/maps/bots/_bot.gsc index 81503d4..bda240e 100644 --- a/maps/bots/_bot.gsc +++ b/maps/bots/_bot.gsc @@ -120,30 +120,7 @@ init() level thread onPlayerConnect(); level thread handleBots(); - maps\bots\_bot_script::register_bot_action( "objective", "powerup", maps\bots\_bot_script::bot_grab_powerup, - maps\bots\_bot_script::bot_powerup_process_order, - maps\bots\_bot_script::bot_powerup_init, - maps\bots\_bot_script::bot_powerup_post_think, - maps\bots\_bot_script::bot_should_grab_powerup, - maps\bots\_bot_script::bot_check_complete_grab_powerup, - maps\bots\_bot_script::bot_powerup_should_cancel, - maps\bots\_bot_script::bot_powerup_should_postpone, - maps\bots\_bot_script::bot_powerup_priority ); - - maps\bots\_bot_script::register_bot_action( "objective", "revive", maps\bots\_bot_script::bot_revive_player, - maps\bots\_bot_script::bot_revive_process_order, - maps\bots\_bot_script::bot_revive_player_init, - maps\bots\_bot_script::bot_revive_player_post_think, - maps\bots\_bot_script::bot_should_revive_player, - maps\bots\_bot_script::bot_check_complete_revive_player, - maps\bots\_bot_script::bot_revive_player_should_cancel, - maps\bots\_bot_script::bot_revive_player_should_postpone, - maps\bots\_bot_script::bot_revive_player_priority ); - maps\bots\_bot_script::register_bot_objective( "powerup" ); - maps\bots\_bot_script::register_bot_objective( "revive" ); - - level thread maps\bots\_bot_script::store_powerups_dropped(); - level thread maps\bots\_bot_script::watch_for_downed_players(); + maps\bots\_bot_script::bot_script_init(); } /* diff --git a/maps/bots/_bot_internal.gsc b/maps/bots/_bot_internal.gsc index b3fe6c8..bfef00e 100644 --- a/maps/bots/_bot_internal.gsc +++ b/maps/bots/_bot_internal.gsc @@ -96,6 +96,9 @@ resetBotVars() self.bot.cur_weap_dist_multi = 1; self.bot.is_cur_sniper = false; + self.bot.prio_objective = false; + self.bot.path_inaccessible = false; + self.bot.rand = randomInt( 100 ); self botStop(); @@ -419,6 +422,8 @@ stance_loop() if ( toStance != "stand" && toStance != "crouch" && toStance != "prone" ) toStance = "crouch"; + toStance = "stand"; //Hack to make the bots never crouch + if ( toStance == "stand" ) self stand(); else if ( toStance == "crouch" ) @@ -1187,7 +1192,7 @@ aim_loop() aimspeed *= 1 + adsAimSpeedFact * adsAmount; } - if ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) ) + if ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !self.bot.prio_objective ) { no_trace_time = self.bot.target.no_trace_time; no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_time"]; @@ -1466,9 +1471,9 @@ walk() */ walk_loop() { - hasTarget = isDefined( self.bot.target ) && isDefined( self.bot.target.entity ); + shouldTarget = isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !self.bot.prio_objective; - if ( hasTarget ) + if ( shouldTarget ) { curweap = self getCurrentWeapon(); @@ -1495,7 +1500,7 @@ walk_loop() isScriptGoal = false; - if ( isDefined( self.bot.script_goal ) && !hasTarget ) + if ( isDefined( self.bot.script_goal ) && !shouldTarget ) { goal = self.bot.script_goal; dist = self.bot.script_goal_dist; @@ -1504,7 +1509,7 @@ walk_loop() } else { - if ( hasTarget ) + if ( shouldTarget ) goal = self.bot.target.last_seen_pos; self notify( "new_goal_internal" ); @@ -1538,11 +1543,11 @@ doWalk( goal, dist, isScriptGoal ) path_was_truncated = ( current + 1 ) >= 32; //Couldn't generate path to goal - self.path_inaccessible = false; + self.bot.path_inaccessible = false; if ( current <= -1 ) { + self.bot.path_inaccessible = true; self notify( "bad_path_internal" ); - self.path_inaccessible = true; return; } diff --git a/maps/bots/_bot_script.gsc b/maps/bots/_bot_script.gsc index 3138578..59b2518 100644 --- a/maps/bots/_bot_script.gsc +++ b/maps/bots/_bot_script.gsc @@ -1,6 +1,43 @@ #include common_scripts\utility; #include maps\_utility; #include maps\bots\_bot_utility; +#include maps\bots\script_objectives\_obj_actions; +#include maps\bots\script_objectives\_obj_common; +#include maps\bots\script_objectives\_obj_trackers; + +/* + Initialize bot script level functions +*/ +bot_script_init() +{ + //maps\bots\script_objectives\_obj_common; + //maps\bots\script_objectives\_obj_actions; + register_bot_action( "objective", "powerup", ::bot_grab_powerup, + ::bot_powerup_process_order, + ::bot_powerup_init, + ::bot_powerup_post_think, + ::bot_should_grab_powerup, + ::bot_check_complete_grab_powerup, + ::bot_powerup_should_cancel, + ::bot_powerup_should_postpone, + ::bot_powerup_priority ); + + register_bot_action( "objective", "revive", ::bot_revive_player, + ::bot_revive_process_order, + ::bot_revive_player_init, + ::bot_revive_player_post_think, + ::bot_should_revive_player, + ::bot_check_complete_revive_player, + ::bot_revive_player_should_cancel, + ::bot_revive_player_should_postpone, + ::bot_revive_player_priority ); + register_bot_objective( "powerup" ); + register_bot_objective( "revive" ); + + //maps\bots\script_objectives\_obj_trackers; + level thread store_powerups_dropped(); + level thread watch_for_downed_players(); +} /* When the bot gets added into the game. @@ -28,7 +65,9 @@ connected() self.on_powerup_grab_func = ::bot_on_powerup_grab; self.on_revive_success_func = ::bot_on_revive_success; - self.path_inaccessible = false; + + self.obj_postponed_reason = ""; + self.obj_cancel_reason = ""; } /* @@ -379,1045 +418,9 @@ start_bot_threads() self endon( "zombified" ); } -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, target_ent, is_global_shared ) -{ - 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" ); - - if ( !isDefined( target_ent ) ) - { - assertMsg( "target_ent is undefined" ); - return; - } - - id = target_ent getEntityNumber(); - - objective_struct = spawnStruct(); - objective_struct.group = objective_group; - objective_struct.is_global_shared = is_global_shared; - objective_struct.target_ent = target_ent; - objective_struct.owner = undefined; - objective_struct.is_objective = true; - objective_struct.bad = false; - - level.zbot_objective_glob[ objective_group ].active_objectives[ "obj_id_" + id ] = objective_struct; -} - -get_bot_objective_by_entity_ref( objective_group, ent ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return; - } - - id = ent getEntityNumber(); - - 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; -} - -bot_get_objective() -{ - return self.zbot_current_objective; -} - -bot_has_objective() -{ - return isDefined( self.zbot_current_objective ); -} - -bot_set_objective( objective_group, ent ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return; - } - - possible_objectives = level.zbot_objective_glob[ objective_group ].active_objectives; - - id = ent getEntityNumber(); - - 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_ent, blocked_by_objective_group, blocked_by_ent ) -{ - if ( !isDefined( primary_ent ) ) - { - assertMsg( "Primary_ent is undefined" ); - return; - } - - if ( !isDefined( blocked_by_ent ) ) - { - assertMsg( "Blocked_by_ent is undefined" ); - return; - } - - primary_id = primary_ent getEntityNumber(); - - blocked_by_id = blocked_by_ent getEntityNumber(); - - 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; - } -} - -bot_is_objective_owner( objective_group, ent ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return false; - } - - id = ent getEntityNumber(); - - 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 false; - } - - 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 false; - } - - return isDefined( objective.owner ) && objective.owner == self; -} - -set_bot_global_shared_objective_owner_by_ent( objective_group, ent, new_owner ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return; - } - - id = ent getEntityNumber(); - - 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; -} - -mark_objective_bad( objective_group, ent ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return; - } - - id = ent getEntityNumber(); - - 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; - } - - objective.bad = true; -} - -free_bot_objective( objective_group, ent ) -{ - if ( !isDefined( ent ) ) - { - assertMsg( "Ent is undefined" ); - return; - } - - id = ent getEntityNumber(); - - 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; - } - - players = getPlayers(); - for ( i = 0; i < players.size; i++ ) - { - if ( isDefined( players[ i ].pers[ "isBot" ] ) && players[ i ].pers[ "isBot" ] ) - { - if ( isDefined( players[ i ].zbot_current_objective ) && players[ i ].zbot_current_objective == objective ) - { - players[ i ].zbot_current_objective = undefined; - } - } - } - - active_objectives[ "obj_id_" + id ] = undefined; -} - -register_bot_action( group_name, action_name, action_func, action_process_order_func, init_func, post_think_func, should_do_func, check_if_complete_func, should_cancel_func, should_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 ].init_func = init_func; - level.zbots_actions[ group_name ][ action_name ].post_think_func = post_think_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 ].should_cancel_func = should_cancel_func; - level.zbots_actions[ group_name ][ action_name ].should_postpone_func = should_postpone_func; - level.zbots_actions[ group_name ][ action_name ].priority_func = priority_func; -} - -initialize_bot_actions_queue() -{ - self.action_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 ] ); - } - } -} - -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 ].queued = 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 ].is_current ) - { - return; - } - - self.action_queue[ group_name ] = self sort_array_by_priority_field( self.action_queue[ group_name ] ); - - action_name = self.action_queue[ group_name ][ 0 ].action_name; - - self [[ level.zbots_actions[ group_name ][ action_name ].init_func ]](); - - self thread [[ level.zbots_actions[ group_name ][ action_name ].action ]](); - - self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = true; - - self thread wait_for_action_completion( group_name, action_name ); -} - -wait_for_action_completion( group_name, action_name ) -{ - self endon( "disconnect" ); - self endon( "stop_action_think" ); - level endon( "end_game" ); - - action_complete_name = action_name + "_complete"; - action_cancel_name = action_name + "_cancel"; - action_postpone_name = action_name + "_postpone"; - - result = self waittill_any_return( action_complete_name, action_cancel_name, action_postpone_name ); - - save_action = false; - - end_state = undefined; - - if ( ( result == action_complete_name ) ) - { - self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false; - self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false; - end_state = "completed"; - } - else if ( result == action_cancel_name ) - { - self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false; - self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false; - end_state = "canceled"; - } - else if ( result == action_postpone_name ) - { - self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = true; - save_action = true; - end_state = "postponed"; - } - - self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = false; - - self notify( action_name + "_end_think" ); - - self [[ level.zbots_actions[ group_name ][ action_name ].post_think_func ]]( end_state ); - - if ( save_action ) - { - postponed_action = self.action_queue[ group_name ][ 0 ]; - 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, 2 ); - self.action_queue[ group_name ][ 0 ] = undefined; - } - else - { - self.action_queue[ group_name ][ 0 ] = undefined; - } -} - -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++ ) - { - - } - */ - - //Reboot the action queue because the last member was deleted which deletes the array - if ( !isDefined( self.action_queue ) || !isDefined( self.action_queue[ group_name ] ) ) - { - self.action_queue = []; - self.action_queue[ group_name ] = []; - } - - 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, action_name ) -{ - assert( isDefined( level.zbots_actions[ group_name ][ action_name ].check_if_complete_func ) ); - - if ( self [[ level.zbots_actions[ group_name ][ action_name ].check_if_complete_func ]]() ) - { - self notify( action_name + "_complete" ); - } -} - -check_if_action_should_be_postponed_in_group( group_name, action_name ) -{ - if ( self [[ level.zbots_actions[ group_name ][ action_name ].should_postpone_func ]]() ) - { - self notify( action_name + "_postpone" ); - } -} - -check_if_action_should_be_canceled_in_group( group_name, action_name ) -{ - if ( self [[ level.zbots_actions[ group_name ][ action_name ].should_cancel_func ]]() ) - { - self notify( action_name + "_cancel" ); - } -} - -check_if_action_should_be_postponed_globally( group_name, action_name ) -{ - if ( action_should_be_postponed_global( group_name, action_name ) ) - { - self notify( action_name + "_postpone" ); - } -} - -check_if_action_should_be_canceled_globally( group_name, action_name ) -{ - if ( action_should_be_canceled_global( group_name, action_name ) ) - { - self notify( 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() -{ - self endon( "disconnect" ); - self endon( "zombified" ); - - while ( true ) - { - wait 0.05; - //Wait until the end of the frame so any variables set by _bot_internal in the current frame will have up to date values - waittillframeend; - - group_name = "objective"; - - self pick_actions_to_add_to_queue( group_name ); - - //self check_for_forced_action( group_name ); - - if ( !isDefined( self.action_queue[ group_name ][ 0 ] ) ) - { - continue; - } - - self process_next_queued_action( group_name ); - - action_name = self.action_queue[ group_name ][ 0 ].action_name; - - self check_if_action_is_completed_in_group( group_name, action_name ); - self check_if_action_should_be_postponed_in_group( group_name, action_name ); - self check_if_action_should_be_canceled_in_group( group_name, action_name ); - - self check_if_action_should_be_postponed_globally( group_name, action_name ); - self check_if_action_should_be_canceled_globally( group_name, action_name ); - } -} - -action_should_be_postponed_global( primary_group_name, action_name ) -{ - return false; -} - -action_should_be_canceled_global( primary_group_name, action_name ) -{ - obj = self bot_get_objective(); - if ( self.path_inaccessible || obj.bad ) - { - return true; - } - 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; -} - -bot_grab_powerup() -{ - self endon( "disconnect" ); - self endon( "powerup_end_think" ); - self endon( "bot_in_invalid_state" ); - level endon( "end_game" ); - - if ( !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 ) - { - return; - } - - powerup_obj = self.available_powerups[ 0 ]; - powerup_obj_ent = powerup_obj.target_ent; - - set_bot_global_shared_objective_owner_by_ent( "powerup", powerup_obj_ent, self ); - self bot_set_objective( "powerup", powerup_obj_ent ); - while ( isDefined( powerup_obj_ent ) && isDefined( powerup_obj ) && self bot_is_objective_owner( "powerup", powerup_obj_ent ) ) - { - wait 1; - self ClearScriptAimPos(); - self SetScriptGoal( powerup_obj_ent.origin ); - - result = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( result != "goal" ) - { - continue; - } - //Wait to see if the bot was able to grab the powerup - wait 0.5; - //Check if powerup still exists - if ( isDefined( powerup_obj_ent ) ) - { - height_difference = self.origin[ 2 ] - powerup_obj_ent.origin[ 2 ]; - if ( height_difference < 49 ) - { - self BotJump(); - wait 0.5; - waittillframeend; - //Check if bot was able to grab the powerup by jumping - if ( self bot_has_objective() || isDefined( powerup_obj_ent ) ) - { - //Mark objective as bad so bots will ignore it from now on - powerup_obj.bad = true; - } - } - else - { - powerup_obj.bad = true; - } - - if ( powerup_obj.bad ) - { - break; - } - } - } -} - -bot_powerup_process_order() -{ - return 0; -} - -bot_powerup_init() -{ - self.successfully_grabbed_powerup = false; -} - -bot_powerup_post_think( state ) -{ - self.successfully_grabbed_powerup = false; - self ClearScriptGoal(); - self ClearScriptAimPos(); - self clear_objective_for_bot(); -} - -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( powerup ) ) - { - continue; - } - if ( obj.bad ) - { - continue; - } - 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, level.bot_allowed_negotiation_links ) ) ) - { - 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() -{ - return self.successfully_grabbed_powerup; -} - -bot_powerup_should_cancel() -{ - return !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 || !isDefined( self.available_powerups[ 0 ].target_ent ); -} - -bot_powerup_should_postpone() -{ - return false; -} - -bot_powerup_priority() -{ - if ( !isDefined( self.available_powerups ) ) - { - return 0; - } - return self.available_powerups[ 0 ].target_ent.priority; -} - -bot_revive_player() -{ - if ( !isDefined( self.available_revives ) || self.available_revives.size <= 0 ) - { - return; - } - - self endon( "disconnect" ); - self endon( "revive_end_think" ); - self endon( "bot_in_invalid_state" ); - level endon( "end_game" ); - - player_to_revive_obj = self.available_revives[ 0 ]; - - set_bot_global_shared_objective_owner_by_ent( "revive", player_to_revive_obj.target_ent, self ); - - player_to_revive = player_to_revive_obj.target_ent; - - //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 ) && self bot_is_objective_owner( "powerup", powerup_obj_ent ) ) - { - wait 1; - //Constantly update the goal just in case the player is moving(T5 or higher only) - self ClearScriptAimPos(); - self SetScriptGoal( player_to_revive.origin, 32 ); - - result = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - //printConsole( result ); - if ( result != "goal" ) - { - //printConsole( "Bot is not at goal" ); - continue; - //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? - } - if ( !isDefined( player_to_revive.revivetrigger ) ) - { - self.should_cancel_revive_obj = true; - return; - } - //Check if the bot is reviving the player already and also that the player isn't being revived already - if ( player_to_revive.revivetrigger.beingrevived ) - { - continue; - } - - SetScriptAimPos( player_to_revive.origin ); - - time = 3.2; - if ( self hasPerk( "specialty_quickrevive" ) ) - { - time /= 2; - } - self BotPressUse( time ); - - while ( self maps\_laststand::is_reviving( player_to_revive ) ) - { - wait 0.05; - } - //Wait to see if we cleared the objective by successfully reviving the player - waittillframeend; - } -} - -bot_revive_process_order() -{ - return 0; -} - -bot_revive_player_init() -{ - self.should_cancel_revive_obj = false; - self.successfully_revived_player = false; -} - -bot_revive_player_post_think( state ) -{ - self.should_cancel_revive_obj = false; - self.successfully_revived_player = false; - self ClearScriptGoal(); - self ClearScriptAimPos(); - self clear_objective_for_bot(); -} - -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; - } - if ( obj.bad ) - { - 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() -{ - return self.successfully_revived_player; -} - -bot_revive_player_should_cancel() -{ - if ( !isDefined( self.available_revives[ 0 ] ) - || !isDefined( self.available_revives[ 0 ].target_ent ) - || !isDefined( self.available_revives[ 0 ].target_ent.revivetrigger ) - || self.should_cancel_revive_obj ) - { - return true; - } - return false; -} - -bot_revive_player_should_postpone() -{ - return false; -} - -bot_revive_player_priority() -{ - return 0; -} - -store_powerups_dropped() -{ - level endon( "end_game" ); - - level thread free_powerups_dropped(); - - level.zbots_powerups = []; - while ( true ) - { - level waittill( "powerup_dropped", powerup ); - waittillframeend; - if ( !isDefined( powerup ) ) - { - continue; - } - add_possible_bot_objective( "powerup", powerup, true ); - maps\bots\_bot_utility::assign_priority_to_powerup( powerup ); - level.zbots_powerups = maps\bots\_bot_utility::sort_array_by_priority_field( level.zbots_powerups, powerup ); - } -} - -free_powerups_dropped() -{ - level endon( "end_game" ); - - while ( true ) - { - level waittill( "powerup_freed", powerup ); - free_bot_objective( "powerup", powerup ); - } -} - -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, true ); - 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", self ); -} - -bot_valid_pump() -{ - level endon( "end_game" ); - - obj_sav = undefined; - - while ( true ) - { - obj_sav = self.zbot_current_objective; - wait 0.5; - if ( !maps\so\zm_common\_zm_utility::is_player_valid( self ) ) - { - if ( isDefined( self ) ) - { - self notify( "bot_in_invalid_state" ); - self clear_objective_for_bot(); - } - else if ( isDefined( obj_sav ) ) - { - set_bot_global_shared_objective_owner_by_ent( obj_sav.group, obj_sav.target_ent, undefined ); - } - - while ( isDefined( self ) && !maps\so\zm_common\_zm_utility::is_player_valid( self ) ) - { - wait 0.5; - } - if ( !isDefined( self ) ) - { - return; - } - } - } -} - -bot_objective_inaccessible_pump() -{ - self endon( "disconnect" ); - level endon( "end_game" ); - - while ( true ) - { - invalid_obj = false; - wait 0.5; - while ( !self bot_has_objective() ) - { - wait 0.5; - } - - while ( self bot_has_objective() ) - { - wait 1; - obj = self bot_get_objective(); - - if ( !isDefined( obj ) || !isDefined( obj.target_ent ) ) - { - invalid_obj = true; - } - else if ( !isDefined( generatePath( self.origin, obj.target_ent.origin, self.team, level.bot_allowed_negotiation_links ) ) ) - { - invalid_obj = true; - } - if ( invalid_obj ) - { - self notify( "bot_objective_inaccessible" ); - self.path_inaccessible = true; - break; - } - } - } -} - -bot_on_powerup_grab( powerup ) -{ - self.successfully_grabbed_powerup = true; -} - -bot_on_revive_success( revivee ) -{ - self.successfully_revived_player = true; } \ No newline at end of file diff --git a/maps/bots/_bot_utility.gsc b/maps/bots/_bot_utility.gsc index 1ee8cfa..63fd7f4 100644 --- a/maps/bots/_bot_utility.gsc +++ b/maps/bots/_bot_utility.gsc @@ -279,7 +279,6 @@ ClearScriptGoal() /* Returns whether the bot is at it's goal */ - AtScriptGoal() { if ( !isDefined( self.bot.script_goal ) ) @@ -289,6 +288,40 @@ AtScriptGoal() return distanceSquared( self.origin, self.bot.script_goal ) <= ( self.bot.script_goal_dist * self.bot.script_goal_dist ); } +/* + Returns whether the bot has a priority objective +*/ +HasPriorityObjective() +{ + return self.bot.prio_objective; +} + +/* + Sets the bot to prioritize the objective over targeting enemies +*/ +SetPriorityObjective() +{ + self.bot.prio_objective = true; + self notify( "kill_goal" ); +} + +/* + Clears the bot's priority objective to allow the bot to target enemies automatically again +*/ +ClearPriorityObjective() +{ + self.bot.prio_objective = false; +} + +/* + Checks whether the path generated by the ASTAR path finding is inaccessible +*/ +GetPathIsInaccessible() +{ + waittillframeend; + return self.bot.path_inaccessible; +} + /* Sets the aim position of the bot */ diff --git a/maps/bots/script_objectives/_obj_actions.gsc b/maps/bots/script_objectives/_obj_actions.gsc new file mode 100644 index 0000000..e006c40 --- /dev/null +++ b/maps/bots/script_objectives/_obj_actions.gsc @@ -0,0 +1,349 @@ +#include common_scripts\utility; +#include maps\_utility; +#include maps\bots\_bot_utility; +#include maps\bots\script_objectives\_obj_common; + +bot_grab_powerup() +{ + self endon( "disconnect" ); + self endon( "powerup_end_think" ); + self endon( "bot_in_invalid_state" ); + level endon( "end_game" ); + + if ( !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 ) + { + return; + } + + powerup_obj = self.available_powerups[ 0 ]; + powerup_obj_ent = powerup_obj.target_ent; + + set_bot_global_shared_objective_owner_by_ent( "powerup", powerup_obj_ent, self ); + self bot_set_objective( "powerup", powerup_obj_ent ); + + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> starts objective" ); + while ( isDefined( powerup_obj_ent ) && isDefined( powerup_obj ) && self bot_is_objective_owner( "powerup", powerup_obj_ent ) ) + { + wait 1; + self SetPriorityObjective(); + self SetScriptGoal( powerup_obj_ent.origin ); + + result = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( result != "goal" ) + { + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> bad path" ); + continue; + } + //Wait to see if the bot was able to grab the powerup + wait 0.5; + //Check if powerup still exists + if ( isDefined( powerup_obj_ent ) ) + { + height_difference = self.origin[ 2 ] - powerup_obj_ent.origin[ 2 ]; + if ( height_difference < 49 ) + { + self BotJump(); + wait 0.5; + waittillframeend; + //Check if bot was able to grab the powerup by jumping + if ( self bot_has_objective() || isDefined( powerup_obj_ent ) ) + { + //Mark objective as bad so bots will ignore it from now on + powerup_obj.bad = true; + } + } + else + { + powerup_obj.bad = true; + } + + if ( powerup_obj.bad ) + { + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> objective was marked as bad" ); + break; + } + } + } +} + +bot_powerup_process_order() +{ + return 0; +} + +bot_powerup_init() +{ + self.successfully_grabbed_powerup = false; +} + +bot_powerup_post_think( state ) +{ + obj = self bot_get_objective(); + powerup_obj_ent = obj.target_ent; + switch ( state ) + { + case "completed": + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> objective was completed" ); + break; + case "postponed": + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> objective was postponed Reason: " + self.obj_postponed_reason ); + break; + case "canceled": + bot_objective_print( "powerup", powerup_obj_ent, "Bot <" + self.playername + "> objective was canceled Reason: " + self.obj_cancel_reason ); + break; + } + self.successfully_grabbed_powerup = false; + self.obj_cancel_reason = ""; + self ClearScriptGoal(); + self ClearScriptAimPos(); + self ClearPriorityObjective(); + self clear_objective_for_bot(); +} + +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( powerup ) ) + { + continue; + } + if ( obj.bad ) + { + continue; + } + 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, level.bot_allowed_negotiation_links ) ) ) + { + 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() +{ + return self.successfully_grabbed_powerup; +} + +bot_powerup_should_cancel() +{ + if ( !isDefined( self.available_powerups ) || self.available_powerups.size <= 0 ) + { + self.obj_cancel_reason = "No available powerups"; + return true; + } + if ( !isDefined( self.available_powerups[ 0 ].target_ent ) ) + { + self.obj_cancel_reason = "Powerup doesn't exist"; + return true; + } + return false ; +} + +bot_powerup_should_postpone() +{ + return false; +} + +bot_powerup_priority() +{ + if ( !isDefined( self.available_powerups ) ) + { + return 0; + } + //return self.available_powerups[ 0 ].target_ent.priority; + return 0; +} + +//TODO: Possibly add the ability to circle revive? +bot_revive_player() +{ + if ( !isDefined( self.available_revives ) || self.available_revives.size <= 0 ) + { + return; + } + + self endon( "disconnect" ); + self endon( "revive_end_think" ); + self endon( "bot_in_invalid_state" ); + level endon( "end_game" ); + + player_to_revive_obj = self.available_revives[ 0 ]; + + player_to_revive = player_to_revive_obj.target_ent; + self bot_set_objective( "revive", player_to_revive ); + set_bot_global_shared_objective_owner_by_ent( "revive", player_to_revive, self ); + bot_objective_print( "revive", player_to_revive, "Bot <" + self.playername + "> objective started" ); + //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 ) && self bot_is_objective_owner( "revive", player_to_revive ) ) + { + wait 1; + //Constantly update the goal just in case the player is moving(T5 or higher only) + self ClearScriptAimPos(); + self SetPriorityObjective(); + self SetScriptGoal( player_to_revive.origin, 32 ); + + result = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + //printConsole( result ); + if ( result != "goal" ) + { + bot_objective_print( "revive", player_to_revive, "Bot <" + self.playername + "> bad path" ); + continue; + } + if ( !isDefined( player_to_revive.revivetrigger ) ) + { + return; + } + //Check if the bot is reviving the player already and also that the player isn't being revived already + if ( player_to_revive.revivetrigger.beingrevived ) + { + continue; + } + + self SetScriptAimPos( player_to_revive.origin ); + + time = 3.2; + if ( self hasPerk( "specialty_quickrevive" ) ) + { + time /= 2; + } + self thread BotPressUse( time ); + + while ( self maps\_laststand::is_reviving( player_to_revive ) ) + { + wait 0.05; + } + //Wait to see if we cleared the objective by successfully reviving the player + waittillframeend; + } +} + +bot_revive_process_order() +{ + return 0; +} + +bot_revive_player_init() +{ + self.should_cancel_revive_obj = false; + self.successfully_revived_player = false; +} + +bot_revive_player_post_think( state ) +{ + obj = self bot_get_objective(); + revive_obj_ent = obj.target_ent; + switch ( state ) + { + case "completed": + bot_objective_print( "revive", revive_obj_ent, "Bot <" + self.playername + "> objective was completed" ); + break; + case "postponed": + bot_objective_print( "revive", revive_obj_ent, "Bot <" + self.playername + "> objective was postponed Reason: " + self.obj_postponed_reason ); + break; + case "canceled": + bot_objective_print( "revive", revive_obj_ent, "Bot <" + self.playername + "> objective was canceled Reason: " + self.obj_cancel_reason ); + break; + } + self.should_cancel_revive_obj = false; + self.successfully_revived_player = false; + self.obj_cancel_reason = ""; + self ClearScriptGoal(); + self ClearScriptAimPos(); + self ClearPriorityObjective(); + self clear_objective_for_bot(); +} + +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++ ) + { + obj = downed_players_objs[ obj_keys[ i ] ]; + if ( isDefined( obj.owner ) ) + { + continue; + } + if ( obj.bad ) + { + continue; + } + self.available_revives[ self.available_revives.size ] = obj; + } + return self.available_revives.size > 0; +} + +bot_check_complete_revive_player() +{ + return self.successfully_revived_player; +} + +bot_revive_player_should_cancel() +{ + if ( !isDefined( self.available_revives[ 0 ] ) ) + { + self.obj_cancel_reason = "Obj didn't exist"; + return true; + } + if ( !isDefined( self.available_revives[ 0 ].target_ent ) ) + { + self.obj_cancel_reason = "Entity didn't exist"; + return true; + } + if ( !isDefined( self.available_revives[ 0 ].target_ent.revivetrigger ) ) + { + self.obj_cancel_reason = "Revive trigger didn't exist"; + return true; + } + return false; +} + +bot_revive_player_should_postpone() +{ + return false; +} + +bot_revive_player_priority() +{ + return 0; +} \ No newline at end of file diff --git a/maps/bots/script_objectives/_obj_common.gsc b/maps/bots/script_objectives/_obj_common.gsc new file mode 100644 index 0000000..aadee9e --- /dev/null +++ b/maps/bots/script_objectives/_obj_common.gsc @@ -0,0 +1,644 @@ +#include common_scripts\utility; +#include maps\_utility; +#include maps\bots\_bot_utility; + +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, target_ent, is_global_shared ) +{ + 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" ); + + if ( !isDefined( target_ent ) ) + { + assertMsg( "target_ent is undefined" ); + return; + } + + id = target_ent getEntityNumber(); + + objective_struct = spawnStruct(); + objective_struct.group = objective_group; + objective_struct.is_global_shared = is_global_shared; + objective_struct.target_ent = target_ent; + objective_struct.owner = undefined; + objective_struct.is_objective = true; + objective_struct.bad = false; + + level.zbot_objective_glob[ objective_group ].active_objectives[ "obj_id_" + id ] = objective_struct; +} + +get_bot_objective_by_entity_ref( objective_group, ent ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + id = ent getEntityNumber(); + + 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; +} + +bot_get_objective() +{ + return self.zbot_current_objective; +} + +bot_has_objective() +{ + return isDefined( self.zbot_current_objective ); +} + +bot_set_objective( objective_group, ent ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + possible_objectives = level.zbot_objective_glob[ objective_group ].active_objectives; + + id = ent getEntityNumber(); + + 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_ent, blocked_by_objective_group, blocked_by_ent ) +{ + if ( !isDefined( primary_ent ) ) + { + assertMsg( "Primary_ent is undefined" ); + return; + } + + if ( !isDefined( blocked_by_ent ) ) + { + assertMsg( "Blocked_by_ent is undefined" ); + return; + } + + primary_id = primary_ent getEntityNumber(); + + blocked_by_id = blocked_by_ent getEntityNumber(); + + 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; + } +} + +bot_is_objective_owner( objective_group, ent ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return false; + } + + id = ent getEntityNumber(); + + 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 false; + } + + 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 false; + } + + return isDefined( objective.owner ) && objective.owner == self; +} + +set_bot_global_shared_objective_owner_by_ent( objective_group, ent, new_owner ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + id = ent getEntityNumber(); + + 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; +} + +mark_objective_bad( objective_group, ent ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + id = ent getEntityNumber(); + + 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; + } + + objective.bad = true; +} + +free_bot_objective( objective_group, ent ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + id = ent getEntityNumber(); + + 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; + } + + players = getPlayers(); + for ( i = 0; i < players.size; i++ ) + { + if ( isDefined( players[ i ].pers[ "isBot" ] ) && players[ i ].pers[ "isBot" ] ) + { + if ( isDefined( players[ i ].zbot_current_objective ) && players[ i ].zbot_current_objective == objective ) + { + players[ i ].zbot_current_objective = undefined; + } + } + } + + active_objectives[ "obj_id_" + id ] = undefined; +} + +bot_objective_print( objective_group, ent, message ) +{ + if ( !isDefined( ent ) ) + { + assertMsg( "Ent is undefined" ); + return; + } + + id = ent getEntityNumber(); + + 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; + } + + if ( getDvarInt( "bot_obj_debug_" + objective_group ) != 0 ) + { + printConsole( "Obj <" + objective_group + "> ent <" + id + "> " + message + "\n" ); + } +} + +/**********Action Section**********/ + +register_bot_action( group_name, action_name, action_func, action_process_order_func, init_func, post_think_func, should_do_func, check_if_complete_func, should_cancel_func, should_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 ].init_func = init_func; + level.zbots_actions[ group_name ][ action_name ].post_think_func = post_think_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 ].should_cancel_func = should_cancel_func; + level.zbots_actions[ group_name ][ action_name ].should_postpone_func = should_postpone_func; + level.zbots_actions[ group_name ][ action_name ].priority_func = priority_func; +} + +initialize_bot_actions_queue() +{ + self.action_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 ] ); + } + } +} + +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 ].queued = 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 ].is_current ) + { + return; + } + + self.action_queue[ group_name ] = self sort_array_by_priority_field( self.action_queue[ group_name ] ); + + action_name = self.action_queue[ group_name ][ 0 ].action_name; + + self [[ level.zbots_actions[ group_name ][ action_name ].init_func ]](); + + self thread [[ level.zbots_actions[ group_name ][ action_name ].action ]](); + + self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = true; + + self thread wait_for_action_completion( group_name, action_name ); +} + +wait_for_action_completion( group_name, action_name ) +{ + self endon( "disconnect" ); + self endon( "stop_action_think" ); + level endon( "end_game" ); + + action_complete_name = action_name + "_complete"; + action_cancel_name = action_name + "_cancel"; + action_postpone_name = action_name + "_postpone"; + + result = self waittill_any_return( action_complete_name, action_cancel_name, action_postpone_name ); + + save_action = false; + + end_state = undefined; + + if ( ( result == action_complete_name ) ) + { + self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false; + self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false; + end_state = "completed"; + } + else if ( result == action_cancel_name ) + { + self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = false; + self.zbot_actions_in_queue[ group_name ][ action_name ].queued = false; + end_state = "canceled"; + } + else if ( result == action_postpone_name ) + { + self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = true; + save_action = true; + end_state = "postponed"; + } + + self.zbot_actions_in_queue[ group_name ][ action_name ].is_current = false; + + self notify( action_name + "_end_think" ); + + self [[ level.zbots_actions[ group_name ][ action_name ].post_think_func ]]( end_state ); + + if ( save_action ) + { + postponed_action = self.action_queue[ group_name ][ 0 ]; + 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, 2 ); + self.action_queue[ group_name ][ 0 ] = undefined; + } + else + { + self.action_queue[ group_name ][ 0 ] = undefined; + } +} + +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++ ) + { + + } + */ + + //Reboot the action queue because the last member was deleted which deletes the array + if ( !isDefined( self.action_queue ) || !isDefined( self.action_queue[ group_name ] ) ) + { + self.action_queue = []; + self.action_queue[ group_name ] = []; + } + + 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, action_name ) +{ + assert( isDefined( level.zbots_actions[ group_name ][ action_name ].check_if_complete_func ) ); + + if ( self [[ level.zbots_actions[ group_name ][ action_name ].check_if_complete_func ]]() ) + { + self notify( action_name + "_complete" ); + } +} + +check_if_action_should_be_postponed_in_group( group_name, action_name ) +{ + if ( self [[ level.zbots_actions[ group_name ][ action_name ].should_postpone_func ]]() ) + { + self notify( action_name + "_postpone" ); + } +} + +check_if_action_should_be_canceled_in_group( group_name, action_name ) +{ + if ( self [[ level.zbots_actions[ group_name ][ action_name ].should_cancel_func ]]() ) + { + self notify( action_name + "_cancel" ); + } +} + +check_if_action_should_be_postponed_globally( group_name, action_name ) +{ + if ( action_should_be_postponed_global( group_name, action_name ) ) + { + self notify( action_name + "_postpone" ); + } +} + +check_if_action_should_be_canceled_globally( group_name, action_name ) +{ + if ( action_should_be_canceled_global( group_name, action_name ) ) + { + self notify( 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() +{ + self endon( "disconnect" ); + self endon( "zombified" ); + + while ( true ) + { + wait 0.05; + //Wait until the end of the frame so any variables set by _bot_internal in the current frame will have up to date values + waittillframeend; + waittillframeend; + + group_name = "objective"; + + self pick_actions_to_add_to_queue( group_name ); + + //self check_for_forced_action( group_name ); + + if ( !isDefined( self.action_queue[ group_name ][ 0 ] ) ) + { + continue; + } + + self process_next_queued_action( group_name ); + + action_name = self.action_queue[ group_name ][ 0 ].action_name; + + self check_if_action_is_completed_in_group( group_name, action_name ); + self check_if_action_should_be_postponed_in_group( group_name, action_name ); + self check_if_action_should_be_canceled_in_group( group_name, action_name ); + + self check_if_action_should_be_postponed_globally( group_name, action_name ); + self check_if_action_should_be_canceled_globally( group_name, action_name ); + } +} + +action_should_be_postponed_global( primary_group_name, action_name ) +{ + return false; +} + +action_should_be_canceled_global( primary_group_name, action_name ) +{ + obj = self bot_get_objective(); + + if ( self GetPathIsInaccessible() ) + { + self.obj_cancel_reason = "Path was inaccessible"; + return true; + } + if ( obj.bad ) + { + self.obj_cancel_reason = "Obj was bad"; + return true; + } + return false; +} \ No newline at end of file diff --git a/maps/bots/script_objectives/_obj_trackers.gsc b/maps/bots/script_objectives/_obj_trackers.gsc new file mode 100644 index 0000000..06b6a5c --- /dev/null +++ b/maps/bots/script_objectives/_obj_trackers.gsc @@ -0,0 +1,148 @@ +#include common_scripts\utility; +#include maps\_utility; +#include maps\bots\_bot_utility; +#include maps\bots\script_objectives\_obj_common; + +store_powerups_dropped() +{ + level endon( "end_game" ); + + level thread free_powerups_dropped(); + + level.zbots_powerups = []; + while ( true ) + { + level waittill( "powerup_dropped", powerup ); + waittillframeend; + if ( !isDefined( powerup ) ) + { + continue; + } + add_possible_bot_objective( "powerup", powerup, true ); + //maps\bots\_bot_utility::assign_priority_to_powerup( powerup ); + //level.zbots_powerups = maps\bots\_bot_utility::sort_array_by_priority_field( level.zbots_powerups, powerup ); + } +} + +free_powerups_dropped() +{ + level endon( "end_game" ); + + while ( true ) + { + level waittill( "powerup_freed", powerup ); + free_bot_objective( "powerup", powerup ); + } +} + +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, true ); + 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", self ); +} + +bot_valid_pump() +{ + level endon( "end_game" ); + + obj_sav = undefined; + + while ( true ) + { + obj_sav = self.zbot_current_objective; + wait 0.5; + if ( !maps\so\zm_common\_zm_utility::is_player_valid( self ) ) + { + if ( isDefined( self ) ) + { + self notify( "bot_in_invalid_state" ); + self clear_objective_for_bot(); + } + else if ( isDefined( obj_sav ) ) + { + set_bot_global_shared_objective_owner_by_ent( obj_sav.group, obj_sav.target_ent, undefined ); + } + + while ( isDefined( self ) && !maps\so\zm_common\_zm_utility::is_player_valid( self ) ) + { + wait 0.5; + } + if ( !isDefined( self ) ) + { + return; + } + } + } +} + +bot_objective_inaccessible_pump() +{ + self endon( "disconnect" ); + level endon( "end_game" ); + + while ( true ) + { + invalid_obj = false; + wait 0.5; + while ( !self bot_has_objective() ) + { + wait 0.5; + } + + while ( self bot_has_objective() ) + { + wait 1; + obj = self bot_get_objective(); + + if ( !isDefined( obj ) || !isDefined( obj.target_ent ) ) + { + invalid_obj = true; + } + else if ( !isDefined( generatePath( self.origin, obj.target_ent.origin, self.team, level.bot_allowed_negotiation_links ) ) ) + { + invalid_obj = true; + } + if ( invalid_obj ) + { + self notify( "bot_objective_inaccessible" ); + self.bot.path_inaccessible = true; + break; + } + } + } +} + +bot_on_powerup_grab( powerup ) +{ + bot_objective_print( "powerup", powerup, "Bot <" + self.playername + "> bot grabbed powerup" ); + self.successfully_grabbed_powerup = true; +} + +bot_on_revive_success( revivee ) +{ + bot_objective_print( "revive", revivee, "Bot <" + self.playername + "> bot revived <" + revivee.playername + ">" ); + self.successfully_revived_player = true; +} \ No newline at end of file