Ejemplo n.º 1
0
    def repair_unit(self, unit, price):
        if self.game.blue.budget > price:
            self.game.blue.budget -= price
            unit.alive = True
            GameUpdateSignal.get_instance().updateGame(self.game)

            # Remove destroyed units in the vicinity
            destroyed_units = self.game.get_destroyed_units()
            for d in destroyed_units:
                p = Point(d["x"], d["z"], self.game.theater.terrain)
                if p.distance_to_point(unit.position) < 15:
                    destroyed_units.remove(d)
                    logging.info("Removed destroyed units " + str(d))
            logging.info(f"Repaired unit: {unit.unit_name}")

        self.update_game()
Ejemplo n.º 2
0
    def repair_unit(self, group, unit, price):
        if self.game.budget > price:
            self.game.budget -= price
            group.units_losts = [u for u in group.units_losts if u.id != unit.id]
            group.units.append(unit)
            GameUpdateSignal.get_instance().updateGame(self.game)

            # Remove destroyed units in the vicinity
            destroyed_units = self.game.get_destroyed_units()
            for d in destroyed_units:
                p = Point(d["x"], d["z"])
                if p.distance_to_point(unit.position) < 15:
                    destroyed_units.remove(d)
                    logging.info("Removed destroyed units " + str(d))
            logging.info("Repaired unit : " + str(unit.id) + " " + str(unit.type))

        self.do_refresh_layout()
Ejemplo n.º 3
0
    def __init__(
        self,
        target: Point,
        home: Point,
        coalition: Coalition,
    ) -> None:
        self._target = target
        self.threat_zone = coalition.opponent.threat_zone.all
        self.home = ShapelyPoint(home.x, home.y)

        max_ip_distance = coalition.doctrine.max_ingress_distance
        min_ip_distance = coalition.doctrine.min_ingress_distance

        # The minimum distance between the home location and the IP.
        min_distance_from_home = nautical_miles(5)

        # The distance that is expected to be needed between the beginning of the attack
        # and weapon release. This buffers the threat zone to give a 5nm window between
        # the edge of the "safe" zone and the actual threat so that "safe" IPs are less
        # likely to end up with the attacker entering a threatened area.
        attack_distance_buffer = nautical_miles(5)

        home_threatened = coalition.opponent.threat_zone.threatened(home)

        shapely_target = ShapelyPoint(target.x, target.y)
        home_to_target_distance = meters(home.distance_to_point(target))

        self.home_bubble = self.home.buffer(home_to_target_distance.meters).difference(
            self.home.buffer(min_distance_from_home.meters)
        )

        # If the home zone is not threatened and home is within LAR, constrain the max
        # range to the home-to-target distance to prevent excessive backtracking.
        #
        # If the home zone *is* threatened, we need to back out of the zone to
        # rendezvous anyway.
        if not home_threatened and (
            min_ip_distance < home_to_target_distance < max_ip_distance
        ):
            max_ip_distance = home_to_target_distance
        max_ip_bubble = shapely_target.buffer(max_ip_distance.meters)
        min_ip_bubble = shapely_target.buffer(min_ip_distance.meters)
        self.ip_bubble = max_ip_bubble.difference(min_ip_bubble)

        # The intersection of the home bubble and IP bubble will be all the points that
        # are within the valid IP range that are not farther from home than the target
        # is. However, if the origin airfield is threatened but there are safe
        # placements for the IP, we should not constrain to the home zone. In this case
        # we'll either end up with a safe zone outside the home zone and pick the
        # closest point in to to home (minimizing backtracking), or we'll have no safe
        # IP anywhere within range of the target, and we'll later pick the IP nearest
        # the edge of the threat zone.
        if home_threatened:
            self.permissible_zone = self.ip_bubble
        else:
            self.permissible_zone = self.ip_bubble.intersection(self.home_bubble)

        if self.permissible_zone.is_empty:
            # If home is closer to the target than the min range, there will not be an
            # IP solution that's close enough to home, in which case we need to ignore
            # the home bubble.
            self.permissible_zone = self.ip_bubble

        safe_zones = self.permissible_zone.difference(
            self.threat_zone.buffer(attack_distance_buffer.meters)
        )

        if not isinstance(safe_zones, MultiPolygon):
            safe_zones = MultiPolygon([safe_zones])
        self.safe_zones = safe_zones
 def distance_to_pixels(self, distance: Distance) -> int:
     p1 = Point(0, 0)
     p2 = Point(0, distance.meters)
     p1a = Point(*self._transform_point(p1))
     p2a = Point(*self._transform_point(p2))
     return int(p1a.distance_to_point(p2a))
Ejemplo n.º 5
0
 def destination_in_range(self, destination: Point) -> bool:
     move_distance = meters(
         destination.distance_to_point(self.control_point.position)
     )
     return move_distance <= MAX_SHIP_DISTANCE
Ejemplo n.º 6
0
    def __init__(self, target: Point, home: Point, ip: Point,
                 coalition: Coalition) -> None:
        self._target = target
        # Normal join placement is based on the path from home to the IP. If no path is
        # found it means that the target is on a direct path. In that case we instead
        # want to enforce that the join point is:
        #
        # * Not closer to the target than the IP.
        # * Not too close to the home airfield.
        # * Not threatened.
        # * A minimum distance from the IP.
        # * Not too sharp a turn at the ingress point.
        self.ip = ShapelyPoint(ip.x, ip.y)
        self.threat_zone = coalition.opponent.threat_zone.all
        self.home = ShapelyPoint(home.x, home.y)

        self.ip_bubble = self.ip.buffer(
            coalition.doctrine.join_distance.meters)

        ip_distance = ip.distance_to_point(target)
        self.target_bubble = ShapelyPoint(target.x,
                                          target.y).buffer(ip_distance)

        # The minimum distance between the home location and the IP.
        min_distance_from_home = nautical_miles(5)

        self.home_bubble = self.home.buffer(min_distance_from_home.meters)

        excluded_zones = shapely.ops.unary_union(
            [self.ip_bubble, self.target_bubble, self.threat_zone])

        if not isinstance(excluded_zones, MultiPolygon):
            excluded_zones = MultiPolygon([excluded_zones])
        self.excluded_zones = excluded_zones

        ip_heading = target.heading_between_point(ip)

        # Arbitrarily large since this is later constrained by the map boundary, and
        # we'll be picking a location close to the IP anyway. Just used to avoid real
        # distance calculations to project to the map edge.
        large_distance = nautical_miles(400).meters
        turn_limit = 40
        ip_limit_ccw = ip.point_from_heading(ip_heading - turn_limit,
                                             large_distance)
        ip_limit_cw = ip.point_from_heading(ip_heading + turn_limit,
                                            large_distance)

        ip_direction_limit_wedge = Polygon([
            (ip.x, ip.y),
            (ip_limit_ccw.x, ip_limit_ccw.y),
            (ip_limit_cw.x, ip_limit_cw.y),
        ])

        permissible_zones = ip_direction_limit_wedge.difference(
            self.excluded_zones).difference(self.home_bubble)
        if permissible_zones.is_empty:
            permissible_zones = MultiPolygon([])
        if not isinstance(permissible_zones, MultiPolygon):
            permissible_zones = MultiPolygon([permissible_zones])
        self.permissible_zones = permissible_zones

        preferred_lines = ip_direction_limit_wedge.intersection(
            self.excluded_zones.boundary).difference(self.home_bubble)

        if preferred_lines.is_empty:
            preferred_lines = MultiLineString([])
        if not isinstance(preferred_lines, MultiLineString):
            preferred_lines = MultiLineString([preferred_lines])
        self.preferred_lines = preferred_lines
Ejemplo n.º 7
0
    def __init__(
        self,
        target: Point,
        home: Point,
        ip: Point,
        join: Point,
        coalition: Coalition,
        theater: ConflictTheater,
    ) -> None:
        self._target = target
        # Hold points are placed one of two ways. Either approach guarantees:
        #
        # * Safe hold point.
        # * Minimum distance to the join point.
        # * Not closer to the target than the join point.
        #
        # 1. As near the join point as possible with a specific distance from the
        #    departure airfield. This prevents loitering directly above the airfield but
        #    also keeps the hold point close to the departure airfield.
        #
        # 2. Alternatively, if the entire home zone is excluded by the above criteria,
        #    as neat the departure airfield as possible within a minimum distance from
        #    the join point, with a restricted turn angle at the join point. This
        #    handles the case where we need to backtrack from the departure airfield and
        #    the join point to place the hold point, but the turn angle limit restricts
        #    the maximum distance of the backtrack while maintaining the direction of
        #    the flight plan.
        self.threat_zone = coalition.opponent.threat_zone.all
        self.home = ShapelyPoint(home.x, home.y)

        self.join = ShapelyPoint(join.x, join.y)

        self.join_bubble = self.join.buffer(
            coalition.doctrine.push_distance.meters)

        join_to_target_distance = join.distance_to_point(target)
        self.target_bubble = ShapelyPoint(
            target.x, target.y).buffer(join_to_target_distance)

        self.home_bubble = self.home.buffer(
            coalition.doctrine.hold_distance.meters)

        excluded_zones = shapely.ops.unary_union(
            [self.join_bubble, self.target_bubble, self.threat_zone])
        if not isinstance(excluded_zones, MultiPolygon):
            excluded_zones = MultiPolygon([excluded_zones])
        self.excluded_zones = excluded_zones

        join_heading = ip.heading_between_point(join)

        # Arbitrarily large since this is later constrained by the map boundary, and
        # we'll be picking a location close to the IP anyway. Just used to avoid real
        # distance calculations to project to the map edge.
        large_distance = nautical_miles(400).meters
        turn_limit = 40
        join_limit_ccw = join.point_from_heading(join_heading - turn_limit,
                                                 large_distance)
        join_limit_cw = join.point_from_heading(join_heading + turn_limit,
                                                large_distance)

        join_direction_limit_wedge = Polygon([
            (join.x, join.y),
            (join_limit_ccw.x, join_limit_ccw.y),
            (join_limit_cw.x, join_limit_cw.y),
        ])

        permissible_zones = (coalition.nav_mesh.map_bounds(
            theater).intersection(join_direction_limit_wedge).difference(
                self.excluded_zones).difference(self.home_bubble))
        if not isinstance(permissible_zones, MultiPolygon):
            permissible_zones = MultiPolygon([permissible_zones])
        self.permissible_zones = permissible_zones
        self.preferred_lines = self.home_bubble.boundary.difference(
            self.excluded_zones)
Ejemplo n.º 8
0
 def km_to_pixel(self, km):
     p1 = Point(0, 0)
     p2 = Point(0, 1000 * km)
     p1a = Point(*self._transform_point(p1))
     p2a = Point(*self._transform_point(p2))
     return p1a.distance_to_point(p2a)