Beispiel #1
0
def assess_ship_design_role(design):
    parts = [get_ship_part(partname) for partname in design.parts if partname and get_ship_part(partname)]

    if any(p.partClass == fo.shipPartClass.colony and p.capacity == 0 for p in parts):
        if design.speed > 0:
            return ShipRoleType.CIVILIAN_OUTPOST
        else:
            return ShipRoleType.BASE_OUTPOST

    if any(p.partClass == fo.shipPartClass.colony and p.capacity > 0 for p in parts):
        if design.speed > 0:
            return ShipRoleType.CIVILIAN_COLONISATION
        else:
            return ShipRoleType.BASE_COLONISATION

    if any(p.partClass == fo.shipPartClass.troops for p in parts):
        if design.speed > 0:
            return ShipRoleType.MILITARY_INVASION
        else:
            return ShipRoleType.BASE_INVASION

    if design.speed == 0:
        if not parts or parts[0].partClass == fo.shipPartClass.shields:  # ToDo: Update logic for new ship designs
            return ShipRoleType.BASE_DEFENSE
        else:
            return ShipRoleType.INVALID

    if design.isArmed or design.hasFighters:
        return ShipRoleType.MILITARY
    if any(p.partClass == fo.shipPartClass.detection for p in parts):
        return ShipRoleType.CIVILIAN_EXPLORATION
    else:   # if no suitable role found, use as (bad) scout as it still has inherent detection
        warning("Defaulting ship role to 'exploration' for ship with parts: %s", design.parts)
        return ShipRoleType.CIVILIAN_EXPLORATION
Beispiel #2
0
    def __get_stats_from_ship(self):
        """Read and store combat related stats from ship"""
        universe = fo.getUniverse()
        ship = universe.getShip(self.__ship_id)
        if not ship:
            return  # TODO: Add some estimate for stealthed ships

        if self._consider_refuel:
            structure = ship.initialMeterValue(fo.meterType.maxStructure)
            shields = ship.initialMeterValue(fo.meterType.maxShield)
        else:
            structure = ship.initialMeterValue(fo.meterType.structure)
            shields = ship.initialMeterValue(fo.meterType.shield)
        attacks = {}
        fighter_launch_rate = 0
        fighter_capacity = 0
        fighter_damage = 0
        flak_shots = 0
        has_bomber = False
        has_interceptors = False
        damage_vs_planets = 0
        design = ship.design
        if design and (ship.isArmed or ship.hasFighters):
            meter_choice = fo.meterType.maxCapacity if self._consider_refuel else fo.meterType.capacity
            for partname in design.parts:
                if not partname:
                    continue
                pc = get_ship_part(partname).partClass
                if pc == fo.shipPartClass.shortRange:
                    allowed_targets = get_allowed_targets(partname)
                    damage = ship.currentPartMeterValue(meter_choice, partname)
                    shots = ship.currentPartMeterValue(fo.meterType.secondaryStat, partname)
                    if allowed_targets & CombatTarget.SHIP:
                        attacks[damage] = attacks.get(damage, 0) + shots
                    if allowed_targets & CombatTarget.FIGHTER:
                        flak_shots += 1
                    if allowed_targets & CombatTarget.PLANET:
                        damage_vs_planets += damage * shots
                elif pc == fo.shipPartClass.fighterBay:
                    fighter_launch_rate += ship.currentPartMeterValue(fo.meterType.capacity, partname)
                elif pc == fo.shipPartClass.fighterHangar:
                    allowed_targets = get_allowed_targets(partname)
                    # for hangars, capacity meter is already counting contributions from ALL hangars.
                    fighter_capacity = ship.currentPartMeterValue(meter_choice, partname)
                    part_damage = ship.currentPartMeterValue(fo.meterType.secondaryStat, partname)
                    if part_damage != fighter_damage and fighter_damage > 0:
                        # the C++ code fails also in this regard, so FOCS content *should* not allow this.
                        # TODO: Depending on future implementation, might actually need to handle this case.
                        warning("Multiple hangar types present on one ship, estimates expected to be wrong.")
                    if allowed_targets & CombatTarget.SHIP:
                        fighter_damage = max(fighter_damage, part_damage)
                    if allowed_targets & CombatTarget.PLANET:
                        has_bomber = True
                    if allowed_targets & CombatTarget.FIGHTER:
                        has_interceptors = True

        self._basic_stats = self.BasicStats(attacks, structure, shields)
        self._fighter_stats = self.FighterStats(fighter_capacity, fighter_launch_rate, fighter_damage)
        self._anti_fighter_stats = self.AntiFighterStats(flak_shots, has_interceptors)
        self._anti_planet_stats = self.AntiPlanetStats(damage_vs_planets, has_bomber)
Beispiel #3
0
def get_fighter_capacity_of_fleet(fleet_id: int) -> Tuple[int, int]:
    """
    Return current and max fighter capacity.
    """
    universe = fo.getUniverse()
    fleet = universe.getFleet(fleet_id)
    cur_capacity = 0
    max_capacity = 0
    ships = (universe.getShip(ship_id)
             for ship_id in (fleet.shipIDs if fleet else []))
    for ship in ships:
        design = ship and ship.design
        design_parts = design.parts if design and design.hasFighters else []
        for partname in design_parts:
            part = get_ship_part(partname)
            if part and part.partClass == fo.shipPartClass.fighterHangar:
                cur_capacity += ship.currentPartMeterValue(
                    fo.meterType.capacity, partname)
                max_capacity += ship.currentPartMeterValue(
                    fo.meterType.maxCapacity, partname)
    return cur_capacity, max_capacity