Fix compile errors. Add bot pathing and movement.

This commit is contained in:
JezuzLizard 2023-04-28 23:43:40 -07:00
parent 558805de77
commit 1990b8c79d
9 changed files with 1051 additions and 399 deletions

View File

@ -2,17 +2,20 @@
#include maps\_utility; #include maps\_utility;
#include maps\so\zm_common\_zm_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_actions_common;
#include scripts\sp\bots\bot_objective_common; #include scripts\sp\bots\bot_objective_common;
#include scripts\sp\bots\bot_difficulty_presets_common; #include scripts\sp\bots\bot_difficulty_presets_common;
#include scripts\sp\bots\bot_personality_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\bot_target_common;
#include scripts\sp\bots\actions\combat; #include scripts\sp\bots\actions\combat;
#include scripts\sp\bots\actions\movement; #include scripts\sp\bots\actions\movement;
#include scripts\sp\bots\actions\objective; #include scripts\sp\bots\actions\objective;
#include scripts\sp\bots\actions\look; #include scripts\sp\bots\actions\look;
#include scripts\sp\bots\bot_utility;
main() main()
{ {
//Objective group is for things to go to usually allowing the bot to kill zombies on the way and survive as normal //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 //Movement actions
//These all need definitions //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", "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", "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", "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( "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( "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", "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", "lookatgoal", ::bot_lookatgoal, ::bot_lookatgoal_process_order, ::bot_should_lookatgoal, ::bot_check_complete_lookatgoal, ::bot_set_complete_lookatgoal, ::bot_lookatgoal_on_completion, ::bot_lookatgoal_should_cancel, ::bot_lookatgoal_on_cancel, ::bot_lookatgoal_should_postpone, ::bot_lookatgoal_on_postpone, ::bot_lookatgoal_priority );
//register_bot_action( "look", "ads", ::bot_ads, ::bot_ads_process_order, ::bot_should_ads, ::bot_check_complete_ads, ::bot_set_complete_ads, ::bot_ads_on_completion, ::bot_ads_should_cancel, ::bot_ads_on_cancel, ::bot_ads_should_postpone, ::bot_ads_on_postpone, ::bot_ads_priority ); //register_bot_action( "look", "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_excellent = 3;
level.bot_weapon_quality_best = 4; 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_none = 0;
level.bot_powerup_priority_low = 1; 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); 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_for_host();
level thread spawn_bots();
level thread on_player_connect(); 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() on_player_connect()
@ -118,19 +247,85 @@ on_player_connect()
while ( true ) while ( true )
{ {
level waittill( "connected", player ); level waittill( "connected", player );
player thread on_player_spawned();
player.client_id = i; player.client_id = i;
if ( player isBot() ) if ( player isBot() )
{ {
player resetBotVars();
player.successfully_grabbed_powerup = false; player.successfully_grabbed_powerup = false;
player.successfully_revived_player = false; player.successfully_revived_player = false;
player.successfully_moved_to_objective = false; player.successfully_moved_to_objective = false;
player.can_do_objective_now = false; player.can_do_objective_now = false;
player.on_powerup_grab_func = ::bot_on_powerup_grab; player.on_powerup_grab_func = ::bot_on_powerup_grab;
player thread zbot_spawn();
}
else
{
player thread bot_control();
} }
i++; 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 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 global canceling and postponing functionality
//TODO: Make shared global objective and normal objective globs work //TODO: Make shared global objective and normal objective globs work
@ -151,7 +346,7 @@ init()
{ {
level.chests[ i ].id = i; level.chests[ i ].id = i;
} }
level thread watch_magicbox_objectives(); //level thread watch_magicbox_objectives();
} }
weapon_spawns = GetEntArray( "weapon_upgrade", "targetname" ); 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 ); self clear_target_damaged_by( target_ent.targetname, id );
} }
spawn_bots() spawn_bots_for_host()
{ {
level waittill( "connected", player ); level waittill( "connected", player );
while ( true )
{
spawn_bots(); spawn_bots();
wait 1;
}
} }
spawn_bots() spawn_bots()
@ -290,18 +481,22 @@ spawn_bots()
while ( bot_count < required_bots ) while ( bot_count < required_bots )
{ {
bot = undefined; bot = undefined;
while ( !isDefined( bot ) ) while ( !isDefined( bot ) && getPlayers().size < getDvarInt( "sv_maxclients" ) )
{ {
bot = addTestClient(); bot = addTestClient();
} }
if ( !isDefined( bot ) )
{
return;
}
bot.pers[ "isBot" ] = true; bot.pers[ "isBot" ] = true;
bot.action_queue = []; bot.action_queue = [];
bot.action_queue[ "objective" ] = []; bot.action_queue[ "objective" ] = [];
bot.action_queue[ "combat" ] = []; bot.action_queue[ "combat" ] = [];
bot.action_queue[ "movement" ] = []; bot.action_queue[ "movement" ] = [];
bot.action_queue[ "look" ] = []; bot.action_queue[ "look" ] = [];
bot register_action_queue_actions(); //bot register_action_queue_actions();
bot thread bot_think(); //bot thread bot_think();
bot_count++; bot_count++;
} }
} }
@ -316,11 +511,11 @@ bot_think()
while ( true ) while ( true )
{ {
wait 0.25; wait 0.25;
if ( !bot_valid( self ) ) if ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
{ {
self notify( "stop_action_think" ); self notify( "stop_action_think" );
self bot_clear_actions_queue(); self bot_clear_actions_queue();
while ( !bot_valid( self ) ) while ( !scripts\sp\bots\bot_utility::bot_valid( self ) )
{ {
wait 1; wait 1;
} }
@ -336,6 +531,8 @@ bot_think()
group_name = "combat"; group_name = "combat";
//self scripts\sp\bots\bot_target_common::bot_pick_target();
self bot_action_think( group_name ); self bot_action_think( group_name );
group_name = "objective"; 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 ) watch_door_objectives( zombie_doors )
{ {
level endon( "end_game" ); level endon( "end_game" );
@ -407,6 +567,8 @@ watch_magicbox_objectives()
{ {
level endon( "end_game" ); level endon( "end_game" );
level waittill( "connected", player );
prev_magicbox = maps\so\zm_common\_zm_magicbox::get_active_magicbox(); prev_magicbox = maps\so\zm_common\_zm_magicbox::get_active_magicbox();
while ( true ) while ( true )
{ {
@ -437,8 +599,8 @@ store_powerups_dropped()
} }
powerup.id = id; powerup.id = id;
add_possible_bot_objective( "powerup", id, true, powerup ); add_possible_bot_objective( "powerup", id, true, powerup );
assign_priority_to_powerup( powerup ); scripts\sp\bots\bot_utility::assign_priority_to_powerup( powerup );
level.zbots_powerups = sort_array_by_priority_field( level.zbots_powerups, powerup ); level.zbots_powerups = scripts\sp\bots\bot_utility::sort_array_by_priority_field( level.zbots_powerups, powerup );
id++; id++;
} }
} }
@ -483,39 +645,6 @@ free_revive_objective_when_needed()
free_bot_objective( "revive", id ); 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 ) bot_on_powerup_grab( powerup )
{ {
self.successfully_grabbed_powerup = true; self.successfully_grabbed_powerup = true;

View File

@ -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;
}

View File

@ -1,3 +1,5 @@
#include scripts\sp\bots\bot_target_common;
bot_lookatobjective() bot_lookatobjective()
{ {
@ -60,7 +62,7 @@ bot_lookattarget()
{ {
target = self.zbot_current_target; target = self.zbot_current_target;
target_ent = target.target_ent; 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; wait 0.05;
} }
} }
@ -195,7 +197,7 @@ bot_lookat( pos, time, vel, doAimPredict )
if ( steps < 1 ) if ( steps < 1 )
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 ) if ( doAimPredict )
{ {

View File

@ -1,3 +1,5 @@
#include scripts\sp\bots\bot_objective_common;
bot_magicbox_purchase() bot_magicbox_purchase()
{ {
self.target_pos = self.available_chests[ 0 ].origin; self.target_pos = self.available_chests[ 0 ].origin;
@ -37,7 +39,7 @@ bot_should_purchase_magicbox()
{ {
if ( isDefined( self.available_chests[ i ].chest_user ) ) if ( isDefined( self.available_chests[ i ].chest_user ) )
{ {
arrayRemoveIndex( self.available_chests, i ); maps\_utility::array_remove_index( self.available_chests, i );
i--; i--;
} }
} }
@ -83,7 +85,7 @@ bot_magicbox_purchase_on_postpone()
bot_magicbox_purchase_priority() bot_magicbox_purchase_priority()
{ {
priority = 0; priority = 0;
const LOW_AMMO_THRESHOLD = 0.3; LOW_AMMO_THRESHOLD = 0.3;
weapons = self getWeaponsListPrimaries(); weapons = self getWeaponsListPrimaries();
if ( weapons.size < 2 ) if ( weapons.size < 2 )
{ {
@ -540,7 +542,7 @@ bot_should_revive_player()
continue; 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; return self.available_revives.size > 0;
} }

View File

@ -4,6 +4,7 @@
#include common_scripts\utility; #include common_scripts\utility;
#include maps\_utility; #include maps\_utility;
#include maps\so\zm_common\_zm_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 ) 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; self.zbot_actions_in_queue[ group_name ][ action_name ].postponed = true;
postponed_action = self.action_queue[ group_name ][ 0 ]; postponed_action = self.action_queue[ group_name ][ 0 ];
self.action_queue[ group_name ][ 0 ] = undefined; 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.action_queue[ group_name ] = array_insert( self.action_queue[ group_name ], postponed_action, 1 );
self thread [[ self.action_queue[ group_name ][ 0 ].on_postpone_func ]](); self 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_keys = getArrayKeys( level.zbots_actions[ group_name ] );
action_priorities_array = []; 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 ] = 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 ].priority = self [[ level.zbots_actions[ group_name ][ action_keys[ i ] ].priority_func ]]();

View File

@ -46,11 +46,11 @@ get_all_objectives_for_group( objective_group )
set_objective_for_bot( objective_group, id ) 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 = 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 ); assert( objective_exists, "Objective with " + id + " id does not point to a objective in group " + objective_group );
if ( !objective_exists ) if ( !objective_exists )
@ -147,7 +147,7 @@ set_bot_global_shared_objective_owner_by_reference( objective_group, objective,
{ {
return; 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 ) if ( !objective.is_global_shared )
{ {
return; return;

View File

@ -1,3 +1,6 @@
#include common_scripts\utility;
#include scripts\sp\bots\_bot_utility;
register_bot_target_type( target_group ) register_bot_target_type( target_group )
{ {
if ( !isDefined( level.zbot_target_glob ) ) if ( !isDefined( level.zbot_target_glob ) )
@ -21,7 +24,7 @@ add_possible_bot_target( target_group, id, target_ent )
target_struct = spawnStruct(); target_struct = spawnStruct();
target_struct.group = target_group; target_struct.group = target_group;
target_struct.id = id; target_struct.target_id = id;
target_struct.damaged_by = []; target_struct.damaged_by = [];
target_struct.targeted_by = []; target_struct.targeted_by = [];
target_struct.target_ent = target_ent; 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; return level.zbot_target_glob[ target_group ].active_targets;
} }
get_all_groups_for_targets()
{
return getArrayKeys( level.zbot_target_glob );
}
bot_has_target() bot_has_target()
{ {
return isDefined( self.zbot_current_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. 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(); myEye = self GetEyePos();
theTime = getTime();
myAngles = self GetPlayerAngles(); myAngles = self GetPlayerAngles();
myFov = self.pers["bots"]["skill"]["fov"]; myFov = 90;
bestTargets = []; hasTarget = self bot_has_target();
bestTime = 2147483647;
rememberTime = self.pers["bots"]["skill"]["remember_time"];
initReactTime = self.pers["bots"]["skill"]["init_react_time"];
hasTarget = isDefined( self.bot.target );
adsAmount = self PlayerADS(); adsAmount = self PlayerADS();
adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; adsFovFact = 1;
if ( hasTarget && !isDefined( self.bot.target.entity ) )
{
self.bot.target = undefined;
hasTarget = false;
}
// reduce fov if ads'ing // reduce fov if ads'ing
if ( adsAmount > 0 ) if ( adsAmount > 0 )
@ -214,180 +212,46 @@ target_loop()
myFov *= 1 - adsFovFact * adsAmount; 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; targets = level.zbot_target_glob[ groups[ i ] ].active_targets;
for ( j = 0; j < targets; j++ )
if ( i == -1 )
{ {
if ( !isDefined( self.bot.script_target ) ) ents[ ents.size ] = targets[ j ].target_ent;
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;
} }
} }
}
else ents = get_array_of_closest( self.origin, ents );
for ( i = 0; i < ents.size; i++ )
{ {
player = level.players[i]; ent = ents[ i ];
targetHead = ent getTagOrigin( "j_head" );
if ( !player IsPlayerModelOK() ) targetAnkleLeft = ent getTagOrigin( "j_ankle_le" );
continue; targetAnkleRight = ent getTagOrigin( "j_ankle_ri" );
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 ); traceHead = bulletTrace( myEye, targetHead, false, undefined );
traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined ); traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined );
traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined ); traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined );
canTargetPlayer = ( ( sightTracePassed( myEye, targetHead, false, undefined ) || canTargetEnt = ( ( sightTracePassed( myEye, targetHead, false, undefined ) ||
sightTracePassed( myEye, targetAnkleLeft, false, undefined ) || sightTracePassed( myEye, targetAnkleLeft, false, undefined ) ||
sightTracePassed( myEye, targetAnkleRight, false, undefined ) ) sightTracePassed( myEye, targetAnkleRight, false, undefined ) )
&& ( ( traceHead["fraction"] >= 1.0 || traceHead["surfacetype"] == "glass" ) || && ( traceHead["fraction"] >= 1.0 ||
( traceAnkleLeft["fraction"] >= 1.0 || traceAnkleLeft["surfacetype"] == "glass" ) || traceAnkleLeft["fraction"] >= 1.0 ||
( traceAnkleRight["fraction"] >= 1.0 || traceAnkleRight["surfacetype"] == "glass" ) ) traceAnkleRight["fraction"] >= 1.0 )
&& ( SmokeTrace( myEye, player.origin, level.smokeRadius ) || && ( getConeDot( ent.origin, self.origin, myAngles ) >= myFov ||
daDist < level.bots_maxKnifeDistance * 4 )
&& ( getConeDot( player.origin, self.origin, myAngles ) >= myFov ||
( isObjDef && obj.trace_time ) ) ); ( isObjDef && obj.trace_time ) ) );
if ( canTargetEnt )
if ( isDefined( self.bot.target_this_frame ) && self.bot.target_this_frame == player )
{ {
self.bot.target_this_frame = undefined; self set_target_for_bot( ent.targetname, ent.target_id );
break;
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;
closest = 2147483647;
toBeTarget = undefined;
bestKeys = getArrayKeys( bestTargets );
for ( i = bestKeys.size - 1; i >= 0; i-- )
{
theDist = bestTargets[bestKeys[i]].dist;
if ( theDist > closest )
continue;
closest = theDist;
toBeTarget = bestTargets[bestKeys[i]];
}
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" );
}
}

View File

@ -47,12 +47,7 @@ parse_bot_weapon_stats_from_table()
*/ */
} }
array_validate( array ) array_add2( array, item )
{
return isDefined( array ) && isArray( array ) && array.size > 0;
}
array_add( array, item )
{ {
array[ array.size ] = item; array[ array.size ] = item;
} }
@ -79,12 +74,12 @@ merge_sort( current_list, func_sort, param )
for ( x = 0; x < middle; x++ ) for ( x = 0; x < middle; x++ )
{ {
array_add( left, current_list[ x ] ); array_add2( left, current_list[ x ] );
} }
for ( ; x < current_list.size; 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 ); left = merge_sort( left, func_sort, param );
@ -136,112 +131,6 @@ quicksort_compare(left, right)
return 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() get_allies()
{ {
return getPlayers( self.team ); return getPlayers( self.team );
@ -263,7 +152,14 @@ are_enemies_horded()
DISTANCE_SQ = 120 * 120; DISTANCE_SQ = 120 * 120;
zombies = get_zombies(); zombies = get_zombies();
amount_in_horde = 0; 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 ); expected_amount_in_horde_min = int( max_eligible_zombies * MINIMUM_PERCENT_TO_BE_HORDE );
if ( isDefined( level.speed_change_round ) ) 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 ) switch ( powerup.powerup_name )
{ {