예제 #1
0
def main():
    logging_config.init_logging(VERSION)

    logging.debug("Python version %s", sys.version)

    if not str(Path(__file__)).isascii():
        logging.warning(
            "Installation path contains non-ASCII characters. This is known to cause problems."
        )

    game: Optional[Game] = None

    args = parse_args()

    # TODO: Flesh out data and then make unconditional.
    if args.warn_missing_weapon_data:
        lint_all_weapon_data()

    load_mods()

    if args.subcommand == "new-game":
        with logged_duration("New game creation"):
            game = create_game(
                args.campaign,
                args.blue,
                args.red,
                args.supercarrier,
                args.auto_procurement,
                args.inverted,
                args.cheats,
                args.date,
                args.restrict_weapons_by_date,
            )
    if args.subcommand == "lint-weapons":
        lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft))
        return

    with Server().run_in_thread():
        run_ui(game, args.dev)
예제 #2
0
    def from_yaml(cls, path: Path) -> SquadronDef:
        from game.ato.ai_flight_planner_db import tasks_for_aircraft
        from game.ato import FlightType

        with path.open(encoding="utf8") as squadron_file:
            data = yaml.safe_load(squadron_file)

        name = data["aircraft"]
        try:
            unit_type = AircraftType.named(name)
        except KeyError as ex:
            raise KeyError(f"Could not find any aircraft named {name}") from ex

        pilots = [Pilot(n, player=False) for n in data.get("pilots", [])]
        pilots.extend([Pilot(n, player=True) for n in data.get("players", [])])
        female_pilot_percentage = data.get("female_pilot_percentage", 6)

        mission_types = [FlightType.from_name(n) for n in data["mission_types"]]
        tasks = tasks_for_aircraft(unit_type)
        for mission_type in list(mission_types):
            if mission_type not in tasks:
                logging.error(
                    f"Squadron has mission type {mission_type} but {unit_type} is not "
                    f"capable of that task: {path}"
                )
                mission_types.remove(mission_type)

        return SquadronDef(
            name=data["name"],
            nickname=data.get("nickname"),
            country=data["country"],
            role=data["role"],
            aircraft=unit_type,
            livery=data.get("livery"),
            mission_types=tuple(mission_types),
            operating_bases=OperatingBases.from_yaml(unit_type, data.get("bases", {})),
            female_pilot_percentage=female_pilot_percentage,
            pilot_pool=pilots,
        )
def aircraft_for_task(task: FlightType) -> list[AircraftType]:
    dcs_types = dcs_types_for_task(task)
    types: list[AircraftType] = []
    for dcs_type in dcs_types:
        types.extend(AircraftType.for_dcs_type(dcs_type))
    return types
예제 #4
0
    def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
        faction = Faction(locales=json.get("locales"))

        faction.country = json.get("country", "/")
        if faction.country not in [c.name for c in country_dict.values()]:
            raise AssertionError(
                'Faction\'s country ("{}") is not a valid DCS country ID'.
                format(faction.country))

        faction.name = json.get("name", "")
        if not faction.name:
            raise AssertionError("Faction has no valid name")

        faction.authors = json.get("authors", "")
        faction.description = json.get("description", "")

        faction.aircrafts = [
            AircraftType.named(n) for n in json.get("aircrafts", [])
        ]
        faction.awacs = [AircraftType.named(n) for n in json.get("awacs", [])]
        faction.tankers = [
            AircraftType.named(n) for n in json.get("tankers", [])
        ]

        faction.aircrafts = list(
            set(faction.aircrafts + faction.awacs + faction.tankers))

        faction.frontline_units = [
            GroundUnitType.named(n) for n in json.get("frontline_units", [])
        ]
        faction.artillery_units = [
            GroundUnitType.named(n) for n in json.get("artillery_units", [])
        ]
        faction.infantry_units = [
            GroundUnitType.named(n) for n in json.get("infantry_units", [])
        ]
        faction.logistics_units = [
            GroundUnitType.named(n) for n in json.get("logistics_units", [])
        ]
        faction.air_defense_units = [
            GroundUnitType.named(n) for n in json.get("air_defense_units", [])
        ]
        faction.missiles = [
            GroundUnitType.named(n) for n in json.get("missiles", [])
        ]

        faction.naval_units = [
            ShipUnitType.named(n) for n in json.get("naval_units", [])
        ]

        faction.preset_groups = [
            ForceGroup.named(n) for n in json.get("preset_groups", [])
        ]

        faction.requirements = json.get("requirements", {})

        faction.carrier_names = json.get("carrier_names", [])
        faction.helicopter_carrier_names = json.get("helicopter_carrier_names",
                                                    [])

        faction.has_jtac = json.get("has_jtac", False)
        jtac_name = json.get("jtac_unit", None)
        if jtac_name is not None:
            faction.jtac_unit = AircraftType.named(jtac_name)
        else:
            faction.jtac_unit = None

        # Load doctrine
        doctrine = json.get("doctrine", "modern")
        if doctrine == "modern":
            faction.doctrine = MODERN_DOCTRINE
        elif doctrine == "coldwar":
            faction.doctrine = COLDWAR_DOCTRINE
        elif doctrine == "ww2":
            faction.doctrine = WWII_DOCTRINE
        else:
            faction.doctrine = MODERN_DOCTRINE

        # Load the building set
        building_set = json.get("building_set", "default")
        if building_set == "default":
            faction.building_set = DEFAULT_AVAILABLE_BUILDINGS
        elif building_set == "ww2free":
            faction.building_set = WW2_FREE
        elif building_set == "ww2ally":
            faction.building_set = WW2_ALLIES_BUILDINGS
        elif building_set == "ww2germany":
            faction.building_set = WW2_GERMANY_BUILDINGS
        else:
            faction.building_set = DEFAULT_AVAILABLE_BUILDINGS

        # Add required buildings for the game logic (e.g. ammo, factory..)
        faction.building_set.extend(REQUIRED_BUILDINGS)

        # Load liveries override
        faction.liveries_overrides = {}
        liveries_overrides = json.get("liveries_overrides", {})
        for name, livery in liveries_overrides.items():
            aircraft = AircraftType.named(name)
            faction.liveries_overrides[aircraft] = [s.lower() for s in livery]

        faction.unrestricted_satnav = json.get("unrestricted_satnav", False)

        return faction
예제 #5
0
    def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
        faction = Faction(locales=json.get("locales"))

        faction.country = json.get("country", "/")
        if faction.country not in [c.name for c in country_dict.values()]:
            raise AssertionError(
                'Faction\'s country ("{}") is not a valid DCS country ID'.format(
                    faction.country
                )
            )

        faction.name = json.get("name", "")
        if not faction.name:
            raise AssertionError("Faction has no valid name")

        faction.authors = json.get("authors", "")
        faction.description = json.get("description", "")

        faction.aircrafts = [AircraftType.named(n) for n in json.get("aircrafts", [])]
        faction.awacs = [AircraftType.named(n) for n in json.get("awacs", [])]
        faction.tankers = [AircraftType.named(n) for n in json.get("tankers", [])]

        faction.aircrafts = list(
            set(faction.aircrafts + faction.awacs + faction.tankers)
        )

        faction.frontline_units = [
            GroundUnitType.named(n) for n in json.get("frontline_units", [])
        ]
        faction.artillery_units = [
            GroundUnitType.named(n) for n in json.get("artillery_units", [])
        ]
        faction.infantry_units = [
            GroundUnitType.named(n) for n in json.get("infantry_units", [])
        ]
        faction.logistics_units = [
            GroundUnitType.named(n) for n in json.get("logistics_units", [])
        ]

        faction.ewrs = json.get("ewrs", [])

        faction.air_defenses = json.get("air_defenses", [])
        # Compatibility for older factions. All air defenses now belong to a
        # single group and the generator decides what belongs where.
        faction.air_defenses.extend(json.get("sams", []))
        faction.air_defenses.extend(json.get("shorads", []))

        faction.missiles = json.get("missiles", [])
        faction.coastal_defenses = json.get("coastal_defenses", [])
        faction.requirements = json.get("requirements", {})

        faction.carrier_names = json.get("carrier_names", [])
        faction.helicopter_carrier_names = json.get("helicopter_carrier_names", [])
        faction.navy_generators = json.get("navy_generators", [])
        faction.aircraft_carrier = load_all_ships(json.get("aircraft_carrier", []))
        faction.helicopter_carrier = load_all_ships(json.get("helicopter_carrier", []))
        faction.destroyers = load_all_ships(json.get("destroyers", []))
        faction.cruisers = load_all_ships(json.get("cruisers", []))
        faction.has_jtac = json.get("has_jtac", False)
        jtac_name = json.get("jtac_unit", None)
        if jtac_name is not None:
            faction.jtac_unit = AircraftType.named(jtac_name)
        else:
            faction.jtac_unit = None
        faction.navy_group_count = int(json.get("navy_group_count", 1))
        faction.missiles_group_count = int(json.get("missiles_group_count", 0))
        faction.coastal_group_count = int(json.get("coastal_group_count", 0))

        # Load doctrine
        doctrine = json.get("doctrine", "modern")
        if doctrine == "modern":
            faction.doctrine = MODERN_DOCTRINE
        elif doctrine == "coldwar":
            faction.doctrine = COLDWAR_DOCTRINE
        elif doctrine == "ww2":
            faction.doctrine = WWII_DOCTRINE
        else:
            faction.doctrine = MODERN_DOCTRINE

        # Load the building set
        building_set = json.get("building_set", "default")
        if building_set == "default":
            faction.building_set = DEFAULT_AVAILABLE_BUILDINGS
        elif building_set == "ww2free":
            faction.building_set = WW2_FREE
        elif building_set == "ww2ally":
            faction.building_set = WW2_ALLIES_BUILDINGS
        elif building_set == "ww2germany":
            faction.building_set = WW2_GERMANY_BUILDINGS
        else:
            faction.building_set = DEFAULT_AVAILABLE_BUILDINGS

        # Load liveries override
        faction.liveries_overrides = {}
        liveries_overrides = json.get("liveries_overrides", {})
        for name, livery in liveries_overrides.items():
            aircraft = AircraftType.named(name)
            faction.liveries_overrides[aircraft] = [s.lower() for s in livery]

        faction.unrestricted_satnav = json.get("unrestricted_satnav", False)

        return faction
예제 #6
0
    def generate(self) -> None:
        position = Conflict.frontline_position(
            self.conflict.front_line, self.game.theater
        )

        frontline_vector = Conflict.frontline_vector(
            self.conflict.front_line, self.game.theater
        )

        # Create player groups at random position
        player_groups = self._generate_groups(
            self.player_planned_combat_groups, frontline_vector, True
        )

        # Create enemy groups at random position
        enemy_groups = self._generate_groups(
            self.enemy_planned_combat_groups, frontline_vector, False
        )

        # TODO: Differentiate AirConflict and GroundConflict classes.
        if self.conflict.heading is None:
            raise RuntimeError(
                "Cannot generate ground units for non-ground conflict. Ground unit "
                "conflicts cannot have the heading `None`."
            )

        # Plan combat actions for groups
        self.plan_action_for_groups(
            self.player_stance,
            player_groups,
            enemy_groups,
            self.conflict.heading + 90,
            self.conflict.blue_cp,
            self.conflict.red_cp,
        )
        self.plan_action_for_groups(
            self.enemy_stance,
            enemy_groups,
            player_groups,
            self.conflict.heading - 90,
            self.conflict.red_cp,
            self.conflict.blue_cp,
        )

        # Add JTAC
        if self.game.player_faction.has_jtac:
            n = "JTAC" + str(self.conflict.blue_cp.id) + str(self.conflict.red_cp.id)
            code = 1688 - len(self.jtacs)

            utype = self.game.player_faction.jtac_unit
            if utype is None:
                utype = AircraftType.named("MQ-9 Reaper")

            jtac = self.mission.flight_group(
                country=self.mission.country(self.game.player_country),
                name=n,
                aircraft_type=utype.dcs_unit_type,
                position=position[0],
                airport=None,
                altitude=5000,
            )
            jtac.points[0].tasks.append(SetInvisibleCommand(True))
            jtac.points[0].tasks.append(SetImmortalCommand(True))
            jtac.points[0].tasks.append(
                OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle)
            )
            frontline = (
                f"Frontline {self.conflict.blue_cp.name}/{self.conflict.red_cp.name}"
            )
            # Note: Will need to change if we ever add ground based JTAC.
            callsign = callsign_for_support_unit(jtac)
            self.jtacs.append(
                JtacInfo(
                    str(jtac.name),
                    n,
                    callsign,
                    frontline,
                    str(code),
                    blue=True,
                )
            )
예제 #7
0
    def generate(self) -> None:
        position = FrontLineConflictDescription.frontline_position(
            self.conflict.front_line, self.game.theater)

        frontline_vector = FrontLineConflictDescription.frontline_vector(
            self.conflict.front_line, self.game.theater)

        # Create player groups at random position
        player_groups = self._generate_groups(
            self.player_planned_combat_groups, frontline_vector, True)

        # Create enemy groups at random position
        enemy_groups = self._generate_groups(self.enemy_planned_combat_groups,
                                             frontline_vector, False)

        # TODO: Differentiate AirConflict and GroundConflict classes.
        if self.conflict.heading is None:
            raise RuntimeError(
                "Cannot generate ground units for non-ground conflict. Ground unit "
                "conflicts cannot have the heading `None`.")

        # Plan combat actions for groups
        self.plan_action_for_groups(
            self.player_stance,
            player_groups,
            enemy_groups,
            self.conflict.heading.right,
            self.conflict.blue_cp,
            self.conflict.red_cp,
        )
        self.plan_action_for_groups(
            self.enemy_stance,
            enemy_groups,
            player_groups,
            self.conflict.heading.left,
            self.conflict.red_cp,
            self.conflict.blue_cp,
        )

        # Add JTAC
        if self.game.blue.faction.has_jtac:
            code: int
            freq = self.radio_registry.alloc_uhf()
            # If the option fc3LaserCode is enabled, force all JTAC
            # laser codes to 1113 to allow lasing for Su-25 Frogfoots and A-10A Warthogs.
            # Otherwise use 1688 for the first JTAC, 1687 for the second etc.
            if self.game.settings.plugins["plugins.jtacautolase.fc3LaserCode"]:
                code = 1113
            else:
                code = self.laser_code_registry.get_next_laser_code()

            utype = self.game.blue.faction.jtac_unit
            if utype is None:
                utype = AircraftType.named("MQ-9 Reaper")

            jtac = self.mission.flight_group(
                country=self.mission.country(self.game.blue.country_name),
                name=namegen.next_jtac_name(),
                aircraft_type=utype.dcs_unit_type,
                position=position[0],
                airport=None,
                altitude=5000,
                maintask=AFAC,
            )
            jtac.points[0].tasks.append(
                FAC(callsign=len(self.air_support.jtacs) + 1,
                    frequency=int(freq.mhz)))
            jtac.points[0].tasks.append(SetInvisibleCommand(True))
            jtac.points[0].tasks.append(SetImmortalCommand(True))
            jtac.points[0].tasks.append(
                OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
            frontline = (
                f"Frontline {self.conflict.blue_cp.name}/{self.conflict.red_cp.name}"
            )
            # Note: Will need to change if we ever add ground based JTAC.
            callsign = callsign_for_support_unit(jtac)
            self.air_support.jtacs.append(
                JtacInfo(
                    jtac.name,
                    jtac.name,
                    callsign,
                    frontline,
                    str(code),
                    blue=True,
                    freq=freq,
                ))