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
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)
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