1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
from collections import Counter
from typing import Optional
from CombatRatingsAI._fleet_combat_stats import get_fleet_combat_stats
from CombatRatingsAI._ship_combat_stats import AttackCount, AttackDamage, ShipCombatStats, get_ship_combat_stats
from common.fo_typing import FleetId, ShipId, SpeciesName
from EnumsAI import MissionType
from freeorion_tools import get_species_ship_shields
from freeorion_tools.caching import cache_for_current_turn
@cache_for_current_turn
def get_empire_standard_military_ship_stats() -> ShipCombatStats:
"""Get the current empire standard military ship stats, i.e. the most common ship type within the empire.
:return: Stats of most common military ship in the empire
"""
# avoid circular imports
from FleetUtilsAI import get_empire_fleet_ids_by_role
stats_dict = Counter()
for fleet_id in get_empire_fleet_ids_by_role(MissionType.MILITARY):
ship_stats = get_fleet_combat_stats(fleet_id, max_stats=True).get_ship_combat_stats()
stats_dict.update(ship_stats)
most_commons = stats_dict.most_common(1)
if most_commons:
return most_commons[0][0]
else:
return default_ship_stats()
def default_ship_stats() -> ShipCombatStats:
"""Return some ship stats to assume if no other intel is available.
:return: Some weak standard ship
"""
return ShipCombatStats(
attacks={AttackDamage(6.0): AttackCount(1)},
structure=15,
shields=0,
fighter_capacity=0,
fighter_launch_rate=0,
fighter_damage=0,
flak_shots=0,
has_interceptors=False,
damage_vs_planets=0,
has_bomber=False,
)
def species_shield_bonus(species: Optional[SpeciesName], shield_type: Optional[str]) -> float:
skill = get_species_ship_shields(species)
shield_class = {
"SH_DEFENSE_GRID": 1,
"SH_DEFLECTOR": 2,
"SH_PLASMA": 3,
"SH_MULTISPEC": 4,
"SH_BLACK": 5,
}
# Ships without or with robotic shield get no bonus, see shields.macro
return skill * shield_class.get(shield_type, 0)
def rating_needed(target: float, current: float = 0) -> float:
"""Estimate the needed rating to achieve target rating.
:param target: Target rating to be reached
:param current: Already existing rating
:return: Estimated missing rating to reach target
"""
if current >= target or target <= 0:
return 0
else:
return target + current - 2 * (target * current) ** 0.5
def rating_difference(first_rating: float, second_rating: float) -> float:
"""Return the absolute nonlinear difference between ratings.
:param first_rating: rating of a first force
:param second_rating: rating of a second force
:return: Estimated rating by which the greater force (nonlinearly) exceeds the lesser
"""
return rating_needed(max(first_rating, second_rating), min(first_rating, second_rating))
def get_fleet_rating(fleet_id: FleetId, enemy_stats: ShipCombatStats = None) -> float:
"""Get rating for the fleet against specified enemy.
:param fleet_id: fleet to be rated
:param enemy_stats: enemy to be rated against
"""
return get_fleet_combat_stats(fleet_id, max_stats=False).get_rating(enemy_stats)
def get_fleet_rating_against_planets(fleet_id: FleetId):
return get_fleet_combat_stats(fleet_id, max_stats=False).get_rating_vs_planets()
def get_ship_rating(ship_id: ShipId, enemy_stats=None):
return get_ship_combat_stats(ship_id=ship_id, max_stats=False).get_rating(enemy_stats)
|