tie dialog title with context details
This commit is contained in:
parent
aa75a5b84f
commit
9e602e8ca4
8 changed files with 109 additions and 46 deletions
|
|
@ -23,6 +23,7 @@ from warchron.model.tie_manager import TieContext, TieResolver
|
||||||
from warchron.model.score_service import ScoreService
|
from warchron.model.score_service import ScoreService
|
||||||
from warchron.controller.closure_workflow import CampaignClosureWorkflow
|
from warchron.controller.closure_workflow import CampaignClosureWorkflow
|
||||||
from warchron.controller.ranking_icon import RankingIcon
|
from warchron.controller.ranking_icon import RankingIcon
|
||||||
|
from warchron.controller.presenter import TiePresenter
|
||||||
from warchron.view.campaign_dialog import CampaignDialog
|
from warchron.view.campaign_dialog import CampaignDialog
|
||||||
from warchron.view.campaign_participant_dialog import CampaignParticipantDialog
|
from warchron.view.campaign_participant_dialog import CampaignParticipantDialog
|
||||||
from warchron.view.sector_dialog import SectorDialog
|
from warchron.view.sector_dialog import SectorDialog
|
||||||
|
|
@ -176,24 +177,17 @@ class CampaignController:
|
||||||
for pid in active
|
for pid in active
|
||||||
]
|
]
|
||||||
counters = [war.get_influence_tokens(pid) for pid in active]
|
counters = [war.get_influence_tokens(pid) for pid in active]
|
||||||
|
data = TiePresenter.build_dialog_data(
|
||||||
|
war, ctx, campaign=war.get_campaign(ctx.context_id)
|
||||||
|
)
|
||||||
dialog = TieDialog(
|
dialog = TieDialog(
|
||||||
parent=self.app.view,
|
parent=self.app.view,
|
||||||
players=players,
|
players=players,
|
||||||
counters=counters,
|
counters=counters,
|
||||||
context_type=ctx.context_type,
|
context_type=ctx.context_type,
|
||||||
context_id=ctx.context_id,
|
context_id=ctx.context_id,
|
||||||
context_name=None,
|
context_name=data.title,
|
||||||
)
|
)
|
||||||
if ctx.objective_id:
|
|
||||||
objective = war.objectives[ctx.objective_id]
|
|
||||||
dialog = TieDialog(
|
|
||||||
parent=self.app.view,
|
|
||||||
players=players,
|
|
||||||
counters=counters,
|
|
||||||
context_type=ctx.context_type,
|
|
||||||
context_id=ctx.context_id,
|
|
||||||
context_name=f"Objective tie: {objective.name}",
|
|
||||||
)
|
|
||||||
if not dialog.exec():
|
if not dialog.exec():
|
||||||
TieResolver.cancel_tie_break(war, ctx)
|
TieResolver.cancel_tie_break(war, ctx)
|
||||||
raise AbortedOperation("Tie resolution cancelled")
|
raise AbortedOperation("Tie resolution cancelled")
|
||||||
|
|
|
||||||
|
|
@ -132,3 +132,8 @@ class WarParticipantScoreDTO:
|
||||||
tokens: int
|
tokens: int
|
||||||
rank_icon: QIcon | None = None
|
rank_icon: QIcon | None = None
|
||||||
objective_icons: Dict[str, QIcon] = field(default_factory=dict)
|
objective_icons: Dict[str, QIcon] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TieDialogData:
|
||||||
|
title: str
|
||||||
|
|
|
||||||
52
src/warchron/controller/presenter.py
Normal file
52
src/warchron/controller/presenter.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
from warchron.constants import ContextType
|
||||||
|
from warchron.controller.dtos import TieDialogData
|
||||||
|
from warchron.model.tie_manager import TieContext
|
||||||
|
from warchron.model.war import War
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
|
from warchron.model.round import Round
|
||||||
|
|
||||||
|
|
||||||
|
class TiePresenter:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_dialog_data(
|
||||||
|
war: War,
|
||||||
|
ctx: TieContext,
|
||||||
|
campaign: Campaign | None = None,
|
||||||
|
round: Round | None = None,
|
||||||
|
) -> TieDialogData:
|
||||||
|
if ctx.context_type == ContextType.WAR:
|
||||||
|
if ctx.objective_id:
|
||||||
|
obj = war.objectives[ctx.objective_id]
|
||||||
|
return TieDialogData(f"War objective tie — {obj.name}")
|
||||||
|
return TieDialogData("War tie")
|
||||||
|
if ctx.context_type == ContextType.CAMPAIGN:
|
||||||
|
if ctx.objective_id:
|
||||||
|
obj = war.objectives[ctx.objective_id]
|
||||||
|
return TieDialogData(f"Campaign objective tie — {obj.name}")
|
||||||
|
return TieDialogData("Campaign tie")
|
||||||
|
if ctx.context_type == ContextType.BATTLE:
|
||||||
|
if campaign:
|
||||||
|
sector = campaign.sectors[ctx.context_id]
|
||||||
|
return TieDialogData(f"Battle tie — {sector.name}")
|
||||||
|
return TieDialogData("Battle tie")
|
||||||
|
if ctx.context_type == ContextType.CHOICE:
|
||||||
|
if ctx.sector_id and campaign and round:
|
||||||
|
sector = campaign.sectors[ctx.sector_id]
|
||||||
|
kind = TiePresenter._choice_kind(round, ctx)
|
||||||
|
return TieDialogData(f"Choice tie — {sector.name} ({kind})")
|
||||||
|
return TieDialogData("Choice tie")
|
||||||
|
return TieDialogData("Tie")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _choice_kind(round: Round, ctx: TieContext) -> str:
|
||||||
|
for pid in ctx.participants:
|
||||||
|
camp_pid = round.campaign.war_to_campaign_part_id(pid)
|
||||||
|
choice = round.choices.get(camp_pid)
|
||||||
|
if not choice:
|
||||||
|
continue
|
||||||
|
if choice.priority_sector_id == ctx.sector_id:
|
||||||
|
return "priority"
|
||||||
|
if choice.secondary_sector_id == ctx.sector_id:
|
||||||
|
return "secondary"
|
||||||
|
return "choice"
|
||||||
|
|
@ -28,6 +28,7 @@ from warchron.controller.closure_workflow import (
|
||||||
RoundClosureWorkflow,
|
RoundClosureWorkflow,
|
||||||
RoundPairingWorkflow,
|
RoundPairingWorkflow,
|
||||||
)
|
)
|
||||||
|
from warchron.controller.presenter import TiePresenter
|
||||||
from warchron.view.choice_dialog import ChoiceDialog
|
from warchron.view.choice_dialog import ChoiceDialog
|
||||||
from warchron.view.battle_dialog import BattleDialog
|
from warchron.view.battle_dialog import BattleDialog
|
||||||
from warchron.view.tie_dialog import TieDialog
|
from warchron.view.tie_dialog import TieDialog
|
||||||
|
|
@ -243,13 +244,26 @@ class RoundController:
|
||||||
for pid in ctx.participants
|
for pid in ctx.participants
|
||||||
]
|
]
|
||||||
counters = [war.get_influence_tokens(pid) for pid in ctx.participants]
|
counters = [war.get_influence_tokens(pid) for pid in ctx.participants]
|
||||||
# TODO display sector name for BATTLE or CHOICE
|
if ctx.context_type == ContextType.BATTLE:
|
||||||
|
# context_id = battle.sector_id
|
||||||
|
campaign = war.get_campaign_by_sector(ctx.context_id)
|
||||||
|
if campaign:
|
||||||
|
round = campaign.get_round_by_battle(ctx.context_id)
|
||||||
|
if ctx.context_type == ContextType.CHOICE:
|
||||||
|
# context_id = round.id
|
||||||
|
campaign = war.get_campaign_by_round(ctx.context_id)
|
||||||
|
if campaign:
|
||||||
|
round = war.get_round(ctx.context_id)
|
||||||
|
data = TiePresenter.build_dialog_data(
|
||||||
|
war, ctx, round=round, campaign=campaign
|
||||||
|
)
|
||||||
dialog = TieDialog(
|
dialog = TieDialog(
|
||||||
parent=self.app.view,
|
parent=self.app.view,
|
||||||
players=players,
|
players=players,
|
||||||
counters=counters,
|
counters=counters,
|
||||||
context_type=ctx.context_type,
|
context_type=ctx.context_type,
|
||||||
context_id=ctx.context_id,
|
context_id=ctx.context_id,
|
||||||
|
context_name=data.title,
|
||||||
)
|
)
|
||||||
if not dialog.exec():
|
if not dialog.exec():
|
||||||
TieResolver.cancel_tie_break(war, ctx)
|
TieResolver.cancel_tie_break(war, ctx)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ from warchron.model.tie_manager import TieContext, TieResolver
|
||||||
from warchron.model.score_service import ScoreService
|
from warchron.model.score_service import ScoreService
|
||||||
from warchron.controller.closure_workflow import WarClosureWorkflow
|
from warchron.controller.closure_workflow import WarClosureWorkflow
|
||||||
from warchron.controller.ranking_icon import RankingIcon
|
from warchron.controller.ranking_icon import RankingIcon
|
||||||
|
from warchron.controller.presenter import TiePresenter
|
||||||
from warchron.view.war_dialog import WarDialog
|
from warchron.view.war_dialog import WarDialog
|
||||||
from warchron.view.objective_dialog import ObjectiveDialog
|
from warchron.view.objective_dialog import ObjectiveDialog
|
||||||
from warchron.view.war_participant_dialog import WarParticipantDialog
|
from warchron.view.war_participant_dialog import WarParticipantDialog
|
||||||
|
|
@ -170,24 +171,18 @@ class WarController:
|
||||||
for pid in active
|
for pid in active
|
||||||
]
|
]
|
||||||
counters = [war.get_influence_tokens(pid) for pid in active]
|
counters = [war.get_influence_tokens(pid) for pid in active]
|
||||||
|
data = TiePresenter.build_dialog_data(
|
||||||
|
war,
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
dialog = TieDialog(
|
dialog = TieDialog(
|
||||||
parent=self.app.view,
|
parent=self.app.view,
|
||||||
players=players,
|
players=players,
|
||||||
counters=counters,
|
counters=counters,
|
||||||
context_type=ctx.context_type,
|
context_type=ctx.context_type,
|
||||||
context_id=ctx.context_id,
|
context_id=ctx.context_id,
|
||||||
context_name=None,
|
context_name=data.title,
|
||||||
)
|
)
|
||||||
if ctx.objective_id:
|
|
||||||
objective = war.objectives[ctx.objective_id]
|
|
||||||
dialog = TieDialog(
|
|
||||||
parent=self.app.view,
|
|
||||||
players=players,
|
|
||||||
counters=counters,
|
|
||||||
context_type=ctx.context_type,
|
|
||||||
context_id=ctx.context_id,
|
|
||||||
context_name=f"Objective tie: {objective.name}",
|
|
||||||
)
|
|
||||||
if not dialog.exec():
|
if not dialog.exec():
|
||||||
TieResolver.cancel_tie_break(war, ctx)
|
TieResolver.cancel_tie_break(war, ctx)
|
||||||
raise AbortedOperation("Tie resolution cancelled")
|
raise AbortedOperation("Tie resolution cancelled")
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ from collections import defaultdict
|
||||||
|
|
||||||
from warchron.constants import ContextType
|
from warchron.constants import ContextType
|
||||||
from warchron.model.war import War
|
from warchron.model.war import War
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
from warchron.model.battle import Battle
|
from warchron.model.battle import Battle
|
||||||
|
from warchron.model.exception import DomainError
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
|
|
@ -26,14 +28,17 @@ class ScoreService:
|
||||||
continue
|
continue
|
||||||
yield from rnd.battles.values()
|
yield from rnd.battles.values()
|
||||||
elif context_type == ContextType.CAMPAIGN:
|
elif context_type == ContextType.CAMPAIGN:
|
||||||
campaign = war.get_campaign(context_id)
|
campaign: Campaign | None = war.get_campaign(context_id)
|
||||||
for rnd in campaign.rounds:
|
if campaign:
|
||||||
if not rnd.is_over:
|
for rnd in campaign.rounds:
|
||||||
continue
|
if not rnd.is_over:
|
||||||
yield from rnd.battles.values()
|
continue
|
||||||
|
yield from rnd.battles.values()
|
||||||
elif context_type == ContextType.BATTLE:
|
elif context_type == ContextType.BATTLE:
|
||||||
battle = war.get_battle(context_id)
|
battle = war.get_battle(context_id)
|
||||||
campaign = war.get_campaign_by_sector(battle.sector_id)
|
campaign = war.get_campaign_by_sector(battle.sector_id)
|
||||||
|
if not campaign:
|
||||||
|
raise DomainError(f"No campaign found for secor {battle.sector_id}")
|
||||||
rnd = campaign.get_round_by_battle(context_id)
|
rnd = campaign.get_round_by_battle(context_id)
|
||||||
if rnd and rnd.is_over:
|
if rnd and rnd.is_over:
|
||||||
yield battle
|
yield battle
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@ from warchron.model.war_event import (
|
||||||
InfluenceSpent,
|
InfluenceSpent,
|
||||||
TieResolved,
|
TieResolved,
|
||||||
)
|
)
|
||||||
from warchron.model.exception import ForbiddenOperation, RequiresConfirmation
|
from warchron.model.exception import (
|
||||||
|
ForbiddenOperation,
|
||||||
|
RequiresConfirmation,
|
||||||
|
DomainError,
|
||||||
|
)
|
||||||
from warchron.model.war_participant import WarParticipant
|
from warchron.model.war_participant import WarParticipant
|
||||||
from warchron.model.objective import Objective
|
from warchron.model.objective import Objective
|
||||||
from warchron.model.campaign_participant import CampaignParticipant
|
from warchron.model.campaign_participant import CampaignParticipant
|
||||||
|
|
@ -80,6 +84,10 @@ class War:
|
||||||
if ev.context_type == ContextType.BATTLE:
|
if ev.context_type == ContextType.BATTLE:
|
||||||
battle = self.get_battle(ev.context_id)
|
battle = self.get_battle(ev.context_id)
|
||||||
campaign = self.get_campaign_by_sector(battle.sector_id)
|
campaign = self.get_campaign_by_sector(battle.sector_id)
|
||||||
|
if not campaign:
|
||||||
|
raise DomainError(
|
||||||
|
f"No campaign found for sector {battle.sector_id}"
|
||||||
|
)
|
||||||
round = campaign.get_round_by_battle(ev.context_id)
|
round = campaign.get_round_by_battle(ev.context_id)
|
||||||
round.is_over = False
|
round.is_over = False
|
||||||
elif ev.context_type == ContextType.CAMPAIGN:
|
elif ev.context_type == ContextType.CAMPAIGN:
|
||||||
|
|
@ -313,12 +321,12 @@ class War:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# TODO replace multiloops by internal has_* method
|
# TODO replace multiloops by internal has_* method
|
||||||
def get_campaign_by_sector(self, sector_id: str) -> Campaign:
|
def get_campaign_by_sector(self, sector_id: str) -> Campaign | None:
|
||||||
for camp in self.campaigns:
|
for camp in self.campaigns:
|
||||||
for sect in camp.sectors.values():
|
for sect in camp.sectors.values():
|
||||||
if sect.id == sector_id:
|
if sect.id == sector_id:
|
||||||
return camp
|
return camp
|
||||||
raise KeyError(f"Sector {sector_id} not found in any Campaign")
|
return None
|
||||||
|
|
||||||
def get_campaign_by_campaign_participant(
|
def get_campaign_by_campaign_participant(
|
||||||
self, participant_id: str
|
self, participant_id: str
|
||||||
|
|
@ -396,6 +404,8 @@ class War:
|
||||||
description: str | None,
|
description: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
camp = self.get_campaign_by_sector(sector_id)
|
camp = self.get_campaign_by_sector(sector_id)
|
||||||
|
if not camp:
|
||||||
|
raise DomainError(f"No campaign found for sector {sector_id}")
|
||||||
camp.update_sector(
|
camp.update_sector(
|
||||||
sector_id,
|
sector_id,
|
||||||
name=name,
|
name=name,
|
||||||
|
|
@ -409,6 +419,8 @@ class War:
|
||||||
|
|
||||||
def remove_sector(self, sector_id: str) -> None:
|
def remove_sector(self, sector_id: str) -> None:
|
||||||
camp = self.get_campaign_by_sector(sector_id)
|
camp = self.get_campaign_by_sector(sector_id)
|
||||||
|
if not camp:
|
||||||
|
raise DomainError(f"No campaign found for sector {sector_id}")
|
||||||
camp.remove_sector(sector_id)
|
camp.remove_sector(sector_id)
|
||||||
|
|
||||||
# Campaign participant methods
|
# Campaign participant methods
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class TieDialog(QDialog):
|
||||||
self.ui: Ui_tieDialog = Ui_tieDialog()
|
self.ui: Ui_tieDialog = Ui_tieDialog()
|
||||||
self.ui.setupUi(self) # type: ignore
|
self.ui.setupUi(self) # type: ignore
|
||||||
self.setWindowIcon(Icons.get(IconName.WARCHRONICO))
|
self.setWindowIcon(Icons.get(IconName.WARCHRONICO))
|
||||||
self.ui.tieContext.setText(self._get_context_title(context_type, context_name))
|
self.ui.tieContext.setText(context_name)
|
||||||
grid = self.ui.playersGridLayout
|
grid = self.ui.playersGridLayout
|
||||||
icon_path = (RESOURCES_DIR / Icons._paths[IconName.TOKENS]).as_posix()
|
icon_path = (RESOURCES_DIR / Icons._paths[IconName.TOKENS]).as_posix()
|
||||||
token_html = (
|
token_html = (
|
||||||
|
|
@ -71,17 +71,3 @@ class TieDialog(QDialog):
|
||||||
|
|
||||||
def get_bids(self) -> Dict[str, bool]:
|
def get_bids(self) -> Dict[str, bool]:
|
||||||
return {pid: checkbox.isChecked() for pid, checkbox in self._checkboxes.items()}
|
return {pid: checkbox.isChecked() for pid, checkbox in self._checkboxes.items()}
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_context_title(
|
|
||||||
context_type: ContextType, context_name: str | None = None
|
|
||||||
) -> str:
|
|
||||||
if context_name:
|
|
||||||
return f"{context_name} tie"
|
|
||||||
titles = {
|
|
||||||
ContextType.BATTLE: "Battle tie",
|
|
||||||
ContextType.CAMPAIGN: "Campaign tie",
|
|
||||||
ContextType.WAR: "War tie",
|
|
||||||
ContextType.CHOICE: "Choice tie",
|
|
||||||
}
|
|
||||||
return titles.get(context_type, "Tie")
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue