Compare commits

...

2 commits

Author SHA1 Message Date
Maxime Réaux
701f6b3292 fix remove round used in sector 2026-02-06 11:13:29 +01:00
Maxime Réaux
6cd3a060c7 save/load participants, objectives, sectors, choices & battles 2026-02-06 09:59:54 +01:00
14 changed files with 167 additions and 20 deletions

View file

@ -62,7 +62,7 @@ class CampaignParticipantDTO:
class SectorDTO: class SectorDTO:
id: str id: str
name: str name: str
round_index: int round_index: int | None
major: str major: str
minor: str minor: str
influence: str influence: str
@ -71,7 +71,7 @@ class SectorDTO:
@dataclass @dataclass
class RoundDTO: class RoundDTO:
id: str id: str
index: int index: int | None
@dataclass(frozen=True, slots=True) @dataclass(frozen=True, slots=True)

View file

@ -1,3 +1,7 @@
from __future__ import annotations
from typing import Any, Dict
class Battle: class Battle:
def __init__( def __init__(
self, self,
@ -33,3 +37,27 @@ 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
def toDict(self) -> Dict[str, Any]:
return {
"sector_id": self.sector_id,
"player_1_id": self.player_1_id,
"player_2_id": self.player_2_id,
"winner_id": self.winner_id,
"score": self.score,
"victory_condition": self.victory_condition,
"comment": self.comment,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> Battle:
battle = Battle(
data["sector_id"],
data.get("player_1_id"),
data.get("player_2_id"),
)
battle.winner_id = data.get("winner_id")
battle.score = data.get("score")
battle.victory_condition = data.get("victory_condition")
battle.comment = data.get("comment")
return battle

View file

@ -40,7 +40,8 @@ class Campaign:
"id": self.id, "id": self.id,
"name": self.name, "name": self.name,
"month": self.month, "month": self.month,
# "participants" : self.participants, "participants": [p.toDict() for p in self.participants.values()],
"sectors": [s.toDict() for s in self.sectors.values()],
"rounds": [rnd.toDict() for rnd in self.rounds], "rounds": [rnd.toDict() for rnd in self.rounds],
"is_over": self.is_over, "is_over": self.is_over,
} }
@ -49,7 +50,12 @@ class Campaign:
def fromDict(data: Dict[str, Any]) -> Campaign: def fromDict(data: Dict[str, Any]) -> Campaign:
camp = Campaign(name=data["name"], month=data["month"]) camp = Campaign(name=data["name"], month=data["month"])
camp.set_id(data["id"]) camp.set_id(data["id"])
# camp.participants = data.get("participants", {}) for p in data.get("participants", []):
part = CampaignParticipant.fromDict(p)
camp.participants[part.id] = part
for s in data.get("sectors", []):
sec = Sector.fromDict(s)
camp.sectors[sec.id] = sec
for rnd_data in data.get("rounds", []): for rnd_data in data.get("rounds", []):
camp.rounds.append(Round.fromDict(rnd_data)) camp.rounds.append(Round.fromDict(rnd_data))
camp.set_state(data.get("is_over", False)) camp.set_state(data.get("is_over", False))
@ -263,10 +269,13 @@ class Campaign:
def remove_round(self, round_id: str) -> None: def remove_round(self, round_id: str) -> None:
rnd = next((r for r in self.rounds if r.id == round_id), None) rnd = next((r for r in self.rounds if r.id == round_id), None)
for sect in self.sectors.values():
if sect.round_id == round_id:
sect.round_id = None
if rnd: if rnd:
self.rounds.remove(rnd) self.rounds.remove(rnd)
def get_round_index(self, round_id: str) -> int: def get_round_index(self, round_id: str | None) -> int | None:
if round_id is None: if round_id is None:
return None return None
for index, rnd in enumerate(self.rounds, start=1): for index, rnd in enumerate(self.rounds, start=1):

View file

@ -1,4 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict
from uuid import uuid4 from uuid import uuid4
@ -22,3 +23,21 @@ class CampaignParticipant:
def set_theme(self, new_theme: str) -> None: def set_theme(self, new_theme: str) -> None:
self.theme = new_theme self.theme = new_theme
def toDict(self) -> Dict[str, Any]:
return {
"id": self.id,
"war_participant_id": self.war_participant_id,
"leader": self.leader,
"theme": self.theme,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> CampaignParticipant:
part = CampaignParticipant(
war_participant_id=data["war_participant_id"],
leader=data.get("leader"),
theme=data.get("theme"),
)
part.set_id(data["id"])
return part

View file

@ -1,3 +1,7 @@
from __future__ import annotations
from typing import Any, Dict
class Choice: class Choice:
def __init__( def __init__(
self, self,
@ -25,3 +29,21 @@ class Choice:
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
def toDict(self) -> Dict[str, Any]:
return {
"participant_id": self.participant_id,
"priority_sector_id": self.priority_sector_id,
"secondary_sector_id": self.secondary_sector_id,
"comment": self.comment,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> Choice:
choice = Choice(
data["participant_id"],
data.get("priority_sector_id"),
data.get("secondary_sector_id"),
)
choice.comment = data.get("comment")
return choice

View file

@ -380,7 +380,9 @@ class Model:
return rnd return rnd
raise KeyError("Round not found") raise KeyError("Round not found")
def get_round_index(self, round_id: str) -> int: def get_round_index(self, round_id: str | None) -> int | None:
if round_id is None:
return None
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
return camp.get_round_index(round_id) return camp.get_round_index(round_id)

View file

@ -1,4 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict
from uuid import uuid4 from uuid import uuid4
@ -16,3 +17,16 @@ class Objective:
def set_description(self, new_description: str) -> None: def set_description(self, new_description: str) -> None:
self.description = new_description self.description = new_description
def toDict(self) -> Dict[str, Any]:
return {
"id": self.id,
"name": self.name,
"description": self.description,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> Objective:
obj = Objective(data["name"], data["description"])
obj.set_id(data["id"])
return obj

View file

@ -22,9 +22,8 @@ class Round:
def toDict(self) -> Dict[str, Any]: def toDict(self) -> Dict[str, Any]:
return { return {
"id": self.id, "id": self.id,
# "sectors" : self.sectors, "choices": [c.toDict() for c in self.choices.values()],
# "choices" : self.choices, "battles": [b.toDict() for b in self.battles.values()],
# "battles" : self.battles,
"is_over": self.is_over, "is_over": self.is_over,
} }
@ -32,9 +31,12 @@ class Round:
def fromDict(data: Dict[str, Any]) -> Round: def fromDict(data: Dict[str, Any]) -> Round:
rnd = Round() rnd = Round()
rnd.set_id(data["id"]) rnd.set_id(data["id"])
# rnd.sectors = data.get("sectors", {}) for c in data.get("choices", []):
# rnd.choices = data.get("choices", {}) choice = Choice.fromDict(c)
# rnd.battles = data.get("battles", {}) rnd.choices[choice.participant_id] = choice
for b in data.get("battles", []):
battle = Battle.fromDict(b)
rnd.battles[battle.sector_id] = battle
rnd.set_state(data.get("is_over", False)) rnd.set_state(data.get("is_over", False))
return rnd return rnd

View file

@ -1,4 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict
from uuid import uuid4 from uuid import uuid4
@ -6,14 +7,14 @@ class Sector:
def __init__( def __init__(
self, self,
name: str, name: str,
round_id: str, round_id: str | None,
major_id: str | None, major_id: str | None,
minor_id: str | None, minor_id: str | None,
influence_id: str | None, influence_id: str | None,
): ):
self.id: str = str(uuid4()) self.id: str = str(uuid4())
self.name: str = name self.name: str = name
self.round_id: str = round_id self.round_id: str | None = round_id
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
@ -37,3 +38,29 @@ class Sector:
def set_influence(self, new_influence_id: str) -> None: def set_influence(self, new_influence_id: str) -> None:
self.influence_objective_id = new_influence_id self.influence_objective_id = new_influence_id
def toDict(self) -> Dict[str, Any]:
return {
"id": self.id,
"name": self.name,
"round_id": self.round_id,
"major_objective_id": self.major_objective_id,
"minor_objective_id": self.minor_objective_id,
"influence_objective_id": self.influence_objective_id,
"mission": self.mission,
"description": self.description,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> Sector:
sec = Sector(
data["name"],
data["round_id"],
data.get("major_objective_id"),
data.get("minor_objective_id"),
data.get("influence_objective_id"),
)
sec.set_id(data["id"])
sec.mission = data.get("mission")
sec.description = data.get("description")
return sec

View file

@ -41,7 +41,8 @@ class War:
"id": self.id, "id": self.id,
"name": self.name, "name": self.name,
"year": self.year, "year": self.year,
# "participants" : self.participants, "participants": [part.toDict() for part in self.participants.values()],
"objectives": [obj.toDict() for obj in self.objectives.values()],
"campaigns": [camp.toDict() for camp in self.campaigns], "campaigns": [camp.toDict() for camp in self.campaigns],
"is_over": self.is_over, "is_over": self.is_over,
} }
@ -50,7 +51,12 @@ class War:
def fromDict(data: Dict[str, Any]) -> War: def fromDict(data: Dict[str, Any]) -> War:
war = War(name=data["name"], year=data["year"]) war = War(name=data["name"], year=data["year"])
war.set_id(data["id"]) war.set_id(data["id"])
# war.participants = data.get("participants", {}) for part_data in data.get("participants", []):
part = WarParticipant.fromDict(part_data)
war.participants[part.id] = part
for obj_data in data.get("objectives", []):
obj = Objective.fromDict(obj_data)
war.objectives[obj.id] = obj
for camp_data in data.get("campaigns", []): for camp_data in data.get("campaigns", []):
war.campaigns.append(Campaign.fromDict(camp_data)) war.campaigns.append(Campaign.fromDict(camp_data))
war.set_state(data.get("is_over", False)) war.set_state(data.get("is_over", False))

View file

@ -1,11 +1,12 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Dict
from uuid import uuid4 from uuid import uuid4
class WarParticipant: class WarParticipant:
def __init__(self, *, player_id: str, faction: str): def __init__(self, *, player_id: str, faction: str):
self.id: str = str(uuid4()) self.id: str = str(uuid4())
self.player_id: str = player_id # ref to WarModel.players self.player_id: str = player_id # ref to Model.players
self.faction: str = faction self.faction: str = faction
def set_id(self, new_id: str) -> None: def set_id(self, new_id: str) -> None:
@ -16,3 +17,19 @@ class WarParticipant:
def set_faction(self, new_faction: str) -> None: def set_faction(self, new_faction: str) -> None:
self.faction = new_faction self.faction = new_faction
def toDict(self) -> Dict[str, Any]:
return {
"id": self.id,
"player_id": self.player_id,
"faction": self.faction,
}
@staticmethod
def fromDict(data: Dict[str, Any]) -> WarParticipant:
part = WarParticipant(
player_id=data["player_id"],
faction=data["faction"],
)
part.set_id(data["id"])
return part

View file

@ -21,7 +21,7 @@ def format_campaign_label(camp: CampaignDTO) -> str:
return f"{camp.name} ({calendar.month_name[camp.month]})" return f"{camp.name} ({calendar.month_name[camp.month]})"
def format_round_label(index: int) -> str: def format_round_label(index: int | None) -> str:
if index is None: if index is None:
return "" return ""
return f"Round {index}" return f"Round {index}"

View file

@ -23,10 +23,11 @@ class SectorDialog(QDialog):
super().__init__(parent) super().__init__(parent)
self.ui: Ui_sectorDialog = Ui_sectorDialog() self.ui: Ui_sectorDialog = Ui_sectorDialog()
self.ui.setupUi(self) # type: ignore self.ui.setupUi(self) # type: ignore
self.ui.sectorName.setText(default_name)
self.ui.majorComboBox.addItem("(none)", None) self.ui.majorComboBox.addItem("(none)", None)
self.ui.minorComboBox.addItem("(none)", None) self.ui.minorComboBox.addItem("(none)", None)
self.ui.influenceComboBox.addItem("(none)", None) self.ui.influenceComboBox.addItem("(none)", None)
self.ui.sectorName.setText(default_name) self.ui.roundComboBox.addItem("(none)", None)
for index, rnd in enumerate(rounds, start=1): for index, rnd in enumerate(rounds, start=1):
self.ui.roundComboBox.addItem(format_round_label(index), rnd.id) self.ui.roundComboBox.addItem(format_round_label(index), rnd.id)
select_if_exists(self.ui.roundComboBox, default_round_id) select_if_exists(self.ui.roundComboBox, default_round_id)

View file

@ -448,7 +448,7 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
if action == edit_action and self.on_edit_item: if action == edit_action and self.on_edit_item:
self.on_edit_item(ItemType.BATTLE, battle_id) self.on_edit_item(ItemType.BATTLE, battle_id)
def show_round_details(self, *, index: int) -> None: def show_round_details(self, *, index: int | None) -> None:
self.roundNb.setText(f"Round {index}") self.roundNb.setText(f"Round {index}")
def display_round_choices(self, participants: List[ChoiceDTO]) -> None: def display_round_choices(self, participants: List[ChoiceDTO]) -> None: