Beispiel #1
0
 def test_poly_triangulation(self):
     points = [Point(1, 2),
               Point(3, 1),
               Point(7, 2),
               Point(9, 4),
               Point(6, 6),
               Point(6, 9),
               Point(4, 8),
               Point(2, 9),
               Point(1, 7),
               Point(0, 5)]
     poly = Polygon(points)
     areas = [x.area() for x in poly.triangulate()]
     self.assertEqual(areas, [2.5, 9.5, 10.0, 7.5, 9.0, 1.0, 5.0, 0.0])
Beispiel #2
0
 def rated_nodes_within(self,
                        polygon: mapping.Polygon,
                        min_rating=0) -> List[Node]:
     return [
         x for x in self.rated_nodes(min_rating)
         if polygon.point_in_poly(x.position)
     ]
Beispiel #3
0
    def test_poly_random(self):
        points = [
            Point(1, 2),
            Point(3, 1),
            Point(7, 2),
            Point(9, 4),
            Point(6, 6),
            Point(6, 9),
            Point(4, 8),
            Point(2, 9),
            Point(1, 7),
            Point(0, 5)]
        poly = Polygon(points)

        for i in range(0, 100):
            rp = poly.random_point()
            self.assertTrue(poly.point_in_poly(rp))
Beispiel #4
0
 def nodes_within(self, polygon: mapping.Polygon) -> List[Node]:
     return [x for x in self.nodes if polygon.point_in_poly(x.position)]
Beispiel #5
0
 def rated_nodes_within(self, polygon: mapping.Polygon, min_rating=0) -> List[Node]:
     return [x for x in self.rated_nodes(min_rating) if polygon.point_in_poly(x.position)]
Beispiel #6
0
 def nodes_within(self, polygon: mapping.Polygon) -> List[Node]:
     return [x for x in self.nodes if polygon.point_in_poly(x.position)]
class CAS(BasicScenario):
    air_force = {
        "blue": {
            "SEAD": {
                "SEAD 01": (USA.name, 2, dcs.planes.F_16C_bl_52d)
            },
            "CAP": {
                "Air Patrol": (USA.name, 2, dcs.planes.F_15C)
            },
            "CAS": {
                "AirCav": (USA.name, 2, dcs.helicopters.AH_64D)
            }
        },
        "red": {
            "CAS": {
                "Hindis": (Russia.name, 2, dcs.helicopters.Mi_24V)
            }
        }
    }

    nato_airspace = Polygon([
        Point(-272807.14285714, 563521.42857143),
        Point(-267949.99999999, 608950),
        Point(-235092.85714285, 638950),
        Point(-208521.42857142, 672950),
        Point(-225949.99999999, 738950),
        Point(-242521.42857142, 820950),
        Point(-243092.85714285, 912857.14285714),
        Point(-273949.99999999, 963714.28571429),
        Point(-415664.28571428, 963714.28571429),
        Point(-392807.14285714, 569142.85714286)
    ])

    def __init__(self, aircraft_types: List[Tuple[str, str]], playercount: int,
                 start: str, unhide):
        super(CAS, self).__init__(not unhide)

        caucasus = self.m.terrain  # type: dcs.terrain.Caucasus

        kutaisi = caucasus.kutaisi()
        kobuleti = caucasus.kobuleti()
        blue_military_airport = [kutaisi, kobuleti]

        red_military_airport = [caucasus.sochi_adler()]

        battle_point = BasicScenario.battle_zones["zugidi"].random_point()

        front_hdg = 30
        isred = False
        for force in [self.blue_force, self.red_force]:
            attack_hdg = (300 + (180 if isred else 0)) % 360
            defense_hdg = (attack_hdg + 180) % 360
            rp = battle_point.point_from_heading(defense_hdg, 7 * 1000)
            for force_type in force:
                for conf in force[force_type]:
                    dist_hdg = front_hdg if random.getrandbits(
                        1) else front_hdg + 180
                    rp = rp.point_from_heading(dist_hdg,
                                               random.randrange(100, 1000))
                    if force_type in ["Artillery", "Supply"]:
                        rp = rp.point_from_heading(
                            random.randrange(defense_hdg - 30,
                                             defense_hdg + 30),
                            random.randrange(500, 3000))
                    else:
                        rp = rp.point_from_heading(
                            random.randrange(attack_hdg - 30, attack_hdg + 30),
                            random.randrange(0, 500))

                    plat = force[force_type][conf]
                    c = self.m.country(plat[0])
                    g = self.m.vehicle_group_platoon(c, conf, plat[1], rp)
                    g.formation_scattered(attack_hdg)
                    if isred:
                        g.hidden = self.hide

                    if force_type not in ["Artillery", "Supply"] and isred:
                        wp = g.add_waypoint(
                            g.position.point_from_heading(attack_hdg, 12000))
                        wp.action = dcs.point.PointAction.Vee
                        g.add_waypoint(
                            wp.position.point_from_heading(
                                random.randrange(attack_hdg - 10,
                                                 attack_hdg + 30), 5000))

                    if force_type in ["Artillery"]:
                        for x in range(0, 10):
                            rect = dcs.mapping.Rectangle.from_point(
                                battle_point.point_from_heading(
                                    attack_hdg, 7000), 2000)
                            g.points[0].tasks.append(
                                dcs.task.FireAtPoint(rect.random_point(), 30,
                                                     30))
            isred = True

        # rp = dcs.mapping.Rectangle.from_point(rp, 200).random_point()
        # fac = self.m.vehicle_group(usa, "FAC", USA.Vehicle.Armor.APC_M1126_Stryker_ICV, rp)
        # fac.points[0].tasks.append(dcs.task.EPLRS(1))
        # fac.points[0].tasks.append(dcs.task.FAC())
        # fac.points[0].tasks.append(dcs.task.SetInvisibleCommand())
        # fac.points[0].tasks.append(dcs.task.OptROE(dcs.task.OptROE.Values.WeaponHold))

        for air_force_idx in self.air_force:
            air_force = self.air_force[air_force_idx]
            airports = blue_military_airport if air_force_idx == "blue" else red_military_airport
            for force_type in air_force:
                for conf in air_force[force_type]:
                    conf_data = air_force[force_type][conf]
                    airport = random.choice(airports)
                    country = self.m.country(conf_data[0])
                    if force_type == "CAP":
                        nato_rect = self.nato_airspace.outbound_rectangle()
                        pp1, pp2 = nato_rect.random_distant_points(
                            nato_rect.width() * 0.6)
                        self.m.patrol_flight(country,
                                             conf,
                                             conf_data[2],
                                             airport,
                                             pp1,
                                             pp2,
                                             group_size=conf_data[1])
                    else:
                        try:
                            pg = self.m.flight_group_from_airport(
                                country,
                                conf,
                                conf_data[2],
                                airport,
                                dcs.task.MainTask.map[force_type],
                                dcs.mission.StartType.Runway,
                                group_size=conf_data[1])
                        except dcs.terrain.RunwayOccupiedError:
                            pg = self.m.flight_group_from_airport(
                                country,
                                conf,
                                conf_data[2],
                                airport,
                                dcs.task.MainTask.map[force_type],
                                dcs.mission.StartType.Warm,
                                group_size=conf_data[1])
                        pg.add_runway_waypoint(airport)
                        if air_force_idx == "red":
                            pg.hidden = self.hide

                        if force_type in ["SEAD", "CAS"]:
                            pg.add_waypoint(battle_point, 1000)

        player_groups = self.place_players(start, aircraft_types,
                                           blue_military_airport, playercount,
                                           dcs.task.CAS)
        for pg in player_groups:
            pg.add_waypoint(battle_point, 0)

        self.m.set_sortie_text("Random CAS")
        self.m.set_description_text("""Random generated CAS test mission.""")
        self.m.set_description_bluetask_text(
            """Support your ground troops at waypoint 2.
Take care of enemy air defense.

2 F-16 are supporting you with a SEAD strike""")
class BasicScenario:
    battle_zones = {
        "zugidi":
        Polygon([
            Point(-270285.71428571, 609257.14285714),
            Point(-264342.85714286, 614142.85714286),
            Point(-257428.57142857, 619485.71428571),
            Point(-250857.14285714, 625171.42857143),
            Point(-248342.85714286, 627457.14285714),
            Point(-244600, 628800),
            Point(-238685.71428571, 635371.42857143),
            Point(-235257.14285714, 639942.85714285),
            Point(-238685.71428571, 640771.42857143),
            Point(-239342.85714286, 642714.28571428),
            Point(-235971.42857143, 644742.85714285),
            Point(-236600, 646142.85714285),
            Point(-234085.71428571, 650142.85714285),
            Point(-239200, 656428.57142857),
            Point(-249828.57142857, 653000),
            Point(-264400, 650000),
            Point(-264828.57142857, 644171.42857142),
            Point(-269885.71428571, 634542.85714285),
            Point(-273600, 635428.57142857),
            Point(-273657.14285714, 642571.42857142),
            Point(-285771.42857143, 640828.57142857),
            Point(-285800, 625514.28571428),
            Point(-279771.42857143, 625285.71428571),
            Point(-273942.85714286, 629371.42857142),
            Point(-272428.57142857, 624828.57142857),
            Point(-273342.85714286, 612285.71428571)
        ]),
        "gori":
        Polygon([
            Point(-258542.85714286, 803857.14285714),
            Point(-258371.42857143, 805685.71428571),
            Point(-264771.42857143, 808828.57142857),
            Point(-262342.85714286, 814571.42857143),
            Point(-271342.85714286, 823057.14285714),
            Point(-282085.71428571, 837771.42857142),
            Point(-283885.71428571, 853599.99999999),
            Point(-303228.57142857, 860571.42857142),
            Point(-297314.28571429, 836971.42857142),
            Point(-291142.85714286, 819942.85714285),
            Point(-292200, 805999.99999999),
            Point(-292142.85714286, 794714.28571428),
            Point(-298371.42857143, 772085.71428571),
            Point(-288257.14285715, 772657.14285713),
            Point(-277028.57142857, 785628.57142856),
            Point(-276685.71428572, 797399.99999999),
            Point(-263771.42857143, 804914.28571428)
        ])
    }

    air_zones = {
        "abkhazia":
        Polygon([
            Point(-187092.85714285, 460857.14285714),
            Point(-149378.57142856, 476285.71428571),
            Point(-147664.28571428, 520000),
            Point(-175378.57142856, 599714.28571429),
            Point(-174521.42857142, 644000),
            Point(-199664.28571428, 624000),
            Point(-233949.99999999, 632857.14285714),
            Point(-271092.85714285, 596000)
        ]),
        "nato":
        Polygon([
            Point(-283950, 568092.85714286),
            Point(-267949.99999999, 608950),
            Point(-235092.85714285, 638950),
            Point(-208521.42857142, 672950),
            Point(-225949.99999999, 738950),
            Point(-242521.42857142, 820950),
            Point(-223092.85714285, 908857.14285714),
            Point(-283664.28571428, 953428.57142858),
            Point(-389092.85714285, 904571.42857143),
            Point(-385092.85714285, 599714.28571429)
        ]),
        "russia_west":
        Polygon([
            Point(-177092.85714285, 463428.57142857),
            Point(-33664.285714277, 224571.42857143),
            Point(24621.428571437, 239714.28571429),
            Point(27192.857142866, 495714.28571429),
            Point(-152235.7142857, 538571.42857143),
            Point(-146521.42857142, 474285.71428572)
        ]),
        "russia_center":
        Polygon([
            Point(-154807.14285713, 539428.57142858),
            Point(-19664.285714275, 541714.28571429),
            Point(-20521.428571418, 688571.42857144),
            Point(-173949.99999999, 688857.14285715)
        ]),
        "russia_east":
        Polygon([
            Point(-169949.99999999, 693714.28571429),
            Point(-24235.714285703, 694285.71428571),
            Point(-94807.142857132, 945714.28571429),
            Point(-209949.99999999, 932571.42857143),
            Point(-225092.85714285, 801142.85714286)
        ])
    }

    red_force = {
        "Armor": {
            "Tank Platoon": (Russia.name, [
                Russia.Vehicle.Armor.MBT_T_90, Russia.Vehicle.Armor.MBT_T_90,
                Russia.Vehicle.Armor.MBT_T_90, Russia.Vehicle.Armor.MBT_T_90
            ]),
            "Tank Platoon 2": (Russia.name, [
                Russia.Vehicle.Armor.MBT_T_90, Russia.Vehicle.Armor.MBT_T_90,
                Russia.Vehicle.Armor.MBT_T_90, Russia.Vehicle.Armor.MBT_T_90
            ])
        },
        "LightArmor": {
            "Light Armor 01": (Russia.name, [
                Russia.Vehicle.Armor.IFV_BMP_3, Russia.Vehicle.Armor.IFV_BMP_3,
                Russia.Vehicle.Armor.IFV_BMP_3
            ]),
            "Light Armor 02": (Russia.name, [
                Russia.Vehicle.Armor.IFV_BMP_3, Russia.Vehicle.Armor.IFV_BMP_3,
                Russia.Vehicle.Armor.IFV_BMP_3
            ]),
            "Light Armor 03": (Russia.name, [
                Russia.Vehicle.Armor.IFV_BMP_3, Russia.Vehicle.Armor.IFV_BMP_3,
                Russia.Vehicle.Armor.IFV_BMP_3
            ])
        },
        "Artillery": {
            "Artillery": (Russia.name, [
                Russia.Vehicle.Artillery.SPH_2S1_Gvozdika,
                Russia.Vehicle.Artillery.SPH_2S1_Gvozdika,
                Russia.Vehicle.Artillery.SPH_2S1_Gvozdika,
                Russia.Vehicle.Artillery.SPH_2S1_Gvozdika,
                Russia.Vehicle.Unarmed.Transport_Ural_4320T,
                Russia.Vehicle.AirDefence.SAM_SA_19_Tunguska_2S6
            ])
        },
        "AirDefence": {
            "Air Defense": (Russia.name, [
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_LN_2P25,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_STR_9S91,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_LN_2P25,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_STR_9S91,
                Russia.Vehicle.Unarmed.CP_SKP_11_ATC_Mobile_Command_Post
            ]),
            "Air Defense 02": (Russia.name, [
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_LN_2P25,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_STR_9S91,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_LN_2P25,
                Russia.Vehicle.AirDefence.SAM_SA_6_Kub_STR_9S91,
                Russia.Vehicle.Unarmed.CP_SKP_11_ATC_Mobile_Command_Post
            ])
        },
        "Supply": {
            "Russia Supply": (Russia.name, [
                Russia.Vehicle.Unarmed.Transport_GAZ_66,
                Russia.Vehicle.Unarmed.Fuel_Truck_ATZ_10,
                Russia.Vehicle.Unarmed.Transport_GAZ_3308,
                Russia.Vehicle.Unarmed.Transport_GAZ_3308,
                Russia.Vehicle.Unarmed.Transport_GAZ_3308
            ])
        }
    }

    blue_force = {
        "Armor": {
            "1st Tank Platoon 01": (USA.name, [
                USA.Vehicle.Armor.MBT_M1A2_Abrams,
                USA.Vehicle.Armor.MBT_M1A2_Abrams,
                USA.Vehicle.Armor.MBT_M1A2_Abrams,
                USA.Vehicle.Armor.MBT_M1A2_Abrams
            ])
        },
        "LightArmor": {
            "1st Light Armor Brigade 01": (USA.name, [
                USA.Vehicle.Armor.IFV_M2A2_Bradley,
                USA.Vehicle.Armor.IFV_M2A2_Bradley,
                USA.Vehicle.Armor.IFV_M2A2_Bradley,
            ])
        },
        "Artillery": {
            "1st Artillery Corps 01": (USA.name, [
                USA.Vehicle.Artillery.SPH_M109_Paladin,
                USA.Vehicle.Artillery.SPH_M109_Paladin,
                USA.Vehicle.Artillery.SPH_M109_Paladin,
                USA.Vehicle.Artillery.SPH_M109_Paladin,
                USA.Vehicle.Unarmed.HEMTT_TFFT,
                USA.Vehicle.AirDefence.SAM_Stinger_comm,
                USA.Vehicle.AirDefence.Stinger_MANPADS
            ])
        },
        "AirDefence": {
            "Air Defense Battery 01": (USA.name, [
                USA.Vehicle.Unarmed.APC_M1025_HMMWV,
                USA.Vehicle.Unarmed.APC_M1025_HMMWV,
                USA.Vehicle.AirDefence.SAM_Avenger_M1097,
                USA.Vehicle.AirDefence.SAM_Avenger_M1097,
                USA.Vehicle.AirDefence.SAM_Avenger_M1097,
                USA.Vehicle.AirDefence.SAM_Avenger_M1097
            ])
        },
        "Supply": {
            "US Supply": (USA.name, [
                USA.Vehicle.Unarmed.Transport_M818,
                USA.Vehicle.Unarmed.Transport_M818,
                USA.Vehicle.Unarmed.Tanker_M978_HEMTT,
                USA.Vehicle.Unarmed.HEMTT_TFFT
            ])
        }
    }

    def __init__(self, hide=True):
        self.hide = hide
        self.m = dcs.Mission()

        self.m.coalition["red"].swap_country(self.m.coalition["blue"],
                                             dcs.countries.Ukraine.name)

        self.red_airports = []  # type: List[dcs.terrain.Airport]
        self.blue_airports = []  # type: List[dcs.terrain.Airport]
        self.setup_airports()

    def dynamic_weather(self, baricsystem: str):
        if baricsystem == "dyncyclone":
            self.m.weather.dynamic_weather(
                dcs.weather.Weather.BaricSystem.Cyclone, 2)
        elif baricsystem == "dynanti":
            self.m.weather.dynamic_weather(
                dcs.weather.Weather.BaricSystem.AntiCyclone, 2)
        elif baricsystem == "dynnone":
            self.m.weather.dynamic_weather(
                dcs.weather.Weather.BaricSystem.None_, 2)
        else:
            self.m.random_weather = True

    def daytime(self, period):
        self.m.random_date()
        self.m.random_daytime(period)

    def setup_airports(self):
        caucasus = self.m.terrain  # type: dcs.terrain.Caucasus
        self.red_airports = caucasus.default_red_airports()
        for a in self.red_airports:
            self.setup_airport(a, "red", [
                dcs.vehicles.AirDefence.SAM_SA_19_Tunguska_2S6,
                dcs.vehicles.AirDefence.SPAAA_ZSU_23_4_Shilka
            ])

        self.blue_airports = caucasus.default_blue_airports()
        for a in self.blue_airports:
            self.setup_airport(a, "blue", [
                dcs.vehicles.AirDefence.SAM_Avenger_M1097,
                dcs.vehicles.AirDefence.AAA_Vulcan_M163
            ])

    def setup_airport(self, airport: dcs.terrain.Airport, side: str,
                      air_def_units: List[Type[dcs.unittype.VehicleType]]):
        airport.set_coalition(side)

        if not airport.civilian:
            if airport.is_red():
                vg = dcs.templates.VehicleTemplate.Russia.sa10_site(
                    self.m,
                    airport.random_unit_zone().center(), 180)
                vg.hidden = self.hide
            elif airport.is_blue():
                dcs.templates.VehicleTemplate.USA.patriot_site(
                    self.m,
                    airport.random_unit_zone().center(), 330)
        else:
            slots = len(airport.parking_slots)
            airdef = int(round(random.random() + slots / 20, 0))
            if airdef:
                vg = self.m.vehicle_group(
                    self.m.country("Russia") if airport.is_red() else
                    self.m.country("USA"), airport.name + " Air Defense",
                    air_def_units[random.randrange(0, len(air_def_units))],
                    airport.random_unit_zone().random_point(), 180)
                if airport.is_red():
                    vg.hidden = self.hide

                for i in range(1, airdef):
                    _type = air_def_units[random.randrange(
                        0, len(air_def_units))]
                    u = self.m.vehicle(
                        airport.name + " Air Defense #" + str(i), _type)
                    vg.add_unit(u)
                vg.formation_scattered(random.randrange(0, 359))

        return airport

    def add_civil_airtraffic(self,
                             planes=(10, 20),
                             helicopters=(0, 10),
                             hidden=True):
        p_count = random.randrange(planes[0], planes[1])
        h_count = random.randrange(helicopters[0], helicopters[1])

        c_count = 1

        def civil_flight(countries, airports):
            country_str = countries[random.randrange(0, len(countries))]
            country = self.m.country(country_str)

            airport = airports[random.randrange(0, len(airports))]

            transports = [
                x for x in country.planes
                if x.task_default == dcs.task.Transport
            ]
            ptype = random.choice(transports)

            slots = airport.free_parking_slot(ptype)

            x = random.randrange(
                dcs.terrain.Caucasus.bounds.bottom + 100 * 1000,
                dcs.terrain.Caucasus.bounds.top - 100 * 1000)
            y = random.randrange(
                dcs.terrain.Caucasus.bounds.left + 600 * 1000,
                dcs.terrain.Caucasus.bounds.right - 130 * 1000)

            pos = dcs.mapping.Point(x, y)
            name = "Civil " + str(c_count)
            rand = random.random()
            if 0.3 < rand < 0.5 and slots:
                pg = self.m.flight_group_from_airport(
                    country,
                    name,
                    ptype,
                    airport,
                    start_type=random.choice([
                        dcs.mission.StartType.Cold, dcs.mission.StartType.Warm
                    ]))
                pg.add_runway_waypoint(airport,
                                       distance=random.randrange(
                                           6000, 8000, 100))
                pg.add_waypoint(pos, random.randrange(5000, 8000, 100), 400)
            elif 0.5 < rand and slots:
                pg = self.m.flight_group_from_airport(country, name, ptype,
                                                      airport)
                pg.uncontrolled = True
            else:
                bound = dcs.mapping.Rectangle(
                    dcs.terrain.Caucasus.bounds.top - 100 * 1000,
                    dcs.terrain.Caucasus.bounds.left + 200 * 1000,
                    dcs.terrain.Caucasus.bounds.bottom + 100 * 1000,
                    dcs.terrain.Caucasus.bounds.right - 130 * 1000)
                point = bound.random_point()

                pg = self.m.flight_group_inflight(
                    country, name, ptype, point,
                    random.randrange(5000, 8000, 100), 400)
                tmp = pg.add_waypoint(dcs.mapping.Point(0, 0),
                                      pg.points[0].alt)
                wp = pg.add_runway_waypoint(airport,
                                            distance=random.randrange(
                                                6000, 8000, 100))
                heading = wp.position.heading_between_point(point)
                tmp.position = wp.position.point_from_heading(
                    heading, 30 * 1000)
                pg.land_at(airport)
            pg.set_frequency(240)
            return pg

        def heli_transport_flight(countries,
                                  airports: List[dcs.terrain.Airport]):
            country_str = countries[random.randrange(0, len(countries))]
            country = self.m.country(country_str)

            transports = [
                x for x in country.helicopters
                if x.task_default == dcs.task.Transport
            ]
            htype = random.choice(transports)

            start_airport = random.choice(airports)
            rand = random.random()
            name = "Helicopter Transport " + str(c_count)
            if 0.7 < rand:
                bound = dcs.mapping.Rectangle.from_point(
                    start_airport.position, 100 * 1000)
                pos = bound.random_point()
                hg = self.m.flight_group_inflight(
                    country, name, htype, pos,
                    random.randrange(800, 1500, 100), 200)
                hg.add_runway_waypoint(start_airport)
                hg.land_at(start_airport)
            elif 0.4 < rand < 0.7:
                hg = self.m.flight_group_from_airport(country, name, htype,
                                                      start_airport)
                hg.uncontrolled = True
            else:
                dest_airport = None
                while True:
                    dest_airport = airports[random.randrange(0, len(airports))]
                    if dest_airport != start_airport:
                        break

                hg = self.m.flight_group_from_airport(
                    country,
                    name,
                    htype,
                    start_airport,
                    start_type=random.choice(list(dcs.mission.StartType)))
                hg.add_runway_waypoint(start_airport)
                hg.add_runway_waypoint(dest_airport)
                hg.land_at(dest_airport)
            return hg

        # red
        red_countries = [dcs.countries.Russia.name]
        for i in range(0, int(p_count / 2)):
            cf = civil_flight(red_countries, self.red_airports)
            cf.hidden = hidden
            cf.points[0].tasks.append(dcs.task.SetInvisibleCommand())
            c_count += 1

        for i in range(0, int(h_count / 2)):
            hf = heli_transport_flight(red_countries, self.red_airports)
            hf.hidden = hidden
            hf.points[0].tasks.append(dcs.task.SetInvisibleCommand())
            c_count += 1

        # blue
        blue_countries = [
            dcs.countries.USA.name, dcs.countries.Ukraine.name,
            dcs.countries.Georgia.name
        ]
        for i in range(0, int(p_count / 2)):
            cf = civil_flight(blue_countries, self.blue_airports)
            cf.hidden = hidden
            cf.points[0].tasks.append(dcs.task.SetInvisibleCommand())
            c_count += 1

        for i in range(0, int(h_count / 2)):
            hf = heli_transport_flight(blue_countries, self.blue_airports)
            hf.hidden = hidden
            hf.points[0].tasks.append(dcs.task.SetInvisibleCommand())
            c_count += 1

    def add_uncontrolled_military_planes(
            self,
            airports: List[dcs.terrain.Airport],
            planes: List[Tuple[str, Type[dcs.unittype.FlyingType], int]],
            hidden=True):

        g_idx = 1
        while planes:
            country, ptype, group_size = planes.pop()

            while True:
                airport = random.choice(airports)

                slots = airport.free_parking_slots(ptype)
                if len(slots) >= group_size:
                    break

            c = self.m.country(country)
            pg = self.m.flight_group_from_airport(c,
                                                  ptype.id + " Flight #" +
                                                  str(g_idx),
                                                  ptype,
                                                  airport,
                                                  parking_slots=slots,
                                                  group_size=group_size)
            pg.uncontrolled = True
            pg.hidden = hidden
            g_idx += 1

    def place_players(self,
                      start,
                      aircraft_types: List[Tuple[str, str]],
                      airports: List[dcs.terrain.Airport],
                      group_size,
                      maintask,
                      placement_rect=None) -> List[dcs.unitgroup.FlyingGroup]:

        aircraft_groups = []  # type: List[dcs.unitgroup.FlyingGroup]
        name = "Airmaster "
        c = 1
        for _type in aircraft_types:
            country = self.m.country(_type[0])
            aircraft_type = _type[1]
            aircraft_type = dict(
                dcs.planes.plane_map,
                **dcs.helicopters.helicopter_map)[aircraft_type]

            airport = airports[random.randrange(0, len(airports))]
            if start == "inflight":
                rp = placement_rect.random_point(
                ) if placement_rect else dcs.mapping.Rectangle.from_point(
                    airport.position, 20 * 1000).random_point()
                altitude = random.randrange(
                    300, 1000,
                    100) if aircraft_type.helicopter else random.randrange(
                        2000, 5000, 100)
                pg = self.m.flight_group_inflight(country,
                                                  name + str(c),
                                                  aircraft_type,
                                                  rp,
                                                  altitude,
                                                  maintask=maintask,
                                                  group_size=group_size)
            else:
                pg = self.m.flight_group_from_airport(
                    country,
                    name + str(c),
                    aircraft_type,
                    airport,
                    maintask=maintask,
                    start_type=dcs.mission.StartType.from_string(start),
                    group_size=group_size)
                pg.add_runway_waypoint(airport)
            aircraft_groups.append(pg)

            for u in pg.units:
                u.set_client()
            c += 1

        if group_size == 1:
            aircraft_groups[0].units[0].set_player()

        return aircraft_groups

    def save(self, filename, stats):
        self.m.save(filename)
        if stats:
            self.m.print_stats(self.m.stats())