wip close round/campaign/war + refacto json None
This commit is contained in:
parent
4c8086caf4
commit
6cbb7c6534
26 changed files with 474 additions and 108 deletions
|
|
@ -28,3 +28,10 @@ class RefreshScope(Enum):
|
||||||
CAMPAIGN_DETAILS = auto()
|
CAMPAIGN_DETAILS = auto()
|
||||||
ROUND_DETAILS = auto()
|
ROUND_DETAILS = auto()
|
||||||
CURRENT_SELECTION_DETAILS = auto()
|
CURRENT_SELECTION_DETAILS = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class ContextType(StrEnum):
|
||||||
|
WAR = "war"
|
||||||
|
CAMPAIGN = "campaign"
|
||||||
|
CHOICE = "choice"
|
||||||
|
BATTLE = "battle"
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,13 @@ class AppController:
|
||||||
self.view.influenceToken.toggled.connect(self.wars.set_influence_token)
|
self.view.influenceToken.toggled.connect(self.wars.set_influence_token)
|
||||||
self.view.addObjectiveBtn.clicked.connect(self.wars.add_objective)
|
self.view.addObjectiveBtn.clicked.connect(self.wars.add_objective)
|
||||||
self.view.addWarParticipantBtn.clicked.connect(self.wars.add_war_participant)
|
self.view.addWarParticipantBtn.clicked.connect(self.wars.add_war_participant)
|
||||||
|
self.view.endWarBtn.clicked.connect(self.wars.close_war)
|
||||||
self.view.addSectorBtn.clicked.connect(self.campaigns.add_sector)
|
self.view.addSectorBtn.clicked.connect(self.campaigns.add_sector)
|
||||||
self.view.addCampaignParticipantBtn.clicked.connect(
|
self.view.addCampaignParticipantBtn.clicked.connect(
|
||||||
self.campaigns.add_campaign_participant
|
self.campaigns.add_campaign_participant
|
||||||
)
|
)
|
||||||
|
self.view.endCampaignBtn.clicked.connect(self.campaigns.close_campaign)
|
||||||
|
self.view.endRoundBtn.clicked.connect(self.rounds.close_round)
|
||||||
self.view.on_edit_item = self.edit_item
|
self.view.on_edit_item = self.edit_item
|
||||||
self.view.on_delete_item = self.delete_item
|
self.view.on_delete_item = self.delete_item
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from warchron.controller.dtos import (
|
||||||
SectorDTO,
|
SectorDTO,
|
||||||
RoundDTO,
|
RoundDTO,
|
||||||
)
|
)
|
||||||
|
from warchron.model.closure_service import ClosureService
|
||||||
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
|
||||||
|
|
@ -50,6 +51,7 @@ class CampaignController:
|
||||||
for p in camp_parts
|
for p in camp_parts
|
||||||
]
|
]
|
||||||
self.app.view.display_campaign_participants(participants_for_display)
|
self.app.view.display_campaign_participants(participants_for_display)
|
||||||
|
self.app.view.endCampaignBtn.setEnabled(not camp.is_over)
|
||||||
|
|
||||||
def _validate_campaign_inputs(self, name: str, month: int) -> bool:
|
def _validate_campaign_inputs(self, name: str, month: int) -> bool:
|
||||||
if not name.strip():
|
if not name.strip():
|
||||||
|
|
@ -99,6 +101,28 @@ class CampaignController:
|
||||||
return
|
return
|
||||||
self.app.model.update_campaign(campaign_id, name=name, month=month)
|
self.app.model.update_campaign(campaign_id, name=name, month=month)
|
||||||
|
|
||||||
|
def close_campaign(self) -> None:
|
||||||
|
campaign_id = self.app.navigation.selected_campaign_id
|
||||||
|
if not campaign_id:
|
||||||
|
return
|
||||||
|
camp = self.app.model.get_campaign(campaign_id)
|
||||||
|
if camp.is_over:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
ties = ClosureService.close_campaign(camp)
|
||||||
|
except RuntimeError as e:
|
||||||
|
QMessageBox.warning(self.app.view, "Cannot close campaign", str(e))
|
||||||
|
return
|
||||||
|
if ties:
|
||||||
|
QMessageBox.information(
|
||||||
|
self.app.view,
|
||||||
|
"Tie detected",
|
||||||
|
"Campaign has unresolved ties.",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
self.app.is_dirty = True
|
||||||
|
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
|
||||||
|
|
||||||
# Campaign participant methods
|
# Campaign participant methods
|
||||||
|
|
||||||
def add_campaign_participant(self) -> None:
|
def add_campaign_participant(self) -> None:
|
||||||
|
|
@ -148,7 +172,12 @@ class CampaignController:
|
||||||
# Sector methods
|
# Sector methods
|
||||||
|
|
||||||
def _validate_sector_inputs(
|
def _validate_sector_inputs(
|
||||||
self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str
|
self,
|
||||||
|
name: str,
|
||||||
|
round_id: str | None,
|
||||||
|
major_id: str | None,
|
||||||
|
minor_id: str | None,
|
||||||
|
influence_id: str | None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
if not name.strip():
|
if not name.strip():
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class WarDTO:
|
||||||
class ObjectiveDTO:
|
class ObjectiveDTO:
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: str | None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True, slots=True)
|
||||||
|
|
@ -63,9 +63,9 @@ class SectorDTO:
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
round_index: int | None
|
round_index: int | None
|
||||||
major: str
|
major: str | None
|
||||||
minor: str
|
minor: str | None
|
||||||
influence: str
|
influence: str | None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -78,8 +78,8 @@ class RoundDTO:
|
||||||
class ChoiceDTO:
|
class ChoiceDTO:
|
||||||
id: str
|
id: str
|
||||||
participant_name: str
|
participant_name: str
|
||||||
priority_sector: str
|
priority_sector: str | None
|
||||||
secondary_sector: str
|
secondary_sector: str | None
|
||||||
comment: str | None
|
comment: str | None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -87,8 +87,8 @@ class ChoiceDTO:
|
||||||
class BattleDTO:
|
class BattleDTO:
|
||||||
id: str
|
id: str
|
||||||
sector_name: str
|
sector_name: str
|
||||||
player_1: str
|
player_1: str | None
|
||||||
player_2: str
|
player_2: str | None
|
||||||
winner: str | None
|
winner: str | None
|
||||||
score: str | None
|
score: str | None
|
||||||
victory_condition: str | None
|
victory_condition: str | None
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
from typing import List, TYPE_CHECKING
|
from typing import List, TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QDialog
|
from PyQt6.QtWidgets import QDialog, QMessageBox
|
||||||
|
|
||||||
from warchron.constants import ItemType, RefreshScope
|
from warchron.constants import ItemType, RefreshScope
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from warchron.controller.app_controller import AppController
|
from warchron.controller.app_controller import AppController
|
||||||
from warchron.controller.dtos import ParticipantOption, SectorDTO, ChoiceDTO, BattleDTO
|
from warchron.controller.dtos import ParticipantOption, SectorDTO, ChoiceDTO, BattleDTO
|
||||||
|
from warchron.model.closure_service import ClosureService
|
||||||
from warchron.view.choices_dialog import ChoicesDialog
|
from warchron.view.choices_dialog import ChoicesDialog
|
||||||
from warchron.view.battles_dialog import BattlesDialog
|
from warchron.view.battles_dialog import BattlesDialog
|
||||||
|
|
||||||
|
|
@ -92,6 +92,7 @@ class RoundController:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.app.view.display_round_battles(battles_for_display)
|
self.app.view.display_round_battles(battles_for_display)
|
||||||
|
self.app.view.endRoundBtn.setEnabled(not rnd.is_over)
|
||||||
|
|
||||||
def add_round(self) -> None:
|
def add_round(self) -> None:
|
||||||
if not self.app.navigation.selected_campaign_id:
|
if not self.app.navigation.selected_campaign_id:
|
||||||
|
|
@ -102,6 +103,28 @@ class RoundController:
|
||||||
RefreshScope.WARS_TREE, item_type=ItemType.ROUND, item_id=rnd.id
|
RefreshScope.WARS_TREE, item_type=ItemType.ROUND, item_id=rnd.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def close_round(self) -> None:
|
||||||
|
round_id = self.app.navigation.selected_round_id
|
||||||
|
if not round_id:
|
||||||
|
return
|
||||||
|
rnd = self.app.model.get_round(round_id)
|
||||||
|
if rnd.is_over:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
ties = ClosureService.close_round(rnd)
|
||||||
|
except RuntimeError as e:
|
||||||
|
QMessageBox.warning(self.app.view, "Cannot close round", str(e))
|
||||||
|
return
|
||||||
|
if ties:
|
||||||
|
QMessageBox.information(
|
||||||
|
self.app.view,
|
||||||
|
"Tie detected",
|
||||||
|
"Round has unresolved ties. Resolution system not implemented yet.",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
self.app.is_dirty = True
|
||||||
|
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
|
||||||
|
|
||||||
# Choice methods
|
# Choice methods
|
||||||
|
|
||||||
def edit_round_choice(self, choice_id: str) -> None:
|
def edit_round_choice(self, choice_id: str) -> None:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from warchron.controller.dtos import (
|
||||||
WarParticipantDTO,
|
WarParticipantDTO,
|
||||||
ObjectiveDTO,
|
ObjectiveDTO,
|
||||||
)
|
)
|
||||||
|
from warchron.model.closure_service import ClosureService
|
||||||
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
|
||||||
|
|
@ -44,6 +45,7 @@ class WarController:
|
||||||
for p in war_parts
|
for p in war_parts
|
||||||
]
|
]
|
||||||
self.app.view.display_war_participants(participants_for_display)
|
self.app.view.display_war_participants(participants_for_display)
|
||||||
|
self.app.view.endWarBtn.setEnabled(not war.is_over)
|
||||||
|
|
||||||
def _validate_war_inputs(self, name: str, year: int) -> bool:
|
def _validate_war_inputs(self, name: str, year: int) -> bool:
|
||||||
if not name.strip():
|
if not name.strip():
|
||||||
|
|
@ -86,6 +88,28 @@ class WarController:
|
||||||
return
|
return
|
||||||
self.app.model.update_war(war_id, name=name, year=year)
|
self.app.model.update_war(war_id, name=name, year=year)
|
||||||
|
|
||||||
|
def close_war(self) -> None:
|
||||||
|
war_id = self.app.navigation.selected_war_id
|
||||||
|
if not war_id:
|
||||||
|
return
|
||||||
|
war = self.app.model.get_war(war_id)
|
||||||
|
if war.is_over:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
ties = ClosureService.close_war(war)
|
||||||
|
except RuntimeError as e:
|
||||||
|
QMessageBox.warning(self.app.view, "Cannot close war", str(e))
|
||||||
|
return
|
||||||
|
if ties:
|
||||||
|
QMessageBox.information(
|
||||||
|
self.app.view,
|
||||||
|
"Tie detected",
|
||||||
|
"War has unresolved ties.",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
self.app.is_dirty = True
|
||||||
|
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
|
||||||
|
|
||||||
def set_major_value(self, value: int) -> None:
|
def set_major_value(self, value: int) -> None:
|
||||||
war_id = self.app.navigation.selected_war_id
|
war_id = self.app.navigation.selected_war_id
|
||||||
if not war_id:
|
if not war_id:
|
||||||
|
|
@ -109,7 +133,7 @@ class WarController:
|
||||||
|
|
||||||
# Objective methods
|
# Objective methods
|
||||||
|
|
||||||
def _validate_objective_inputs(self, name: str, description: str) -> bool:
|
def _validate_objective_inputs(self, name: str, description: str | None) -> bool:
|
||||||
if not name.strip():
|
if not name.strip():
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self.app.view, "Invalid name", "Objective name cannot be empty."
|
self.app.view, "Invalid name", "Objective name cannot be empty."
|
||||||
|
|
|
||||||
|
|
@ -40,26 +40,30 @@ class Battle:
|
||||||
def set_comment(self, new_comment: str | None) -> None:
|
def set_comment(self, new_comment: str | None) -> None:
|
||||||
self.comment = new_comment
|
self.comment = new_comment
|
||||||
|
|
||||||
|
# TODO improve draw detection
|
||||||
|
def is_draw(self) -> bool:
|
||||||
|
return self.winner_id is None and self.score is not None
|
||||||
|
|
||||||
def toDict(self) -> Dict[str, Any]:
|
def toDict(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"sector_id": self.sector_id,
|
"sector_id": self.sector_id,
|
||||||
"player_1_id": self.player_1_id,
|
"player_1_id": self.player_1_id or None,
|
||||||
"player_2_id": self.player_2_id,
|
"player_2_id": self.player_2_id or None,
|
||||||
"winner_id": self.winner_id,
|
"winner_id": self.winner_id or None,
|
||||||
"score": self.score,
|
"score": self.score or None,
|
||||||
"victory_condition": self.victory_condition,
|
"victory_condition": self.victory_condition or None,
|
||||||
"comment": self.comment,
|
"comment": self.comment or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fromDict(data: Dict[str, Any]) -> Battle:
|
def fromDict(data: Dict[str, Any]) -> Battle:
|
||||||
battle = Battle(
|
battle = Battle(
|
||||||
data["sector_id"],
|
data["sector_id"],
|
||||||
data.get("player_1_id"),
|
data.get("player_1_id") or None,
|
||||||
data.get("player_2_id"),
|
data.get("player_2_id") or None,
|
||||||
)
|
)
|
||||||
battle.winner_id = data.get("winner_id")
|
battle.winner_id = data.get("winner_id") or None
|
||||||
battle.score = data.get("score")
|
battle.score = data.get("score") or None
|
||||||
battle.victory_condition = data.get("victory_condition")
|
battle.victory_condition = data.get("victory_condition") or None
|
||||||
battle.comment = data.get("comment")
|
battle.comment = data.get("comment") or None
|
||||||
return battle
|
return battle
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,12 @@ class Campaign:
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_sector(
|
def add_sector(
|
||||||
self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str
|
self,
|
||||||
|
name: str,
|
||||||
|
round_id: str | None,
|
||||||
|
major_id: str | None,
|
||||||
|
minor_id: str | None,
|
||||||
|
influence_id: str | None,
|
||||||
) -> Sector:
|
) -> Sector:
|
||||||
sect = Sector(name, round_id, major_id, minor_id, influence_id)
|
sect = Sector(name, round_id, major_id, minor_id, influence_id)
|
||||||
self.sectors[sect.id] = sect
|
self.sectors[sect.id] = sect
|
||||||
|
|
@ -168,10 +173,10 @@ class Campaign:
|
||||||
sector_id: str,
|
sector_id: str,
|
||||||
*,
|
*,
|
||||||
name: str,
|
name: str,
|
||||||
round_id: str,
|
round_id: str | None,
|
||||||
major_id: str,
|
major_id: str | None,
|
||||||
minor_id: str,
|
minor_id: str | None,
|
||||||
influence_id: str,
|
influence_id: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
sect = self.get_sector(sector_id)
|
sect = self.get_sector(sector_id)
|
||||||
old_round_id = sect.round_id
|
old_round_id = sect.round_id
|
||||||
|
|
@ -308,6 +313,9 @@ class Campaign:
|
||||||
|
|
||||||
# Battle methods
|
# Battle methods
|
||||||
|
|
||||||
|
def all_rounds_finished(self) -> bool:
|
||||||
|
return all(r.is_over for r in self.rounds)
|
||||||
|
|
||||||
def create_battle(self, round_id: str, sector_id: str) -> Battle:
|
def create_battle(self, round_id: str, sector_id: str) -> Battle:
|
||||||
rnd = self.get_round(round_id)
|
rnd = self.get_round(round_id)
|
||||||
return rnd.create_battle(sector_id)
|
return rnd.create_battle(sector_id)
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,17 @@ class Choice:
|
||||||
def toDict(self) -> Dict[str, Any]:
|
def toDict(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"participant_id": self.participant_id,
|
"participant_id": self.participant_id,
|
||||||
"priority_sector_id": self.priority_sector_id,
|
"priority_sector_id": self.priority_sector_id or None,
|
||||||
"secondary_sector_id": self.secondary_sector_id,
|
"secondary_sector_id": self.secondary_sector_id or None,
|
||||||
"comment": self.comment,
|
"comment": self.comment or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fromDict(data: Dict[str, Any]) -> Choice:
|
def fromDict(data: Dict[str, Any]) -> Choice:
|
||||||
choice = Choice(
|
choice = Choice(
|
||||||
data["participant_id"],
|
data["participant_id"],
|
||||||
data.get("priority_sector_id"),
|
data.get("priority_sector_id") or None,
|
||||||
data.get("secondary_sector_id"),
|
data.get("secondary_sector_id") or None,
|
||||||
)
|
)
|
||||||
choice.comment = data.get("comment")
|
choice.comment = data.get("comment") or None
|
||||||
return choice
|
return choice
|
||||||
|
|
|
||||||
83
src/warchron/model/closure_service.py
Normal file
83
src/warchron/model/closure_service.py
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from warchron.constants import ContextType
|
||||||
|
from warchron.model.tie_manager import ResolutionContext
|
||||||
|
from warchron.model.war import War
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
|
from warchron.model.round import Round
|
||||||
|
|
||||||
|
|
||||||
|
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 []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def close_campaign(campaign: Campaign) -> List[ResolutionContext]:
|
||||||
|
if not campaign.all_rounds_finished():
|
||||||
|
raise RuntimeError("All rounds must be finished to close their campaign")
|
||||||
|
ties: List[ResolutionContext] = []
|
||||||
|
# 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 []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def close_war(war: War) -> List[ResolutionContext]:
|
||||||
|
if not war.all_campaigns_finished():
|
||||||
|
raise RuntimeError("All campaigns must be finished to close their war")
|
||||||
|
ties: List[ResolutionContext] = []
|
||||||
|
# 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 []
|
||||||
23
src/warchron/model/influence_service.py
Normal file
23
src/warchron/model/influence_service.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
from warchron.model.war import War
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
|
from warchron.model.battle import Battle
|
||||||
|
from warchron.model.war_event import InfluenceGained
|
||||||
|
|
||||||
|
|
||||||
|
class InfluenceService:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def apply_battle_result(war: War, campaign: Campaign, battle: Battle) -> None:
|
||||||
|
if battle.winner_id is None:
|
||||||
|
return
|
||||||
|
sector = campaign.sectors[battle.sector_id]
|
||||||
|
# if sector grants influence
|
||||||
|
if sector.influence_objective_id and war.influence_token:
|
||||||
|
participant = war.participants[battle.winner_id]
|
||||||
|
participant.events.append(
|
||||||
|
InfluenceGained(
|
||||||
|
participant_id=participant.id,
|
||||||
|
amount=1,
|
||||||
|
source=f"battle:{battle.sector_id}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -182,7 +182,9 @@ class Model:
|
||||||
|
|
||||||
# Objective methods
|
# Objective methods
|
||||||
|
|
||||||
def add_objective(self, war_id: str, name: str, description: str) -> Objective:
|
def add_objective(
|
||||||
|
self, war_id: str, name: str, description: str | None
|
||||||
|
) -> Objective:
|
||||||
war = self.get_war(war_id)
|
war = self.get_war(war_id)
|
||||||
return war.add_objective(name, description)
|
return war.add_objective(name, description)
|
||||||
|
|
||||||
|
|
@ -195,7 +197,7 @@ class Model:
|
||||||
raise KeyError("Objective not found")
|
raise KeyError("Objective not found")
|
||||||
|
|
||||||
def update_objective(
|
def update_objective(
|
||||||
self, objective_id: str, *, name: str, description: str
|
self, objective_id: str, *, name: str, description: str | None
|
||||||
) -> None:
|
) -> None:
|
||||||
war = self.get_war_by_objective(objective_id)
|
war = self.get_war_by_objective(objective_id)
|
||||||
war.update_objective(objective_id, name=name, description=description)
|
war.update_objective(objective_id, name=name, description=description)
|
||||||
|
|
@ -229,6 +231,11 @@ class Model:
|
||||||
def get_player_from_war_participant(self, war_part: WarParticipant) -> Player:
|
def get_player_from_war_participant(self, war_part: WarParticipant) -> Player:
|
||||||
return self.get_player(war_part.player_id)
|
return self.get_player(war_part.player_id)
|
||||||
|
|
||||||
|
def get_participant_name(self, participant_id: str) -> str:
|
||||||
|
war = self.get_war_by_war_participant(participant_id)
|
||||||
|
war_part = war.get_war_participant(participant_id)
|
||||||
|
return self.players[war_part.player_id].name
|
||||||
|
|
||||||
def update_war_participant(self, participant_id: str, *, faction: str) -> None:
|
def update_war_participant(self, participant_id: str, *, faction: str) -> None:
|
||||||
war = self.get_war_by_war_participant(participant_id)
|
war = self.get_war_by_war_participant(participant_id)
|
||||||
war.update_war_participant(participant_id, faction=faction)
|
war.update_war_participant(participant_id, faction=faction)
|
||||||
|
|
@ -290,10 +297,10 @@ class Model:
|
||||||
self,
|
self,
|
||||||
campaign_id: str,
|
campaign_id: str,
|
||||||
name: str,
|
name: str,
|
||||||
round_id: str,
|
round_id: str | None,
|
||||||
major_id: str,
|
major_id: str | None,
|
||||||
minor_id: str,
|
minor_id: str | None,
|
||||||
influence_id: str,
|
influence_id: str | None,
|
||||||
) -> Sector:
|
) -> Sector:
|
||||||
camp = self.get_campaign(campaign_id)
|
camp = self.get_campaign(campaign_id)
|
||||||
return camp.add_sector(name, round_id, major_id, minor_id, influence_id)
|
return camp.add_sector(name, round_id, major_id, minor_id, influence_id)
|
||||||
|
|
@ -312,10 +319,10 @@ class Model:
|
||||||
sector_id: str,
|
sector_id: str,
|
||||||
*,
|
*,
|
||||||
name: str,
|
name: str,
|
||||||
round_id: str,
|
round_id: str | None,
|
||||||
major_id: str,
|
major_id: str | None,
|
||||||
minor_id: str,
|
minor_id: str | None,
|
||||||
influence_id: str,
|
influence_id: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
war = self.get_war_by_sector(sector_id)
|
war = self.get_war_by_sector(sector_id)
|
||||||
war.update_sector(
|
war.update_sector(
|
||||||
|
|
@ -343,11 +350,6 @@ class Model:
|
||||||
camp = self.get_campaign(camp_id)
|
camp = self.get_campaign(camp_id)
|
||||||
return camp.add_campaign_participant(player_id, leader, theme)
|
return camp.add_campaign_participant(player_id, leader, theme)
|
||||||
|
|
||||||
def get_participant_name(self, participant_id: str) -> str:
|
|
||||||
war = self.get_war_by_war_participant(participant_id)
|
|
||||||
war_part = war.get_war_participant(participant_id)
|
|
||||||
return self.players[war_part.player_id].name
|
|
||||||
|
|
||||||
# TODO replace multiloops by internal has_* method
|
# TODO replace multiloops by internal has_* method
|
||||||
def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
|
def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
|
||||||
for war in self.wars.values():
|
for war in self.wars.values():
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ from uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
class Objective:
|
class Objective:
|
||||||
def __init__(self, name: str, description: str):
|
def __init__(self, name: str, description: str | None):
|
||||||
self.id: str = str(uuid4())
|
self.id: str = str(uuid4())
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
self.description: str = description
|
self.description: str | None = description
|
||||||
|
|
||||||
def set_id(self, new_id: str) -> None:
|
def set_id(self, new_id: str) -> None:
|
||||||
self.id = new_id
|
self.id = new_id
|
||||||
|
|
@ -15,18 +15,18 @@ class Objective:
|
||||||
def set_name(self, new_name: str) -> None:
|
def set_name(self, new_name: str) -> None:
|
||||||
self.name = new_name
|
self.name = new_name
|
||||||
|
|
||||||
def set_description(self, new_description: str) -> None:
|
def set_description(self, new_description: str | None) -> None:
|
||||||
self.description = new_description
|
self.description = new_description
|
||||||
|
|
||||||
def toDict(self) -> Dict[str, Any]:
|
def toDict(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"description": self.description,
|
"description": self.description or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fromDict(data: Dict[str, Any]) -> Objective:
|
def fromDict(data: Dict[str, Any]) -> Objective:
|
||||||
obj = Objective(data["name"], data["description"])
|
obj = Objective(data["name"], data["description"] or None)
|
||||||
obj.set_id(data["id"])
|
obj.set_id(data["id"])
|
||||||
return obj
|
return obj
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ class Round:
|
||||||
for bat in self.battles.values()
|
for bat in self.battles.values()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def all_battles_finished(self) -> bool:
|
||||||
|
return all(
|
||||||
|
b.winner_id is not None or b.is_draw() for b in self.battles.values()
|
||||||
|
)
|
||||||
|
|
||||||
def create_battle(self, sector_id: str) -> Battle:
|
def create_battle(self, sector_id: str) -> Battle:
|
||||||
if sector_id not in self.battles:
|
if sector_id not in self.battles:
|
||||||
battle = Battle(sector_id=sector_id, player_1_id=None, player_2_id=None)
|
battle = Battle(sector_id=sector_id, player_1_id=None, player_2_id=None)
|
||||||
|
|
|
||||||
39
src/warchron/model/score_service.py
Normal file
39
src/warchron/model/score_service.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from warchron.model.war import War
|
||||||
|
|
||||||
|
|
||||||
|
class ScoreService:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def compute_victory_points_for_participant(war: "War", participant_id: str) -> int:
|
||||||
|
total = 0
|
||||||
|
for campaign in war.campaigns:
|
||||||
|
for round_ in campaign.rounds:
|
||||||
|
for battle in round_.battles.values():
|
||||||
|
if battle.winner_id == participant_id:
|
||||||
|
sector = campaign.sectors[battle.sector_id]
|
||||||
|
if sector.major_objective_id:
|
||||||
|
total += war.major_value
|
||||||
|
if sector.minor_objective_id:
|
||||||
|
total += war.minor_value
|
||||||
|
return total
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def compute_narrative_points_for_participant(
|
||||||
|
war: "War", participant_id: str
|
||||||
|
) -> dict[str, int]:
|
||||||
|
totals: dict[str, int] = {}
|
||||||
|
for obj_id in war.objectives:
|
||||||
|
totals[obj_id] = 0
|
||||||
|
for campaign in war.campaigns:
|
||||||
|
for round_ in campaign.rounds:
|
||||||
|
for battle in round_.battles.values():
|
||||||
|
if battle.winner_id == participant_id:
|
||||||
|
sector = campaign.sectors[battle.sector_id]
|
||||||
|
if sector.major_objective_id:
|
||||||
|
totals[sector.major_objective_id] += war.major_value
|
||||||
|
if sector.minor_objective_id:
|
||||||
|
totals[sector.minor_objective_id] += war.minor_value
|
||||||
|
return totals
|
||||||
|
|
@ -14,7 +14,7 @@ class Sector:
|
||||||
):
|
):
|
||||||
self.id: str = str(uuid4())
|
self.id: str = str(uuid4())
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
self.round_id: str | None = round_id
|
self.round_id: str | None = round_id # ref to Campaign.rounds
|
||||||
self.major_objective_id: str | None = major_id # ref to War.objectives
|
self.major_objective_id: str | None = major_id # ref to War.objectives
|
||||||
self.minor_objective_id: str | None = minor_id # ref to War.objectives
|
self.minor_objective_id: str | None = minor_id # ref to War.objectives
|
||||||
self.influence_objective_id: str | None = influence_id # ref to War.objectives
|
self.influence_objective_id: str | None = influence_id # ref to War.objectives
|
||||||
|
|
@ -27,16 +27,16 @@ class Sector:
|
||||||
def set_name(self, new_name: str) -> None:
|
def set_name(self, new_name: str) -> None:
|
||||||
self.name = new_name
|
self.name = new_name
|
||||||
|
|
||||||
def set_round(self, new_round_id: str) -> None:
|
def set_round(self, new_round_id: str | None) -> None:
|
||||||
self.round_id = new_round_id
|
self.round_id = new_round_id
|
||||||
|
|
||||||
def set_major(self, new_major_id: str) -> None:
|
def set_major(self, new_major_id: str | None) -> None:
|
||||||
self.major_objective_id = new_major_id
|
self.major_objective_id = new_major_id
|
||||||
|
|
||||||
def set_minor(self, new_minor_id: str) -> None:
|
def set_minor(self, new_minor_id: str | None) -> None:
|
||||||
self.minor_objective_id = new_minor_id
|
self.minor_objective_id = new_minor_id
|
||||||
|
|
||||||
def set_influence(self, new_influence_id: str) -> None:
|
def set_influence(self, new_influence_id: str | None) -> None:
|
||||||
self.influence_objective_id = new_influence_id
|
self.influence_objective_id = new_influence_id
|
||||||
|
|
||||||
def toDict(self) -> Dict[str, Any]:
|
def toDict(self) -> Dict[str, Any]:
|
||||||
|
|
@ -44,11 +44,11 @@ class Sector:
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"round_id": self.round_id,
|
"round_id": self.round_id,
|
||||||
"major_objective_id": self.major_objective_id,
|
"major_objective_id": self.major_objective_id or None,
|
||||||
"minor_objective_id": self.minor_objective_id,
|
"minor_objective_id": self.minor_objective_id or None,
|
||||||
"influence_objective_id": self.influence_objective_id,
|
"influence_objective_id": self.influence_objective_id or None,
|
||||||
"mission": self.mission,
|
"mission": self.mission or None,
|
||||||
"description": self.description,
|
"description": self.description or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -56,11 +56,11 @@ class Sector:
|
||||||
sec = Sector(
|
sec = Sector(
|
||||||
data["name"],
|
data["name"],
|
||||||
data["round_id"],
|
data["round_id"],
|
||||||
data.get("major_objective_id"),
|
data.get("major_objective_id") or None,
|
||||||
data.get("minor_objective_id"),
|
data.get("minor_objective_id") or None,
|
||||||
data.get("influence_objective_id"),
|
data.get("influence_objective_id") or None,
|
||||||
)
|
)
|
||||||
sec.set_id(data["id"])
|
sec.set_id(data["id"])
|
||||||
sec.mission = data.get("mission")
|
sec.mission = data.get("mission") or None
|
||||||
sec.description = data.get("description")
|
sec.description = data.get("description") or None
|
||||||
return sec
|
return sec
|
||||||
|
|
|
||||||
46
src/warchron/model/tie_manager.py
Normal file
46
src/warchron/model/tie_manager.py
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
from warchron.model.war import War
|
||||||
|
from warchron.model.war_event import InfluenceSpent
|
||||||
|
|
||||||
|
|
||||||
|
class ResolutionContext:
|
||||||
|
def __init__(self, context_type: str, context_id: str, participant_ids: list[str]):
|
||||||
|
self.context_type = context_type
|
||||||
|
self.context_id = context_id
|
||||||
|
self.participant_ids = participant_ids
|
||||||
|
|
||||||
|
self.current_bids: dict[str, int] = {}
|
||||||
|
self.round_index: int = 0
|
||||||
|
self.is_resolved: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class TieResolver:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve(
|
||||||
|
war: War,
|
||||||
|
context: ResolutionContext,
|
||||||
|
bids: dict[str, int],
|
||||||
|
) -> str | None:
|
||||||
|
# verify available token for each player
|
||||||
|
for pid, amount in bids.items():
|
||||||
|
participant = war.participants[pid]
|
||||||
|
if participant.influence_tokens() < amount:
|
||||||
|
raise ValueError("Not enough influence tokens")
|
||||||
|
# apply spending
|
||||||
|
for pid, amount in bids.items():
|
||||||
|
if amount > 0:
|
||||||
|
war.participants[pid].events.append(
|
||||||
|
InfluenceSpent(
|
||||||
|
participant_id=pid,
|
||||||
|
amount=amount,
|
||||||
|
context=context.context_type,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# determine winner
|
||||||
|
max_bid = max(bids.values())
|
||||||
|
winners = [pid for pid, b in bids.items() if b == max_bid]
|
||||||
|
if len(winners) == 1:
|
||||||
|
context.is_resolved = True
|
||||||
|
return winners[0]
|
||||||
|
# persisting tie → None
|
||||||
|
return None
|
||||||
|
|
@ -86,7 +86,7 @@ class War:
|
||||||
|
|
||||||
# Objective methods
|
# Objective methods
|
||||||
|
|
||||||
def add_objective(self, name: str, description: str) -> Objective:
|
def add_objective(self, name: str, description: str | None) -> Objective:
|
||||||
obj = Objective(name, description)
|
obj = Objective(name, description)
|
||||||
self.objectives[obj.id] = obj
|
self.objectives[obj.id] = obj
|
||||||
return obj
|
return obj
|
||||||
|
|
@ -104,7 +104,7 @@ class War:
|
||||||
return obj.name if obj else ""
|
return obj.name if obj else ""
|
||||||
|
|
||||||
def update_objective(
|
def update_objective(
|
||||||
self, objective_id: str, *, name: str, description: str
|
self, objective_id: str, *, name: str, description: str | None
|
||||||
) -> None:
|
) -> None:
|
||||||
obj = self.get_objective(objective_id)
|
obj = self.get_objective(objective_id)
|
||||||
obj.set_name(name)
|
obj.set_name(name)
|
||||||
|
|
@ -173,6 +173,9 @@ class War:
|
||||||
def get_default_campaign_values(self) -> Dict[str, Any]:
|
def get_default_campaign_values(self) -> Dict[str, Any]:
|
||||||
return {"month": datetime.now().month}
|
return {"month": datetime.now().month}
|
||||||
|
|
||||||
|
def all_campaigns_finished(self) -> bool:
|
||||||
|
return all(c.is_over for c in self.campaigns)
|
||||||
|
|
||||||
def add_campaign(self, name: str, month: int | None = None) -> Campaign:
|
def add_campaign(self, name: str, month: int | None = None) -> Campaign:
|
||||||
if month is None:
|
if month is None:
|
||||||
month = self.get_default_campaign_values()["month"]
|
month = self.get_default_campaign_values()["month"]
|
||||||
|
|
@ -247,10 +250,10 @@ class War:
|
||||||
sector_id: str,
|
sector_id: str,
|
||||||
*,
|
*,
|
||||||
name: str,
|
name: str,
|
||||||
round_id: str,
|
round_id: str | None,
|
||||||
major_id: str,
|
major_id: str | None,
|
||||||
minor_id: str,
|
minor_id: str | None,
|
||||||
influence_id: str,
|
influence_id: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
camp = self.get_campaign_by_sector(sector_id)
|
camp = self.get_campaign_by_sector(sector_id)
|
||||||
camp.update_sector(
|
camp.update_sector(
|
||||||
|
|
|
||||||
30
src/warchron/model/war_event.py
Normal file
30
src/warchron/model/war_event.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
|
class WarEvent:
|
||||||
|
def __init__(self, participant_id: str):
|
||||||
|
self.id: str = str(uuid4())
|
||||||
|
self.participant_id: str = participant_id
|
||||||
|
self.timestamp: datetime = datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
class TieResolved(WarEvent):
|
||||||
|
def __init__(self, participant_id: str, context_type: str, context_id: str):
|
||||||
|
super().__init__(participant_id)
|
||||||
|
self.context_type = context_type # battle, round, campaign, war
|
||||||
|
self.context_id = context_id
|
||||||
|
|
||||||
|
|
||||||
|
class InfluenceGained(WarEvent):
|
||||||
|
def __init__(self, participant_id: str, amount: int, source: str):
|
||||||
|
super().__init__(participant_id)
|
||||||
|
self.amount = amount
|
||||||
|
self.source = source # "battle", "tie_resolution", etc.
|
||||||
|
|
||||||
|
|
||||||
|
class InfluenceSpent(WarEvent):
|
||||||
|
def __init__(self, participant_id: str, amount: int, context: str):
|
||||||
|
super().__init__(participant_id)
|
||||||
|
self.amount = amount
|
||||||
|
self.context = context # "battle_tie", "campaign_tie", etc.
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from warchron.model.war import War
|
||||||
|
from warchron.model.war_event import WarEvent, InfluenceSpent, InfluenceGained
|
||||||
|
from warchron.model.score_service import ScoreService
|
||||||
|
|
||||||
|
|
||||||
class WarParticipant:
|
class WarParticipant:
|
||||||
|
|
@ -8,6 +14,7 @@ class WarParticipant:
|
||||||
self.id: str = str(uuid4())
|
self.id: str = str(uuid4())
|
||||||
self.player_id: str = player_id # ref to Model.players
|
self.player_id: str = player_id # ref to Model.players
|
||||||
self.faction: str = faction
|
self.faction: str = faction
|
||||||
|
self.events: list[WarEvent] = []
|
||||||
|
|
||||||
def set_id(self, new_id: str) -> None:
|
def set_id(self, new_id: str) -> None:
|
||||||
self.id = new_id
|
self.id = new_id
|
||||||
|
|
@ -33,3 +40,16 @@ class WarParticipant:
|
||||||
)
|
)
|
||||||
part.set_id(data["id"])
|
part.set_id(data["id"])
|
||||||
return part
|
return part
|
||||||
|
|
||||||
|
# Computed properties
|
||||||
|
|
||||||
|
def influence_tokens(self) -> int:
|
||||||
|
gained = sum(e.amount for e in self.events if isinstance(e, InfluenceGained))
|
||||||
|
spent = sum(e.amount for e in self.events if isinstance(e, InfluenceSpent))
|
||||||
|
return gained - spent
|
||||||
|
|
||||||
|
def victory_points(self, war: "War") -> int:
|
||||||
|
return ScoreService.compute_victory_points_for_participant(war, self.id)
|
||||||
|
|
||||||
|
def narrative_points(self, war: "War") -> Dict[str, int]:
|
||||||
|
return ScoreService.compute_narrative_points_for_participant(war, self.id)
|
||||||
|
|
|
||||||
|
|
@ -49,20 +49,26 @@ class BattlesDialog(QDialog):
|
||||||
def get_sector_id(self) -> str:
|
def get_sector_id(self) -> str:
|
||||||
return cast(str, self.ui.sectorComboBox.currentData())
|
return cast(str, self.ui.sectorComboBox.currentData())
|
||||||
|
|
||||||
def get_player_1_id(self) -> str:
|
def get_player_1_id(self) -> str | None:
|
||||||
return cast(str, self.ui.player1ComboBox.currentData())
|
text = cast(str, self.ui.player1ComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_player_2_id(self) -> str:
|
def get_player_2_id(self) -> str | None:
|
||||||
return cast(str, self.ui.player2ComboBox.currentData())
|
text = cast(str, self.ui.player2ComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_winner_id(self) -> str:
|
def get_winner_id(self) -> str | None:
|
||||||
return cast(str, self.ui.winnerComboBox.currentData())
|
text = cast(str, self.ui.winnerComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_score(self) -> str:
|
def get_score(self) -> str | None:
|
||||||
return self.ui.score.text().strip()
|
text = self.ui.score.text().strip()
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_victory_condition(self) -> str:
|
def get_victory_condition(self) -> str | None:
|
||||||
return self.ui.victoryCondition.text().strip()
|
text = self.ui.victoryCondition.text().strip()
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_comment(self) -> str:
|
def get_comment(self) -> str | None:
|
||||||
return self.ui.battleComment.toPlainText().strip()
|
text = self.ui.battleComment.toPlainText().strip()
|
||||||
|
return text if text else None
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,14 @@ class ChoicesDialog(QDialog):
|
||||||
def get_participant_id(self) -> str:
|
def get_participant_id(self) -> str:
|
||||||
return cast(str, self.ui.playerComboBox.currentData())
|
return cast(str, self.ui.playerComboBox.currentData())
|
||||||
|
|
||||||
def get_priority_id(self) -> str:
|
def get_priority_id(self) -> str | None:
|
||||||
return cast(str, self.ui.priorityComboBox.currentData())
|
text = cast(str, self.ui.priorityComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_secondary_id(self) -> str:
|
def get_secondary_id(self) -> str | None:
|
||||||
return cast(str, self.ui.secondaryComboBox.currentData())
|
text = cast(str, self.ui.secondaryComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_comment(self) -> str:
|
def get_comment(self) -> str | None:
|
||||||
return self.ui.choiceComment.toPlainText().strip()
|
text = self.ui.choiceComment.toPlainText().strip()
|
||||||
|
return text if text else None
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,6 @@ class ObjectiveDialog(QDialog):
|
||||||
def get_objective_name(self) -> str:
|
def get_objective_name(self) -> str:
|
||||||
return self.ui.objectiveName.text().strip()
|
return self.ui.objectiveName.text().strip()
|
||||||
|
|
||||||
def get_objective_description(self) -> str:
|
def get_objective_description(self) -> str | None:
|
||||||
return self.ui.objectiveDescription.toPlainText().strip()
|
text = self.ui.objectiveDescription.toPlainText().strip()
|
||||||
|
return text if text else None
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,21 @@ class SectorDialog(QDialog):
|
||||||
def get_sector_name(self) -> str:
|
def get_sector_name(self) -> str:
|
||||||
return self.ui.sectorName.text().strip()
|
return self.ui.sectorName.text().strip()
|
||||||
|
|
||||||
def get_round_id(self) -> str:
|
def get_round_id(self) -> str | None:
|
||||||
return cast(str, self.ui.roundComboBox.currentData())
|
text = cast(str, self.ui.roundComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_major_id(self) -> str:
|
def get_major_id(self) -> str | None:
|
||||||
return cast(str, self.ui.majorComboBox.currentData())
|
text = cast(str, self.ui.majorComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_minor_id(self) -> str:
|
def get_minor_id(self) -> str | None:
|
||||||
return cast(str, self.ui.minorComboBox.currentData())
|
text = cast(str, self.ui.minorComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
def get_influence_id(self) -> str:
|
def get_influence_id(self) -> str | None:
|
||||||
return cast(str, self.ui.influenceComboBox.currentData())
|
text = cast(str, self.ui.influenceComboBox.currentData())
|
||||||
|
return text if text else None
|
||||||
|
|
||||||
|
|
||||||
|
# TODO fix mission + description missing
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,7 @@ class Ui_MainWindow(object):
|
||||||
spacerItem15 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
spacerItem15 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||||
self.horizontalLayout_13.addItem(spacerItem15)
|
self.horizontalLayout_13.addItem(spacerItem15)
|
||||||
self.resolvePairingBtn = QtWidgets.QPushButton(parent=self.pageRound)
|
self.resolvePairingBtn = QtWidgets.QPushButton(parent=self.pageRound)
|
||||||
self.resolvePairingBtn.setEnabled(True)
|
self.resolvePairingBtn.setEnabled(False)
|
||||||
self.resolvePairingBtn.setObjectName("resolvePairingBtn")
|
self.resolvePairingBtn.setObjectName("resolvePairingBtn")
|
||||||
self.horizontalLayout_13.addWidget(self.resolvePairingBtn)
|
self.horizontalLayout_13.addWidget(self.resolvePairingBtn)
|
||||||
self.verticalLayout_8.addLayout(self.horizontalLayout_13)
|
self.verticalLayout_8.addLayout(self.horizontalLayout_13)
|
||||||
|
|
@ -486,7 +486,7 @@ class Ui_MainWindow(object):
|
||||||
|
|
||||||
self.retranslateUi(MainWindow)
|
self.retranslateUi(MainWindow)
|
||||||
self.tabWidget.setCurrentIndex(1)
|
self.tabWidget.setCurrentIndex(1)
|
||||||
self.selectedDetailsStack.setCurrentIndex(1)
|
self.selectedDetailsStack.setCurrentIndex(3)
|
||||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
def retranslateUi(self, MainWindow):
|
def retranslateUi(self, MainWindow):
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStackedWidget" name="selectedDetailsStack">
|
<widget class="QStackedWidget" name="selectedDetailsStack">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="pageEmpty">
|
<widget class="QWidget" name="pageEmpty">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
|
@ -873,7 +873,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="resolvePairingBtn">
|
<widget class="QPushButton" name="resolvePairingBtn">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Resolve pairing</string>
|
<string>Resolve pairing</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue