2026-02-11 19:22:43 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
from typing import List
|
|
|
|
|
|
|
|
|
|
from warchron.constants import ContextType
|
2026-02-17 16:37:36 +01:00
|
|
|
from warchron.model.exception import ForbiddenOperation
|
2026-02-20 11:01:25 +01:00
|
|
|
from warchron.model.result_checker import ResultChecker
|
2026-02-17 16:37:36 +01:00
|
|
|
from warchron.model.war_event import InfluenceGained
|
2026-02-11 19:22:43 +01:00
|
|
|
from warchron.model.war import War
|
|
|
|
|
from warchron.model.campaign import Campaign
|
|
|
|
|
from warchron.model.round import Round
|
2026-02-17 16:37:36 +01:00
|
|
|
from warchron.model.battle import Battle
|
2026-02-11 19:22:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClosureService:
|
|
|
|
|
|
2026-02-17 16:37:36 +01:00
|
|
|
# Round methods
|
|
|
|
|
|
2026-02-11 19:22:43 +01:00
|
|
|
@staticmethod
|
2026-02-17 16:37:36 +01:00
|
|
|
def check_round_closable(round: Round) -> None:
|
|
|
|
|
if round.is_over:
|
|
|
|
|
raise ForbiddenOperation("Round already closed")
|
2026-02-11 19:22:43 +01:00
|
|
|
if not round.all_battles_finished():
|
2026-02-17 16:37:36 +01:00
|
|
|
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
|
2026-02-17 16:37:36 +01:00
|
|
|
if battle.winner_id is not None:
|
|
|
|
|
base_winner = campaign.participants[battle.winner_id].war_participant_id
|
2026-02-20 11:01:25 +01:00
|
|
|
effective_winner = ResultChecker.get_effective_winner_id(
|
2026-02-17 16:37:36 +01:00
|
|
|
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}",
|
2026-02-11 19:22:43 +01:00
|
|
|
)
|
2026-02-17 16:37:36 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def finalize_round(round: Round) -> None:
|
2026-02-11 19:22:43 +01:00
|
|
|
round.is_over = True
|
2026-02-17 16:37:36 +01:00
|
|
|
|
|
|
|
|
# Campaign methods
|
2026-02-11 19:22:43 +01:00
|
|
|
|
|
|
|
|
@staticmethod
|
2026-02-20 11:01:25 +01:00
|
|
|
def check_campaign_closable(campaign: Campaign) -> None:
|
|
|
|
|
if campaign.is_over:
|
|
|
|
|
raise ForbiddenOperation("Campaign already closed")
|
2026-02-11 19:22:43 +01:00
|
|
|
if not campaign.all_rounds_finished():
|
2026-02-20 11:01:25 +01:00
|
|
|
raise ForbiddenOperation(
|
|
|
|
|
"All rounds must be closed to close their campaign"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def finalize_campaign(campaign: Campaign) -> None:
|
2026-02-11 19:22:43 +01:00
|
|
|
campaign.is_over = True
|
|
|
|
|
|
2026-02-17 16:37:36 +01:00
|
|
|
# War methods
|
|
|
|
|
|
2026-02-11 19:22:43 +01:00
|
|
|
@staticmethod
|
2026-02-17 16:37:36 +01:00
|
|
|
def close_war(war: War) -> List[str]:
|
2026-02-11 19:22:43 +01:00
|
|
|
if not war.all_campaigns_finished():
|
|
|
|
|
raise RuntimeError("All campaigns must be finished to close their war")
|
2026-02-17 16:37:36 +01:00
|
|
|
ties: List[str] = []
|
2026-02-11 19:22:43 +01:00
|
|
|
# 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 []
|