def backcheck(self, simple=False): if self.is_clear(): self_from_goal = self.predictions['self_from_goal'] if self_from_goal > 500: if self.playstyle != self.playstyles.Defensive and not simple and ( (self.team == 0 and self.ball.location.y > 2048) or (self.team == 1 and self.ball.location.y < -2048)): bc_x = 0 bc_y = 0 ball_loc = self.ball.location.y * side(not self.team) if ball_loc > 2560 * side(not self.team): if self.ball.location.x > 2048: bc_x = 2048 elif self.ball.location.x < -2048: bc_x = -2048 if len(self.predictions['teammates_from_goal'] ) > 0 and max( self.predictions['teammates_from_goal'] ) is self_from_goal: bc_y = max(1024, ball_loc - 1000) * side(not self.team) self.push(goto(Vector(bc_x, bc_y, 17), self.ball.location)) else: self.push(goto(self.friend_goal.location)) return True return False return True
def defend(self): if not self.me.airborne: if self.shooting and not self.predictions[ 'own_goal'] and self.ball.location.y * side( self.team) < self.defense_switch[self.playstyle]: self.clear() if self.is_clear(): ball = self.ball_prediction_struct.slices[cap( round(self.predictions['enemy_time_to_ball'] * 0.95) * 60, 0, len(self.ball_prediction_struct.slices) - 1)].physics.location ball = Vector(ball.x, ball.y, ball.z) if self.predictions['self_from_goal'] > 2560: self.backcheck() if self.me.boost < 72 and ball.y * side(self.team) < -1280: self.goto_nearest_boost( only_small=ball.y * side(self.team) > -2560) elif self.predictions['self_from_goal'] > 750: self.backcheck() else: face_target_routine = face_target(ball=True) ball_f = face_target_routine.get_ball_target(self) if ball_f.y * side(self.team) > -3840 and abs( Vector(x=1).angle2D(self.me.local_location(ball_f)) ) >= 1 and self.me.velocity.magnitude() < 100: self.push(face_target_routine) return
def run(self, agent): ball_slice = agent.ball_prediction_struct.slices[ agent.future_ball_location_slice].physics.location ball_loc = Vector(ball_slice.x, ball_slice.y) agent.line(ball_loc, ball_loc + Vector(z=185), agent.renderer.white()) ball_loc.y *= side(agent.team) if ball_loc.y < -2560 or (ball_loc.y < agent.ball.location.y * side(agent.team)): ball_loc = Vector(agent.ball.location.x, agent.ball.location.y * side(agent.team) + 640) distance = 1280 target = Vector(y=(ball_loc.y + distance) * side(agent.team)) agent.line(target, target + Vector(z=642), (255, 0, 255)) target.x = (abs(ball_loc.x) + (250 if target.y < -1280 else -( 1024 if abs(ball_loc.x) > 1024 else ball_loc.x))) * sign( ball_loc.x) self_to_target = agent.me.location.dist(target) if self_to_target < 250 and ball_loc.y < -640 and agent.me.velocity.magnitude( ) < 100 and abs( Vector(x=1).angle2D( agent.me.local_location(agent.ball.location))) > 0.1: agent.push(face_target(ball=True)) else: self.goto.target = target self.goto.vector = agent.ball.location self.goto.run(agent, manual=True) if self_to_target < 500: agent.controller.boost = False
def run(self, agent): ball_slice = agent.ball_prediction_struct.slices[ agent.future_ball_location_slice].physics.location ball = Vector(ball_slice.x, cap(ball_slice.y, -5100, 5100)) agent.line(ball, ball + Vector(z=185), agent.renderer.white()) ball.y *= side(agent.team) if ball.y < agent.ball.location.y * side(agent.team): ball = Vector(agent.ball.location.x, agent.ball.location.y * side(agent.team) + 640) target = self.get_target(agent) agent.line(target, target + Vector(z=642), (255, 0, 255)) if target.flat_dist(agent.me.location) < 350: if agent.me.velocity.magnitude() > 100: self.brake.run(agent, manual=True) elif abs(Vector(x=1).angle2D(agent.me.local_location(ball))) > 0.5: agent.pop() agent.push(face_target(ball=True)) else: agent.pop() else: self.goto.target = target self.goto.run(agent, manual=True)
def handle_quick_chat(self, index, team, quick_chat): if self.kickoff_done and team is self.team and index is not self.index and len( self.friends) != 0: if quick_chat is QuickChats.Information_IGotIt: if side( self.team ) * self.ball.location.y < 4200 and not self.predictions[ 'own_goal'] and not self.shooting: self.can_shoot = self.time if side(self.team) * self.ball.location.y < 2560: self.can_shoot -= 2.5 elif side(self.team) * self.ball.location.y < 750: self.can_shoot -= 2 else: self.can_shoot -= 1.5 if self.shooting and self.shot_weight == -1: self.clear() self.backcheck() elif quick_chat is QuickChats.Information_GoForIt: if self.playstyle is self.playstyles.Neutral: self.can_shoot = None if not self.shooting and self.me.boost >= 36: if not self.smart_shot( self.best_shot, cap=6) and not self.smart_shot( self.offensive_shots[0], cap=6) and not self.smart_shot( self.anti_shot, cap=6) and len(self.friends) > 1: self.push(short_shot(self.foe_goal.location))
def run(self, agent): target = agent.ball.location + Vector(y=200 * side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) defaultThrottle(agent, 2300) distance = local_target.magnitude() agent.controller.throttle = 1 agent.controller.boost = True if distance < 650: if len(agent.foes ) > 0 and agent.predictions['closest_enemy'] > 1000: if distance < 100 or distance > 500: agent.pop() agent.kickoff_done = True defaultPD( agent, agent.ball.location - Vector(y=500 * side(agent.team))) elif distance < 450: agent.pop() agent.kickoff_done = True agent.push(flip(agent.me.local(agent.foe_goal.location)))
def run(self, agent): if self.start_time is None: self.start_time = agent.time ball_loc = agent.ball.location.y * side(agent.team) if agent.time - self.start_time > 0.5 or agent.playstyle is agent.playstyles.Defensive or ball_loc > 2560: agent.pop() return target = Vector(y=(ball_loc + 1280) * side(agent.team)) if agent.ball.location.x > 2560: target.x = 2560 if ball_loc <= 0 else 1024 elif agent.ball.location.x < -2560: target.x = -2560 if ball_loc <= 0 else -1024 self_to_target = agent.me.location.dist(target) if self_to_target > 250: self.goto.target = target self.goto.vector = agent.ball.location self.goto.run(agent, manual=True) if self_to_target < 500: agent.controller.boost = False agent.controller.throttle = cap(agent.controller.throttle, -0.75, 0.75)
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 playstyle_defend(self): if self.shooting and not self.predictions[ 'own_goal'] and self.ball.location.z * side(self.team) < 750: self.clear() if self.is_clear(): if self.predictions['self_from_goal'] > 2560: self.backcheck(simple=True) if self.me.boost < 72: self.goto_nearest_boost( only_small=self.ball.location.y * side(self.team) > -2560) elif self.predictions['self_from_goal'] > 750: self.backcheck(simple=True)
def get_slices(agent, cap_, weight=None, start_slice=12): # Get the struct struct = agent.ball_prediction_struct min_time_to_ball = agent.predictions['self_min_time_to_ball'] - (1 / 15) # Make sure it isn't empty if struct is None or min_time_to_ball > cap_: return if start_slice / 60 < min_time_to_ball: start_slice = round(min_time_to_ball * 60) - 1 ball_y = agent.ball.location.y * side(agent.team) foes = len( tuple(foe for foe in agent.foes if not foe.demolished and foe.location.y * side(agent.team) < ball_y + 75)) if not agent.predictions[ 'goal'] and agent.ball_to_goal > 2560 and agent.ball.location.dist( agent.foe_goal.location) > 900 and foes > 0: factor = 1.2 - 0.04 * foes cap_ = min(agent.predictions['enemy_time_to_ball'] * factor, cap_) end_slices = None # If we're shooting, crop the struct if agent.shooting and agent.shot_weight != -1: # Get the time remaining time_remaining = agent.stack[0].intercept_time - agent.time if time_remaining < 0.5 and time_remaining >= 0: return # if the shot is done but it's working on it's 'follow through', then ignore this stuff if time_remaining > 0: # Convert the time remaining into number of slices, and take off the minimum gain accepted from the time min_gain = 0.05 if weight is None or weight is agent.shot_weight else -( agent.max_shot_weight - agent.shot_weight + 1) end_slice = round(min(time_remaining - min_gain, cap_) * 60) if end_slices is None: # Cap the slices end_slice = round(cap_ * 60) # We can't end a slice index that's lower than the start index if end_slice <= start_slice: return # for every second worth of slices that we have to search, skip 1 more slice (for performance reasons) - min 1 and max 3 skip = cap(end_slice - start_slice / 60, 1, 3) return struct.slices[start_slice:end_slice:skip]
def run(self, agent): if self.start_time is None: self.start_time = agent.time if not self.wave_dash: time_elapsed = agent.time - self.start_time if time_elapsed > 0.75: self.wave_dash = True agent.push(wave_dash()) target = agent.ball.location + Vector(y=200 * side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 650: if len(agent.foes ) > 0 and agent.predictions['closest_enemy'] > 1000: if distance < 100 or distance > 700: agent.pop() agent.kickoff_done = True else: agent.pop() agent.kickoff_done = True agent.push( flip( agent.me.local(agent.foe_goal.location - agent.me.location)))
def playstyle_neutral(self): if self.is_clear(): if self.predictions['self_to_ball'] > 3840: self.backcheck() elif self.me.boost < 60 and self.ball.location.y * side( self.team) < -1280 and not self.predictions[ 'goal'] and self.ball.location.flat_dist( self.foe_goal.location) > 1280: self.goto_nearest_boost() if self.is_clear(): self.backcheck() elif self.odd_tick % 2 == 0 and self.shooting and not self.me.airborne and self.can_shoot is None: shot = self.get_shot(self.best_shot) if shot is None: shot = self.get_shot(self.offensive_shots[0], cap=2.5) if shot is not None: if shot['intercept_time'] < self.shot_time - 0.05: self.shoot_from(shot, clear_on_valid=True) if self.is_clear() or self.stack[-1].__class__.__name__ in { "goto", "goto_boost", "brake", "dynamic_backcheck", "retreat" } and self.odd_tick == 0: if not self.smart_shot(self.best_shot) and not self.smart_shot( self.offensive_shots[0], cap=2.5) and self.is_clear(): self.backcheck()
def init(self): foe_team = -1 if self.team == 1 else 1 team = -foe_team # note that the second value may be positive or negative self.kickoff_left = (-2048 * side(self.team), 2560) self.kickoff_right = (2048 * side(self.team), 2560) self.kickoff_back = (0, 4608) self.kickoff_back_left = (-256 * side(self.team), 3840) self.kickoff_back_right = (256 * side(self.team), 3840) self.offensive_shots = ((Vector(foe_team * 893, foe_team * 5120, 321.3875), Vector(foe_team * -893, foe_team * 5120, 321.3875)), (Vector(foe_team * 893, foe_team * 5120, 321.3875), Vector(foe_team * 893, foe_team * 6000, 321.3875)), (Vector(foe_team * -893, foe_team * 5120, 321.3875), Vector(foe_team * -893, foe_team * 6000, 321.3875))) self.defensive_shots = (self.offensive_shots[0], (Vector( 4096, foe_team * 3968, 1900), Vector(2944, foe_team * 5120, 1900)), (Vector(-4096, foe_team * 3968, 1900), Vector(-2944, foe_team * 5120, 1900))) self.best_shot = (Vector(foe_team * 793, foe_team * 5213, 321.3875), Vector(-foe_team * 793, foe_team * 5213, 321.3875)) self.anti_shot = (Vector(-team * 2048, team * 5120, 2000), Vector(team * 2048, team * 5120, 2000)) self.max_shot_weight = 4 self.playstyles_switch = { self.playstyles.Defensive: self.defend, self.playstyles.Neutral: self.neutral, self.playstyles.Offensive: self.attack } self.defense_switch = { self.playstyles.Defensive: 1920, self.playstyles.Neutral: 1280, self.playstyles.Offensive: 640 }
def run(self, agent): if agent.ball.location.y * side(agent.team) < 2560 and agent.playstyle is not agent.playstyles.Defensive: agent.pop() return team_to_ball = [car.location.flat_dist(agent.ball.location) for car in agent.friends if car.location.y * side(agent.team) >= agent.ball.location.y * side(agent.team) - 50 and abs(car.location.x) < abs(agent.ball.location.x)] self_to_ball = agent.me.location.flat_dist(agent.ball.location) team_to_ball.append(self_to_ball) team_to_ball.sort() if len(agent.friends) <= 1 or (agent.ball.location.x <= 900 and agent.ball.location.x >= -900) or len(team_to_ball) <= 1: target = agent.friend_goal.location elif team_to_ball[-1] == self_to_ball: target = agent.friend_goal.right_post if abs(agent.ball.location.x) > 900 else agent.friend_goal.left_post else: target = agent.friend_goal.left_post if abs(agent.ball.location.x) > 900 else agent.friend_goal.right_post target = target.copy() if agent.ball.location.y * side(agent.team) > 4620 and target == agent.friend_goal.location: target.y = (agent.ball.location.y * side(agent.team) + 250) * side(agent.team) else: target = target + Vector(y=-245 * side(agent.team)) target = target.flatten() agent.line(target, target + Vector(z=100)) if target.flat_dist(agent.me.location) < 100: if abs(agent.me.local(agent.me.velocity).x) > 10 and not self.facing: agent.push(brake()) return if self.facing or (abs(agent.me.local(agent.me.velocity).x) < 10 and Vector(x=1).angle(agent.me.local(agent.ball.location - agent.me.location)) > 0.25): self.facing = True if self.counter == 0: agent.controller.jump = True elif self.counter == 2: agent.pop() agent.push(ball_recovery()) self.counter += 1 return agent.pop() else: self.goto.target = target self.goto.run(agent, manual=True)
def handle_quick_chat(self, index, team, quick_chat): try: if team is self.team and index is not self.index: if quick_chat is QuickChats.Information_IGotIt: if side( self.team ) * self.ball.location.y < 4200 and not self.predictions[ 'own_goal'] and not self.shooting: self.can_shoot = self.time if side(self.team) * self.ball.location.y > 2560: self.can_shoot += 2.5 elif side(self.team) * self.ball.location.y > 750: self.can_shoot += 2 else: self.can_shoot += 1 except Exception: print_exc()
def offensive_kickoff(self): # note that the second value may be positive or negative left = (-2048 * side(self.team), 2560) right = (2048 * side(self.team), 2560) back = (0, 4608) # back_left = (-256 * side(self.team), 3840) # back_right = (256 * side(self.team), 3840) def kickoff_check(pair): return almost_equals(pair[0], self.me.location.x, 50) and almost_equals( pair[1], abs(self.me.location.y), 50) if kickoff_check(back): self.push(back_kickoff()) elif kickoff_check(left) or kickoff_check(right): self.push(corner_kickoff()) else: self.push(generic_kickoff()) # if kickoff_check(right): # self.push(right_kickoff()) # elif kickoff_check(left): # self.push(left_kickoff()) # elif kickoff_check(back): # self.push(back_kickoff()) # elif kickoff_check(back_left): # self.push(back_left_kickoff()) # elif kickoff_check(back_right): # self.push(back_right_kickoff()) self.send_quick_chat(QuickChats.CHAT_TEAM_ONLY, QuickChats.Information_IGotIt) self.print("I got it!") send_comm(self, {"attacking": True}) self.playstyle = self.playstyles.Offensive
def get_target(self, agent): target = None ball_slice = agent.ball_prediction_struct.slices[ agent.future_ball_location_slice].physics.location ball = Vector(ball_slice.x, ball_slice.y, ball_slice.z) ball_y = ball.y * side(agent.team) team_to_ball = [ car.location.flat_dist(ball) for car in agent.friends if car.location.y * side(agent.team) >= ball_y - 50 and abs(car.location.x) < abs(ball.x) ] self_to_ball = agent.me.location.flat_dist(ball) team_to_ball.append(self_to_ball) team_to_ball.sort() if agent.me.location.y * side(agent.team) >= ball_y - 50 and abs( agent.me.location.x) < abs(ball.x): if len(agent.friends) == 0 or abs( ball.x) < 900 or team_to_ball[-1] is self_to_ball: target = agent.friend_goal.location elif team_to_ball[0] is self_to_ball: target = agent.friend_goal.right_post if abs( ball.x) > 10 else agent.friend_goal.left_post if target is None: if len(agent.friends) <= 1: target = agent.friend_goal.location else: target = agent.friend_goal.left_post if abs( ball.x) > 10 else agent.friend_goal.right_post target = target.copy() target.y += 250 * side(agent.team) if len(agent.friends) == 0 or abs( ball.x) < 900 or team_to_ball[-1] is self_to_ball else -245 * side( agent.team) return target.flatten()
def neutral(self): if self.can_shoot is None and (self.is_clear() or self.odd_tick == 0) and self.smart_shot( self.best_shot, cap=5): return if not self.me.airborne and not self.shooting and self.me.boost < 12: if self.is_clear(): self.goto_nearest_boost() if not self.is_clear(): return if self.can_shoot is None and (self.is_clear() or self.odd_tick == 0): for i, shot in enumerate( self.defensive_shots if self.ball.location.y * side(self.team) > -2560 and len(self.friends) != 0 else self.offensive_shots): shot_weight = get_weight(self, index=i) if self.shooting and shot_weight < self.shot_weight: break shot = self.get_shot(shot, weight=shot_weight, cap=4) if shot is not None: if self.shooting: self.upgrade_shot(shot) else: self.shoot_from(shot, clear_on_valid=True) return if ( self.is_clear() or self.get_stack_name() == "ball_recovery" ) and self.boost_amount == 'unlimited' and self.gravity.z > -700 and self.me.location.z > 750 and self.predictions[ 'self_to_ball'] > 2560: if not self.is_clear(): self.clear() self.push(boost_down()) return if self.is_clear() and not self.me.airborne: if self.can_shoot is not None and self.me.boost < 50: self.goto_nearest_boost() if not self.is_clear(): return self.backcheck()
def get_slices(agent, cap_, weight=None, start_slice=12): # Get the struct struct = agent.ball_prediction_struct # Make sure it isn't empty if struct is None: return ball_y = agent.ball.location.y * side(agent.team) foes = tuple( foe for foe in agent.foes if not foe.demolished and foe.location.y * side(agent.team) < ball_y) # If we're shooting, crop the struct if agent.shooting: # Get the time remaining time_remaining = agent.stack[0].intercept_time - agent.time # Convert the time remaining into number of slices, and take off the minimum gain accepted from the time min_gain = 0.05 end_slice = math.ceil(min(time_remaining - min_gain, cap_) * 60) # We can't end a slice index that's lower than the start index if end_slice <= 12: return # Half the time, double the slices if time_remaining <= 3: return struct.slices[start_slice:end_slice] return struct.slices[start_slice:end_slice:2] # If we're not shooting, then cap the slices at the cap end_slice = math.ceil(cap_ * 60) # Start 0.2 seconds in, and skip every other data point return struct.slices[start_slice:end_slice:2]
def backcheck(self, simple=False, clear_on_valid=False): if self.is_clear() or clear_on_valid: if self.playstyle is not self.playstyles.Defensive and not simple and self.ball.location.y * side( self.team) < 2560: if clear_on_valid: self.clear() self.push(dynamic_backcheck()) elif self.me.location.dist(self.friend_goal.location + Vector(y=-250 * side(self.team))) > 500: if clear_on_valid: self.clear() self.push(retreat()) else: return False return True
def run(self, agent): if self.flip: agent.kickoff_done = True agent.pop() return target = agent.ball.location + Vector(y=200*side(agent.team)) local_target = agent.me.local(target - agent.me.location) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 550: self.flip = True agent.push(flip(agent.me.local(agent.foe_goal.location - agent.me.location)))
def run(self, agent): if self.start_time == -1: self.start_time = agent.time if self.flip or agent.time - self.start_time > 3: agent.kickoff_done = True agent.pop() return target = agent.ball.location + Vector(y=( 200 if agent.gravity.z < -600 and agent.gravity.z > -700 else 50) * side(agent.team)) local_target = agent.me.local_location(target) defaultPD(agent, local_target) agent.controller.throttle = 1 agent.controller.boost = True distance = local_target.magnitude() if distance < 550: self.flip = True agent.push(flip(agent.me.local_location(agent.foe_goal.location)))
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)
def run(self, agent): agent.shooting = True agent.shot_weight = agent.max_shot_weight - 1 if self.ball_location is None or not shot_valid(agent, self, threshold=75): self.ball_location, self.intercept_time, self.direction = self.get_intercept(agent) if self.ball_location is None: agent.shooting = False agent.shot_weight = -1 agent.pop() return agent.shot_time = self.intercept_time t = self.intercept_time - agent.time # if we ran out of time, just pop # this can be because we were successful or not - we can't tell if t < -0.3: agent.shooting = False agent.shot_weight = -1 agent.pop() return if self.brake: if agent.ball.location.dist(agent.me.location) < 250 and agent.ball.location.y * side(agent.team) + 10 < agent.me.location.y and agent.ball.location.z < 190: agent.pop() agent.flip(agent.me.local(agent.ball.location)) else: # current velocity u = agent.me.local(agent.me.velocity).x a = brake_accel.x # calculate how much distance we need to slow down x = (u ** 2 * -1) / (2 * a) if self.ball_location.dist(agent.me.location) <= x: self.brake = True agent.push(brake()) return agent.line(self.ball_location.flatten(), self.ball_location.flatten() + Vector(z=250), color=[255, 0, 255]) angles = defaultPD(agent, agent.me.local(self.ball_location - agent.me.location), self.direction) # We want to get there before the ball does, so take the time we have and get 3 fifths of it required_speed = cap(agent.me.location.dist(self.ball_location) / ((self.intercept_time - agent.time) * (3/5)), 600, 2275) defaultThrottle(agent, required_speed, self.direction) agent.controller.boost = False if abs(angles[1]) > 0.3 else agent.controller.boost agent.controller.handbrake = True if abs(angles[1]) >= 2.3 or (agent.me.local(agent.me.velocity).x >= 1400 and abs(angles[1]) > 1.5) and self.direction == 1 else False
def run(self): # predictions self.update_predictions() # act on the predictions if not self.kickoff_done: if self.is_clear(): if len(self.friends) > 0: if almost_equals(self.predictions['team_to_ball'][0], self.predictions['self_to_ball'], 5): self.offensive_kickoff() elif almost_equals(self.predictions['team_to_ball'][-1], self.predictions['self_to_ball'], 5): self.defensive_kickoff() elif len(self.foes) == 0 or almost_equals( self.predictions['closest_enemy'], self.predictions['self_to_ball'], 10): self.offensive_kickoff() else: self.defensive_kickoff() return if self.can_shoot is None: self.dbg_3d("Can shoot: 0") else: self.dbg_3d( f"Can shoot: {round(3 - (self.time - self.can_shoot), 2)}") 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 self.predictions['enemy_time_to_ball'] != 7: self.sphere(enemy_intercept_location, 92.75, self.renderer.red()) self_intercept_location = self.ball_prediction_struct.slices[ self.min_intercept_slice].physics.location self_intercept_location = Vector(self_intercept_location.x, self_intercept_location.y, self_intercept_location.z) if self.predictions['self_min_time_to_ball'] != 7: self.sphere(self_intercept_location, 92.75, self.renderer.green()) if side(self.team) * enemy_intercept_location.y >= self.defense_switch[ self.playstyle] or self.predictions['own_goal']: for shot in self.defensive_shots: self.line(*shot, self.renderer.team_color(alt_color=True)) self.dbg_3d("(Defending)") if self.predictions['enemy_time_to_ball'] > self.predictions[ 'self_min_time_to_ball'] + ( 3 if self.shooting else 1) and self.me.boost < 36 and not self.is_clear( ) and self.get_stack_name() == 'goto_boost': return ball_loc = self_intercept_location * side(self.team) self_loc = self.me.location * side(self.team) # This is a list of all tm8s that are onside team_to_ball = [ car.location.flat_dist(self.ball.location) for car in self.friends if car.location.y * side(self.team) >= ball_loc.y + 95 and abs(car.location.x) < abs(self.ball.location.x) - 320 ] self_to_ball = self.me.location.flat_dist(self.ball.location) team_to_ball.append(self_to_ball) team_to_ball.sort() if len(team_to_ball) == 1 or team_to_ball[math.ceil( len(team_to_ball) / 2)] + 10 > self_to_ball: self.can_shoot = None if self.can_shoot is None and (self.is_clear() or self.odd_tick == 0): if self_loc.y > ball_loc.y + 95 and self.smart_shot( self.best_shot, cap=4): return if ball_loc.y - self_loc.y > ( ball_loc.x - self_loc.x ) * 1.5 and ( self.predictions['own_goal'] or (len(team_to_ball) > 1 and team_to_ball[math.ceil( len(team_to_ball) / 2)] + 10 > self_to_ball) or (len(team_to_ball) == 1 and self_to_ball < 2560) or (abs(ball_loc.x) < 900 and ball_loc.y > 1280) ) and team_to_ball[0] is self_to_ball and self.smart_shot( self.anti_shot, weight=self.max_shot_weight - 3, cap=4): return if self_loc.y > ball_loc.y + 95: for i, shot in enumerate( self.defensive_shots if self.predictions['self_min_time_to_ball'] * 2 < self.predictions['enemy_time_to_ball'] else self.defensive_shots[1:]): shot_weight = get_weight(self, index=i) if self.shooting and shot_weight < self.shot_weight: break shot = self.get_shot(shot, weight=shot_weight, cap=4) if shot is not None: if self.shooting: self.upgrade_shot(shot) else: self.shoot_from(shot, clear_on_valid=True) return if self.smart_shot(self.anti_shot, weight=self.max_shot_weight - 3, cap=3): return if not self.me.airborne and (not self.shooting or self.shot_weight == -1): if self.predictions['enemy_time_to_ball'] > self.predictions[ 'self_min_time_to_ball'] + ( 3 if self.shooting else 1) and self.me.boost < 36 and ( self.is_clear() or self.get_stack_name() != 'goto_boost' ) and self.goto_nearest_boost(clear_on_valid=True): return if not self.predictions[ 'own_goal'] and self_loc.y <= ball_loc.y - 50 and not self.is_clear( ) and self.get_stack_name() == 'goto_boost' and abs( ball_loc.x) > 1024 and self.backcheck( clear_on_valid=True): return if self.is_clear() and not self.backcheck(): face_target_routine = face_target(ball=True) ball_f = face_target_routine.get_ball_target(self) if ball_f.y * side(self.team) > -3840 and abs( Vector(x=1).angle2D(self.me.local_location(ball_f)) ) >= 1 and self.me.velocity.magnitude() < 100: self.push(face_target_routine) return return if self.me.airborne and self.is_clear(): self.push(recovery()) if not self.is_clear() and self.get_stack_name( ) == "short_shot" and self.me.location.y * side( self.team) < self.ball.location.y * side(self.team): self.clear() self.playstyles_switch[self.playstyle]() ""
def run(self, agent): if not agent.shooting: agent.shooting = True if self.time == -1: self.time = agent.time elapsed = agent.time - self.time T = self.intercept_time - agent.time xf = agent.me.location + agent.me.velocity * T + 0.5 * agent.gravity * T * T vf = agent.me.velocity + agent.gravity * T slice_n = math.ceil(T * 60) agent.dbg_2d(f"Shot slice #: {slice_n}") if T > 0.1 or self.target is None: ball = agent.ball_prediction_struct.slices[ slice_n].physics.location self.ball = Vector(ball.x, ball.y, ball.z) self.target = self.ball - (self.shot_vector * agent.best_shot_value * 0.8) if agent.me.location.z > 2044 - agent.me.hitbox.height * 1.1: self.ceiling = True self.target -= Vector(z=92) if not self.ceiling and (self.jumping or not agent.me.airborne): agent.dbg_2d("Jumping") if not self.jumping or not agent.me.airborne: self.jumping = True self.jump_time = agent.time self.counter = 0 jump_elapsed = agent.time - self.jump_time tau = jump_max_duration - jump_elapsed if jump_elapsed == 0: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * T vf += agent.me.up * jump_acc * tau xf += agent.me.up * jump_acc * tau * (T - 0.5 * tau) if self.fast_aerial: vf += agent.me.up * jump_speed xf += agent.me.up * jump_speed * (T - tau) if jump_elapsed < jump_max_duration: agent.controller.jump = True elif self.counter < 6: self.counter += 1 if self.counter == 3: agent.controller.jump = True self.dodging = True elif self.counter == 6: self.dodging = self.jumping = False elif jump_elapsed < jump_max_duration: agent.controller.jump = True else: self.jumping = False if self.ceiling: agent.dbg_2d(f"Ceiling shot") delta_x = self.target - xf direction = delta_x.normalize() agent.line(agent.me.location, self.target, agent.renderer.white()) c_vf = vf + agent.me.location agent.line(c_vf - Vector(z=100), c_vf + Vector(z=100), agent.renderer.blue()) agent.line(xf - Vector(z=100), xf + Vector(z=100), agent.renderer.red()) agent.line(self.target - Vector(z=100), self.target + Vector(z=100), agent.renderer.green()) if not self.dodging: target = delta_x if delta_x.magnitude() > 50 else ( self.target - agent.me.location) if self.jumping: target = target.flatten() target = agent.me.local(target) if abs(Vector(x=1).angle(target)) > 0.005: defaultPD(agent, target, upside_down=self.shot_vector.z < 0 and not self.jumping) if abs(agent.me.forward.dot(direction)) > 0.5: delta_v = delta_x.dot(agent.me.forward) / T if agent.me.boost > 0 and delta_v >= agent.boost_accel * min_boost_time: agent.controller.boost = True else: agent.controller.throttle = cap( delta_v / (throttle_accel * min_boost_time), -1, 1) if T <= 0 or (not self.jumping and not agent.me.airborne) or ( not self.jumping and T > 2 and self.fast_aerial and not virxrlcu.aerial_shot_is_viable( T + 0.3, 144, agent.boost_accel, agent.gravity.tuple(), 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, self.ball.tuple())): agent.pop() agent.shooting = False agent.shot_weight = -1 agent.shot_time = -1 agent.push(ball_recovery()) elif (self.ceiling and self.target.dist(agent.me.location) < 92 + agent.me.hitbox.length and not agent.me.doublejumped and agent.me.location.z < agent.ball.location.z + 92 and self.target.y * side(agent.team) > -4240) or ( not self.ceiling and not self.fast_aerial and self.target.dist(agent.me.location) < 92 + agent.me.hitbox.length and not agent.me.doublejumped): agent.dbg_2d("Flipping") agent.controller.jump = True local_target = agent.me.local_location(self.target) agent.controller.pitch = abs( local_target.x) * -sign(local_target.x) agent.controller.yaw = abs(local_target.y) * sign(local_target.y)
def attack(self): if self.can_shoot is None and (self.is_clear() or self.odd_tick == 0) and self.smart_shot( self.best_shot, cap=6): return if (self.is_clear() or self.get_stack_name() == "short_shot" ) and not self.me.airborne and self.me.boost < 12: self.goto_nearest_boost(clear_on_valid=True) if not self.is_clear() and self.get_stack_name() == "goto_boost": self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Information_GoForIt) return if not self.is_clear() and self.get_stack_name( ) == "goto_boost" and self.me.boost < 24: return if self.can_shoot is None and (self.is_clear() or self.odd_tick == 0): for i, shot in enumerate( self.defensive_shots if self.ball.location.y * side(self.team) > -2560 and len(self.friends) != 0 else self.offensive_shots): shot_weight = get_weight(self, index=i) if self.shooting and shot_weight < self.shot_weight: break shot = self.get_shot(shot, weight=shot_weight, cap=6) if shot is not None: if self.shooting: self.upgrade_shot(shot) else: self.shoot_from(shot, clear_on_valid=True) return if not self.predictions['goal'] and ( self.is_clear() or self.shot_weight == self.max_shot_weight - 3) and self.me.location.y * side(self.team) > ( self.ball.location.y * side(self.team)) + 1280: shot = self.get_shot(self.anti_shot, weight=self.max_shot_weight - 3, cap=6) if shot is not None: if self.shooting: self.upgrade_shot(shot) else: self.shoot_from(shot, clear_on_valid=True) return if self.is_clear(): self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Information_GoForIt) if ( self.is_clear() or self.get_stack_name() == "ball_recovery" ) and self.boost_amount == 'unlimited' and self.gravity.z > -700 and self.me.location.z > 750 and self.predictions[ 'self_to_ball'] > 2560: if not self.is_clear(): self.clear() self.push(boost_down()) return if self.is_clear() and not self.me.airborne: if self.can_shoot is not None and self.me.boost < 50: self.goto_nearest_boost() if not self.is_clear(): return self.backcheck()
def run(self): """ This is for state setting the ball to high up for aerial testing "" if not self.shooting and self.ball.location.z < 98: ball_state = BallState(Physics(location=GSVec3(0, -3000, self.ball.location.z), velocity=GSVec3(0, 0, 2000), angular_velocity=GSVec3(0, 0, 0))) game_state = GameState(ball=ball_state) self.set_game_state(game_state) if not self.shooting: self.smart_shot((self.foe_goal.left_post, self.foe_goal.right_post)) if self.is_clear(): self.push(goto(Vector(), self.foe_goal.location)) """ self.dbg_3d(self.playstyle.name) for _ in range(len(self.friends) + len(self.foes) + 1): try: msg = self.matchcomms.incoming_broadcast.get_nowait() except Empty: break if msg.get("VirxEB" ) is not None and msg['VirxEB']['team'] is self.team: msg = msg['VirxEB'] if self.playstyle is self.playstyles.Defensive: if msg.get("match_defender") and msg['index'] < self.index: self.playstyle = self.playstyles.Neutral self.clear() self.goto_nearest_boost() self.can_shoot = self.time self.print("You can defend") elif self.playstyle is self.playstyles.Offensive: if msg.get("attacking") and msg['index'] < self.index: self.playstyle = self.playstyles.Neutral self.clear() self.goto_nearest_boost() self.kickoff_done = True self.can_shoot = self.time self.print("All yours!") if not self.kickoff_done: if self.is_clear(): if len(self.friends) > 0: try: if almost_equals( min(self.predictions['teammates_to_ball']), self.predictions['self_to_ball'], 5): self.offensive_kickoff() elif almost_equals( max(self.predictions['teammates_to_ball']), self.predictions['self_to_ball'], 5): self.defensive_kickoff() except ValueError: return elif almost_equals(self.predictions['closest_enemy'], self.predictions['self_to_ball'], 50): self.offensive_kickoff() else: self.can_shoot = self.time self.defensive_kickoff() else: if self.can_shoot is not None and self.time - self.can_shoot >= 3: self.can_shoot = None if not self.is_clear( ) and self.stack[0].__class__.__name__ == "atba" and ( self.predictions['closest_enemy'] < 1000 or self.ball_to_goal > 1500): self.clear() elif self.is_clear() and self.predictions[ 'closest_enemy'] is not None and self.predictions[ 'closest_enemy'] > 2500 and self.ball_to_goal < 1500 and side( self.team) is sign(self.me.location.y) and abs( self.me.location.y) > 5400: self.push(atba()) self.playstyles_switch[self.playstyle]() if self.debug_ball_path: ball_prediction = self.predictions['ball_struct'] if ball_prediction is not None: for i in range( 0, ball_prediction.num_slices - (ball_prediction.num_slices % self.debug_ball_path_precision) - self.debug_ball_path_precision, self.debug_ball_path_precision): self.line( ball_prediction.slices[i].physics.location, ball_prediction.slices[ i + self.debug_ball_path_precision].physics. location) if self.shooting and self.shot_weight != -1: self.dbg_2d(self.stack[0].intercept_time - self.time) ""
def goto_nearest_boost(self, only_small=False, clear_on_valid=False): if self.is_clear() or clear_on_valid: self.send_quick_chat(QuickChats.CHAT_TEAM_ONLY, QuickChats.Information_NeedBoost) ball_slice = self.ball_prediction_struct.slices[min( round(self.future_ball_location_slice * 1.1), 6)].physics ball = Vector(ball_slice.location.x, ball_slice.location.y, ball_slice.location.z) ball_v = Vector(ball_slice.velocity.x, ball_slice.velocity.y, ball_slice.velocity.z) ball_y = ball.y * side(self.team) if not only_small: if len(self.friends) > 0: large_boosts = ( boost for boost in self.boosts if boost.large and boost.active and ( (self.playstyle is self.playstyles.Offensive and boost.location.y * side(self.team) < -3000) or (self.playstyle is self.playstyles.Neutral and boost.location.y * side(self.team) > -100) or (self.playstyle is self.playstyles.Defensive and boost.location.y * side(self.team) > 3000))) else: if (ball_v.angle2D(self.foe_goal.location - ball) < 1 and ball_y > 0) or abs( ball.x) < 900 or self.predictions['own_goal']: large_boosts = None else: ball_x = sign(ball.x) large_boosts = ( boost for boost in self.boosts if boost.large and boost.active and ( boost.location.y * side(self.team) > ball_y - 50) and sign(boost.location.x) == ball_x) if large_boosts is not None: closest = peek_generator(large_boosts) if closest is not None: closest_distance = closest.location.flat_dist( self.me.location) for item in large_boosts: item_distance = item.location.flat_dist( self.me.location) if item_distance is closest_distance: if item.location.flat_dist( self.me.location ) < closest.location.flat_dist( self.me.location): closest = item closest_distance = item_distance elif item_distance < closest_distance: closest = item closest_distance = item_distance if clear_on_valid: self.clear() self.push(goto_boost(closest)) return True if (ball_v.angle2D(self.foe_goal.location - ball) < 1 and ball_y > 0) or self.predictions['own_goal']: return False ball_x = sign(ball.x) small_boosts = (boost for boost in self.boosts if not boost.large and boost.active and boost.location.y * side(self.team) > ball_y - 50 and sign(boost.location.x) == ball_x) closest = peek_generator(small_boosts) if closest is not None: closest_distance = closest.location.flat_dist( self.me.location) + (closest.location.flat_dist( self.friend_goal.location) / 400) for item in small_boosts: item_distance = item.location.flat_dist( self.me.location) + (item.location.flat_dist( self.friend_goal.location) / 400) if item_distance < closest_distance: item_loc = item.location.y * side(self.team) if (self.playstyle is self.playstyles.Offensive and item_loc < -2560 ) or ( self.playstyle is self.playstyles.Neutral and item_loc < -100) or ( self.playstyle is self.playstyles.Defensive and item_loc > 1280): closest = item closest_distance = item_distance if clear_on_valid: self.clear() self.push(goto_boost(closest)) return True return False
def update_predictions(self): len_friends = len(self.friends) can_shoot = True if len(self.foes) > 0: foe_distances = tuple( self.ball.location.flat_dist(foe.location) for foe in self.foes if not foe.demolished) self_dist = self.ball.location.flat_dist(self.me.location) if len(foe_distances) > 0: if self.odd_tick == 0: self.predictions['enemy_time_to_ball'] = min( tuple(self.time_to_ball(foe) for foe in self.foes)) self.predictions['closest_enemy'] = min(foe_distances) else: self.predictions['enemy_time_to_ball'] = 7 self.predictions['closest_enemy'] = math.inf else: self.predictions['enemy_time_to_ball'] = 7 self.predictions['closest_enemy'] = math.inf self.future_ball_location_slice = cap( round(self.predictions['enemy_time_to_ball'] * 60), 0, len(self.ball_prediction_struct.slices) - 1) self.dbg_2d( f"Predicted enemy time to ball: {round(self.predictions['enemy_time_to_ball'], 1)}" ) self.predictions[ 'self_from_goal'] = self.friend_goal.location.flat_dist( self.me.location) self.predictions['self_to_ball'] = self.ball.location.flat_dist( self.me.location) if not self.predictions['was_down']: self.predictions[ 'was_down'] = self.game.friend_score - self.game.foe_score > 1 if len_friends > 0: teammates = tuple(itertools.chain(self.friends, [self.me])) self.predictions["team_from_goal"] = sorted( tuple( self.friend_goal.location.flat_dist(teammate.location) if not teammate.demolished else math.inf for teammate in teammates)) self.predictions["team_to_ball"] = sorted( tuple( self.ball.location.flat_dist(teammate.location) if not teammate.demolished else math.inf for teammate in teammates)) if len_friends >= 2 and can_shoot: can_shoot = self.predictions[ 'self_from_goal'] != self.predictions["team_from_goal"][0] if self.odd_tick == 0: self.predictions['self_min_time_to_ball'] = self.time_to_ball( self.me) self.min_intercept_slice = cap( round(self.predictions['self_min_time_to_ball'] * 60), 0, len(self.ball_prediction_struct.slices) - 1) if self.odd_tick % 2 == 0: if self.goalie: self.playstyle = self.playstyles.Defensive # elif len_friends > 0: # ball_loc_y = self.ball.location.y * side(self.team) # if ball_loc_y < 2560: # # If we're down or up by 2 goals in 2's, then start playing more defensive # self_time_to_ball = self.predictions['self_min_time_to_ball'] * 1.05 # team_time_to_ball = min(tuple(self.time_to_ball(teammate) for teammate in self.friends)) * 1.05 # if ball_loc_y < -1280 and self_time_to_ball < team_time_to_ball and self.predictions['self_from_goal'] != self.predictions["team_from_goal"][0]: # self.playstyle = self.playstyles.Offensive if len_friends > 1 or (len_friends == 1 and (self.predictions['was_down'] or abs(self.game.friend_score - self.game.foe_score) <= 1)) else self.playstyles.Neutral # elif self.predictions['self_from_goal'] == self.predictions["team_from_goal"][0]: # self.playstyle = self.playstyles.Defensive if len_friends > 1 else self.playstyles.Neutral # else: # self.playstyle = self.playstyles.Neutral # else: # self.playstyle = self.playstyles.Defensive else: self_time_to_ball = self.predictions[ 'self_min_time_to_ball'] * 1.05 if self.ball.location.y * side(self.team) < 640: self.playstyle = self.playstyles.Offensive if self_time_to_ball < self.predictions[ 'enemy_time_to_ball'] else self.playstyles.Neutral else: self.playstyle = self.playstyles.Neutral if self_time_to_ball < self.predictions[ 'enemy_time_to_ball'] else self.playstyles.Defensive is_own_goal = False is_goal = False if self.ball_prediction_struct is not None: for ball_slice in self.ball_prediction_struct.slices[30::12]: location = ball_slice.physics.location.y * side(self.team) if location >= 5212.75: is_own_goal = True break if location <= -5212.75: is_goal = True break if is_own_goal and not self.predictions['own_goal']: self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Compliments_NiceShot) if is_goal and not self.predictions['goal']: self.send_quick_chat(QuickChats.CHAT_EVERYONE, QuickChats.Reactions_Wow) self.predictions["own_goal"] = is_own_goal self.predictions["goal"] = is_goal self.dbg_2d( f"Minimum time to ball: {round(self.predictions['self_min_time_to_ball'], 1)}" ) if not can_shoot and self.can_shoot is None: self.can_shoot = self.time - 2.9 if self.can_shoot is not None and (self.time - self.can_shoot >= 3 or self.predictions['own_goal']): self.can_shoot = None