diff --git a/README.md b/README.md
index d8fbdf6..65b9e72 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,6 @@ cd warchron_app
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
-pip install -e .
```
### Run
diff --git a/main.py b/main.py
index 4e7d4a0..d5443db 100644
--- a/main.py
+++ b/main.py
@@ -1,4 +1,7 @@
import sys
+import os
+
+sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "src"))
from PyQt6.QtWidgets import QApplication
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index 3bf3163..0000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,67 +0,0 @@
-[project]
-name = "warchron"
-version = "1.0.0"
-description = "A simple local app to track players' campaigns for tabletop wargames."
-requires-python = ">=3.12"
-
-[build-system]
-requires = ["setuptools>=61"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools]
-package-dir = {"" = "src"}
-
-[tool.setuptools.packages.find]
-where = ["src"]
-
-# === BLACK CONFIGURATION (FORMATTER) ===
-[tool.black]
-line-length = 88
-target-version = ['py312']
-include = '\.pyi?$' # File types to format (.py and .pyi)
-extend-exclude = '''
-/(
- # directories
- \.eggs
- | \.git
- | \.venv
- | venv
- | build
- | dist
-)/
-'''
-
-[tool.flake8]
-max-line-length = 88
-extend-ignore = ["E203", "W503"]
-exclude = [
- ".git",
- "__pycache__",
- ".venv",
- "build",
- "dist",
- "src/warchron/view/ui"
-]
-
-[tool.mypy]
-python_version = "3.12"
-mypy_path = "src"
-strict = true
-explicit_package_bases = true
-disallow_untyped_decorators = false
-exclude = [
- ".git",
- "__pycache__",
- ".venv",
- "build",
- "dist",
- "src/warchron/view/ui"
-]
-
-[[tool.mypy.overrides]]
-module = "PyQt6.*"
-ignore_missing_imports = true
-
-[[tool.mypy.overrides]]
-module = "warchron.view.ui.*"
-ignore_errors = true
diff --git a/requirements.txt b/requirements.txt
index b587ef0..abcc883 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1 @@
-PyQt6>=6.6,<6.8
-mypy==1.19.1
-black==25.12.0
-flake8==7.3.0
-flake8-pyproject
\ No newline at end of file
+PyQt6>=6.6,<6.8
\ No newline at end of file
diff --git a/src/warchron/__init__.py b/src/warchron/controller/__ini__.py
similarity index 100%
rename from src/warchron/__init__.py
rename to src/warchron/controller/__ini__.py
diff --git a/src/warchron/controller/controller.py b/src/warchron/controller/controller.py
index 8d92385..b246f76 100644
--- a/src/warchron/controller/controller.py
+++ b/src/warchron/controller/controller.py
@@ -1,24 +1,11 @@
-from typing import List
from pathlib import Path
from PyQt6.QtWidgets import QMessageBox, QDialog
-
from warchron.model.model import Model
from warchron.view.view import View
+
from warchron.constants import ItemType, RefreshScope
-from warchron.controller.dtos import (
- ParticipantOption,
- TreeSelection,
- WarDTO,
- WarParticipantDTO,
- ObjectiveDTO,
- CampaignDTO,
- CampaignParticipantDTO,
- SectorDTO,
- RoundDTO,
- ChoiceDTO,
- BattleDTO,
-)
+from warchron.controller.dtos import ParticipantOption
from warchron.view.view import (
PlayerDialog,
WarDialog,
@@ -33,13 +20,13 @@ from warchron.view.view import (
class Controller:
- def __init__(self, model: Model, view: View) -> None:
+ def __init__(self, model: Model, view: View):
self.model: Model = model
self.view: View = view
self.current_file: Path | None = None
- self.selected_war_id: str | None = None
- self.selected_campaign_id: str | None = None
- self.selected_round_id: str | None = None
+ self.selected_war_id: str = None
+ self.selected_campaign_id: str = None
+ self.selected_round_id: str = None
self.view.on_close_callback = self.on_app_close
self.is_dirty: bool = False
self.__connect()
@@ -51,7 +38,7 @@ class Controller:
self.view.on_add_campaign = self.add_campaign
self.view.on_add_round = self.add_round
- def __connect(self) -> None:
+ def __connect(self):
self.view.actionExit.triggered.connect(self.view.close)
self.view.actionNew.triggered.connect(self.new)
self.view.actionOpen.triggered.connect(self.open_file)
@@ -86,7 +73,7 @@ class Controller:
# Menu bar methods
- def new(self) -> None:
+ def new(self):
if self.is_dirty:
reply = QMessageBox.question(
self.view,
@@ -103,7 +90,7 @@ class Controller:
self.refresh_wars_view()
self.update_window_title()
- def open_file(self) -> None:
+ def open_file(self):
if self.is_dirty:
reply = QMessageBox.question(
self.view,
@@ -123,7 +110,7 @@ class Controller:
self.refresh_wars_view()
self.update_window_title()
- def save(self) -> None:
+ def save(self):
if not self.current_file:
self.save_as()
return
@@ -131,7 +118,7 @@ class Controller:
self.is_dirty = False
self.update_window_title()
- def save_as(self) -> None:
+ def save_as(self):
path = self.view.ask_save_file()
if not path:
return
@@ -142,102 +129,83 @@ class Controller:
# Display methods
- def update_window_title(self) -> None:
+ def update_window_title(self):
base = "WarChron"
if self.current_file:
base += f" - {self.current_file.name}"
else:
- base += " - New file"
+ base += f" - New file"
if self.is_dirty:
base = base + " *"
self.view.setWindowTitle(base)
- def refresh_players_view(self) -> None:
+ def refresh_players_view(self):
players = self.model.get_all_players()
- players_for_display: List[ParticipantOption] = [
- ParticipantOption(id=p.id, name=p.name) for p in players
- ]
- self.view.display_players(players_for_display)
+ self.view.display_players(players)
- def refresh_wars_view(self) -> None:
- wars: List[WarDTO] = [
- WarDTO(
- id=w.id,
- name=w.name,
- year=w.year,
- _campaigns=[
- CampaignDTO(
- id=c.id,
- name=c.name,
- month=c.month,
- _rounds=[
- RoundDTO(id=r.id, index=c.get_round_index(r.id))
- for r in c.get_all_rounds()
- ],
- )
- for c in w.get_all_campaigns()
- ],
- )
- for w in self.model.get_all_wars()
- ]
+ def refresh_wars_view(self):
+ wars = self.model.get_all_wars()
self.view.display_wars_tree(wars)
- def _fill_war_details(self, war_id: str) -> None:
+ def _fill_war_details(self, war_id: str):
war = self.model.get_war(war_id)
self.view.show_war_details(name=war.name, year=war.year)
objectives = war.get_all_objectives()
- objectives_for_display: List[ObjectiveDTO] = [
- ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description)
- for obj in objectives
- ]
- self.view.display_war_objectives(objectives_for_display)
+ self.view.display_war_objectives(objectives)
war_parts = war.get_all_war_participants()
- participants_for_display: List[WarParticipantDTO] = [
- WarParticipantDTO(
- id=p.id,
- player_name=self.model.get_player_name(p.player_id),
- faction=p.faction,
+ participants_for_display = [
+ (
+ self.model.get_player_name(
+ p.player_id,
+ ),
+ p.faction,
+ p.id,
)
for p in war_parts
]
self.view.display_war_participants(participants_for_display)
- def _fill_campaign_details(self, campaign_id: str) -> None:
+ def _fill_campaign_details(self, campaign_id: str):
camp = self.model.get_campaign(campaign_id)
self.view.show_campaign_details(name=camp.name, month=camp.month)
sectors = camp.get_all_sectors()
+ sectors_for_display = []
war = self.model.get_war_by_campaign(camp.id)
- sectors_for_display: List[SectorDTO] = [
- SectorDTO(
- id=sect.id,
- name=sect.name,
- round_index=camp.get_round_index(sect.round_id),
- major=war.get_objective_name(sect.major_objective_id),
- minor=war.get_objective_name(sect.minor_objective_id),
- influence=war.get_objective_name(sect.influence_objective_id),
+ for sect in sectors:
+ round_index = camp.get_round_index(sect.round_id)
+ major_name = war.get_objective_name(sect.major_objective_id)
+ minor_name = war.get_objective_name(sect.minor_objective_id)
+ influence_name = war.get_objective_name(sect.influence_objective_id)
+ sectors_for_display.append(
+ (
+ sect.name,
+ round_index,
+ major_name,
+ minor_name,
+ influence_name,
+ sect.id,
+ )
)
- for sect in sectors
- ]
self.view.display_campaign_sectors(sectors_for_display)
camp_parts = camp.get_all_campaign_participants()
- participants_for_display: List[CampaignParticipantDTO] = [
- CampaignParticipantDTO(
- id=p.id,
- player_name=self.model.get_participant_name(p.war_participant_id),
- leader=p.leader or "",
- theme=p.theme or "",
+ participants_for_display = [
+ (
+ self.model.get_participant_name(p.war_participant_id),
+ p.leader,
+ p.theme,
+ p.id,
)
for p in camp_parts
]
self.view.display_campaign_participants(participants_for_display)
- def _fill_round_details(self, round_id: str) -> None:
+ def _fill_round_details(self, round_id: str):
rnd = self.model.get_round(round_id)
camp = self.model.get_campaign_by_round(round_id)
self.view.show_round_details(index=camp.get_round_index(round_id))
participants = self.model.get_round_participants(round_id)
- sectors = camp.get_sectors_in_round(round_id)
- choices_for_display: List[ChoiceDTO] = []
+ sectors = camp.get_all_sectors()
+ choices_for_display = []
for part in participants:
choice = rnd.get_choice(part.id)
if not choice:
@@ -245,74 +213,52 @@ class Controller:
round_id=rnd.id, participant_id=part.id
)
priority_name = (
- camp.get_sector_name(choice.priority_sector_id)
- if choice.priority_sector_id is not None
- else ""
+ camp.get_sector_name(choice.priority_sector_id) if choice else ""
)
secondary_name = (
- camp.get_sector_name(choice.secondary_sector_id)
- if choice.secondary_sector_id is not None
- else ""
+ camp.get_sector_name(choice.secondary_sector_id) if choice else ""
)
choices_for_display.append(
- ChoiceDTO(
- id=choice.participant_id,
- participant_name=self.model.get_participant_name(
- part.war_participant_id
- ),
- priority_sector=priority_name,
- secondary_sector=secondary_name,
- comment=choice.comment,
+ (
+ self.model.get_player_name(part.id),
+ priority_name,
+ secondary_name,
+ choice.participant_id,
)
)
self.view.display_round_choices(choices_for_display)
- battles_for_display: List[BattleDTO] = []
+ battles_for_display = []
for sect in sectors:
battle = rnd.get_battle(sect.id)
if not battle:
battle = self.model.create_battle(round_id=rnd.id, sector_id=sect.id)
- if battle.player_1_id:
- camp_part = camp.participants[battle.player_1_id]
- player_1_name = self.model.get_participant_name(
- camp_part.war_participant_id
- )
- else:
- player_1_name = ""
- if battle.player_2_id:
- camp_part = camp.participants[battle.player_2_id]
- player_2_name = self.model.get_participant_name(
- camp_part.war_participant_id
- )
- else:
- player_2_name = ""
- if battle.winner_id:
- camp_part = camp.participants[battle.winner_id]
- winner_name = self.model.get_participant_name(
- camp_part.war_participant_id
- )
- else:
- winner_name = ""
+ player_1_name = (
+ self.model.get_player_name(battle.player_1_id)
+ if battle.player_1_id
+ else ""
+ )
+ player_2_name = (
+ self.model.get_player_name(battle.player_2_id)
+ if battle.player_2_id
+ else ""
+ )
battles_for_display.append(
- BattleDTO(
- id=battle.sector_id,
- sector_name=camp.get_sector_name(battle.sector_id),
- player_1=player_1_name,
- player_2=player_2_name,
- winner=winner_name,
- score=battle.score,
- victory_condition=battle.victory_condition,
- comment=battle.comment,
+ (
+ camp.get_sector_name(battle.sector_id),
+ player_1_name,
+ player_2_name,
+ battle.sector_id,
)
)
self.view.display_round_battles(battles_for_display)
- def on_tree_selection_changed(self, selection: TreeSelection | None) -> None:
+ def on_tree_selection_changed(self, selection):
self.selected_war_id = None
self.selected_campaign_id = None
self.selected_round_id = None
if selection:
- item_type = selection.type
- item_id = selection.id
+ item_type = selection["type"]
+ item_id = selection["id"]
if item_type == ItemType.WAR:
self.selected_war_id = item_id
self.view.show_details(ItemType.WAR)
@@ -331,11 +277,11 @@ class Controller:
return
self.update_actions_state()
- def update_actions_state(self) -> None:
+ def update_actions_state(self):
self.view.set_add_campaign_enabled(self.selected_war_id is not None)
self.view.set_add_round_enabled(self.selected_campaign_id is not None)
- def refresh(self, scope: RefreshScope) -> None:
+ def refresh(self, scope: RefreshScope):
match scope:
case RefreshScope.PLAYERS_LIST:
self.refresh_players_view()
@@ -359,28 +305,26 @@ class Controller:
def refresh_and_select(
self, scope: RefreshScope, *, item_type: ItemType, item_id: str
- ) -> None:
+ ):
self.refresh(scope)
self.view.select_tree_item(item_type=item_type, item_id=item_id)
- def edit_item(self, item_type: str, item_id: str) -> None:
+ def edit_item(self, item_type: str, item_id: str):
if item_type == ItemType.PLAYER:
play = self.model.get_player(item_id)
- player_dialog = PlayerDialog(self.view, default_name=play.name)
- if player_dialog.exec() == QDialog.DialogCode.Accepted:
- name = player_dialog.get_player_name()
+ dialog = PlayerDialog(self.view, default_name=play.name)
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ name = dialog.get_player_name()
if not self._validate_player_inputs(name):
return
self.model.update_player(item_id, name=name)
self.refresh(RefreshScope.PLAYERS_LIST)
elif item_type == ItemType.WAR:
war = self.model.get_war(item_id)
- war_dialog = WarDialog(
- self.view, default_name=war.name, default_year=war.year
- )
- if war_dialog.exec() == QDialog.DialogCode.Accepted:
- name = war_dialog.get_war_name()
- year = war_dialog.get_war_year()
+ dialog = WarDialog(self.view, default_name=war.name, default_year=war.year)
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ name = dialog.get_war_name()
+ year = dialog.get_war_year()
if not self._validate_war_inputs(name, year):
return
self.model.update_war(item_id, name=name, year=year)
@@ -389,12 +333,12 @@ class Controller:
)
elif item_type == ItemType.CAMPAIGN:
camp = self.model.get_campaign(item_id)
- camp_dialog = CampaignDialog(
+ dialog = CampaignDialog(
self.view, default_name=camp.name, default_month=camp.month
)
- if camp_dialog.exec() == QDialog.DialogCode.Accepted:
- name = camp_dialog.get_campaign_name()
- month = camp_dialog.get_campaign_month()
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ name = dialog.get_campaign_name()
+ month = dialog.get_campaign_month()
if not self._validate_campaign_inputs(name, month):
return
self.model.update_campaign(item_id, name=name, month=month)
@@ -403,29 +347,28 @@ class Controller:
)
elif item_type == ItemType.OBJECTIVE:
obj = self.model.get_objective(item_id)
- obj_dialog = ObjectiveDialog(
+ dialog = ObjectiveDialog(
self.view, default_name=obj.name, default_description=obj.description
)
- if obj_dialog.exec() == QDialog.DialogCode.Accepted:
- name = obj_dialog.get_objective_name()
- description = obj_dialog.get_objective_description()
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ name = dialog.get_objective_name()
+ description = dialog.get_objective_description()
if not self._validate_objective_inputs(name, description):
return
self.model.update_objective(item_id, name=name, description=description)
self.refresh(RefreshScope.WAR_DETAILS)
elif item_type == ItemType.WAR_PARTICIPANT:
- war_part = self.model.get_war_participant(item_id)
- player = self.model.get_player(war_part.player_id)
- play_opt = ParticipantOption(id=player.id, name=player.name)
- war_part_dialog = WarParticipantDialog(
+ camp_part = self.model.get_war_participant(item_id)
+ player = self.model.get_player(camp_part.player_id)
+ dialog = WarParticipantDialog(
self.view,
- players=[play_opt],
- default_player_id=war_part.id,
- default_faction=war_part.faction,
+ players=[player],
+ default_player_id=camp_part.id,
+ default_faction=camp_part.faction,
editable_player=False,
)
- if war_part_dialog.exec() == QDialog.DialogCode.Accepted:
- faction = war_part_dialog.get_participant_faction()
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ faction = dialog.get_participant_faction()
self.model.update_war_participant(item_id, faction=faction)
self.refresh(RefreshScope.WAR_DETAILS)
elif item_type == ItemType.SECTOR:
@@ -433,30 +376,23 @@ class Controller:
camp = self.model.get_campaign_by_sector(item_id)
war = self.model.get_war_by_campaign(camp.id)
rounds = camp.get_all_rounds()
- rnd_dto: List[RoundDTO] = [
- RoundDTO(id=rnd.id, index=i) for i, rnd in enumerate(rounds, start=1)
- ]
objectives = war.get_all_objectives()
- obj_dto: List[ObjectiveDTO] = [
- ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description)
- for obj in objectives
- ]
- sect_dialog = SectorDialog(
+ dialog = SectorDialog(
self.view,
default_name=sect.name,
- rounds=rnd_dto,
+ rounds=rounds,
default_round_id=sect.round_id,
- objectives=obj_dto,
+ objectives=objectives,
default_major_id=sect.major_objective_id,
default_minor_id=sect.minor_objective_id,
default_influence_id=sect.influence_objective_id,
)
- if sect_dialog.exec() == QDialog.DialogCode.Accepted:
- name = sect_dialog.get_sector_name()
- round_id = sect_dialog.get_round_id()
- major_id = sect_dialog.get_major_id()
- minor_id = sect_dialog.get_minor_id()
- influence_id = sect_dialog.get_influence_id()
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ name = dialog.get_sector_name()
+ round_id = dialog.get_round_id()
+ major_id = dialog.get_major_id()
+ minor_id = dialog.get_minor_id()
+ influence_id = dialog.get_influence_id()
self.model.update_sector(
item_id,
name=name,
@@ -471,7 +407,7 @@ class Controller:
war_part = self.model.get_war_participant(camp_part.war_participant_id)
player = self.model.get_player(war_part.player_id)
part_opt = [ParticipantOption(id=player.id, name=player.name)]
- camp_part_dialog = CampaignParticipantDialog(
+ dialog = CampaignParticipantDialog(
self.view,
participants=part_opt,
default_participant_id=camp_part.id,
@@ -479,9 +415,9 @@ class Controller:
default_theme=camp_part.theme,
editable_player=False,
)
- if camp_part_dialog.exec() == QDialog.DialogCode.Accepted:
- leader = camp_part_dialog.get_participant_leader()
- theme = camp_part_dialog.get_participant_theme()
+ if dialog.exec() == QDialog.DialogCode.Accepted:
+ leader = dialog.get_participant_leader()
+ theme = dialog.get_participant_theme()
self.model.update_campaign_participant(
item_id, leader=leader, theme=theme
)
@@ -493,7 +429,7 @@ class Controller:
self.edit_round_battle(item_id)
self.refresh(RefreshScope.ROUND_DETAILS)
- def delete_item(self, item_type: str, item_id: str) -> None:
+ def delete_item(self, item_type: str, item_id: str):
reply = QMessageBox.question(
self.view,
"Confirm deletion",
@@ -546,7 +482,7 @@ class Controller:
return False
return True
- def add_player(self) -> None:
+ def add_player(self):
dialog = PlayerDialog(self.view)
result = dialog.exec() # modal blocking dialog
if result == QDialog.DialogCode.Accepted:
@@ -570,7 +506,7 @@ class Controller:
return False
return True
- def add_war(self) -> None:
+ def add_war(self):
dialog = WarDialog(
self.view, default_year=self.model.get_default_war_values()["year"]
)
@@ -596,7 +532,7 @@ class Controller:
return False
return True
- def add_objective(self) -> None:
+ def add_objective(self):
if not self.selected_war_id:
return
dialog = ObjectiveDialog(self.view)
@@ -612,14 +548,11 @@ class Controller:
# War participant methods
- def add_war_participant(self) -> None:
+ def add_war_participant(self):
if not self.selected_war_id:
return
players = self.model.get_available_players(self.selected_war_id)
- play_opts: List[ParticipantOption] = [
- ParticipantOption(id=p.id, name=p.name) for p in players
- ]
- dialog = WarParticipantDialog(self.view, players=play_opts)
+ dialog = WarParticipantDialog(self.view, players=players)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
player_id = dialog.get_player_id()
@@ -645,7 +578,7 @@ class Controller:
return False
return True
- def add_campaign(self) -> None:
+ def add_campaign(self):
if not self.selected_war_id:
return
dialog = CampaignDialog(
@@ -668,7 +601,7 @@ class Controller:
# Campaign participant methods
- def add_campaign_participant(self) -> None:
+ def add_campaign_participant(self):
if not self.selected_campaign_id:
return
participants = self.model.get_available_war_participants(
@@ -697,7 +630,6 @@ class Controller:
def _validate_sector_inputs(
self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str
) -> bool:
-
if not name.strip():
QMessageBox.warning(
self.view, "Invalid name", "Sector name cannot be empty."
@@ -706,22 +638,15 @@ class Controller:
# allow same objectives in different fields?
return True
- def add_sector(self) -> None:
+ def add_sector(self):
if not self.selected_campaign_id:
return
war = self.model.get_war_by_campaign(self.selected_campaign_id)
camp = self.model.get_campaign(self.selected_campaign_id)
rounds = camp.get_all_rounds()
- rnd_objs: List[RoundDTO] = [
- RoundDTO(id=rnd.id, index=camp.get_round_index(rnd.id)) for rnd in rounds
- ]
objectives = war.get_all_objectives()
- obj_dtos: List[ObjectiveDTO] = [
- ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description)
- for obj in objectives
- ]
dialog = SectorDialog(
- self.view, default_name="", rounds=rnd_objs, objectives=obj_dtos
+ self.view, default_name="", rounds=rounds, objectives=objectives
)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
@@ -742,7 +667,7 @@ class Controller:
# Round methods
- def add_round(self) -> None:
+ def add_round(self):
if not self.selected_campaign_id:
return
rnd = self.model.add_round(self.selected_campaign_id)
@@ -753,36 +678,25 @@ class Controller:
# Choice methods
- def edit_round_choice(self, choice_id: str) -> None:
+ def edit_round_choice(self, choice_id: str):
round_id = self.selected_round_id
if not round_id:
return
- war = self.model.get_war_by_round(round_id)
+ # camp, rnd, participants, sectors = self.model.get_round_choices_data(round_id)
camp = self.model.get_campaign_by_round(round_id)
rnd = camp.get_round(round_id)
sectors = camp.get_sectors_in_round(round_id)
- sect_opts: List[SectorDTO] = [
- SectorDTO(
- id=sect.id,
- name=sect.name,
- round_index=camp.get_round_index(sect.round_id),
- major=war.get_objective_name(sect.major_objective_id),
- minor=war.get_objective_name(sect.minor_objective_id),
- influence=war.get_objective_name(sect.influence_objective_id),
- )
- for sect in sectors
- ]
choice = rnd.get_choice(choice_id)
if not choice:
return
- participant = camp.participants[choice.participant_id]
- player = self.model.get_player_from_campaign_participant(participant)
- part_opt = ParticipantOption(id=participant.id, name=player.name)
+ part = camp.participants[choice.participant_id]
+ player = self.model.get_player(part.id)
+ part_opt = ParticipantOption(id=player.id, name=player.name)
dialog = ChoicesDialog(
self.view,
participants=[part_opt],
- default_participant_id=participant.id,
- sectors=sect_opts,
+ default_participant_id=part.id,
+ sectors=sectors,
default_priority_id=choice.priority_sector_id,
default_secondary_id=choice.secondary_sector_id,
default_comment=choice.comment,
@@ -791,7 +705,7 @@ class Controller:
return
self.model.update_choice(
round_id=round_id,
- participant_id=participant.id,
+ participant_id=part.id,
priority_sector_id=dialog.get_priority_id(),
secondary_sector_id=dialog.get_secondary_id(),
comment=dialog.get_comment(),
@@ -799,11 +713,10 @@ class Controller:
# Battle methods
- def edit_round_battle(self, battle_id: str) -> None:
+ def edit_round_battle(self, battle_id: str):
round_id = self.selected_round_id
if not round_id:
return
- war = self.model.get_war_by_round(round_id)
camp = self.model.get_campaign_by_round(round_id)
rnd = camp.get_round(round_id)
participants = camp.get_all_campaign_participants()
@@ -811,22 +724,13 @@ class Controller:
if not battle:
return
sect = camp.sectors[battle.sector_id]
- sect_dto = SectorDTO(
- id=sect.id,
- name=sect.name,
- round_index=camp.get_round_index(sect.round_id),
- major=war.get_objective_name(sect.major_objective_id),
- minor=war.get_objective_name(sect.minor_objective_id),
- influence=war.get_objective_name(sect.influence_objective_id),
- )
-
- part_opts: List[ParticipantOption] = []
- for participant in participants:
- player = self.model.get_player_from_campaign_participant(participant)
- part_opts.append(ParticipantOption(id=participant.id, name=player.name))
+ part_opts: list[ParticipantOption] = []
+ for part in participants:
+ player = self.model.get_player(part.id)
+ part_opts.append(ParticipantOption(id=part.id, name=player.name))
dialog = BattlesDialog(
self.view,
- sectors=[sect_dto],
+ sectors=[sect],
default_sector_id=sect.id,
players=part_opts,
default_player_1_id=battle.player_1_id,
diff --git a/src/warchron/controller/dtos.py b/src/warchron/controller/dtos.py
index cf063bd..83e930b 100644
--- a/src/warchron/controller/dtos.py
+++ b/src/warchron/controller/dtos.py
@@ -1,4 +1,3 @@
-from typing import List
from dataclasses import dataclass
@@ -6,90 +5,3 @@ from dataclasses import dataclass
class ParticipantOption:
id: str
name: str
-
-
-@dataclass(frozen=True, slots=True)
-class TreeSelection:
- type: str
- id: str
-
-
-@dataclass
-class WarDTO:
- id: str
- name: str
- year: int
- _campaigns: List["CampaignDTO"] | None = None
-
- def get_all_campaigns(self) -> List["CampaignDTO"]:
- return self._campaigns or []
-
-
-@dataclass(frozen=True, slots=True)
-class ObjectiveDTO:
- id: str
- name: str
- description: str
-
-
-@dataclass(frozen=True, slots=True)
-class WarParticipantDTO:
- id: str
- player_name: str
- faction: str
-
-
-@dataclass
-class CampaignDTO:
- id: str
- name: str
- month: int
- _rounds: List["RoundDTO"] | None = None
-
- def get_all_rounds(self) -> List["RoundDTO"]:
- return self._rounds or []
-
-
-@dataclass(frozen=True, slots=True)
-class CampaignParticipantDTO:
- id: str
- player_name: str
- leader: str
- theme: str
-
-
-@dataclass(frozen=True, slots=True)
-class SectorDTO:
- id: str
- name: str
- round_index: int
- major: str
- minor: str
- influence: str
-
-
-@dataclass
-class RoundDTO:
- id: str
- index: int
-
-
-@dataclass(frozen=True, slots=True)
-class ChoiceDTO:
- id: str
- participant_name: str
- priority_sector: str
- secondary_sector: str
- comment: str | None
-
-
-@dataclass(frozen=True, slots=True)
-class BattleDTO:
- id: str
- sector_name: str
- player_1: str
- player_2: str
- winner: str | None
- score: str | None
- victory_condition: str | None
- comment: str | None
diff --git a/src/warchron/controller/__init__.py b/src/warchron/model/__ini__.py
similarity index 100%
rename from src/warchron/controller/__init__.py
rename to src/warchron/model/__ini__.py
diff --git a/src/warchron/model/campaign.py b/src/warchron/model/campaign.py
index bf3431e..df6ae94 100644
--- a/src/warchron/model/campaign.py
+++ b/src/warchron/model/campaign.py
@@ -1,33 +1,32 @@
from __future__ import annotations
from uuid import uuid4
-from typing import Any, Dict, List
from warchron.model.round import Round, Choice, Battle
class Campaign:
- def __init__(self, name: str, month: int) -> None:
+ def __init__(self, name: str, month: int):
self.id: str = str(uuid4())
self.name: str = name
self.month: int = month
- self.participants: Dict[str, CampaignParticipant] = {}
- self.sectors: Dict[str, Sector] = {}
- self.rounds: List[Round] = []
+ self.participants: dict[str, CampaignParticipant] = {}
+ self.sectors: dict[str, Sector] = {}
+ self.rounds: list[Round] = []
self.is_over = False
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_name(self, new_name: str) -> None:
+ def set_name(self, new_name: str):
self.name = new_name
- def set_month(self, new_month: int) -> None:
+ def set_month(self, new_month: int):
self.month = new_month
- def set_state(self, new_state: bool) -> None:
+ def set_state(self, new_state: bool):
self.is_over = new_state
- def toDict(self) -> Dict[str, Any]:
+ def toDict(self):
return {
"id": self.id,
"name": self.name,
@@ -38,7 +37,7 @@ class Campaign:
}
@staticmethod
- def fromDict(data: Dict[str, Any]) -> Campaign:
+ def fromDict(data: dict):
camp = Campaign(name=data["name"], month=data["month"])
camp.set_id(data["id"])
# camp.participants = data.get("participants", {})
@@ -78,18 +77,18 @@ class Campaign:
except KeyError:
raise KeyError(f"Participant {participant_id} not in campaign {self.id}")
- def get_all_campaign_participants(self) -> List[CampaignParticipant]:
+ def get_all_campaign_participants(self) -> list[CampaignParticipant]:
return list(self.participants.values())
def update_campaign_participant(
self, participant_id: str, *, leader: str, theme: str
- ) -> None:
+ ):
part = self.get_campaign_participant(participant_id)
# Can't change referred War.participant
part.set_leader(leader)
part.set_theme(theme)
- def remove_campaign_participant(self, participant_id: str) -> None:
+ def remove_campaign_participant(self, participant_id: str):
# TODO manage choices referring to it
# TODO manage battles referring to it
del self.participants[participant_id]
@@ -111,7 +110,7 @@ class Campaign:
return ""
return self.sectors[sector_id].name
- def get_all_sectors(self) -> List[Sector]:
+ def get_all_sectors(self) -> list[Sector]:
return list(self.sectors.values())
# TODO manage choices referring to it (round order!)
@@ -124,7 +123,7 @@ class Campaign:
major_id: str,
minor_id: str,
influence_id: str,
- ) -> None:
+ ):
sect = self.get_sector(sector_id)
sect.set_name(name)
sect.set_round(round_id)
@@ -132,12 +131,12 @@ class Campaign:
sect.set_minor(minor_id)
sect.set_influence(influence_id)
- def remove_sector(self, sector_id: str) -> None:
+ def remove_sector(self, sector_id: str):
# TODO manage choices referring to it
# TODO manage battles referring to it
del self.sectors[sector_id]
- def get_sectors_in_round(self, round_id: str) -> List[Sector]:
+ def get_sectors_in_round(self, round_id: str) -> list[Sector]:
sectors = [s for s in self.sectors.values() if s.round_id == round_id]
return sectors
@@ -152,7 +151,7 @@ class Campaign:
return rnd
raise KeyError(f"Round {round_id} not found")
- def get_all_rounds(self) -> List[Round]:
+ def get_all_rounds(self) -> list[Round]:
return list(self.rounds)
def add_round(self) -> Round:
@@ -160,7 +159,7 @@ class Campaign:
self.rounds.append(round)
return round
- def remove_round(self, round_id: str) -> None:
+ def remove_round(self, round_id: str):
rnd = next((r for r in self.rounds if r.id == round_id), None)
if rnd:
self.rounds.remove(rnd)
@@ -173,6 +172,14 @@ class Campaign:
return index
raise KeyError("Round not found in campaign")
+ def get_round_name(self, round_id: str | None) -> str:
+ if round_id is None:
+ return ""
+ for rnd in self.rounds:
+ if rnd.id == round_id:
+ return rnd.name
+ return ""
+
# Choice methods
def create_choice(self, round_id: str, participant_id: str) -> Choice:
@@ -186,13 +193,13 @@ class Campaign:
priority_sector_id: str | None,
secondary_sector_id: str | None,
comment: str | None,
- ) -> None:
+ ):
rnd = self.get_round(round_id)
rnd.update_choice(
participant_id, priority_sector_id, secondary_sector_id, comment
)
- def remove_choice(self, round_id: str, participant_id: str) -> None:
+ def remove_choice(self, round_id: str, participant_id: str) -> Choice:
rnd = self.get_round(round_id)
rnd.remove_choice(participant_id)
@@ -212,7 +219,7 @@ class Campaign:
score: str | None,
victory_condition: str | None,
comment: str | None,
- ) -> None:
+ ):
rnd = self.get_round(round_id)
rnd.update_battle(
sector_id,
@@ -224,7 +231,7 @@ class Campaign:
comment,
)
- def remove_battle(self, round_id: str, sector_id: str) -> None:
+ def remove_battle(self, round_id: str, sector_id: str) -> Battle:
rnd = self.get_round(round_id)
rnd.remove_battle(sector_id)
@@ -238,16 +245,16 @@ class CampaignParticipant:
self.leader: str | None = leader
self.theme: str | None = theme
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_war_participant(self, new_participant: str) -> None:
+ def set_war_participant(self, new_participant: str):
self.war_participant_id = new_participant
- def set_leader(self, new_faction: str) -> None:
+ def set_leader(self, new_faction: str):
self.leader = new_faction
- def set_theme(self, new_theme: str) -> None:
+ def set_theme(self, new_theme: str):
self.theme = new_theme
@@ -269,20 +276,20 @@ class Sector:
self.mission: str | None = None
self.description: str | None = None
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_name(self, new_name: str) -> None:
+ def set_name(self, new_name: str):
self.name = new_name
- def set_round(self, new_round_id: str) -> None:
+ def set_round(self, new_round_id: str):
self.round_id = new_round_id
- def set_major(self, new_major_id: str) -> None:
+ def set_major(self, new_major_id: str):
self.major_objective_id = new_major_id
- def set_minor(self, new_minor_id: str) -> None:
+ def set_minor(self, new_minor_id: str):
self.minor_objective_id = new_minor_id
- def set_influence(self, new_influence_id: str) -> None:
+ def set_influence(self, new_influence_id: str):
self.influence_objective_id = new_influence_id
diff --git a/src/warchron/model/model.py b/src/warchron/model/model.py
index 1a17563..d4f017b 100644
--- a/src/warchron/model/model.py
+++ b/src/warchron/model/model.py
@@ -1,4 +1,3 @@
-from typing import Any, Dict, List
from pathlib import Path
import json
import shutil
@@ -11,25 +10,25 @@ from warchron.model.round import Round, Choice, Battle
class Model:
- def __init__(self) -> None:
- self.players: Dict[str, Player] = {}
- self.wars: Dict[str, War] = {}
+ def __init__(self):
+ self.players: dict[str, Player] = {}
+ self.wars: dict[str, War] = {}
# File management methods
- def new(self) -> None:
+ def new(self):
self.players.clear()
self.wars.clear()
- def load(self, path: Path) -> None:
+ def load(self, path: Path):
self.players.clear()
self.wars.clear()
self._load_data(path)
- def save(self, path: Path) -> None:
+ def save(self, path: Path):
self._save_data(path)
- def _load_data(self, path: Path) -> None:
+ def _load_data(self, path: Path):
if not path.exists() or path.stat().st_size == 0:
return # Start empty
try:
@@ -46,7 +45,7 @@ class Model:
except json.JSONDecodeError:
raise RuntimeError("Data file is corrupted")
- def _save_data(self, path: Path) -> None:
+ def _save_data(self, path: Path):
if path.exists():
shutil.copy(path, path.with_suffix(".json.bak"))
data = {
@@ -59,31 +58,31 @@ class Model:
# Player methods
- def add_player(self, name: str) -> Player:
+ def add_player(self, name):
player = Player(name)
self.players[player.id] = player
return player
- def get_player(self, id: str) -> Player:
+ def get_player(self, id):
return self.players[id]
def get_player_name(self, player_id: str) -> str:
return self.players[player_id].name
- def update_player(self, player_id: str, *, name: str) -> None:
+ def update_player(self, player_id: str, *, name: str):
player = self.get_player(player_id)
player.set_name(name)
- def get_all_players(self) -> List[Player]:
+ def get_all_players(self) -> list[Player]:
return list(self.players.values())
- def remove_player(self, player_id: str) -> None:
+ def remove_player(self, player_id: str):
# TODO manage war_participants referring to it
del self.players[player_id]
# War methods
- def get_default_war_values(self) -> Dict[str, Any]:
+ def get_default_war_values(self) -> dict:
return {"year": datetime.now().year}
def add_war(self, name: str, year: int) -> War:
@@ -91,7 +90,7 @@ class Model:
self.wars[war.id] = war
return war
- def get_war(self, id: str) -> War:
+ def get_war(self, id) -> War:
return self.wars[id]
def get_war_by_campaign(self, campaign_id: str) -> War:
@@ -101,20 +100,20 @@ class Model:
return war
raise KeyError(f"Campaign {campaign_id} not found in any War")
- def get_war_by_sector(self, sector_id: str) -> War:
+ def get_war_by_sector(self, sector_id: str) -> Campaign:
for war in self.wars.values():
for camp in war.campaigns:
for sect in camp.sectors.values():
if sect.id == sector_id:
- return war
+ return camp
raise KeyError(f"Sector {sector_id} not found in any War")
- def get_war_by_round(self, round_id: str) -> War:
+ def get_war_by_round(self, round_id: str) -> Campaign:
for war in self.wars.values():
for camp in war.campaigns:
for rnd in camp.rounds:
if rnd.id == round_id:
- return war
+ return camp
raise KeyError(f"Round {round_id} not found in any War")
def get_war_by_objective(self, objective_id: str) -> War:
@@ -137,15 +136,15 @@ class Model:
return war
raise KeyError(f"Participant {participant_id} not found")
- def update_war(self, war_id: str, *, name: str, year: int) -> None:
+ def update_war(self, war_id: str, *, name: str, year: int):
war = self.get_war(war_id)
war.set_name(name)
war.set_year(year)
- def get_all_wars(self) -> List[War]:
+ def get_all_wars(self) -> list[War]:
return list(self.wars.values())
- def remove_war(self, war_id: str) -> None:
+ def remove_war(self, war_id: str):
del self.wars[war_id]
# Objective methods
@@ -154,26 +153,24 @@ class Model:
war = self.get_war(war_id)
return war.add_objective(name, description)
- def get_objective(self, objective_id: str) -> Objective:
+ def get_objective(self, objective_id) -> Objective:
for war in self.wars.values():
for obj in war.objectives.values():
if obj.id == objective_id:
return obj
raise KeyError("Objective not found")
- def update_objective(
- self, objective_id: str, *, name: str, description: str
- ) -> None:
+ def update_objective(self, objective_id: str, *, name: str, description: str):
war = self.get_war_by_objective(objective_id)
war.update_objective(objective_id, name=name, description=description)
- def remove_objective(self, objective_id: str) -> None:
+ def remove_objective(self, objective_id: str):
war = self.get_war_by_objective(objective_id)
war.remove_objective(objective_id)
# War participant methods
- def get_available_players(self, war_id: str) -> List[Player]:
+ def get_available_players(self, war_id: str) -> list[Player]:
war = self.get_war(war_id)
return [
player for player in self.players.values() if not war.has_player(player.id)
@@ -185,27 +182,24 @@ class Model:
war = self.get_war(war_id)
return war.add_war_participant(player_id, faction)
- def get_war_participant(self, participant_id: str) -> WarParticipant:
+ def get_war_participant(self, participant_id) -> WarParticipant:
for war in self.wars.values():
for part in war.participants.values():
if part.id == participant_id:
return part
raise KeyError("Participant not found")
- def get_player_from_war_participant(self, war_part: WarParticipant) -> Player:
- return self.get_player(war_part.player_id)
-
- def update_war_participant(self, participant_id: str, *, faction: str) -> None:
+ def update_war_participant(self, participant_id: str, *, faction: str):
war = self.get_war_by_war_participant(participant_id)
war.update_war_participant(participant_id, faction=faction)
- def remove_war_participant(self, participant_id: str) -> None:
+ def remove_war_participant(self, participant_id: str):
war = self.get_war_by_war_participant(participant_id)
war.remove_war_participant(participant_id)
# Campaign methods
- def get_default_campaign_values(self, war_id: str) -> Dict[str, Any]:
+ def get_default_campaign_values(self, war_id: str) -> dict:
war = self.get_war(war_id)
return war.get_default_campaign_values()
@@ -213,7 +207,7 @@ class Model:
war = self.get_war(war_id)
return war.add_campaign(name, month)
- def get_campaign(self, campaign_id: str) -> Campaign:
+ def get_campaign(self, campaign_id) -> Campaign:
for war in self.wars.values():
for campaign in war.campaigns:
if campaign.id == campaign_id:
@@ -241,11 +235,11 @@ class Model:
return camp
raise KeyError(f"Sector {sector_id} not found")
- def update_campaign(self, campaign_id: str, *, name: str, month: int) -> None:
+ def update_campaign(self, campaign_id: str, *, name: str, month: int):
war = self.get_war_by_campaign(campaign_id)
war.update_campaign(campaign_id, name=name, month=month)
- def remove_campaign(self, campaign_id: str) -> None:
+ def remove_campaign(self, campaign_id: str):
war = self.get_war_by_campaign(campaign_id)
war.remove_campaign(campaign_id)
@@ -263,7 +257,7 @@ class Model:
camp = self.get_campaign(campaign_id)
return camp.add_sector(name, round_id, major_id, minor_id, influence_id)
- def get_sector(self, sector_id: str) -> Sector:
+ def get_sector(self, sector_id) -> Sector:
for war in self.wars.values():
for camp in war.campaigns:
for sect in camp.sectors.values():
@@ -280,7 +274,7 @@ class Model:
major_id: str,
minor_id: str,
influence_id: str,
- ) -> None:
+ ):
war = self.get_war_by_sector(sector_id)
war.update_sector(
sector_id,
@@ -291,13 +285,13 @@ class Model:
influence_id=influence_id,
)
- def remove_sector(self, sector_id: str) -> None:
+ def remove_sector(self, sector_id: str):
camp = self.get_campaign_by_sector(sector_id)
camp.remove_sector(sector_id)
# Campaign participant methods
- def get_available_war_participants(self, campaign_id: str) -> List[WarParticipant]:
+ def get_available_war_participants(self, campaign_id: str) -> list[WarParticipant]:
war = self.get_war_by_campaign(campaign_id)
return war.get_available_war_participants(campaign_id)
@@ -312,7 +306,7 @@ class Model:
war_part = war.get_war_participant(participant_id)
return self.players[war_part.player_id].name
- def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
+ def get_campaign_participant(self, participant_id) -> CampaignParticipant:
for war in self.wars.values():
for camp in war.campaigns:
for part in camp.participants.values():
@@ -320,23 +314,17 @@ class Model:
return part
raise KeyError("Participant not found")
- def get_player_from_campaign_participant(
- self, camp_part: CampaignParticipant
- ) -> Player:
- war_part = self.get_war_participant(camp_part.war_participant_id)
- return self.get_player(war_part.player_id)
-
def update_campaign_participant(
self,
participant_id: str,
*,
leader: str,
theme: str,
- ) -> None:
+ ):
war = self.get_war_by_campaign_participant(participant_id)
war.update_campaign_participant(participant_id, leader=leader, theme=theme)
- def remove_campaign_participant(self, participant_id: str) -> None:
+ def remove_campaign_participant(self, participant_id: str):
war = self.get_war_by_campaign_participant(participant_id)
war.remove_campaign_participant(participant_id)
@@ -358,15 +346,15 @@ class Model:
camp = self.get_campaign_by_round(round_id)
return camp.get_round_index(round_id)
- def get_round_sectors(self, round_id: str) -> List[Sector]:
+ def get_round_sectors(self, round_id: str) -> list[Sector]:
camp = self.get_campaign_by_round(round_id)
return [s for s in camp.sectors.values() if s.round_id == round_id]
- def get_round_participants(self, round_id: str) -> List[CampaignParticipant]:
+ def get_round_participants(self, round_id: str) -> list[CampaignParticipant]:
camp = self.get_campaign_by_round(round_id)
return list(camp.participants.values())
- def remove_round(self, round_id: str) -> None:
+ def remove_round(self, round_id: str):
war = self.get_war_by_round(round_id)
war.remove_round(round_id)
@@ -376,6 +364,13 @@ class Model:
war = self.get_war_by_round(round_id)
return war.create_choice(round_id, participant_id)
+ def get_round_choices_data(self, round_id: str):
+ camp = self.get_campaign_by_round(round_id)
+ rnd = self.get_round(round_id)
+ participants = camp.participants.values()
+ sectors = [s for s in camp.sectors.values() if s.round_id == round_id]
+ return camp, rnd, participants, sectors
+
def update_choice(
self,
round_id: str,
@@ -383,13 +378,13 @@ class Model:
priority_sector_id: str | None,
secondary_sector_id: str | None,
comment: str | None,
- ) -> None:
+ ):
war = self.get_war_by_round(round_id)
war.update_choice(
round_id, participant_id, priority_sector_id, secondary_sector_id, comment
)
- def remove_choice(self, round_id: str, participant_id: str) -> None:
+ def remove_choice(self, round_id: str, participant_id: str):
war = self.get_war_by_round(round_id)
war.remove_choice(round_id, participant_id)
@@ -409,7 +404,7 @@ class Model:
score: str | None,
victory_condition: str | None,
comment: str | None,
- ) -> None:
+ ):
war = self.get_war_by_round(round_id)
war.update_battle(
round_id,
@@ -422,6 +417,6 @@ class Model:
comment,
)
- def remove_battle(self, round_id: str, sector_id: str) -> None:
+ def remove_battle(self, round_id: str, sector_id: str):
war = self.get_war_by_round(round_id)
war.remove_battle(round_id, sector_id)
diff --git a/src/warchron/model/objective.py b/src/warchron/model/objective.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/warchron/model/player.py b/src/warchron/model/player.py
index b8b9934..8f07176 100644
--- a/src/warchron/model/player.py
+++ b/src/warchron/model/player.py
@@ -1,24 +1,22 @@
-from __future__ import annotations
-from typing import Any, Dict
from uuid import uuid4
class Player:
- def __init__(self, name: str) -> None:
- self.id: str = str(uuid4())
- self.name: str = name
-
- def set_id(self, new_id: str) -> None:
- self.id = new_id
-
- def set_name(self, name: str) -> None:
+ def __init__(self, name):
+ self.id = str(uuid4())
self.name = name
- def toDict(self) -> Dict[str, Any]:
+ def set_id(self, new_id):
+ self.id = new_id
+
+ def set_name(self, name):
+ self.name = name
+
+ def toDict(self):
return {"id": self.id, "name": self.name}
@staticmethod
- def fromDict(data: Dict[str, Any]) -> Player:
+ def fromDict(data: dict):
play = Player(name=data["name"])
play.set_id(data["id"])
return play
diff --git a/src/warchron/model/repository.py b/src/warchron/model/repository.py
new file mode 100644
index 0000000..d000abf
--- /dev/null
+++ b/src/warchron/model/repository.py
@@ -0,0 +1,24 @@
+import json
+import shutil
+from pathlib import Path
+
+DATA_FILE = Path("data/warmachron.json")
+
+
+def load_data():
+ if not DATA_FILE.exists() or DATA_FILE.stat().st_size == 0:
+ return {"version": 1, "players": {}, "wars": []}
+
+ try:
+ with open(DATA_FILE, "r", encoding="utf-8") as f:
+ return json.load(f)
+ except json.JSONDecodeError:
+ raise RuntimeError("Data file is corrupted")
+
+
+def save_data(data):
+ if DATA_FILE.exists():
+ shutil.copy(DATA_FILE, DATA_FILE.with_suffix(".json.bak"))
+
+ with open(DATA_FILE, "w", encoding="utf-8") as f:
+ json.dump(data, f, indent=2)
diff --git a/src/warchron/model/round.py b/src/warchron/model/round.py
index 420eea8..a975c3a 100644
--- a/src/warchron/model/round.py
+++ b/src/warchron/model/round.py
@@ -1,22 +1,21 @@
from __future__ import annotations
from uuid import uuid4
-from typing import Any, Dict
class Round:
- def __init__(self) -> None:
+ def __init__(self):
self.id: str = str(uuid4())
- self.choices: Dict[str, Choice] = {}
- self.battles: Dict[str, Battle] = {}
+ self.choices: dict[str, Choice] = {}
+ self.battles: dict[str, Battle] = {}
self.is_over: bool = False
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_state(self, new_state: bool) -> None:
+ def set_state(self, new_state: bool):
self.is_over = new_state
- def toDict(self) -> Dict[str, Any]:
+ def toDict(self):
return {
"id": self.id,
# "sectors" : self.sectors,
@@ -26,7 +25,7 @@ class Round:
}
@staticmethod
- def fromDict(data: Dict[str, Any]) -> Round:
+ def fromDict(data: dict):
rnd = Round()
rnd.set_id(data["id"])
# rnd.sectors = data.get("sectors", {})
@@ -56,14 +55,13 @@ class Round:
priority_sector_id: str | None,
secondary_sector_id: str | None,
comment: str | None,
- ) -> None:
+ ):
choice = self.get_choice(participant_id)
- if choice:
- choice.set_priority(priority_sector_id)
- choice.set_secondary(secondary_sector_id)
- choice.set_comment(comment)
+ choice.set_priority(priority_sector_id)
+ choice.set_secondary(secondary_sector_id)
+ choice.set_comment(comment)
- def remove_choice(self, participant_id: str) -> None:
+ def remove_choice(self, participant_id: str):
del self.choices[participant_id]
# Battle methods
@@ -86,17 +84,16 @@ class Round:
score: str | None,
victory_condition: str | None,
comment: str | None,
- ) -> None:
+ ):
bat = self.get_battle(sector_id)
- if bat:
- bat.set_player_1(player_1_id)
- bat.set_player_2(player_2_id)
- bat.set_winner(winner_id)
- bat.set_score(score)
- bat.set_victory_condition(victory_condition)
- bat.set_comment(comment)
+ bat.set_player_1(player_1_id)
+ bat.set_player_2(player_2_id)
+ bat.set_winner(winner_id)
+ bat.set_score(score)
+ bat.set_victory_condition(victory_condition)
+ bat.set_comment(comment)
- def remove_battle(self, sector_id: str) -> None:
+ def remove_battle(self, sector_id: str):
del self.battles[sector_id]
@@ -116,16 +113,16 @@ class Choice:
)
self.comment: str | None = None
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.participant_id = new_id
- def set_priority(self, new_priority_id: str | None) -> None:
+ def set_priority(self, new_priority_id: str):
self.priority_sector_id = new_priority_id
- def set_secondary(self, new_secondary_id: str | None) -> None:
+ def set_secondary(self, new_secondary_id: str):
self.secondary_sector_id = new_secondary_id
- def set_comment(self, new_comment: str | None) -> None:
+ def set_comment(self, new_comment: str):
self.comment = new_comment
@@ -144,23 +141,23 @@ class Battle:
self.victory_condition: str | None = None
self.comment: str | None = None
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.sector_id = new_id
- def set_player_1(self, new_player_id: str | None) -> None:
+ def set_player_1(self, new_player_id: str):
self.player_1_id = new_player_id
- def set_player_2(self, new_player_id: str | None) -> None:
+ def set_player_2(self, new_player_id: str):
self.player_2_id = new_player_id
- def set_winner(self, new_player_id: str | None) -> None:
+ def set_winner(self, new_player_id: str):
self.winner_id = new_player_id
- def set_score(self, new_score: str | None) -> None:
+ def set_score(self, new_score: str):
self.score = new_score
- def set_victory_condition(self, new_victory_condition: str | None) -> None:
+ def set_victory_condition(self, new_victory_condition: str):
self.victory_condition = new_victory_condition
- def set_comment(self, new_comment: str | None) -> None:
+ def set_comment(self, new_comment: str):
self.comment = new_comment
diff --git a/src/warchron/model/war.py b/src/warchron/model/war.py
index 70cf6f4..8cb9464 100644
--- a/src/warchron/model/war.py
+++ b/src/warchron/model/war.py
@@ -1,35 +1,34 @@
from __future__ import annotations
from uuid import uuid4
from datetime import datetime
-from typing import Any, Dict, List
from warchron.model.campaign import Campaign, Sector, CampaignParticipant
from warchron.model.round import Round, Choice, Battle
class War:
- def __init__(self, name: str, year: int) -> None:
+ def __init__(self, name: str, year: int):
self.id: str = str(uuid4())
self.name: str = name
self.year: int = year
- self.participants: Dict[str, WarParticipant] = {}
- self.objectives: Dict[str, Objective] = {}
- self.campaigns: List[Campaign] = []
+ self.participants: dict[str, WarParticipant] = {}
+ self.objectives: dict[str, Objective] = {}
+ self.campaigns: list[Campaign] = []
self.is_over: bool = False
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_name(self, new_name: str) -> None:
+ def set_name(self, new_name: str):
self.name = new_name
- def set_year(self, new_year: int) -> None:
+ def set_year(self, new_year: int):
self.year = new_year
- def set_state(self, new_state: bool) -> None:
+ def set_state(self, new_state: bool):
self.is_over = new_state
- def toDict(self) -> Dict[str, Any]:
+ def toDict(self):
return {
"id": self.id,
"name": self.name,
@@ -40,7 +39,7 @@ class War:
}
@staticmethod
- def fromDict(data: Dict[str, Any]) -> War:
+ def fromDict(data: dict):
war = War(name=data["name"], year=data["year"])
war.set_id(data["id"])
# war.participants = data.get("participants", {})
@@ -59,7 +58,7 @@ class War:
def get_objective(self, id: str) -> Objective:
return self.objectives[id]
- def get_all_objectives(self) -> List[Objective]:
+ def get_all_objectives(self) -> list[Objective]:
return list(self.objectives.values())
def get_objective_name(self, objective_id: str | None) -> str:
@@ -68,14 +67,12 @@ class War:
obj = self.objectives.get(objective_id)
return obj.name if obj else ""
- def update_objective(
- self, objective_id: str, *, name: str, description: str
- ) -> None:
+ def update_objective(self, objective_id: str, *, name: str, description: str):
obj = self.get_objective(objective_id)
obj.set_name(name)
obj.set_description(description)
- def remove_objective(self, objective_id: str) -> None:
+ def remove_objective(self, objective_id: str):
# TODO manage sectors referring to it
del self.objectives[objective_id]
@@ -100,15 +97,15 @@ class War:
def get_war_participant(self, id: str) -> WarParticipant:
return self.participants[id]
- def get_all_war_participants(self) -> List[WarParticipant]:
+ def get_all_war_participants(self) -> list[WarParticipant]:
return list(self.participants.values())
- def update_war_participant(self, player_id: str, *, faction: str) -> None:
+ def update_war_participant(self, player_id: str, *, faction: str):
part = self.get_war_participant(player_id)
# Can't change referred Model.players
part.set_faction(faction)
- def remove_war_participant(self, player_id: str) -> None:
+ def remove_war_participant(self, player_id: str):
# TODO manage campaign_participants referring to it
del self.participants[player_id]
@@ -117,7 +114,7 @@ class War:
def has_campaign(self, campaign_id: str) -> bool:
return any(c.id == campaign_id for c in self.campaigns)
- def get_default_campaign_values(self) -> Dict[str, Any]:
+ def get_default_campaign_values(self) -> dict:
return {"month": datetime.now().month}
def add_campaign(self, name: str, month: int | None = None) -> Campaign:
@@ -153,15 +150,15 @@ class War:
return camp
raise KeyError(f"Participant {participant_id} not found in any Campaign")
- def update_campaign(self, campaign_id: str, *, name: str, month: int) -> None:
+ def update_campaign(self, campaign_id: str, *, name: str, month: int):
camp = self.get_campaign(campaign_id)
camp.set_name(name)
camp.set_month(month)
- def get_all_campaigns(self) -> List[Campaign]:
+ def get_all_campaigns(self) -> list[Campaign]:
return list(self.campaigns)
- def remove_campaign(self, campaign_id: str) -> None:
+ def remove_campaign(self, campaign_id: str):
camp = self.get_campaign(campaign_id)
self.campaigns.remove(camp)
@@ -169,7 +166,7 @@ class War:
def add_sector(
self,
- campaign_id: str,
+ campaign_id,
name: str,
round_id: str,
major_id: str,
@@ -179,12 +176,8 @@ class War:
camp = self.get_campaign(campaign_id)
return camp.add_sector(name, round_id, major_id, minor_id, influence_id)
- def get_sector(self, sector_id: str) -> Sector:
- for camp in self.campaigns:
- for sect in camp.sectors.values():
- if sect.id == sector_id:
- return sect
- raise KeyError("Sector not found")
+ def get_sector(self, id: str) -> Sector:
+ return self.sectors[id]
def update_sector(
self,
@@ -195,7 +188,7 @@ class War:
major_id: str,
minor_id: str,
influence_id: str,
- ) -> None:
+ ):
camp = self.get_campaign_by_sector(sector_id)
camp.update_sector(
sector_id,
@@ -206,13 +199,13 @@ class War:
influence_id=influence_id,
)
- def remove_sector(self, sector_id: str) -> None:
+ def remove_sector(self, sector_id: str):
camp = self.get_campaign_by_sector(sector_id)
camp.remove_sector(sector_id)
# Campaign participant methods
- def get_available_war_participants(self, campaign_id: str) -> List[WarParticipant]:
+ def get_available_war_participants(self, campaign_id: str) -> list[WarParticipant]:
camp = self.get_campaign(campaign_id)
return [
part
@@ -226,8 +219,8 @@ class War:
camp = self.get_campaign(campaign_id)
return camp.add_campaign_participant(participant_id, leader, theme)
- def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
- for camp in self.campaigns:
+ def get_campaign_participant(self, participant_id) -> CampaignParticipant:
+ for camp in self.campaigns.values():
for part in camp.participants.values():
if part.id == participant_id:
return part
@@ -235,11 +228,11 @@ class War:
def update_campaign_participant(
self, participant_id: str, *, leader: str, theme: str
- ) -> None:
+ ):
camp = self.get_campaign_by_campaign_participant(participant_id)
camp.update_campaign_participant(participant_id, leader=leader, theme=theme)
- def remove_campaign_participant(self, participant_id: str) -> None:
+ def remove_campaign_participant(self, participant_id: str):
camp = self.get_campaign_by_campaign_participant(participant_id)
camp.remove_campaign_participant(participant_id)
@@ -253,7 +246,7 @@ class War:
camp = self.get_campaign(campaign_id)
return camp.add_round()
- def remove_round(self, round_id: str) -> None:
+ def remove_round(self, round_id: str):
camp = self.get_campaign_by_round(round_id)
camp.remove_round(round_id)
@@ -270,13 +263,13 @@ class War:
priority_sector_id: str | None,
secondary_sector_id: str | None,
comment: str | None,
- ) -> None:
+ ):
camp = self.get_campaign_by_round(round_id)
camp.update_choice(
- round_id, participant_id, priority_sector_id, secondary_sector_id, comment
+ participant_id, priority_sector_id, secondary_sector_id, comment
)
- def remove_choice(self, round_id: str, participant_id: str) -> None:
+ def remove_choice(self, round_id: str, participant_id: str):
camp = self.get_campaign_by_round(round_id)
camp.remove_choice(round_id, participant_id)
@@ -296,10 +289,9 @@ class War:
score: str | None,
victory_condition: str | None,
comment: str | None,
- ) -> None:
+ ):
camp = self.get_campaign_by_round(round_id)
camp.update_battle(
- round_id,
sector_id,
player_1_id,
player_2_id,
@@ -309,7 +301,7 @@ class War:
comment,
)
- def remove_battle(self, round_id: str, sector_id: str) -> None:
+ def remove_battle(self, round_id: str, sector_id: str):
camp = self.get_campaign_by_round(round_id)
camp.remove_battle(round_id, sector_id)
@@ -320,13 +312,13 @@ class Objective:
self.name: str = name
self.description: str = description
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_name(self, new_name: str) -> None:
+ def set_name(self, new_name: str):
self.name = new_name
- def set_description(self, new_description: str) -> None:
+ def set_description(self, new_description: str):
self.description = new_description
@@ -336,11 +328,11 @@ class WarParticipant:
self.player_id: str = player_id # ref to WarModel.players
self.faction: str = faction
- def set_id(self, new_id: str) -> None:
+ def set_id(self, new_id: str):
self.id = new_id
- def set_player(self, new_player: str) -> None:
+ def set_player(self, new_player: str):
self.player_id = new_player
- def set_faction(self, new_faction: str) -> None:
+ def set_faction(self, new_faction: str):
self.faction = new_faction
diff --git a/src/warchron/model/war_participant.py b/src/warchron/model/war_participant.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/warchron/model/__init__.py b/src/warchron/view/__ini__.py
similarity index 100%
rename from src/warchron/model/__init__.py
rename to src/warchron/view/__ini__.py
diff --git a/src/warchron/view/__init__.py b/src/warchron/view/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/warchron/view/ui/ui_main_window.py b/src/warchron/view/ui/ui_main_window.py
index 8e1cd65..04374bf 100644
--- a/src/warchron/view/ui/ui_main_window.py
+++ b/src/warchron/view/ui/ui_main_window.py
@@ -70,12 +70,12 @@ class Ui_MainWindow(object):
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_2.addItem(spacerItem1)
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
- self.splitter = QtWidgets.QSplitter(parent=self.warsTab)
- self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
- self.splitter.setObjectName("splitter")
- self.warsTree = QtWidgets.QTreeWidget(parent=self.splitter)
+ self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_6.setObjectName("horizontalLayout_6")
+ self.warsTree = QtWidgets.QTreeWidget(parent=self.warsTab)
self.warsTree.setObjectName("warsTree")
- self.selectedDetailsStack = QtWidgets.QStackedWidget(parent=self.splitter)
+ self.horizontalLayout_6.addWidget(self.warsTree)
+ self.selectedDetailsStack = QtWidgets.QStackedWidget(parent=self.warsTab)
self.selectedDetailsStack.setObjectName("selectedDetailsStack")
self.pageEmpty = QtWidgets.QWidget()
self.pageEmpty.setObjectName("pageEmpty")
@@ -137,6 +137,8 @@ class Ui_MainWindow(object):
self.addObjectiveBtn.setObjectName("addObjectiveBtn")
self.horizontalLayout_9.addWidget(self.addObjectiveBtn)
self.gridLayout_3.addLayout(self.horizontalLayout_9, 2, 0, 1, 4)
+ spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.gridLayout_3.addItem(spacerItem4, 5, 3, 1, 1)
self.endWarBtn = QtWidgets.QPushButton(parent=self.pageWar)
self.endWarBtn.setEnabled(True)
self.endWarBtn.setObjectName("endWarBtn")
@@ -177,8 +179,8 @@ class Ui_MainWindow(object):
self.endCampaignBtn.setEnabled(True)
self.endCampaignBtn.setObjectName("endCampaignBtn")
self.gridLayout_4.addWidget(self.endCampaignBtn, 5, 1, 1, 1)
- spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.gridLayout_4.addItem(spacerItem4, 5, 2, 1, 1)
+ spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.gridLayout_4.addItem(spacerItem5, 5, 2, 1, 1)
self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
self.horizontalLayout_12.setObjectName("horizontalLayout_12")
self.campaignParticipantsTable = QtWidgets.QTableWidget(parent=self.pageCampaign)
@@ -254,8 +256,8 @@ class Ui_MainWindow(object):
self.endRoundBtn.setEnabled(True)
self.endRoundBtn.setObjectName("endRoundBtn")
self.gridLayout_5.addWidget(self.endRoundBtn, 5, 1, 1, 1)
- spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.gridLayout_5.addItem(spacerItem5, 5, 2, 1, 1)
+ spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.gridLayout_5.addItem(spacerItem6, 5, 2, 1, 1)
self.horizontalLayout_15 = QtWidgets.QHBoxLayout()
self.horizontalLayout_15.setObjectName("horizontalLayout_15")
self.battlesTable = QtWidgets.QTableWidget(parent=self.pageRound)
@@ -302,14 +304,15 @@ class Ui_MainWindow(object):
self.horizontalLayout_14.addWidget(self.roundNb)
self.gridLayout_5.addLayout(self.horizontalLayout_14, 0, 0, 1, 3)
self.selectedDetailsStack.addWidget(self.pageRound)
- self.verticalLayout_3.addWidget(self.splitter)
+ self.horizontalLayout_6.addWidget(self.selectedDetailsStack)
+ self.verticalLayout_3.addLayout(self.horizontalLayout_6)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
self.tabWidget.addTab(self.warsTab, icon2, "")
self.verticalLayout.addWidget(self.tabWidget)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
- self.menubar.setGeometry(QtCore.QRect(0, 0, 1288, 21))
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1288, 31))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(parent=self.menubar)
self.menuFile.setObjectName("menuFile")
@@ -384,7 +387,7 @@ class Ui_MainWindow(object):
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(1)
- self.selectedDetailsStack.setCurrentIndex(1)
+ self.selectedDetailsStack.setCurrentIndex(3)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
diff --git a/src/warchron/view/ui/ui_main_window.ui b/src/warchron/view/ui/ui_main_window.ui
index 0be2351..49cde9f 100644
--- a/src/warchron/view/ui/ui_main_window.ui
+++ b/src/warchron/view/ui/ui_main_window.ui
@@ -137,476 +137,490 @@
-
-
-
- Qt::Horizontal
-
-
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+ -
+
+
+ 3
-
-
-
-
- 1
-
-
-
- -
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Select an element within the tree to show/edit details.
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
+
+
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Select an element within the tree to show/edit details.
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Name
+
+
+
+
+ Faction
+
+
+
+
+ Campaigns
+
+
+
+
+ Victory pts.
+
+
+
+
+ Theme pts
+
+
+
+
+ -
+
+
+ Add participant
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 10
+
+
+
+ Add objective
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ true
+
+
+ End war
+
+
+
+ -
+
+
+ Participants
+
+
+
+ -
+
+
+ Objectives
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ warName
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ warYear
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Sectors
+
+
+
+ -
+
+
+ Participants
+
+
+
+ -
+
+
+ true
+
+
+ End campaign
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
-
+
+
+
+ Name
+
+
+
+
+ Leader
+
+
+
+
+ Theme
+
+
+
+
+ Victory pts.
+
+
+
+
+ Theme pts.
+
+
+
+
+ -
+
+
+ Add participant
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Name
+
+
+
+
+ Round
+
+
+
+
+ Major obj.
+
+
+
+
+ Minor opp.
+
+
+
+
+ Influence imp.
+
+
+
+
+ Description
+
+
+
+
+ -
+
+
+ true
+
+
+ Add Sector
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ campaignName
+
+
+
+ -
+
+
+
+ 12
+
+
+
+ campaignMonth
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Choices
+
+
+
+ -
+
+
+ Battles
+
+
+
+ -
+
+
+ true
+
+
+ End round
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
-
+
+
+
+ Sector
+
+
+
+
+ Player 1
+
+
+
+
+ Player 2
+
+
+
+
+ -
+
+
+ false
+
+
+ Count results
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Player
+
+
+
+
+ Priority
+
+
+
+
+ Secondary
+
+
+
+
+ -
+
+
+ true
+
+
+ Resolve pairing
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 12
+
+
+
+ Round Nb
+
+
+
+
+
+
+
-
-
- -
-
-
-
-
-
-
- Name
-
-
-
-
- Faction
-
-
-
-
- Campaigns
-
-
-
-
- Victory pts.
-
-
-
-
- Theme pts
-
-
-
-
- -
-
-
- Add participant
-
-
-
-
-
- -
-
-
-
-
-
-
- Name
-
-
-
-
- Description
-
-
-
-
- -
-
-
- true
-
-
-
- 10
-
-
-
- Add objective
-
-
-
-
-
- -
-
-
- true
-
-
- End war
-
-
-
- -
-
-
- Participants
-
-
-
- -
-
-
- Objectives
-
-
-
- -
-
-
-
-
-
-
- 12
-
-
-
- warName
-
-
-
- -
-
-
-
- 12
-
-
-
- warYear
-
-
-
-
-
-
-
-
-
- -
-
-
- Sectors
-
-
-
- -
-
-
- Participants
-
-
-
- -
-
-
- true
-
-
- End campaign
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
- Name
-
-
-
-
- Leader
-
-
-
-
- Theme
-
-
-
-
- Victory pts.
-
-
-
-
- Theme pts.
-
-
-
-
- -
-
-
- Add participant
-
-
-
-
-
- -
-
-
-
-
-
-
- Name
-
-
-
-
- Round
-
-
-
-
- Major obj.
-
-
-
-
- Minor opp.
-
-
-
-
- Influence imp.
-
-
-
-
- Description
-
-
-
-
- -
-
-
- true
-
-
- Add Sector
-
-
-
-
-
- -
-
-
-
-
-
-
- 12
-
-
-
- campaignName
-
-
-
- -
-
-
-
- 12
-
-
-
- campaignMonth
-
-
-
-
-
-
-
-
-
- -
-
-
- Choices
-
-
-
- -
-
-
- Battles
-
-
-
- -
-
-
- true
-
-
- End round
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
- Sector
-
-
-
-
- Player 1
-
-
-
-
- Player 2
-
-
-
-
- -
-
-
- false
-
-
- Count results
-
-
-
-
-
- -
-
-
-
-
-
-
- Player
-
-
-
-
- Priority
-
-
-
-
- Secondary
-
-
-
-
- -
-
-
- true
-
-
- Resolve pairing
-
-
-
-
-
- -
-
-
-
-
-
-
- 12
-
-
-
- Round Nb
-
-
-
-
-
-
-
-
-
+
+
@@ -620,7 +634,7 @@
0
0
1288
- 21
+ 31