From 1990b8c79de56b131ec448c9007465027b1f3fc1 Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Fri, 28 Apr 2023 23:43:40 -0700 Subject: [PATCH] Fix compile errors. Add bot pathing and movement. --- scripts/sp/T4ZM_zbots_main.gsc | 309 ++++++--- scripts/sp/bots/_bot_internal.gsc | 758 +++++++++++++++++++++++ scripts/sp/bots/actions/look.gsc | 6 +- scripts/sp/bots/actions/objective.gsc | 8 +- scripts/sp/bots/bot_actions_common.gsc | 5 +- scripts/sp/bots/bot_objective_common.gsc | 6 +- scripts/sp/bots/bot_pathing | 0 scripts/sp/bots/bot_target_common.gsc | 228 ++----- scripts/sp/bots/bot_utility.gsc | 130 +--- 9 files changed, 1051 insertions(+), 399 deletions(-) create mode 100644 scripts/sp/bots/_bot_internal.gsc delete mode 100644 scripts/sp/bots/bot_pathing diff --git a/scripts/sp/T4ZM_zbots_main.gsc b/scripts/sp/T4ZM_zbots_main.gsc index 2f5f11e..38983a5 100644 --- a/scripts/sp/T4ZM_zbots_main.gsc +++ b/scripts/sp/T4ZM_zbots_main.gsc @@ -2,17 +2,20 @@ #include maps\_utility; #include maps\so\zm_common\_zm_utility; +#include scripts\sp\bots\_bot_internal; + #include scripts\sp\bots\bot_actions_common; #include scripts\sp\bots\bot_objective_common; #include scripts\sp\bots\bot_difficulty_presets_common; #include scripts\sp\bots\bot_personality_presets_common; -#include scripts\sp\bots\bot_pathing; #include scripts\sp\bots\bot_target_common; #include scripts\sp\bots\actions\combat; #include scripts\sp\bots\actions\movement; #include scripts\sp\bots\actions\objective; #include scripts\sp\bots\actions\look; +#include scripts\sp\bots\bot_utility; + main() { //Objective group is for things to go to usually allowing the bot to kill zombies on the way and survive as normal @@ -41,14 +44,14 @@ main() //Movement actions //These all need definitions - register_bot_action( "movement", "movetoobjective", ::bot_movetoobjective, ::bot_movetoobjective_process_order ::bot_should_movetoobjective, ::bot_check_complete_movetoobjective, ::bot_set_complete_movetoobjective, ::bot_movetoobjective_on_completion, ::bot_movetoobjective_should_cancel, ::bot_movetoobjective_on_cancel, ::bot_movetoobjective_should_postpone, ::bot_movetoobjective_on_postpone, ::bot_movetoobjective_priority ); + register_bot_action( "movement", "movetoobjective", ::bot_movetoobjective, ::bot_movetoobjective_process_order, ::bot_should_movetoobjective, ::bot_check_complete_movetoobjective, ::bot_set_complete_movetoobjective, ::bot_movetoobjective_on_completion, ::bot_movetoobjective_should_cancel, ::bot_movetoobjective_on_cancel, ::bot_movetoobjective_should_postpone, ::bot_movetoobjective_on_postpone, ::bot_movetoobjective_priority ); //register_bot_action( "movement", "moveoverride", ::bot_moveoverride, ::bot_moveoverride_process_order, ::bot_should_moveoverride, ::bot_check_complete_moveoverride, ::bot_set_complete_moveoverride, ::bot_moveoverride_on_completion, ::bot_moveoverride_should_cancel, ::bot_moveoverride_on_cancel, ::bot_moveoverride_should_postpone, ::bot_moveoverride_on_postpone, ::bot_moveoverride_priority ); register_bot_action( "movement", "train", ::bot_train, ::bot_train_process_order, ::bot_should_train, ::bot_check_complete_train, ::bot_set_complete_train, ::bot_train_on_completion, ::bot_train_should_cancel, ::bot_train_on_cancel, ::bot_train_should_postpone, ::bot_train_on_postpone, ::bot_train_priority ); register_bot_action( "movement", "camp", ::bot_camp, ::bot_camp_process_order, ::bot_should_camp, ::bot_check_complete_camp, ::bot_set_complete_camp, ::bot_camp_on_completion, ::bot_camp_should_cancel, ::bot_camp_on_cancel, ::bot_camp_should_postpone, ::bot_camp_on_postpone, ::bot_camp_priority ); register_bot_action( "movement", "flee", ::bot_flee, ::bot_flee_process_order, ::bot_should_flee, ::bot_check_complete_flee, ::bot_set_complete_flee, ::bot_flee_on_completion, ::bot_flee_should_cancel, ::bot_flee_on_cancel, ::bot_flee_should_postpone, ::bot_flee_on_postpone, ::bot_flee_priority ); //register_bot_action( "follow" ) - register_bot_action( "look", "lookatobjective", ::bot_lookatobjective, ::bot_lookatobjective_process_order ::bot_should_lookatobjective, ::bot_check_complete_lookatobjective, ::bot_set_complete_lookatobjective, ::bot_lookatobjective_on_completion, ::bot_lookatobjective_should_cancel, ::bot_lookatobjective_on_cancel, ::bot_lookatobjective_should_postpone, ::bot_lookatobjective_on_postpone, ::bot_lookatobjective_priority ); + register_bot_action( "look", "lookatobjective", ::bot_lookatobjective, ::bot_lookatobjective_process_order, ::bot_should_lookatobjective, ::bot_check_complete_lookatobjective, ::bot_set_complete_lookatobjective, ::bot_lookatobjective_on_completion, ::bot_lookatobjective_should_cancel, ::bot_lookatobjective_on_cancel, ::bot_lookatobjective_should_postpone, ::bot_lookatobjective_on_postpone, ::bot_lookatobjective_priority ); register_bot_action( "look", "lookattarget", ::bot_lookattarget, ::bot_lookattarget_process_order, ::bot_should_lookattarget, ::bot_check_complete_lookattarget, ::bot_set_complete_lookattarget, ::bot_lookattarget_on_completion, ::bot_lookattarget_should_cancel, ::bot_lookattarget_on_cancel, ::bot_lookattarget_should_postpone, ::bot_lookattarget_on_postpone, ::bot_lookattarget_priority ); register_bot_action( "look", "lookatgoal", ::bot_lookatgoal, ::bot_lookatgoal_process_order, ::bot_should_lookatgoal, ::bot_check_complete_lookatgoal, ::bot_set_complete_lookatgoal, ::bot_lookatgoal_on_completion, ::bot_lookatgoal_should_cancel, ::bot_lookatgoal_on_cancel, ::bot_lookatgoal_should_postpone, ::bot_lookatgoal_on_postpone, ::bot_lookatgoal_priority ); //register_bot_action( "look", "ads", ::bot_ads, ::bot_ads_process_order, ::bot_should_ads, ::bot_check_complete_ads, ::bot_set_complete_ads, ::bot_ads_on_completion, ::bot_ads_should_cancel, ::bot_ads_on_cancel, ::bot_ads_should_postpone, ::bot_ads_on_postpone, ::bot_ads_priority ); @@ -89,6 +92,22 @@ main() level.bot_weapon_quality_excellent = 3; level.bot_weapon_quality_best = 4; + level.bots_minSprintDistance = 315; + level.bots_minSprintDistance *= level.bots_minSprintDistance; + level.bots_minGrenadeDistance = 256; + level.bots_minGrenadeDistance *= level.bots_minGrenadeDistance; + level.bots_maxGrenadeDistance = 1024; + level.bots_maxGrenadeDistance *= level.bots_maxGrenadeDistance; + level.bots_maxKnifeDistance = 80; + level.bots_maxKnifeDistance *= level.bots_maxKnifeDistance; + level.bots_goalDistance = 27.5; + level.bots_goalDistance *= level.bots_goalDistance; + level.bots_noADSDistance = 200; + level.bots_noADSDistance *= level.bots_noADSDistance; + level.bots_maxShotgunDistance = 500; + level.bots_maxShotgunDistance *= level.bots_maxShotgunDistance; + level.bots_listenDist = 100; + /* level.bot_powerup_priority_none = 0; level.bot_powerup_priority_low = 1; @@ -105,11 +124,121 @@ main() register_bot_powerup_priority( "zombie_blood", level.bot_powerup_priority_high, level.bot_powerup_priority_urgent); */ - level.zbot_path_nodes = getAllNodes(); - - level thread spawn_bots(); + level thread spawn_bots_for_host(); level thread on_player_connect(); + + level.waypoints = getAllNodes(); + + level.waypoints_inside_playable_area = get_nodes_in_playable_area(); + + level.waypointCount = level.waypoints.size; + + level.waypoint_count_inside_playable_area = level.waypoints_inside_playable_area.size; +} + +/* + We clear all of the script variables and other stuff for the bots. +*/ +resetBotVars() +{ + self.bot = spawnStruct(); + self.bot.script_target = undefined; + self.bot.script_target_offset = undefined; + self.bot.target = undefined; + self.bot.targets = []; + self.bot.target_this_frame = undefined; + self.bot.after_target = undefined; + self.bot.after_target_pos = undefined; + self.bot.moveTo = self.origin; + + self.bot.script_aimpos = undefined; + + self.bot.script_goal = undefined; + self.bot.script_goal_dist = 0.0; + + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; + self.bot.towards_goal = undefined; + self.bot.astar = []; + self.bot.stop_move = false; + self.bot.greedy_path = false; + self.bot.climbing = false; + self.bot.wantsprint = false; + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + + self.bot.isfrozen = false; + self.bot.sprintendtime = -1; + self.bot.isreloading = false; + self.bot.issprinting = false; + self.bot.isfragging = false; + self.bot.issmoking = false; + self.bot.isfraggingafter = false; + self.bot.issmokingafter = false; + self.bot.isknifing = false; + self.bot.isknifingafter = false; + + self.bot.semi_time = false; + self.bot.jump_time = undefined; + self.bot.last_fire_time = -1; + + self.bot.is_cur_full_auto = false; + self.bot.cur_weap_dist_multi = 1; + self.bot.is_cur_sniper = false; + + self.bot.rand = randomInt( 100 ); + + self botStop(); +} + +get_nodes_in_playable_area() +{ + total_nodes = getAllNodes(); + filtered_nodes = []; + for ( i = 0; i < total_nodes.size; i++ ) + { + if ( !is_point_in_playable_area( total_nodes[ i ].origin ) ) + { + continue; + } + filtered_nodes[ filtered_nodes.size ] = total_nodes[ i ]; + if ( ( i % 10 ) == 0 ) + { + wait 0.05; + } + } + return filtered_nodes; +} + +is_point_in_playable_area( point ) +{ + playable_area = getentarray( "playable_area", "targetname" ); + + in_playable_area = false; + + if ( !isDefined( playable_area ) || playable_area.size < 1 ) + { + in_playable_area = true; + } + + temp_ent = spawn( "script_origin", point ); + + if ( !in_playable_area ) + { + for ( p = 0; p < playable_area.size; p++ ) + { + if ( temp_ent isTouching( playable_area[ p ] ) ) + { + in_playable_area = true; + break; + } + } + } + + temp_ent delete(); + + return in_playable_area; } on_player_connect() @@ -118,19 +247,85 @@ on_player_connect() while ( true ) { level waittill( "connected", player ); + player thread on_player_spawned(); player.client_id = i; if ( player isBot() ) { + player resetBotVars(); player.successfully_grabbed_powerup = false; player.successfully_revived_player = false; player.successfully_moved_to_objective = false; player.can_do_objective_now = false; player.on_powerup_grab_func = ::bot_on_powerup_grab; + player thread zbot_spawn(); + } + else + { + player thread bot_control(); } i++; } } +bot_control() +{ + self endon( "disconnect" ); + self notifyOnPlayerCommand( "+smoke", "new_script_goal" ); + while ( true ) + { + self waittill( "new_script_goal" ); + players = getPlayers(); + for ( i = 0; i < players.size; i++ ) + { + if ( players[ i ] isBot() ) + { + players[ i ] scripts\sp\bots\_bot_utility::SetScriptGoal( self.origin ); + players[ i ] thread clear_script_on_event(); + } + } + self iPrintLn( "Set new goal for bots" ); + } +} + +clear_script_on_event() +{ + self endon( "disconnect" ); + result = self waittill_any_return( "new_goal", "goal", "bad_path" ); + if ( result != "new_goal" ) + { + self scripts\sp\bots\_bot_utility::ClearScriptGoal(); + } +} + +on_player_spawned() +{ + self waittill( "spawned_player" ); + self.score = 100000; +} + +zbot_spawn() +{ + level endon( "end_game" ); + self endon( "disconnect" ); + + while ( true ) + { + self waittill( "spawned_player" ); + self thread doBotMovement(); + //self thread grenade_danger(); + //self thread check_reload(); + //self thread stance(); + self thread walk(); + //self thread target(); + //self thread updateBones(); + //self thread aim(); + //self thread watchHoldBreath(); + //self thread onNewEnemy(); + //self thread watchGrenadeFire(); + //self thread watchPickupGun(); + } +} + //TODO: Make postponing save the settings for the action so when the action is being executed again the bot tries to do/get the same thing //TODO: Make global canceling and postponing functionality //TODO: Make shared global objective and normal objective globs work @@ -151,7 +346,7 @@ init() { level.chests[ i ].id = i; } - level thread watch_magicbox_objectives(); + //level thread watch_magicbox_objectives(); } weapon_spawns = GetEntArray( "weapon_upgrade", "targetname" ); @@ -272,15 +467,11 @@ remove_target_damaged_by_after_time( target_ent, id ) self clear_target_damaged_by( target_ent.targetname, id ); } -spawn_bots() +spawn_bots_for_host() { level waittill( "connected", player ); - while ( true ) - { - spawn_bots(); - wait 1; - } + spawn_bots(); } spawn_bots() @@ -290,18 +481,22 @@ spawn_bots() while ( bot_count < required_bots ) { bot = undefined; - while ( !isDefined( bot ) ) + 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 register_action_queue_actions(); + //bot thread bot_think(); bot_count++; } } @@ -316,11 +511,11 @@ bot_think() while ( true ) { wait 0.25; - if ( !bot_valid( self ) ) + if ( !scripts\sp\bots\bot_utility::bot_valid( self ) ) { self notify( "stop_action_think" ); self bot_clear_actions_queue(); - while ( !bot_valid( self ) ) + while ( !scripts\sp\bots\bot_utility::bot_valid( self ) ) { wait 1; } @@ -336,6 +531,8 @@ bot_think() group_name = "combat"; + //self scripts\sp\bots\bot_target_common::bot_pick_target(); + self bot_action_think( group_name ); group_name = "objective"; @@ -344,43 +541,6 @@ bot_think() } } -bot_movement_think() -{ - level endon( "end_game" ); - self endon( "disconnect" ); - /* - if ( self any_zombies_targeting_self() ) - { - - } - */ - self.currently_moving = false; - while ( true ) - { - wait 0.05; - if ( isDefined( self.target_pos ) && !self.currently_moving ) - { - self lookAt( self.target_pos ); - self addGoal( self.target_pos, 36, 4, "move_to_target_pos" ); - self.currently_moving = true; - } - if ( self hasGoal( "move_to_target_pos" ) ) - { - if ( self atGoal( "move_to_target_pos" ) ) - { - self clearLookat(); - self.currently_moving = false; - if ( isDefined( self.goal_type ) && isDefined( level.bot_at_goal_callback[ self.goal_type ] ) ) - { - self [[ level.bot_at_goal_callback[ self.goal_type ] ]](); - } - } - } - - self doBotMovement_loop(); - } -} - watch_door_objectives( zombie_doors ) { level endon( "end_game" ); @@ -407,6 +567,8 @@ watch_magicbox_objectives() { level endon( "end_game" ); + level waittill( "connected", player ); + prev_magicbox = maps\so\zm_common\_zm_magicbox::get_active_magicbox(); while ( true ) { @@ -437,8 +599,8 @@ store_powerups_dropped() } powerup.id = id; add_possible_bot_objective( "powerup", id, true, powerup ); - assign_priority_to_powerup( powerup ); - level.zbots_powerups = sort_array_by_priority_field( level.zbots_powerups, powerup ); + 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++; } } @@ -483,39 +645,6 @@ free_revive_objective_when_needed() free_bot_objective( "revive", id ); } -doBotMovement_loop() -{ - move_To = self.bot.moveTo; - angles = self GetPlayerAngles(); - dir = ( 0, 0, 0 ); - - if ( DistanceSquared( self.origin, move_To ) >= 49 ) - { - cosa = cos( 0 - angles[1] ); - sina = sin( 0 - angles[1] ); - - // get the direction - dir = move_To - self.origin; - - // rotate our direction according to our angles - dir = ( dir[0] * cosa - dir[1] * sina, - dir[0] * sina + dir[1] * cosa, - 0 ); - - // make the length 127 - dir = VectorNormalize( dir ) * 127; - - // invert the second component as the engine requires this - dir = ( dir[0], 0 - dir[1], 0 ); - } - - // move! - if ( self.bot.wantsprint && self.bot.issprinting ) - dir = ( 127, dir[1], 0 ); - - self botMovement( int( dir[0] ), int( dir[1] ) ); -} - bot_on_powerup_grab( powerup ) { self.successfully_grabbed_powerup = true; diff --git a/scripts/sp/bots/_bot_internal.gsc b/scripts/sp/bots/_bot_internal.gsc new file mode 100644 index 0000000..0cb3c7e --- /dev/null +++ b/scripts/sp/bots/_bot_internal.gsc @@ -0,0 +1,758 @@ +#include scripts\sp\bots\_bot_utility; +#include maps\_utility; +#include common_scripts\utility; + +/* + Bot moves towards the point +*/ +doBotMovement() +{ + self endon( "disconnect" ); + self endon( "zombified" ); + + data = spawnStruct(); + data.wasMantling = false; + + for ( data.i = 0; true; data.i += 0.05 ) + { + wait 0.05; + + waittillframeend; + self doBotMovement_loop( data ); + } +} + +/* + Bot moves towards the point +*/ +doBotMovement_loop( data ) +{ + move_To = self.bot.moveTo; + angles = self GetPlayerAngles(); + dir = ( 0, 0, 0 ); + + if ( DistanceSquared( self.origin, move_To ) >= 49 ) + { + cosa = cos( 0 - angles[1] ); + sina = sin( 0 - angles[1] ); + + // get the direction + dir = move_To - self.origin; + + // rotate our direction according to our angles + dir = ( dir[0] * cosa - dir[1] * sina, + dir[0] * sina + dir[1] * cosa, + 0 ); + + // make the length 127 + dir = VectorNormalize( dir ) * 127; + + // invert the second component as the engine requires this + dir = ( dir[0], 0 - dir[1], 0 ); + } + + startPos = self.origin + ( 0, 0, 50 ); + startPosForward = startPos + anglesToForward( ( 0, angles[1], 0 ) ) * 25; + bt = bulletTrace( startPos, startPosForward, false, self ); + + if ( bt["fraction"] >= 1 ) + { + // check if need to jump + bt = bulletTrace( startPosForward, startPosForward - ( 0, 0, 40 ), false, self ); + + if ( bt["fraction"] < 1 && bt["normal"][2] > 0.9 && data.i > 1.5 ) + { + data.i = 0; + self thread jump(); + } + } + // check if need to knife glass + else if ( bt["surfacetype"] == "glass" ) + { + if ( data.i > 1.5 ) + { + data.i = 0; + self thread knife(); + } + } + else + { + // check if need to crouch + if ( bulletTracePassed( startPos - ( 0, 0, 25 ), startPosForward - ( 0, 0, 25 ), false, self ) && !self.bot.climbing ) + self crouch(); + } + + // move! + if ( self.bot.wantsprint && self.bot.issprinting ) + dir = ( 127, dir[1], 0 ); + + self botMovement( int( dir[0] ), int( dir[1] ) ); +} + +/* + This is the main walking logic for the bot. +*/ +walk() +{ + self endon( "disconnect" ); + self endon( "zombified" ); + + for ( ;; ) + { + wait 0.05; + + self botMoveTo( self.origin ); + + //if ( !getDvarInt( "bots_play_move" ) ) + // continue; + + if ( level.intermission || self.bot.isfrozen || self.bot.stop_move ) + continue; + + self walk_loop(); + } +} + +/* + This is the main walking logic for the bot. +*/ +walk_loop() +{ + hasTarget = isDefined( self.bot.target ) && isDefined( self.bot.target.entity ); + + if ( hasTarget ) + { + curweap = self getCurrentWeapon(); + + if ( self.bot.isfraggingafter || self.bot.issmokingafter ) + { + return; + } + + if ( self.bot.target.trace_time && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) ) + { + if ( self maps\_laststand::player_is_in_laststand() || self GetStance() == "prone" || ( self.bot.is_cur_sniper && self PlayerADS() > 0 ) ) + return; + + if ( self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"] ) + self strafe( self.bot.target.entity ); + + return; + } + } + + dist = 16; + + goal = level.waypoints_inside_playable_area[randomInt( level.waypoint_count_inside_playable_area )].origin; + + isScriptGoal = false; + + if ( isDefined( self.bot.script_goal ) && !hasTarget ) + { + goal = self.bot.script_goal; + dist = self.bot.script_goal_dist; + + isScriptGoal = true; + } + else + { + if ( hasTarget ) + goal = self.bot.target.last_seen_pos; + + self notify( "new_goal_internal" ); + } + + self doWalk( goal, dist, isScriptGoal ); + self.bot.towards_goal = undefined; + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; +} + +/* + Will walk to the given goal when dist near. Uses AStar path finding with the level's nodes. +*/ +doWalk( goal, dist, isScriptGoal ) +{ + level endon( "end_game" ); + self endon( "kill_goal" ); + self endon( "goal_internal" ); //so that the watchOnGoal notify can happen same frame, not a frame later + + dist *= dist; + + if ( isScriptGoal ) + self thread doWalkScriptNotify(); + + self thread killWalkOnEvents(); + self thread watchOnGoal( goal, dist ); + + current = self initAStar( goal ); + + path_was_truncated = ( current + 1 ) >= 32; + + //Couldn't generate path to goal + if ( current <= -1 ) + { + self notify( "bad_path_internal" ); + return; + } + + // skip waypoints we already completed to prevent rubber banding + if ( current > 0 && self.bot.astar[current] == self.bot.last_next_wp && self.bot.astar[current - 1] == self.bot.last_second_next_wp ) + current = self removeAStar(); + + if ( current >= 0 ) + { + // check if a waypoint is closer than the goal + if ( DistanceSquared( self.origin, level.waypoints[self.bot.astar[current]].origin ) < DistanceSquared( self.origin, goal ) || DistanceSquared( level.waypoints[self.bot.astar[current]].origin, PlayerPhysicsTrace( self.origin + ( 0, 0, 32 ), level.waypoints[self.bot.astar[current]].origin ) ) > 1.0 ) + { + while ( current >= 0 ) + { + self.bot.next_wp = self.bot.astar[current]; + self.bot.second_next_wp = -1; + + if ( current > 0 ) + self.bot.second_next_wp = self.bot.astar[current - 1]; + + self notify( "new_static_waypoint" ); + + self movetowards( level.waypoints[self.bot.next_wp].origin ); + self.bot.last_next_wp = self.bot.next_wp; + self.bot.last_second_next_wp = self.bot.second_next_wp; + + current = self removeAStar(); + } + } + } + + if ( path_was_truncated ) + { + self notify( "kill_goal" ); + return; + } + + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; + self notify( "finished_static_waypoints" ); + + if ( DistanceSquared( self.origin, goal ) > dist ) + { + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + self movetowards( goal ); // any better way?? + } + + self notify( "finished_goal" ); + + wait 1; + + if ( DistanceSquared( self.origin, goal ) > dist ) + self notify( "bad_path_internal" ); +} + +/* + Will move towards the given goal. Will try to not get stuck by crouching, then jumping and then strafing around objects. +*/ +movetowards( goal ) +{ + if ( !isDefined( goal ) ) + return; + + self.bot.towards_goal = goal; + + lastOri = self.origin; + stucks = 0; + timeslow = 0; + time = 0; + + if ( self.bot.issprinting ) + tempGoalDist = level.bots_goalDistance * 2; + else + tempGoalDist = level.bots_goalDistance; + + while ( distanceSquared( self.origin, goal ) > tempGoalDist ) + { + self botMoveTo( goal ); + + if ( time > 3000 ) + { + time = 0; + + if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) + { + self thread knife(); + wait 0.5; + + stucks++; + + randomDir = self getRandomLargestStafe( stucks ); + + self BotNotifyBotEvent( "stuck" ); + + self botMoveTo( randomDir ); + wait stucks; + self stand(); + + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + } + + lastOri = self.origin; + } + else if ( timeslow > 0 && ( timeslow % 1000 ) == 0 ) + { + self thread doMantle(); + } + else if ( time == 2000 ) + { + if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) + self crouch(); + } + else if ( time == 1750 ) + { + if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) + { + // check if directly above or below + if ( abs( goal[2] - self.origin[2] ) > 64 && getConeDot( goal + ( 1, 1, 0 ), self.origin + ( -1, -1, 0 ), VectorToAngles( ( goal[0], goal[1], self.origin[2] ) - self.origin ) ) < 0.64 && DistanceSquared2D( self.origin, goal ) < 32 * 32 ) + { + stucks = 2; + } + } + } + + wait 0.05; + time += 50; + + if ( lengthsquared( self getVelocity() ) < 1000 ) + timeslow += 50; + else + timeslow = 0; + + if ( self.bot.issprinting ) + tempGoalDist = level.bots_goalDistance * 2; + else + tempGoalDist = level.bots_goalDistance; + + if ( stucks >= 2 ) + self notify( "bad_path_internal" ); + } + + self.bot.towards_goal = undefined; + self notify( "completed_move_to" ); +} + +/* + The bot will strafe left or right from their enemy. +*/ +strafe( target ) +{ + self endon( "kill_goal" ); + self thread killWalkOnEvents(); + + angles = VectorToAngles( vectorNormalize( target.origin - self.origin ) ); + anglesLeft = ( 0, angles[1] + 90, 0 ); + anglesRight = ( 0, angles[1] - 90, 0 ); + + myOrg = self.origin + ( 0, 0, 16 ); + left = myOrg + anglestoforward( anglesLeft ) * 500; + right = myOrg + anglestoforward( anglesRight ) * 500; + + traceLeft = BulletTrace( myOrg, left, false, self ); + traceRight = BulletTrace( myOrg, right, false, self ); + + strafe = traceLeft["position"]; + + if ( traceRight["fraction"] > traceLeft["fraction"] ) + strafe = traceRight["position"]; + + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + self botMoveTo( strafe ); + wait 2; + self notify( "kill_goal" ); +} + +/* + Will return the pos of the largest trace from the bot. +*/ +getRandomLargestStafe( dist ) +{ + //find a better algo? + traces = NewHeap( ::HeapTraceFraction ); + myOrg = self.origin + ( 0, 0, 16 ); + + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 0, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 0, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, 100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 100 * dist, 0 ), false, self ) ); + + toptraces = []; + + top = traces.data[0]; + toptraces[toptraces.size] = top; + traces HeapRemove(); + + while ( traces.data.size && top["fraction"] - traces.data[0]["fraction"] < 0.1 ) + { + toptraces[toptraces.size] = traces.data[0]; + traces HeapRemove(); + } + + return toptraces[randomInt( toptraces.size )]["position"]; +} + +/* + Calls the astar search algorithm for the path to the goal. +*/ +initAStar( goal ) +{ + nodes = generatePath( self.origin, goal, self.team, false ); + if ( !isDefined( nodes ) ) + { + return -1; + } + node_indexes = []; + for ( i = nodes.size - 1; i >= 0; i-- ) + { + node_indexes[ node_indexes.size ] = nodes[ i ] getNodeNumber(); + } + self.bot.astar = node_indexes; + + return self.bot.astar.size - 1; +} + +/* + Cleans up the astar nodes for one node. +*/ +removeAStar() +{ + remove = self.bot.astar.size - 1; + + self.bot.astar[remove] = undefined; + + return self.bot.astar.size - 1; +} + +/* + Does the notify for goal completion for outside scripts +*/ +doWalkScriptNotify() +{ + self endon( "disconnect" ); + self endon( "zombified" ); + self endon( "kill_goal" ); + + if ( self waittill_either_return( "goal_internal", "bad_path_internal" ) == "goal_internal" ) + self notify( "goal" ); + else + self notify( "bad_path" ); +} + +/* + Will stop the goal walk when an enemy is found or flashed or a new goal appeared for the bot. +*/ +killWalkOnEvents() +{ + self endon( "kill_goal" ); + self endon( "disconnect" ); + self endon( "zombified" ); + + self waittill_any( "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal" ); + + waittillframeend; + + self notify( "kill_goal" ); +} + +/* + Will kill the goal when the bot made it to its goal. +*/ +watchOnGoal( goal, dis ) +{ + self endon( "disconnect" ); + self endon( "zombified" ); + self endon( "kill_goal" ); + + while ( DistanceSquared( self.origin, goal ) > dis ) + wait 0.05; + + self notify( "goal_internal" ); +} + +/* + Bot will move towards here +*/ +botMoveTo( where ) +{ + self.bot.moveTo = where; +} + +/* + Bot will reload. +*/ +reload() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_reload" ); + self endon( "bot_reload" ); + + self botAction( "+reload" ); + wait 0.05; + self botAction( "-reload" ); +} + +/* + Bot will hold the frag button for a time +*/ +frag( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_frag" ); + self endon( "bot_frag" ); + + if ( !isDefined( time ) ) + time = 0.05; + + self botAction( "+frag" ); + self.bot.isfragging = true; + self.bot.isfraggingafter = true; + + if ( time ) + wait time; + + self botAction( "-frag" ); + self.bot.isfragging = false; + + wait 1.25; + self.bot.isfraggingafter = false; +} + +/* + Bot will hold the 'smoke' button for a time. +*/ +smoke( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_smoke" ); + self endon( "bot_smoke" ); + + if ( !isDefined( time ) ) + time = 0.05; + + self botAction( "+smoke" ); + self.bot.issmoking = true; + self.bot.issmokingafter = true; + + if ( time ) + wait time; + + self botAction( "-smoke" ); + self.bot.issmoking = false; + + wait 1.25; + self.bot.issmokingafter = false; +} + +/* + Bot will fire if true or not. +*/ +fire( what ) +{ + self notify( "bot_fire" ); + + if ( what ) + self botAction( "+fire" ); + else + self botAction( "-fire" ); +} + +/* + Bot will fire for a time. +*/ +pressFire( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_fire" ); + self endon( "bot_fire" ); + + if ( !isDefined( time ) ) + time = 0.05; + + self botAction( "+fire" ); + + if ( time ) + wait time; + + self botAction( "-fire" ); +} + +/* + Bot will ads if true or not. +*/ +ads( what ) +{ + self notify( "bot_ads" ); + + if ( what ) + self botAction( "+ads" ); + else + self botAction( "-ads" ); +} + +/* + Bot will press ADS for a time. +*/ +pressADS( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_ads" ); + self endon( "bot_ads" ); + + if ( !isDefined( time ) ) + time = 0.05; + + self botAction( "+ads" ); + + if ( time ) + wait time; + + self botAction( "-ads" ); +} + +/* + Bot will press use for a time. +*/ +use( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_use" ); + self endon( "bot_use" ); + + if ( !isDefined( time ) ) + time = 0.05; + + self botAction( "+activate" ); + + if ( time ) + wait time; + + self botAction( "-activate" ); +} + +/* + Bot will jump. +*/ +jump() +{ + self endon( "zombified" ); + self endon( "disconnect" ); + self notify( "bot_jump" ); + self endon( "bot_jump" ); + + if ( self getStance() != "stand" ) + { + self stand(); + wait 1; + } + + self botAction( "+gostand" ); + wait 0.05; + self botAction( "-gostand" ); +} + +/* + Bots do the mantle +*/ +doMantle() +{ + self endon( "disconnect" ); + self endon( "zombified" ); + self endon( "kill_goal" ); + + self jump(); + + wait 0.35; + + self jump(); +} + +/* + Bot will stand. +*/ +stand() +{ + self botAction( "-gocrouch" ); + self botAction( "-goprone" ); +} + +/* + Bot will crouch. +*/ +crouch() +{ + self botAction( "+gocrouch" ); + self botAction( "-goprone" ); +} + +/* + Bot will knife. +*/ +knife() +{ + self endon( "zombified" ); + self endon( "disconnect" ); + self notify( "bot_knife" ); + self endon( "bot_knife" ); + + self.bot.isknifing = true; + self.bot.isknifingafter = true; + + self botAction( "+melee" ); + wait 0.05; + self botAction( "-melee" ); + + self.bot.isknifing = false; + + wait 1; + + self.bot.isknifingafter = false; +} + +/* + Returns true if the bot can fire their current weapon. +*/ +canFire( curweap ) +{ + if ( curweap == "none" ) + return false; + + return self GetWeaponammoclip( curweap ); +} + +/* + Returns true if the bot is in range of their target. +*/ +isInRange( dist, curweap ) +{ + if ( curweap == "none" ) + return false; + + weapclass = weaponClass( curweap ); + + if ( weapclass == "spread" && dist > level.bots_maxShotgunDistance ) + return false; + + if ( curweap == "m2_flamethrower_mp" && dist > level.bots_maxShotgunDistance ) + return false; + + return true; +} \ No newline at end of file diff --git a/scripts/sp/bots/actions/look.gsc b/scripts/sp/bots/actions/look.gsc index 10f985f..5e9db40 100644 --- a/scripts/sp/bots/actions/look.gsc +++ b/scripts/sp/bots/actions/look.gsc @@ -1,3 +1,5 @@ +#include scripts\sp\bots\bot_target_common; + bot_lookatobjective() { @@ -60,7 +62,7 @@ bot_lookattarget() { target = self.zbot_current_target; target_ent = target.target_ent; - self bot_lookat( target_ent getTagOrigin( "j_head" ), time, vel, doAimPredict ); + self bot_lookat( target_ent getTagOrigin( "j_head" ) ); wait 0.05; } } @@ -195,7 +197,7 @@ bot_lookat( pos, time, vel, doAimPredict ) if ( steps < 1 ) steps = 1; - myEye = self GetEyePos(); // get our eye pos + myEye = self scripts\sp\bots\_bot_utility::GetEyePos(); // get our eye pos if ( doAimPredict ) { diff --git a/scripts/sp/bots/actions/objective.gsc b/scripts/sp/bots/actions/objective.gsc index 0f9bfa3..4aef244 100644 --- a/scripts/sp/bots/actions/objective.gsc +++ b/scripts/sp/bots/actions/objective.gsc @@ -1,3 +1,5 @@ +#include scripts\sp\bots\bot_objective_common; + bot_magicbox_purchase() { self.target_pos = self.available_chests[ 0 ].origin; @@ -37,7 +39,7 @@ bot_should_purchase_magicbox() { if ( isDefined( self.available_chests[ i ].chest_user ) ) { - arrayRemoveIndex( self.available_chests, i ); + maps\_utility::array_remove_index( self.available_chests, i ); i--; } } @@ -83,7 +85,7 @@ bot_magicbox_purchase_on_postpone() bot_magicbox_purchase_priority() { priority = 0; - const LOW_AMMO_THRESHOLD = 0.3; + LOW_AMMO_THRESHOLD = 0.3; weapons = self getWeaponsListPrimaries(); if ( weapons.size < 2 ) { @@ -540,7 +542,7 @@ bot_should_revive_player() continue; } - self.available_revives[ self.available_revives.size ] = downed_players[ obj_keys[ i ] ]; + self.available_revives[ self.available_revives.size ] = downed_players_objs[ obj_keys[ i ] ]; } return self.available_revives.size > 0; } diff --git a/scripts/sp/bots/bot_actions_common.gsc b/scripts/sp/bots/bot_actions_common.gsc index ffda98d..536489e 100644 --- a/scripts/sp/bots/bot_actions_common.gsc +++ b/scripts/sp/bots/bot_actions_common.gsc @@ -4,6 +4,7 @@ #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 ) { @@ -118,7 +119,7 @@ wait_for_action_completion( group_name, action_name ) 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_keys[ i ] ].priority_func ]](); + 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 ]](); } @@ -230,7 +231,7 @@ 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++ ); + 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 ]](); diff --git a/scripts/sp/bots/bot_objective_common.gsc b/scripts/sp/bots/bot_objective_common.gsc index 909784b..973ee49 100644 --- a/scripts/sp/bots/bot_objective_common.gsc +++ b/scripts/sp/bots/bot_objective_common.gsc @@ -46,11 +46,11 @@ get_all_objectives_for_group( objective_group ) set_objective_for_bot( objective_group, id ) { - possible_objectives = level.zbot_objective_glob[ primary_objective_group ].active_objectives; + possible_objectives = level.zbot_objective_glob[ objective_group ].active_objectives; objective = possible_objectives[ "obj_id_" + id ]; - objective_exists = isDefined( primary_objective ); + objective_exists = isDefined( objective ); assert( objective_exists, "Objective with " + id + " id does not point to a objective in group " + objective_group ); if ( !objective_exists ) @@ -147,7 +147,7 @@ set_bot_global_shared_objective_owner_by_reference( objective_group, objective, { 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 ); + 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; diff --git a/scripts/sp/bots/bot_pathing b/scripts/sp/bots/bot_pathing deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/sp/bots/bot_target_common.gsc b/scripts/sp/bots/bot_target_common.gsc index ddbeaf9..a88baf5 100644 --- a/scripts/sp/bots/bot_target_common.gsc +++ b/scripts/sp/bots/bot_target_common.gsc @@ -1,3 +1,6 @@ +#include common_scripts\utility; +#include scripts\sp\bots\_bot_utility; + register_bot_target_type( target_group ) { if ( !isDefined( level.zbot_target_glob ) ) @@ -21,7 +24,7 @@ add_possible_bot_target( target_group, id, target_ent ) target_struct = spawnStruct(); target_struct.group = target_group; - target_struct.id = id; + target_struct.target_id = id; target_struct.damaged_by = []; target_struct.targeted_by = []; target_struct.target_ent = target_ent; @@ -46,6 +49,11 @@ 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 ); @@ -188,25 +196,15 @@ free_bot_target( target_group, id ) /* The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. */ -target_loop() +/* +bot_pick_target() { myEye = self GetEyePos(); - theTime = getTime(); myAngles = self GetPlayerAngles(); - myFov = self.pers["bots"]["skill"]["fov"]; - bestTargets = []; - bestTime = 2147483647; - rememberTime = self.pers["bots"]["skill"]["remember_time"]; - initReactTime = self.pers["bots"]["skill"]["init_react_time"]; - hasTarget = isDefined( self.bot.target ); + myFov = 90; + hasTarget = self bot_has_target(); adsAmount = self PlayerADS(); - adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; - - if ( hasTarget && !isDefined( self.bot.target.entity ) ) - { - self.bot.target = undefined; - hasTarget = false; - } + adsFovFact = 1; // reduce fov if ads'ing if ( adsAmount > 0 ) @@ -214,180 +212,46 @@ target_loop() myFov *= 1 - adsFovFact * adsAmount; } - playercount = level.players.size; + groups = get_all_groups_for_targets(); - for ( i = -1; i < playercount; i++ ) + ents = []; + for ( i = 0; i < groups.size; i++ ) { - obj = undefined; - - if ( i == -1 ) + targets = level.zbot_target_glob[ groups[ i ] ].active_targets; + for ( j = 0; j < targets; j++ ) { - if ( !isDefined( self.bot.script_target ) ) - continue; - - ent = self.bot.script_target; - key = ent getEntityNumber() + ""; - daDist = distanceSquared( self.origin, ent.origin ); - obj = self.bot.targets[key]; - isObjDef = isDefined( obj ); - entOrigin = ent.origin; - - if ( isDefined( self.bot.script_target_offset ) ) - entOrigin += self.bot.script_target_offset; - - if ( SmokeTrace( myEye, entOrigin, level.smokeRadius ) && bulletTracePassed( myEye, entOrigin, false, ent ) ) - { - if ( !isObjDef ) - { - obj = self createTargetObj( ent, theTime ); - obj.offset = self.bot.script_target_offset; - - self.bot.targets[key] = obj; - } - - self targetObjUpdateTraced( obj, daDist, ent, theTime, true ); - } - else - { - if ( !isObjDef ) - continue; - - self targetObjUpdateNoTrace( obj ); - - if ( obj.no_trace_time > rememberTime ) - { - self.bot.targets[key] = undefined; - continue; - } - } + ents[ ents.size ] = targets[ j ].target_ent; } - else - { - player = level.players[i]; - - if ( !player IsPlayerModelOK() ) - continue; - - if ( player == self ) - continue; - - key = player getEntityNumber() + ""; - obj = self.bot.targets[key]; - daDist = distanceSquared( self.origin, player.origin ); - isObjDef = isDefined( obj ); - - if ( ( level.teamBased && self.team == player.team ) || player.sessionstate != "playing" || !isAlive( player ) ) - { - if ( isObjDef ) - self.bot.targets[key] = undefined; - - continue; - } - - targetHead = player getTagOrigin( "j_head" ); - targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); - targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); - - traceHead = bulletTrace( myEye, targetHead, false, undefined ); - traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined ); - traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined ); - - canTargetPlayer = ( ( sightTracePassed( myEye, targetHead, false, undefined ) || - sightTracePassed( myEye, targetAnkleLeft, false, undefined ) || - sightTracePassed( myEye, targetAnkleRight, false, undefined ) ) - - && ( ( traceHead["fraction"] >= 1.0 || traceHead["surfacetype"] == "glass" ) || - ( traceAnkleLeft["fraction"] >= 1.0 || traceAnkleLeft["surfacetype"] == "glass" ) || - ( traceAnkleRight["fraction"] >= 1.0 || traceAnkleRight["surfacetype"] == "glass" ) ) - - && ( SmokeTrace( myEye, player.origin, level.smokeRadius ) || - daDist < level.bots_maxKnifeDistance * 4 ) - - && ( getConeDot( player.origin, self.origin, myAngles ) >= myFov || - ( isObjDef && obj.trace_time ) ) ); - - if ( isDefined( self.bot.target_this_frame ) && self.bot.target_this_frame == player ) - { - self.bot.target_this_frame = undefined; - - canTargetPlayer = true; - } - - if ( canTargetPlayer ) - { - if ( !isObjDef ) - { - obj = self createTargetObj( player, theTime ); - - self.bot.targets[key] = obj; - } - - self targetObjUpdateTraced( obj, daDist, player, theTime, false ); - } - else - { - if ( !isObjDef ) - continue; - - self targetObjUpdateNoTrace( obj ); - - if ( obj.no_trace_time > rememberTime ) - { - self.bot.targets[key] = undefined; - continue; - } - } - } - - if ( !isdefined( obj ) ) - continue; - - if ( theTime - obj.time < initReactTime ) - continue; - - timeDiff = theTime - obj.trace_time_time; - - if ( timeDiff < bestTime ) - { - bestTargets = []; - bestTime = timeDiff; - } - - if ( timeDiff == bestTime ) - bestTargets[key] = obj; } - if ( hasTarget && isDefined( bestTargets[self.bot.target.entity getEntityNumber() + ""] ) ) - return; + ents = get_array_of_closest( self.origin, ents ); - closest = 2147483647; - toBeTarget = undefined; - - bestKeys = getArrayKeys( bestTargets ); - - for ( i = bestKeys.size - 1; i >= 0; i-- ) + for ( i = 0; i < ents.size; i++ ) { - theDist = bestTargets[bestKeys[i]].dist; + ent = ents[ i ]; + targetHead = ent getTagOrigin( "j_head" ); + targetAnkleLeft = ent getTagOrigin( "j_ankle_le" ); + targetAnkleRight = ent getTagOrigin( "j_ankle_ri" ); - if ( theDist > closest ) - continue; + traceHead = bulletTrace( myEye, targetHead, false, undefined ); + traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined ); + traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined ); - closest = theDist; - toBeTarget = bestTargets[bestKeys[i]]; + canTargetEnt = ( ( sightTracePassed( myEye, targetHead, false, undefined ) || + sightTracePassed( myEye, targetAnkleLeft, false, undefined ) || + sightTracePassed( myEye, targetAnkleRight, false, undefined ) ) + + && ( traceHead["fraction"] >= 1.0 || + traceAnkleLeft["fraction"] >= 1.0 || + traceAnkleRight["fraction"] >= 1.0 ) + + && ( getConeDot( ent.origin, self.origin, myAngles ) >= myFov || + ( isObjDef && obj.trace_time ) ) ); + if ( canTargetEnt ) + { + self set_target_for_bot( ent.targetname, ent.target_id ); + break; + } } - - beforeTargetID = -1; - newTargetID = -1; - - if ( hasTarget && isDefined( self.bot.target.entity ) ) - beforeTargetID = self.bot.target.entity getEntityNumber(); - - if ( isDefined( toBeTarget ) && isDefined( toBeTarget.entity ) ) - newTargetID = toBeTarget.entity getEntityNumber(); - - if ( beforeTargetID != newTargetID ) - { - self.bot.target = toBeTarget; - self notify( "new_enemy" ); - } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/scripts/sp/bots/bot_utility.gsc b/scripts/sp/bots/bot_utility.gsc index e708748..ce03e5c 100644 --- a/scripts/sp/bots/bot_utility.gsc +++ b/scripts/sp/bots/bot_utility.gsc @@ -47,12 +47,7 @@ parse_bot_weapon_stats_from_table() */ } -array_validate( array ) -{ - return isDefined( array ) && isArray( array ) && array.size > 0; -} - -array_add( array, item ) +array_add2( array, item ) { array[ array.size ] = item; } @@ -79,12 +74,12 @@ merge_sort( current_list, func_sort, param ) for ( x = 0; x < middle; x++ ) { - array_add( left, current_list[ x ] ); + array_add2( left, current_list[ x ] ); } for ( ; x < current_list.size; x++ ) { - array_add( right, current_list[ x ] ); + array_add2( right, current_list[ x ] ); } left = merge_sort( left, func_sort, param ); @@ -97,7 +92,7 @@ merge_sort( current_list, func_sort, param ) quickSort(array, compare_func) { - return quickSortMid(array, 0, array.size -1, compare_func); + return quickSortMid(array, 0, array.size - 1, compare_func); } quickSortMid( array, start, end, compare_func ) @@ -136,112 +131,6 @@ quicksort_compare(left, right) return left <= right; } -push( array, val, index ) -{ - if ( !isdefined( index ) ) - { - // use max free integer as index - index = 0; - keys = GetArrayKeys( array ); - for ( i = 0; i < keys.size; i++ ) - { - key = keys[ i ]; - if ( IsInt( key ) && ( key >= index ) ) - { - index = key + 1; - } - } - } - - array = array_insert( array, val, index ); - return array; -} - -bot_spawn_init() -{ - time = gettime(); - - if ( !isdefined( self.bot ) ) - { - self.bot = spawnstruct(); - self.bot.threat = spawnstruct(); - } - - self.bot.glass_origin = undefined; - self.bot.ignore_entity = []; - self.bot.previous_origin = self.origin; - self.bot.time_ads = 0; - self.bot.update_c4 = time + randomintrange( 1000, 3000 ); - self.bot.update_crate = time + randomintrange( 1000, 3000 ); - self.bot.update_crouch = time + randomintrange( 1000, 3000 ); - self.bot.update_failsafe = time + randomintrange( 1000, 3000 ); - self.bot.update_idle_lookat = time + randomintrange( 1000, 3000 ); - self.bot.update_killstreak = time + randomintrange( 1000, 3000 ); - self.bot.update_lookat = time + randomintrange( 1000, 3000 ); - self.bot.update_objective = time + randomintrange( 1000, 3000 ); - self.bot.update_objective_patrol = time + randomintrange( 1000, 3000 ); - self.bot.update_patrol = time + randomintrange( 1000, 3000 ); - self.bot.update_toss = time + randomintrange( 1000, 3000 ); - self.bot.update_launcher = time + randomintrange( 1000, 3000 ); - self.bot.update_weapon = time + randomintrange( 1000, 3000 ); - - self.bot.threat.entity = undefined; - self.bot.threat.position = ( 0, 0, 0 ); - self.bot.threat.time_first_sight = 0; - self.bot.threat.time_recent_sight = 0; - self.bot.threat.time_aim_interval = 0; - self.bot.threat.time_aim_correct = 0; - self.bot.threat.update_riotshield = 0; -} - -bot_should_hip_fire() -{ - enemy = self.bot.threat.entity; - weapon = self getcurrentweapon(); - - if ( weapon == "none" ) - return 0; - - if ( weaponisdualwield( weapon ) ) - return 1; - - weapon_class = weaponclass( weapon ); - - if ( isplayer( enemy ) && weapon_class == "spread" ) - return 1; - - distsq = distancesquared( self.origin, enemy.origin ); - distcheck = 0; - - switch ( weapon_class ) - { - case "mg": - distcheck = 250; - break; - case "smg": - distcheck = 350; - break; - case "spread": - distcheck = 400; - break; - case "pistol": - distcheck = 200; - break; - case "rocketlauncher": - distcheck = 0; - break; - case "rifle": - default: - distcheck = 300; - break; - } - - if ( isweaponscopeoverlay( weapon ) ) - distcheck = 500; - - return distsq < distcheck * distcheck; -} - get_allies() { return getPlayers( self.team ); @@ -263,7 +152,14 @@ are_enemies_horded() DISTANCE_SQ = 120 * 120; zombies = get_zombies(); amount_in_horde = 0; - max_eligible_zombies = isDefined( level.speed_change_round ) ? zombies.size - level.speed_change_num : zombies.size; + 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 ) ) { @@ -448,7 +344,7 @@ assign_priority_to_powerup( powerup ) } } - if ( maps\mp\zombies\_zm_laststand::player_any_player_in_laststand() ) + if ( maps\_laststand::player_any_player_in_laststand() ) { switch ( powerup.powerup_name ) {