Esempio n. 1
0
def shot_valid(agent, shot, target=None):
    # Returns True if the ball is still where the shot anticipates it to be
    if target is None:
        target = shot.ball_location

    threshold = agent.best_shot_value * 2

    # First finds the two closest slices in the ball prediction to shot's intercept_time
    # threshold controls the tolerance we allow the ball to be off by
    slices = agent.ball_prediction_struct.slices
    soonest = 0
    latest = len(slices)-1
    while len(slices[soonest:latest+1]) > 2:
        midpoint = (soonest+latest) // 2
        if slices[midpoint].game_seconds > shot.intercept_time:
            latest = midpoint
        else:
            soonest = midpoint
    # preparing to interpolate between the selected slices
    dt = slices[latest].game_seconds - slices[soonest].game_seconds
    time_from_soonest = shot.intercept_time - slices[soonest].game_seconds
    soonest = (slices[soonest].physics.location.x, slices[soonest].physics.location.y, slices[soonest].physics.location.z)
    slopes = (Vector(slices[latest].physics.location.x, slices[latest].physics.location.y, slices[latest].physics.location.z) - Vector(*soonest)) * (1/dt)
    # Determining exactly where the ball will be at the given shot's intercept_time
    predicted_ball_location = Vector(*soonest) + (slopes * time_from_soonest)
    # Comparing predicted location with where the shot expects the ball to be
    return target.dist(predicted_ball_location) < threshold
Esempio n. 2
0
    def tmcp_ball_check(self):
        shot_name = self.get_stack_name()
        shot_time = self.stack[
            0].intercept_time if shot_name != "short_shot" else 7

        if shot_time > 1 and (shot_name != "Aerial" or shot_time > 3):
            is_short_shot = shot_name == "short_shot"
            for friend in self.friends:
                action = friend.tmcp_action
                if action is not None and action[
                        'type'] == "BALL" and action['time'] != -1:
                    if is_short_shot:
                        self.clear()
                        break

                    action_time = action['time'] - self.time
                    if action_time > 0:
                        f_shot_vector = Vector(*action['direction'])
                        time_dif = 0.5 if f_shot_vector.magnitude(
                        ) != 0 and self.stack[0].shot_vector.angle(
                            f_shot_vector) > 1 else 0.2
                        if (action_time < shot_time - time_dif and
                                shot_time > self.enemy_time_to_ball + time_dif
                            ) or (action_time > shot_time + time_dif
                                  and action_time <
                                  self.enemy_time_to_ball - time_dif):
                            self.clear()
                            break
Esempio n. 3
0
    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
Esempio n. 4
0
    def run(self, me, time):
        me.reset_ctrl()

        if self.jumping or (self.jump_time == -1 and me.on_ground):
            if self.jump_time == -1:
                self.jump_type_fast = self.fast_aerial
                self.jumping = True
                self.jump_time = time
                self.counter = 0

            jump_elapsed = time - self.jump_time

            if self.jump_type_fast:
                if jump_elapsed <= jump_max_duration:
                    me.ctrl.jump = True
                else:
                    self.counter += 1

                if self.counter == 3:
                    me.ctrl.jump = True
                    self.dodging = True
                elif self.counter == 4:
                    self.dodging = self.jumping = False
                    self.jump_time = -1
            elif jump_elapsed <= jump_max_duration:
                me.ctrl.jump = True
            else:
                self.jumping = False
                self.jump_time = -1

        delta_x = self.target - me.location
        if delta_x.magnitude() > boost_accel:
            delta_x *= boost_accel / delta_x.magnitude()

        delta_xy = Vector(
            delta_x.x - me.velocity.x, delta_x.y - me.velocity.y, 1000 if
            (not self.jumping or not self.jump_type_fast) else 0)
        direction = delta_xy.normalize()

        if self.counter in {0, 4}:
            defaultPD(me,
                      me.local(delta_xy),
                      up=sign(math.sin(time)) * (-1 if me.index == 60 else 1) *
                      (Vector() - me.location).flatten().normalize())

        me.ctrl.throttle = 1
        # only boost/throttle if we're facing the right direction
        if abs(me.forward.angle(delta_xy)) < 1 and (not self.jumping or
                                                    not self.jump_type_fast):
            # tap boost to keep height
            if delta_x.z - me.velocity.z * 0.5 > 0:
                me.ctrl.boost = True

            # if the target is relatively far, hold boost even when we're higher than the target to keep moving
            if delta_x.z < 0 and me.forward.z < 0.5:
                me.ctrl.boost = True
Esempio n. 5
0
def post_correction(ball_location, left_target, right_target):
    # this function returns target locations that are corrected to account for the ball's radius
    # If the left and right post swap sides, a goal cannot be scored
    # We purposely make this a bit larger so that our shots have a higher chance of success
    ball_radius = 120
    goal_line_perp = (right_target - left_target).cross(Vector(z=1))
    left = left_target + ((left_target - ball_location).normalize().cross(Vector(z=-1))*ball_radius)
    right = right_target + ((right_target - ball_location).normalize().cross(Vector(z=1))*ball_radius)
    left = left_target if (left-left_target).dot(goal_line_perp) > 0 else left
    right = right_target if (right-right_target).dot(goal_line_perp) > 0 else right
    swapped = (left - ball_location).normalize().cross(Vector(z=1)).dot((right - ball_location).normalize()) > -0.1
    return left, right, swapped
Esempio n. 6
0
 def __init__(self, pitch=0, yaw=0, roll=0):
     CP = math.cos(pitch)
     SP = math.sin(pitch)
     CY = math.cos(yaw)
     SY = math.sin(yaw)
     CR = math.cos(roll)
     SR = math.sin(roll)
     # List of 3 vectors, each descriping the direction of an axis: Forward, Left, and Up
     self.data = (Vector(CP * CY, CP * SY, SP),
                  Vector(CY * SP * SR - CR * SY, SY * SP * SR + CR * CY,
                         -CP * SR),
                  Vector(-CR * CY * SP - SR * SY, -CR * SY * SP + SR * CY,
                         CP * CR))
     self.forward, self.right, self.up = self.data
Esempio n. 7
0
    def circular_procession(self, packet: GameTickPacket, drones,
                            start_time) -> StepResult:
        self.ball.update(packet)

        elapsed = packet.game_info.seconds_elapsed - start_time
        inactive_drones = max((elapsed - 4) / 0.48, 0)
        radian_spacing = 2 * math.pi / max(60 - inactive_drones, 16)
        adjusted_radius = radius - elapsed * 75

        for i, drone in enumerate(drones):
            if i >= inactive_drones:
                if i < 60:
                    progress = i * radian_spacing + elapsed * .25
                    target = [
                        adjusted_radius * math.sin(progress),
                        adjusted_radius * math.cos(progress), 0
                    ]
                    slow_to_pos(drone, target)
                continue

            if len(self.drone_aerials) == i:
                progress = i * radian_spacing + (elapsed + 2) * .25
                target = Vector(adjusted_radius * math.sin(progress),
                                adjusted_radius * math.cos(progress),
                                200 + i * 10)
                self.drone_aerials.append(Hover(target, i != 60))

            self.drone_aerials[i].target.z += 0.1
            self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed)

            if i == 60:
                break
        return StepResult(finished=inactive_drones > 61)
Esempio n. 8
0
def backsolve(target, car, time, gravity):
    # Finds the acceleration required for a car to reach a target in a specific amount of time
    d = target - car.location
    dvx = ((d.x/time) - car.velocity.x) / time
    dvy = ((d.y/time) - car.velocity.y) / time
    dvz = (((d.z/time) - car.velocity.z) / time) - (gravity.z * time)
    return Vector(dvx, dvy, dvz)
Esempio n. 9
0
def find_landing_plane(l: Vector, v: Vector, g: float):
    if abs(l.y) >= 5120 or (v.x == 0 and v.y == 0 and g == 0):
        return 5

    times = [
        -1, -1, -1, -1, -1, -1
    ]  #  side_wall_pos, side_wall_neg, back_wall_pos, back_wall_neg, ceiling, floor

    if v.x != 0:
        times[0] = (4080 - l.x) / v.x
        times[1] = (-4080 - l.x) / v.x

    if v.y != 0:
        times[2] = (5110 - l.y) / v.y
        times[3] = (-5110 - l.y) / v.y

    if g != 0:
        # this is the vertex of the equation, which also happens to be the apex of the trajectory
        h = v.z / -g  # time to apex
        k = v.z * v.z / -g  # vertical height at apex

        # a is the current gravity... because reasons
        # a = g

        climb_dist = -l.z

        # if the gravity is inverted, the the ceiling becomes the floor and the floor becomes the ceiling...
        if g < 0:
            climb_dist += 2030
            if k >= climb_dist:
                times[4] = vertex_quadratic_solve_for_x_min_non_neg(
                    g, h, k, climb_dist)
        elif g > 0:
            climb_dist += 20
            if k <= climb_dist:
                times[5] = vertex_quadratic_solve_for_x_min_non_neg(
                    g, h, k, climb_dist)

        # this is necessary because after we reach our terminal velocity, the equation becomes linear (distance_remaining / terminal_velocity)
        terminal_velocity = (2300 - v.flatten().magnitude()) * sign(g)
        falling_time_until_terminal_velocity = (terminal_velocity - v.z) / g
        falling_distance_until_terminal_velocity = v.z * falling_time_until_terminal_velocity + -g * (
            falling_time_until_terminal_velocity *
            falling_time_until_terminal_velocity) / 2.

        fall_distance = -l.z
        if g < 0:
            times[5] = get_landing_time(
                fall_distance + 20, falling_time_until_terminal_velocity,
                falling_distance_until_terminal_velocity, terminal_velocity, k,
                h, g)
        else:
            times[4] = get_landing_time(
                fall_distance + 2030, falling_time_until_terminal_velocity,
                falling_distance_until_terminal_velocity, terminal_velocity, k,
                h, g)

    return times.index(min(item for item in times if item >= 0))
Esempio n. 10
0
    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
                }
Esempio n. 11
0
    def setup_circle_align(self, packet: GameTickPacket, drones,
                           start_time) -> StepResult:
        self.ball.update(packet)
        self.game_interface.set_game_state(
            GameState(ball=BallState(physics=Physics(
                location=Vector3(drones[60].location.x, drones[60].location.y),
                velocity=Vector3(0, 0),
                angular_velocity=Vector3(*drones[60].raw_angular_velocity)))))

        radian_spacing = 2 * math.pi / 20
        radian_spacing_v = 2 * math.pi / 10

        for i, drone in enumerate(drones):
            if i == 60:
                self.drone_aerials[i].target = Vector(0, 0, 1000)
            else:
                # 0 & 1: center circle
                # 2, 3, 4, & 5: side circles
                group = i % 6

                if group < 2:
                    progress = (i // 6 * 2 + group) * radian_spacing
                    self.drone_aerials[i].target = Vector(
                        radius2 * math.sin(progress),
                        radius2 * math.cos(progress), 1000)
                elif group < 4:
                    progress = (i // 6 * 2 + (group - 2)) * radian_spacing
                    Q = radius3 * math.sin(progress)
                    adjusted_radius = radius2 + Q
                    self.drone_aerials[i].target = Vector(
                        adjusted_radius * math.sin(progress),
                        adjusted_radius * math.cos(progress), 1000 + Q)
                else:
                    progress = (i // 6 * 2 + (group - 4)) * radian_spacing
                    Q = radius3 * math.sin(progress)
                    adjusted_radius = radius2 - Q
                    self.drone_aerials[i].target = Vector(
                        adjusted_radius * math.sin(progress),
                        adjusted_radius * math.cos(progress), 1000 - Q)
            self.drone_aerials[i].run(drone, packet.game_info.seconds_elapsed)

            if i == 60:
                break

        return StepResult(finished=True)
Esempio n. 12
0
def valid_ceiling_shot(agent: VirxERLU, cap_=5):
    struct = agent.ball_prediction_struct

    if struct is None:
        return

    end_slice = math.ceil(cap_ * 60)
    slices = struct.slices[30:end_slice:2]

    if agent.me.location.x * side(agent.team) > 0:
        quadrilateral = (round(agent.foe_goal.right_post.flatten()),
                         round(agent.foe_goal.left_post.flatten()))
    else:
        quadrilateral = (round(agent.foe_goal.left_post.flatten()),
                         round(agent.foe_goal.right_post.flatten()))

    quadrilateral += (
        Vector(0, 640),
        Vector(round(agent.me.location.x - (200 * sign(agent.me.location.x))),
               round(agent.me.location.y - (200 * side(agent.team)))),
    )

    agent.polyline(quadrilateral + (quadrilateral[0], ),
                   agent.renderer.team_color(alt_color=True))

    for ball_slice in slices:
        intercept_time = ball_slice.game_seconds
        time_remaining = intercept_time - agent.time

        if time_remaining <= 0:
            return

        ball_location = Vector(ball_slice.physics.location.x,
                               ball_slice.physics.location.y,
                               ball_slice.physics.location.z)

        if ball_location.z < 642:
            continue

        if not point_inside_quadrilateral_2d(round(ball_location.flatten()),
                                             quadrilateral):
            continue

        return ball_location
Esempio n. 13
0
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
Esempio n. 14
0
    def __init__(self, name, team, index):
        super().__init__(name, team, index)

        self.debug_2d_bool = self.name == self.true_name
        self.debug_vector = Vector(0, 0)
        self.goalie = False
        self.jump = True
        self.double_jump = True
        self.ground_shot = True
        self.aerials = True
Esempio n. 15
0
def find_slope(shot_vector, car_to_target):
    # Finds the slope of your car's position relative to the shot vector (shot vector is y axis)
    # 10 = you are on the axis and the ball is between you and the direction to shoot in
    # -10 = you are on the wrong side
    # 1 = you're about 45 degrees offcenter
    d = shot_vector.dot(car_to_target)
    e = abs(shot_vector.cross(Vector(z=1)).dot(car_to_target))
    try:
        f = d / e
    except ZeroDivisionError:
        return 10*sign(d)
    return cap(f, -3, 3)
Esempio n. 16
0
def in_field(point, radius):
    # determines if a point is inside the standard soccer field
    point = Vector(abs(point.x), abs(point.y), abs(point.z))
    if point.x > 4080 - radius:
        return False
    elif point.y > 5900 - radius:
        return False
    elif point.x > 880 - radius and point.y > 5105 - radius:
        return False
    elif point.x > 2650 and point.y > -point.x + 8025 - radius:
        return False
    return True
Esempio n. 17
0
    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
Esempio n. 18
0
    def render_time_predictions(self):
        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.enemy_time_to_ball != 7:
            self.sphere(enemy_intercept_location, self.ball_radius,
                        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.me.minimum_time_to_ball != 7:
            self.sphere(self_intercept_location, self.ball_radius,
                        self.renderer.green())

        cap_location = self.ball_prediction_struct.slices[
            round(get_cap(self, 6) * 60) - 1].physics.location
        cap_location = Vector(cap_location.x, cap_location.y, cap_location.z)
        self.sphere(cap_location, self.ball_radius, self.renderer.orange())
Esempio n. 19
0
def ray_intersects_with_line(origin, direction, point1, point2):
    v1 = origin - point1
    v2 = point2 - point1
    v3 = Vector(-direction.y, direction.x)
    v_dot = v2.dot(v3)

    t1 = v2.cross(v1).magnitude() / v_dot

    if t1 < 0:
        return

    t2 = v1.dot(v3) / v_dot

    if 0 <= t1 and t2 <= 1:
        return t1
Esempio n. 20
0
def defaultPD(agent, local_target, upside_down=False):
    # points the car towards a given local target.
    # Direction can be changed to allow the car to steer towards a target while driving backwards
    up = agent.me.local(Vector(z=-1 if upside_down else 1))  # where "up" is in local coordinates
    target_angles = (
        math.atan2(local_target.z, local_target.x),  # angle required to pitch towards target
        math.atan2(local_target.y, local_target.x),  # angle required to yaw towards target
        math.atan2(up.y, up.z)  # angle required to roll upright
    )
    # Once we have the angles we need to rotate, we feed them into PD loops to determing the controller inputs
    agent.controller.steer = steerPD(target_angles[1], 0)
    agent.controller.pitch = steerPD(target_angles[0], agent.me.angular_velocity.y/4)
    agent.controller.yaw = steerPD(target_angles[1], -agent.me.angular_velocity.z/4)
    agent.controller.roll = steerPD(target_angles[2], agent.me.angular_velocity.x/2)
    # Returns the angles, which can be useful for other purposes
    return target_angles
Esempio n. 21
0
    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
Esempio n. 22
0
    def initialize_agent(self):
        super().initialize_agent()

        self.cheating = self.true_name == "VirxEMB"
        if self.cheating:
            self.boost_amount = "unlimited"

        self.playstyles = Playstyle
        self.playstyle = self.playstyles.Neutral

        self.predictions = {
            "closest_enemy": 0,
            "team_from_goal": (),
            "team_to_ball": (),
            "self_from_goal": 0,
            "self_to_ball": 0,
            "was_down": False
        }

        self.closest_foes = []
        self.friend_times = []

        self.profiler_threshold = 0.8
        self.profiler_loss = 0.005
        self.profiler_gain = 0.21
        self.profiler_last_save = 0
        self.last_ball_touch_time = -1
        self.unpause_timer = -1

        self.enemy_time_to_ball = 7
        self.max_shot_weight = 4
        self.min_intercept_slice = 180
        self.own_goal = {"location": Vector(), "slice": -1}
        self.is_own_goal = False
        self.is_goal = False
        self.side = side(self.team)
Esempio n. 23
0
    def update_predictions(self):
        is_other_tick = self.odd_tick % 2 == 0
        is_forth_tick = self.odd_tick == 0
        if self.num_foes > 0:
            foe_distances = tuple(
                self.ball.location.flat_dist(foe.location)
                for foe in self.alive_foes)
            if len(foe_distances) > 0:
                if is_forth_tick or len(self.closest_foes) != self.num_foes:
                    for foe in self.foes:
                        foe.minimum_time_to_ball = self.time_to_ball(
                            foe) if not foe.demolished else 7

                    self.closest_foes = sorted(
                        [foe for foe in self.foes],
                        key=lambda foe: foe.minimum_time_to_ball)
                    self.enemy_time_to_ball = self.closest_foes[
                        0].minimum_time_to_ball

                self.predictions['closest_enemy'] = min(foe_distances)
            else:
                self.closest_foes = []
                self.enemy_time_to_ball = 7
                self.predictions['closest_enemy'] = math.inf
        else:
            self.closest_foes = []
            self.enemy_time_to_ball = 7
            self.predictions['closest_enemy'] = math.inf

        self.future_ball_location_slice = min(
            round(self.enemy_time_to_ball * 60),
            self.ball_prediction_struct.num_slices - 1)
        self.dbg_2d(
            f"Predicted enemy time to ball: {round(self.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 self.num_friends > 0:
            teammates = tuple(itertools.chain(self.alive_friends, [self.me]))

            self.predictions["team_from_goal"] = sorted(
                tuple(
                    self.friend_goal.location.flat_dist(teammate.location)
                    for teammate in teammates))
            self.predictions["team_to_ball"] = sorted(
                tuple(
                    self.ball.location.flat_dist(teammate.location)
                    for teammate in teammates))

        if self.cheating:
            if is_other_tick:
                cars = {self.index: CarState(boost_amount=100)}
                self.set_game_state(GameState(cars=cars))
            self.me.boost = 100

        if is_forth_tick:
            self.me.minimum_time_to_ball = self.time_to_ball(self.me)
        self.min_intercept_slice = min(
            round(self.me.minimum_time_to_ball * 60),
            self.ball_prediction_struct.num_slices - 1)
        self.dbg_2d(
            f"Minimum time to ball: {round(self.me.minimum_time_to_ball, 1)}")

        for friend in self.friends:
            if friend.demolished:
                friend.minimum_time_to_ball = 7
                continue

            action = friend.tmcp_action
            if action is not None:
                action_type = action['type']

                if action_type in {"BALL", "READY"} and action['time'] != -1:
                    time = action['time'] - self.time
                    friend.minimum_time_to_ball = time if time > 0 else 7
                else:
                    friend.minimum_time_to_ball = 7
            elif is_forth_tick:
                mttb = self.time_to_ball(friend) * abs(
                    friend.local_velocity().angle2D(
                        friend.local_location(self.ball.location)))
                if mttb > 6: mttb = 7
                friend.minimum_time_to_ball = mttb

        self.friend_times = sorted(
            [friend for friend in self.alive_friends],
            key=lambda friend: friend.minimum_time_to_ball)

        if is_other_tick:
            is_own_goal = False
            is_goal = False

            if self.ball_prediction_struct is not None:
                own_goal_slice = -1

                for i, ball_slice in enumerate(
                        self.ball_prediction_struct.slices[30::12]):
                    location = ball_slice.physics.location.y * self.side

                    if location >= 5212.75:
                        is_own_goal = True
                        own_goal_slice = i
                        break

                    if location <= -5212.75:
                        is_goal = True
                        break

                self.own_goal = {"location": Vector(), "slice": -1}

                if is_own_goal:
                    for i, ball_slice in enumerate(
                            self.ball_prediction_struct.slices[::15]):
                        if ball_slice.physics.location.y * self.side >= 5200:
                            self.own_goal["location"] = Vector.from_vector(
                                ball_slice.physics.location)
                            self.own_goal["slice"] = i
                            break

                    if self.cheating and not self.shooting:
                        tp_own_goal = None
                        for ball_slice in self.ball_prediction_struct.slices[:
                                                                             30]:
                            if ball_slice.physics.location.y * self.side >= 5200:
                                tp_own_goal = ball_slice.physics.location
                                break

                        if tp_own_goal is not None:
                            cars = {
                                self.index:
                                CarState(
                                    Physics(location=Vector3(
                                        tp_own_goal.x, tp_own_goal.y,
                                        tp_own_goal.z),
                                            velocity=Vector3(0, 0, 0)))
                            }
                            self.set_game_state(GameState(cars=cars))

                if is_own_goal and not self.is_own_goal:
                    self.send_quick_chat(QuickChats.CHAT_EVERYONE,
                                         QuickChats.Compliments_NiceShot)

                if is_goal and not self.is_goal:
                    self.send_quick_chat(QuickChats.CHAT_EVERYONE,
                                         QuickChats.Reactions_Wow)

            self.is_own_goal = is_own_goal
            self.is_goal = is_goal
Esempio n. 24
0
    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
Esempio n. 25
0
    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]()
        ""
Esempio n. 26
0
    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 * self.side, 2560)
        self.kickoff_right = (2048 * self.side, 2560)
        self.kickoff_back = (0, 4608)
        self.kickoff_back_left = (-256 * self.side, 3840)
        self.kickoff_back_right = (256 * self.side, 3840)

        self.offensive_shots = ((Vector(foe_team * 893, foe_team * 5120,
                                        min(self.ball_radius * 2, 321.3875)),
                                 Vector(
                                     foe_team * -893, foe_team * 5120,
                                     max(642.775 - self.ball_radius,
                                         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,
                                 min(self.ball_radius * 3, 321.3875)),
                          Vector(-foe_team * 793, foe_team * 5213,
                                 max(642.775 - self.ball_radius * 2,
                                     321.3875)))
        self.anti_shot = (Vector(-team * 1536, team * 5120, 1285.55),
                          Vector(team * 1536, team * 5120, 1285.55))

        if self.name in {"VirxEB", "VirxEMB"}:
            print(f"{self.name}: Check me out at https://www.virxcase.dev!!!")
Esempio n. 27
0
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
Esempio n. 28
0
def in_field(point, radius):
    # determines if a point is inside the standard soccer field
    point = Vector(abs(point.x), abs(point.y), abs(point.z))
    return not (point.x > 4080 - radius or point.y > 5900 - radius or (point.x > 880 - radius and point.y > 5105 - radius) or (point.x > 2650 and point.y > -point.x + 8025 - radius))
Esempio n. 29
0
    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"]))
Esempio n. 30
0
    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
        }