detect and resolve battle tie with influence_token

This commit is contained in:
Maxime Réaux 2026-02-17 16:37:36 +01:00
parent 115ddf8d50
commit 818d2886f4
23 changed files with 808 additions and 172 deletions

View file

@ -2,44 +2,69 @@ from __future__ import annotations
from typing import List
from warchron.constants import ContextType
from warchron.model.tie_manager import ResolutionContext
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:
@staticmethod
def close_round(round: Round) -> List[ResolutionContext]:
if not round.all_battles_finished():
raise RuntimeError("All battles must be finished to close their round")
ties = []
for battle in round.battles.values():
if battle.is_draw():
participants: list[str] = []
if battle.player_1_id is not None:
participants.append(battle.player_1_id)
if battle.player_2_id is not None:
participants.append(battle.player_2_id)
ties.append(
ResolutionContext(
context_type=ContextType.BATTLE,
context_id=battle.sector_id,
# TODO ref to War.participants at some point
participant_ids=participants,
)
)
if ties:
return ties
round.is_over = True
return []
# Round methods
@staticmethod
def close_campaign(campaign: Campaign) -> List[ResolutionContext]:
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
if battle.winner_id is not None:
base_winner = campaign.participants[battle.winner_id].war_participant_id
else:
base_winner = None
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[ResolutionContext] = []
ties: List[str] = []
# for round in campaign.rounds:
# # compute score
# # if participants have same score
@ -59,11 +84,13 @@ class ClosureService:
campaign.is_over = True
return []
# War methods
@staticmethod
def close_war(war: War) -> List[ResolutionContext]:
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[ResolutionContext] = []
ties: List[str] = []
# for campaign in war.campaigns:
# # compute score
# # if participants have same score