def find_aerial(agent, target, cap_=4): struct = agent.predictions['ball_struct'] if struct is None: return max_aerial_height = math.inf if len(agent.friends) == 0 and len(agent.foes) == 1: max_aerial_height = 643 i = 10 # Begin by looking 0.2 seconds into the future while i < struct.num_slices: intercept_time = struct.slices[i].game_seconds time_remaining = intercept_time - agent.time if time_remaining <= 0: return ball_location = Vector(struct.slices[i].physics.location.x, struct.slices[i].physics.location.y, struct.slices[i].physics.location.z) if abs(ball_location.y) > 5212: break ball_velocity = Vector( struct.slices[i].physics.velocity.x, struct.slices[i].physics.velocity.y, struct.slices[i].physics.velocity.z).magnitude() i += 15 - cap(int(ball_velocity // 150), 0, 13) # we don't actually need to calculate if we can get there; it is_viable function will do that for us # we just need a few variables to find the best shot vector car_to_ball = ball_location - agent.me.location direction = car_to_ball.normalize() left, right, swapped = post_correction(ball_location, target[0], target[1]) if not swapped: left_vector = (left - ball_location).normalize() right_vector = (right - ball_location).normalize() best_shot_vector = direction.clamp(left_vector, right_vector) # relax the in_field requirement # reduce cap_ from 6 to 4 (by default) if in_field(ball_location - (100 * best_shot_vector), 1) and is_fast_shot(agent.me.location, ball_location, intercept_time, agent.time, cap_): slope = find_slope(best_shot_vector, car_to_ball) ball_intercept = ball_location - 92 * best_shot_vector if slope > 0.5 and 275 < ball_intercept.z and ball_intercept.z < max_aerial_height: aerial = Aerial(ball_intercept, intercept_time) if aerial.is_viable(agent): return aerial
def find_any_shot(agent, cap_=6, can_aerial=True, can_double_jump=True, can_jump=True, can_ground=True): if not can_aerial and not can_double_jump and not can_jump and not can_ground: agent.print("WARNING: All shots were disabled when find_any_shot was ran") return # Only meant for routines that require a defined intercept time/place in the future # Assemble data in a form that can be passed to C me = agent.me.get_raw(agent) game_info = ( agent.boost_accel, agent.ball_radius ) gravity = tuple(agent.gravity) is_on_ground = not agent.me.airborne can_ground = is_on_ground and can_ground can_jump = is_on_ground and can_jump can_double_jump = is_on_ground and can_double_jump can_aerial = (not is_on_ground or agent.time - agent.me.land_time > 0.5) and can_aerial any_ground = can_ground or can_jump or can_double_jump if not any_ground and not can_aerial: return # Here we get the slices that need to be searched - by defining a cap, we can reduce the number of slices and improve search times slices = get_slices(agent, cap_) if slices is None: return # Loop through the slices for ball_slice in slices: # Gather some data about the slice intercept_time = ball_slice.game_seconds T = intercept_time - agent.time - (1 / 120) if T <= 0: return ball_location = (ball_slice.physics.location.x, ball_slice.physics.location.y, ball_slice.physics.location.z) if abs(ball_location[1]) > 5212.75: return # abandon search if ball is scored at/after this point ball_info = (ball_location, (ball_slice.physics.velocity.x, ball_slice.physics.velocity.y, ball_slice.physics.velocity.z)) # Check if we can make a shot at this slice # This operation is very expensive, so we use C to improve run time shot = virxrlcu.parse_slice_for_shot(can_ground, can_jump, can_double_jump, can_aerial, T, *game_info, gravity, ball_info, me) if shot['found'] == 1: shot_type = ShotType(shot["shot_type"]) if shot_type == ShotType.AERIAL: return Aerial(intercept_time, fast_aerial=shot['fast']) return SHOT_SWITCH[shot_type](intercept_time)
def find_any_aerial(agent, cap_=3): struct = agent.predictions['ball_struct'] if struct is None: return max_aerial_height = math.inf if len(agent.friends) == 0 and len(agent.foes) == 1: max_aerial_height = 643 i = 10 # Begin by looking 0.2 seconds into the future while i < struct.num_slices: intercept_time = struct.slices[i].game_seconds time_remaining = intercept_time - agent.time if time_remaining <= 0: return ball_location = Vector(struct.slices[i].physics.location.x, struct.slices[i].physics.location.y, struct.slices[i].physics.location.z) if abs(ball_location.y) > 5212: break ball_velocity = Vector( struct.slices[i].physics.velocity.x, struct.slices[i].physics.velocity.y, struct.slices[i].physics.velocity.z).magnitude() i += 15 - cap(int(ball_velocity // 150), 0, 13) if 275 > ball_location.z or ball_location.z > max_aerial_height: continue # remove the need for a target to hit the ball to if is_fast_shot(agent.me.location, ball_location, intercept_time, agent.time, cap_): aerial = Aerial(ball_location, intercept_time) if aerial.is_viable(agent): return aerial
def find_any_aerial(agent, cap_=3): slices = get_slices(agent, cap_) if slices is None: return me = (agent.me.location.tuple(), agent.me.velocity.tuple(), agent.me.up.tuple(), agent.me.forward.tuple(), 1 if agent.me.airborne else -1, agent.me.boost if agent.boost_amount != 'unlimited' else 100000) gravity = agent.gravity.tuple() max_aerial_height = 735 if len(agent.friends) == 0 and len( agent.foes) == 1 else math.inf min_aerial_height = 551 if max_aerial_height > 643 and agent.me.location.z >= 2044 - agent.me.hitbox.height * 1.1 else ( 0 if agent.boost_amount == 'unlimited' else 450) for ball_slice in slices: intercept_time = ball_slice.game_seconds time_remaining = intercept_time - agent.time if time_remaining <= 0: return ball_location = (ball_slice.physics.location.x, ball_slice.physics.location.y, ball_slice.physics.location.z) if abs(ball_location[1]) > 5212.75: return if min_aerial_height > ball_location[2] or ball_location[ 2] > max_aerial_height: continue shot = virxrlcu.parse_slice_for_aerial_shot(time_remaining, agent.best_shot_value, agent.boost_accel, gravity, ball_location, me) if shot['found'] == 1: return Aerial(intercept_time, Vector(*shot['best_shot_vector']), shot['fast'])
def find_any_shot(agent, cap_=3, can_aerial=True, can_double_jump=True, can_jump=True): if not can_aerial and not can_double_jump and not can_jump: agent.print("WARNING: All shots were disabled when find_shot was ran") return slices = get_slices(agent, cap_) if slices is None: return me = (agent.me.location.tuple(), agent.me.forward.tuple(), agent.me.boost if agent.boost_amount != 'unlimited' else 100000, agent.me.local_velocity().x) game_info = (agent.best_shot_value, agent.boost_accel) if can_aerial: me_a = (me[0], agent.me.velocity.tuple(), agent.me.up.tuple(), me[1], 1 if agent.me.airborne else -1, me[2]) gravity = agent.gravity.tuple() max_aerial_height = 643 if len(agent.friends) == 0 and len( agent.foes) == 1 else math.inf min_aerial_height = 551 if max_aerial_height > 643 and agent.me.location.z >= 2044 - agent.me.hitbox.height * 1.1 else ( 0 if agent.boost_amount == 'unlimited' else 450) for ball_slice in slices: intercept_time = ball_slice.game_seconds time_remaining = intercept_time - agent.time if time_remaining <= 0: return ball_location = (ball_slice.physics.location.x, ball_slice.physics.location.y, ball_slice.physics.location.z) if abs(ball_location[1]) > 5212.75: return if can_jump: shot = virxrlcu.parse_slice_for_jump_shot(time_remaining - 0.1, *game_info, ball_location, *me) if shot['found'] == 1: return jump_shot(intercept_time, Vector(*shot['best_shot_vector'])) if can_double_jump and time_remaining >= 0.5: shot = virxrlcu.parse_slice_for_double_jump( time_remaining - 0.3, *game_info, ball_location, *me) if shot['found'] == 1: return double_jump(intercept_time, Vector(*shot['best_shot_vector'])) if can_aerial and not (min_aerial_height > ball_location[2] or ball_location[2] > max_aerial_height): shot = virxrlcu.parse_slice_for_aerial_shot( time_remaining, *game_info, gravity, ball_location, me_a) if shot['found'] == 1: return Aerial(intercept_time, Vector(*shot['best_shot_vector']), shot['fast'])
def find_shot(agent, target, cap_=6, can_aerial=True, can_double_jump=True, can_jump=True, can_ground=True): if not can_aerial and not can_double_jump and not can_jump and not can_ground: agent.print("WARNING: All shots were disabled when find_shot was ran") return # Takes a tuple of (left,right) target pairs and finds routines that could hit the ball between those target pairs # Only meant for routines that require a defined intercept time/place in the future # Assemble data in a form that can be passed to C targets = (tuple(target[0]), tuple(target[1])) me = agent.me.get_raw(agent) game_info = (agent.boost_accel, agent.best_shot_value) gravity = tuple(agent.gravity) max_aerial_height = 1200 if len(agent.friends) == 0 and len( agent.foes) == 1 else math.inf min_aerial_height = 551 if max_aerial_height > 1200 and agent.me.location.z >= 2044 - agent.me.hitbox.height * 1.1 else ( 150 if agent.boost_amount == 'unlimited' or agent.me.airborne else 450) is_on_ground = not agent.me.airborne can_ground = is_on_ground and can_ground can_jump = is_on_ground and can_jump can_double_jump = is_on_ground and can_double_jump if not can_ground and not can_jump and not can_double_jump and not can_aerial: return # Here we get the slices that need to be searched - by defining a cap, we can reduce the number of slices and improve search times slices = get_slices(agent, cap_) if slices is None: return # Loop through the slices for ball_slice in slices: # Gather some data about the slice intercept_time = ball_slice.game_seconds time_remaining = intercept_time - agent.time - (1 / 120) if time_remaining <= 0: return ball_location = (ball_slice.physics.location.x, ball_slice.physics.location.y, ball_slice.physics.location.z) if abs(ball_location[1]) > 5212.75: return # abandon search if ball is scored at/after this point ball_info = (ball_location, (ball_slice.physics.velocity.x, ball_slice.physics.velocity.y, ball_slice.physics.velocity.z)) # Check if we can make a shot at this slice # This operation is very expensive, so we use C to improve run time shot = virxrlcu.parse_slice_for_shot_with_target( can_ground, can_jump, can_double_jump, can_aerial and (min_aerial_height < ball_location[2] < max_aerial_height), time_remaining, *game_info, gravity, ball_info, me, targets) if shot['found'] == 1: if shot['shot_type'] == 3: return Aerial( intercept_time, (Vector(*shot['targets'][0]), Vector(*shot['targets'][1])), shot['fast']) shot_switch = [ground_shot, jump_shot, double_jump] return shot_switch[shot['shot_type']]( intercept_time, (Vector(*shot['targets'][0]), Vector(*shot['targets'][1])))
def find_risky_hits(agent, targets, cap_=4): hits = {name: [] for name in targets} struct = agent.predictions['ball_struct'] if struct is None: return hits i = 10 # Begin by looking 0.2 seconds into the future while i < struct.num_slices: intercept_time = struct.slices[i].game_seconds time_remaining = intercept_time - agent.time if time_remaining > 0: ball_location = Vector(struct.slices[i].physics.location.x, struct.slices[i].physics.location.y, struct.slices[i].physics.location.z) if abs(ball_location.y) > 5200: break ball_velocity = Vector( struct.slices[i].physics.velocity.x, struct.slices[i].physics.velocity.y, struct.slices[i].physics.velocity.z).magnitude() i += 15 - cap(int(ball_velocity // 150), 0, 13) if ball_location.z < 300: continue car_to_ball = ball_location - agent.me.location direction, distance = car_to_ball.normalize(True) # assume we are traveling towards the ball distance -= (agent.me.velocity.flatten().magnitude() * i / 60) forward_angle = direction.angle(agent.me.forward) forward_time = time_remaining - (forward_angle * 0.318 * 0.5 ) # cut this times in half # remove the 5% extra distance assumption and forget about boost requirements if forward_time > 0 and (distance / forward_time) < 2300: for pair in targets: left, right, swapped = post_correction( ball_location, targets[pair][0], targets[pair][1]) if not swapped: left_vector = (left - ball_location).normalize() right_vector = (right - ball_location).normalize() best_shot_vector = direction.clamp( left_vector, right_vector) # relax the in_field requirement # reduce cap_ from 6 to 4 (by default) if in_field(ball_location - (100 * best_shot_vector), 1) and is_fast_shot( agent.me.location, ball_location, intercept_time, agent.time, cap_): slope = find_slope(best_shot_vector, car_to_ball) ball_intercept = ball_location - 92 * best_shot_vector if slope > 1: aerial = Aerial(ball_intercept, intercept_time) if aerial.is_viable(agent): hits[pair].append(aerial) return hits else: return hits return hits
def find_shot(agent: VirxERLU, target, weight=0, cap_=6, can_aerial=True, can_double_jump=True, can_jump=True, can_ground=True): if not can_aerial and not can_double_jump and not can_jump and not can_ground: agent.print("WARNING: All shots were disabled when find_shot was ran") return # Takes a tuple of (left,right) target pair or (right,left) anti-target pair and finds routines that could hit the ball between those target pairs # Only meant for routines that require a defined intercept time/place in the future cap_, aerial_time_cap = get_cap(agent, cap_, True, target is agent.anti_shot) # Assemble data in a form that can be passed to C targets = ( tuple(target[0]), tuple(target[1]) ) me = agent.me.get_raw(agent) game_info = ( agent.boost_accel, agent.ball_radius ) gravity = tuple(agent.gravity) max_aerial_height = 1000 if agent.num_friends == 0 and agent.num_foes == 1 else math.inf min_aerial_height = 551 if max_aerial_height > 1000 and agent.me.location.z >= 2044 - agent.me.hitbox.height * 1.1 and not agent.me.doublejumped else 300 is_on_ground = not agent.me.airborne can_ground = is_on_ground and can_ground can_jump = is_on_ground and can_jump can_double_jump = is_on_ground and can_double_jump can_aerial = (not is_on_ground or agent.time - agent.me.land_time > 0.5) and can_aerial any_ground = can_ground or can_jump or can_double_jump if not any_ground and not can_aerial: return # Here we get the slices that need to be searched - by defining a cap, we can reduce the number of slices and improve search times slices = get_slices(agent, cap_, weight=weight) if slices is None: return # Loop through the slices for ball_slice in slices: # Gather some data about the slice intercept_time = ball_slice.game_seconds T = intercept_time - agent.time - (1 / 120) if T <= 0: return ball_location = (ball_slice.physics.location.x, ball_slice.physics.location.y, ball_slice.physics.location.z) if abs(ball_location[1]) > 5212.75: return # abandon search if ball is scored at/after this point ball_info = (ball_location, (ball_slice.physics.velocity.x, ball_slice.physics.velocity.y, ball_slice.physics.velocity.z)) # disable aerials if need be should_aerial = can_aerial and (min_aerial_height < ball_location[2] < max_aerial_height) and T < aerial_time_cap if not any_ground and not should_aerial: continue # Check if we can make a shot at this slice # This operation is very expensive, so we use C to improve run time shot = virxrlcu.parse_slice_for_shot_with_target(can_ground, can_jump, can_double_jump, should_aerial, T, *game_info, gravity, ball_info, me, targets) if shot['found'] == 1: shot_type = ShotType(shot["shot_type"]) if shot_type == ShotType.AERIAL: return Aerial(intercept_time, (Vector(*shot['targets'][0]), Vector(*shot['targets'][1])), weight, shot['fast']) return SHOT_SWITCH[shot_type](intercept_time, (Vector(*shot['targets'][0]), Vector(*shot['targets'][1])), weight)