def get_cap(agent: VirxERLU, cap_, get_aerial_cap=False, is_anti_shot=False): if agent.num_friends == 0 or not ( agent.me.minimum_time_to_ball > agent.friend_times[0].minimum_time_to_ball and is_anti_shot): foes = len( tuple(foe for foe in agent.foes if not foe.demolished and foe.location.y * side(agent.team) < agent.ball.location.y * side(agent.team) - 150)) if foes != 0 and agent.enemy_time_to_ball != 7: future_ball_location_slice = min( round(agent.enemy_time_to_ball * 1.15 * 60), agent.ball_prediction_struct.num_slices - 1) foe_factor = max( abs(agent.closest_foes[0].local_velocity().angle2D( agent.closest_foes[0].local_location(agent.ball.location))) * 4, 4) foe_intercept_location = agent.ball_prediction_struct.slices[ future_ball_location_slice].physics.location foe_intercept_location = Vector(foe_intercept_location.x, foe_intercept_location.y) cap_slices = round(cap_) * 60 for i, ball_slice in enumerate( agent.ball_prediction_struct. slices[future_ball_location_slice:cap_slices:2]): ball_loc = Vector(ball_slice.physics.location.x, ball_slice.physics.location.y) if foe_intercept_location.dist( ball_loc) >= agent.ball_radius * foe_factor + ( agent.me.hitbox.width * (2 + foes)): cap_ = (i - 1) / 60 break if not get_aerial_cap: return cap_ aerial_cap = agent.enemy_time_to_ball if agent.enemy_time_to_ball < cap_ and agent.num_friends < 2 and agent.num_foes != 0 else cap_ if agent.num_friends == 0 and not agent.is_own_goal and agent.num_foes != 0: aerial_cap /= 2 return cap_, aerial_cap
def goto_nearest_boost(self, only_small=False, clear_on_valid=False): self.send_quick_chat(QuickChats.CHAT_TEAM_ONLY, QuickChats.Information_NeedBoost) # principle # if we can get to the boost and then back to into position before out opponent can get to the ball and then the ball can get to our net, the boost is marked as a viable option # out of all the viable options, we pick the option that's closest to our own car # however, we must respect the only_small clause as well as prioritize large boosts over the small pads, as well as rule out pads that our tm8s are going for (provided by their TMCP packets) min_foe = self.closest_foes[0] if self.num_foes > 0 else None ignore_foe = min_foe is None or min_foe.minimum_time_to_ball == 7 min_seconds = math.inf enemy_post = retreat().get_target(self) shadow_routine = shadow() friend_post = shadow_routine.get_target( self) if shadow_routine.is_viable(self) else enemy_post if self.is_own_goal: return if not ignore_foe: enemy_intercept_location = self.ball_prediction_struct.slices[ self.future_ball_location_slice].physics.location enemy_intercept_location = Vector(enemy_intercept_location.x, enemy_intercept_location.y, enemy_intercept_location.z) if enemy_intercept_location.flat_dist(enemy_post) < 2560: return dist_to_goal = enemy_intercept_location.dist(enemy_post) min_foe_speed = min_foe.location.dist( enemy_intercept_location) / self.enemy_time_to_ball min_seconds = dist_to_goal * 1.2 / min_foe_speed min_seconds = dist_to_goal / (min_foe_speed * (1 - (0.0305 / 120))** (120 * min_seconds)) foe_factor = max( abs(min_foe.local_velocity().angle2D( min_foe.local_location(self.ball.location))), 1) min_seconds += min_foe.minimum_time_to_ball * foe_factor claimed_boosts = tuple(friend.tmcp_action['target'] for friend in self.alive_friends if friend.tmcp_action is not None and friend.tmcp_action['type'] == "BOOST") active_unclaimed_boosts = tuple( boost for boost in self.boosts if boost.active and boost.index not in claimed_boosts) big_pads = (boost for boost in active_unclaimed_boosts if boost.large) small_pads = (boost for boost in active_unclaimed_boosts if not boost.large) car_mag = self.me.velocity.magnitude() car_mag_adj = (car_mag + 2300) / 2 car_speed = self.me.local_velocity().x turn_rad = turn_radius(car_mag) car_z = self.me.location.z - self.me.hitbox.height / 2 for boosts in ((big_pads if not only_small else ()), small_pads): viable_boosts = [] for boost in boosts: angle = boost.location.angle2D(self.me.forward) time = (angle * turn_rad / car_mag) if car_mag > 400 else (1.8 * (angle / math.pi)) dist = boost.location.flat_dist( self.me.location) + (car_z - 17) if dist > 1280: time += (dist - 1280) / car_mag_adj dist = 1280 dist += boost.location.flat_dist(friend_post) time += dist / ((car_mag + 1410) / 2) if time < min_seconds: viable_boosts.append({"pad": boost, "time": time}) if len(viable_boosts) > 0: if clear_on_valid: self.clear() self.push( goto_boost( min(viable_boosts, key=lambda boost: boost["time"])["pad"]))
def is_inside_turn_radius(turn_rad, local_target, steer_direction): # turn_rad is the turn radius local_target = local_target.flatten() circle = Vector(y=-steer_direction * turn_rad) return circle.dist(local_target) < turn_rad