warchron_app/src/warchron/model/closure_service.py

110 lines
3.7 KiB
Python
Raw Normal View History

from __future__ import annotations
from typing import List
from warchron.constants import ContextType
from warchron.model.exception import ForbiddenOperation
from warchron.model.tie_manager import TieResolver
from warchron.model.war_event import InfluenceGained
from warchron.model.war import War
from warchron.model.campaign import Campaign
from warchron.model.round import Round
from warchron.model.battle import Battle
class ClosureService:
# Round methods
@staticmethod
def check_round_closable(round: Round) -> None:
if round.is_over:
raise ForbiddenOperation("Round already closed")
if not round.all_battles_finished():
raise ForbiddenOperation(
"All battles must be finished to close their round"
)
@staticmethod
def apply_battle_outcomes(war: War, campaign: Campaign, battle: Battle) -> None:
already_granted = any(
isinstance(e, InfluenceGained) and e.source == f"battle:{battle.sector_id}"
for e in war.events
)
if already_granted:
return
2026-02-19 14:17:42 +01:00
base_winner = None
if battle.winner_id is not None:
base_winner = campaign.participants[battle.winner_id].war_participant_id
effective_winner = TieResolver.get_effective_winner_id(
war,
ContextType.BATTLE,
battle.sector_id,
base_winner,
)
if effective_winner is None:
return
sector = campaign.sectors[battle.sector_id]
if sector.influence_objective_id and war.influence_token:
war.events.append(
InfluenceGained(
participant_id=effective_winner,
amount=1,
source=f"battle:{battle.sector_id}",
)
)
@staticmethod
def finalize_round(round: Round) -> None:
round.is_over = True
# Campaign methods
@staticmethod
def close_campaign(campaign: Campaign) -> List[str]:
if not campaign.all_rounds_finished():
raise RuntimeError("All rounds must be finished to close their campaign")
ties: List[str] = []
# for round in campaign.rounds:
# # compute score
# # if participants have same score
# ties.append(
# ResolutionContext(
# context_type=ContextType.CAMPAIGN,
# context_id=campaign.id,
# participant_ids=[
# # TODO ref to War.participants at some point
# campaign.participants[campaign_participant_id],
# campaign.participants[campaign_participant_id],
# ],
# )
# )
if ties:
return ties
campaign.is_over = True
return []
# War methods
@staticmethod
def close_war(war: War) -> List[str]:
if not war.all_campaigns_finished():
raise RuntimeError("All campaigns must be finished to close their war")
ties: List[str] = []
# for campaign in war.campaigns:
# # compute score
# # if participants have same score
# ties.append(
# ResolutionContext(
# context_type=ContextType.WAR,
# context_id=war.id,
# participant_ids=[
# war.participants[war_participant_id],
# war.participants[war_participant_id],
# ],
# )
# )
if ties:
return ties
war.is_over = True
return []