def get_shot(self, target=None, weight=None, cap=None): if self.predictions['self_min_time_to_ball'] == 7: return if self.can_shoot is None or self.predictions['own_goal'] or ( self.playstyle is self.playstyles.Neutral and target is self.best_shot): if weight is None: weight = get_weight(self, target) can_aerial = self.aerials can_double_jump = self.double_jump can_jump = self.jump can_ground = self.ground_shot if len(self.friends) == 0: can_aerial = can_aerial and (self.predictions['own_goal'] or (self.me.location.z > 300 and self.me.airborne)) self_intercept_location = self.ball_prediction_struct.slices[ self.min_intercept_slice].physics.location self_intercept_location = Vector( abs(self_intercept_location.x), self_intercept_location.y * side(self.team)) can_double_jump = can_double_jump and ( self_intercept_location.x < 1300 or self_intercept_location.y > 3840) if not can_aerial and not can_double_jump and not can_jump and not can_ground: return if target is self.anti_shot and self.me.location.y * side( self.team) > 5120: target = None shot = find_shot(self, target, weight=weight, cap_=6 if cap is None else cap, can_aerial=can_aerial, can_double_jump=can_double_jump, can_jump=can_jump, can_ground=can_ground ) if target is not None else find_any_shot( self, cap_=3 if cap is None else cap, can_aerial=can_aerial, can_double_jump=can_double_jump, can_jump=can_jump, can_ground=can_ground) if shot is not None: return { "weight": weight, "intercept_time": shot.intercept_time, "is_best_shot": target is self.best_shot, "shot": shot }
def get_shot(self, target=None, weight=None, cap=None): if self.me.minimum_time_to_ball == 7: return if weight is None: weight = self.get_weight(target) can_aerial = self.aerials can_double_jump = self.double_jump can_jump = self.jump can_ground = self.ground_shot if self.num_friends == 0 and self.num_foes == 1: can_aerial = can_aerial and ( self.is_own_goal or (self.me.location.z > 300 and self.me.airborne) or target is self.best_shot or not self.can_any_foe_aerial()) if self.num_friends == 0: self_intercept_location = self.ball_prediction_struct.slices[ self.min_intercept_slice].physics.location self_intercept_location = Vector( abs(self_intercept_location.x), self_intercept_location.y * self.side) can_double_jump = can_double_jump and ( self_intercept_location.x < 1300 or self_intercept_location.y > 3840) if not can_aerial and not can_double_jump and not can_jump and not can_ground: return if target is self.anti_shot and self.me.location.y * self.side > 5120: target = None shot = find_shot( self, target, weight=weight, cap_=6 if cap is None else cap, can_aerial=can_aerial, can_double_jump=can_double_jump, can_jump=can_jump, can_ground=can_ground) if target is not None else find_any_shot( self, cap_=4 if cap is None else cap, can_aerial=can_aerial, can_double_jump=can_double_jump, can_jump=can_jump, can_ground=can_ground) if shot is not None: return shot
def run(self): # NOTE This method is ran every tick # If the kickoff isn't done if not self.kickoff_done: # If the stack is clear if self.is_clear(): # Push a generic kickoff to the stack # TODO make kickoff routines for each of the 5 kickoffs positions self.push(routines.generic_kickoff()) # we don't want to do anything else during our kickoff return # If the stack if clear and we're in the air if self.is_clear() and self.me.airborne: # Recover - This routine supports floor, wall, and ceiling recoveries, as well as recovering towards a target self.push(routines.recovery()) # we've made our decision and we don't want to run anything else return # If we have less than 36 boost # TODO this bot will go for boost no matter what - this is AWFUL, especially in a 1v1! if self.me.boost < 36: # If the stack is clear if self.is_clear(): # Get a list of all of the large, active boosts boosts = tuple(boost for boost in self.boosts if boost.active and boost.large) # if there's at least one large and active boost if len(boosts) > 0: # Get the closest boost closest_boost = min(boosts, key=lambda boost: boost.location.dist( self.me.location)) # Goto the nearest boost self.push(routines.goto_boost(closest_boost)) # we've made our decision and we don't want to run anything else if not self.is_clear(): return # if the stack is clear, then run the following - otherwise, if the stack isn't empty, then look for a shot every 4th tick while the other routine is running if self.is_clear() or self.odd_tick == 0: shot = None # TODO we might miss the net, even when using a target - make a pair of targets that are small than the goal so we have a better chance of scoring! # If the ball is on the enemy's side of the field, or slightly on our side if self.ball.location.y * utils.side(self.team) < 640: # Find a shot, on target - double_jump, jump_shot, and ground_shot are automatically disabled if we're airborne shot = tools.find_shot(self, self.foe_goal_shot) # TODO Using an anti-target here could be cool - do to this, pass in a target tuple that's (right_target, left_target) (instead of (left, right)) into tools.find_shot (NOT tools.find_any_shot) # TODO When possible, we might want to take a little bit more time to shot the ball anywhere in the opponent's end - this target should probably be REALLY LONG AND HIGH! # If we're behind the ball and we couldn't find a shot on target if shot is None and self.ball.location.y * utils.side( self.team) < self.me.location.y * utils.side(self.team): # Find a shot, but without a target - double_jump, jump_shot, and ground_shot are automatically disabled if we're airborne shot = tools.find_any_shot(self) # If we found a shot if shot is not None: # If the stack is clear if self.is_clear(): # Shoot self.push(shot) # If the stack isn't clear else: # Get the current shot's name (ex jump_shot, double_jump, ground_shot or Aerial) as a string current_shot_name = self.stack[0].__class__.__name__ # Get the new shot's name as a string new_shot_name = shot.__class__.__name__ # If the shots are the same type if new_shot_name is current_shot_name: # Update the existing shot with the new information self.stack[0].update(shot) # If the shots are of different types else: # Clear the stack self.clear() # Shoot self.push(shot) # we've made our decision and we don't want to run anything else return # TODO this setup is far from ideal - a custom shadow/retreat routine is probably best for the bot... # Make sure to put custom routines in a separate file from VirxERLU routines, so you can easily update VirxERLU to newer versions. # If the stack is still clear if self.is_clear(): # If ball is in our half if self.ball.location.y * utils.side(self.team) > 640: retreat_routine = routines.retreat() # Check if the retreat routine is viable if retreat_routine.is_viable(self): # Retreat back to the net self.push(retreat_routine) # If the ball isn't in our half else: shadow_routine = routines.shadow() # Check if the shadow routine is viable if shadow_routine.is_viable(self): # Shadow self.push(shadow_routine)