def preferred_patrol_altitude(self) -> Distance: if self.patrol_altitude is not None: return self.patrol_altitude else: # Estimate based on max speed. # Aircaft with max speed 600 kph will prefer patrol at 10 000 ft # Aircraft with max speed 2800 kph will prefer pratrol at 33 000 ft altitude_for_lowest_speed = feet(10 * 1000) altitude_for_highest_speed = feet(33 * 1000) lowest_speed = kph(600) highest_speed = kph(2800) factor = (self.max_speed - lowest_speed).kph / (highest_speed - lowest_speed).kph altitude = ( altitude_for_lowest_speed + (altitude_for_highest_speed - altitude_for_lowest_speed) * factor) logging.debug( f"Preferred patrol altitude for {self.dcs_unit_type.id}: {altitude.feet}" ) rounded_altitude = feet(round(1000 * round(altitude.feet / 1000))) return max( altitude_for_lowest_speed, min(altitude_for_highest_speed, rounded_altitude), )
def generate_convoy(self, convoy: Convoy) -> VehicleGroup: group = self._create_mixed_unit_group( convoy.name, convoy.route_start, convoy.units, convoy.player_owned, ) if self.game.settings.convoys_travel_full_distance: end_point = convoy.route_end else: # convoys_travel_full_distance is disabled, so have the convoy only move the first segment on the route. # This option aims to remove long routes for ground vehicles between control points, # since the CPU load for pathfinding long routes on DCS can be pretty heavy. frontline = convoy.origin.front_line_with(convoy.destination) # Select the first route segment from the origin towards the destination # so the convoy spawns at the origin CP. This allows the convoy to be # targeted by BAI flights and starts it within the protection umbrella of the CP. end_point = frontline.segments[0].point_b group.add_waypoint( end_point, speed=kph(40).kph, move_formation=PointAction.OnRoad, ) self.make_drivable(group) self.unit_map.add_convoy_units(group, convoy) return group
def generate_convoy(self, convoy: Convoy) -> VehicleGroup: group = self._create_mixed_unit_group( convoy.name, convoy.route_start, convoy.units, convoy.player_owned, ) group.add_waypoint( convoy.route_end, speed=kph(40).kph, move_formation=PointAction.OnRoad, ) self.make_drivable(group) self.unit_map.add_convoy_units(group, convoy) return group
def for_flight(cls, flight: Flight, altitude: Distance) -> Speed: if not issubclass(flight.unit_type, FlyingType): raise TypeError("Flight has non-flying unit") # TODO: Expose both a cruise speed and target speed. # The cruise speed can be used for ascent, hold, join, and RTB to save # on fuel, but mission speed will be fast enough to keep the flight # safer. # DCS's max speed is in kph at 0 MSL. max_speed = kph(flight.unit_type.max_speed) if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL: # Aircraft is supersonic. Limit to mach 0.8 to conserve fuel and # account for heavily loaded jets. return mach(0.8, altitude) # For subsonic aircraft, assume the aircraft can reasonably perform at # 80% of its maximum, and that it can maintain the same mach at altitude # as it can at sea level. This probably isn't great assumption, but # might. be sufficient given the wiggle room. We can come up with # another heuristic if needed. cruise_mach = max_speed.mach() * 0.8 return mach(cruise_mach, altitude)
def patrol_speed(self) -> Speed: # 2021-08-02: patrol_speed will currently have no effect because # CAS doesn't use OrbitAction. But all PatrollingFlightPlan are expected # to have patrol_speed return kph(0)
def max_speed(self) -> Speed: return kph(self.dcs_unit_type.max_speed)