Skip to content

Feature - Campaign Persistence#90

Merged
Tapawingo merged 23 commits intomainfrom
feature/campaign-persistence
Nov 24, 2025
Merged

Feature - Campaign Persistence#90
Tapawingo merged 23 commits intomainfrom
feature/campaign-persistence

Conversation

@Tapawingo
Copy link
Contributor

@Tapawingo Tapawingo commented Nov 19, 2025

When merged this pull request will:

  • Add campaign saving/loading system
  • Add Unit state persistence
  • Wire up unit reinforcements
  • Wire up Resupply
  • Add basic unit experience system
  • Fix minor UX bug with the new/edit unit in the scenario editor

Issue ticket number and link

Checklist before requesting a review

  • I have performed a self-review of my code.
  • I have tested my code.
  • I have documented my code in accordance with gdscript_documentation_comments.
  • I have requested a review in discord.
  • I have moved the related issues to the review section in the SCRUM Board.

@GianRathgeb
Copy link
Contributor

Looks good to me but before aproving, there are some smaller thigns that could lead to bugs in the future

  • scripts/core/Game.gd (lines 247-278) only serializes ScenarioData.units, while the player’s roster lives in scenario.playable_units (instantiated in scripts/ui/HQTable.gd (lines 36-37)). As a result, CampaignSave.unit_states never records the playable units’ casualties, cohesion, equipment, or ammo, so “unit state persistence / save casualties” doesn’t actually happen—every mission reload resets units to their template defaults.

  • Pre-mission persistence also breaks because HQTable.generate_playable_units (scripts/ui/HQTable.gd (lines 266-289)) instantiates fresh ScenarioUnit objects directly from ContentDB and ignores any saved strength/ammo state captured by _save_temp_unit_states in Unit Select. Reinforcements or resupply spent before “Deploy” vanish when the mission scene starts.

  • Reinforcement spending is tracked only on Game.current_scenario.replacement_pool inside Unit Select (scripts/ui/UnitSelect.gd (lines 661-700)). The campaign-level pool (Game.get_replacement_pool/set_replacement_pool, persisted via campaign_replacement_pool) is never updated, so replacement counts reset whenever you reopen the scene and nothing gets saved.

  • The “Track unit experience, grant bonuses. Players become attached to units.” line came from the task description rather than the PR itself, and, indeed, the current code still doesn’t touch UnitData.experience other than displaying it (scripts/ui/UnitSelect.gd (line 390)), so there’s no experience gain or bonus logic implemented.

the resupply and replacement pools shouldn't be persisted in the campaign but rather set on a per-mission basis to reflect available supply for that mission.

Also fixed menu issues by refactoring supply panel to not expand outside the screen rect.
@Tapawingo
Copy link
Contributor Author

scripts/core/Game.gd (lines 247-278) only serializes ScenarioData.units, while the player’s roster lives in scenario.playable_units (instantiated in scripts/ui/HQTable.gd (lines 36-37)). As a result, CampaignSave.unit_states never records the playable units’ casualties, cohesion, equipment, or ammo, so “unit state persistence / save casualties” doesn’t actually happen—every mission reload resets units to their template defaults.

Pushed a fix which fixes this.

Pre-mission persistence also breaks because HQTable.generate_playable_units (scripts/ui/HQTable.gd (lines 266-289)) instantiates fresh ScenarioUnit objects directly from ContentDB and ignores any saved strength/ammo state captured by _save_temp_unit_states in Unit Select. Reinforcements or resupply spent before “Deploy” vanish when the mission scene starts.

Pushed a fix for this.

Reinforcement spending is tracked only on Game.current_scenario.replacement_pool inside Unit Select (scripts/ui/UnitSelect.gd (lines 661-700)). The campaign-level pool (Game.get_replacement_pool/set_replacement_pool, persisted via campaign_replacement_pool) is never updated, so replacement counts reset whenever you reopen the scene and nothing gets saved.

This is intended behaviour, the supply, equipment and reinforcement pools are on a per-mission basis (so the designer can design a lack of supply for certain missions). The campaign wide pool is a deprecated pool from when i was still conceptualizing how this should work.

The “Track unit experience, grant bonuses. Players become attached to units.” line came from the task description rather than the PR itself, and, indeed, the current code still doesn’t touch UnitData.experience other than displaying it (scripts/ui/UnitSelect.gd (line 390)), so there’s no experience gain or bonus logic implemented.

Pushed a implementation of this system.

I think this is not from this PR but I found this issue that the button is almost out of screen in this menu bar (see picture)

Fixed this (and made the UI better).

@GianRathgeb
Copy link
Contributor

Most of this is fixed. Since AI is way better at describing this, here is a little description from AI that can help solving the issues:
Playable unit state persistence: Now implemented. Game.save_campaign_state() writes state for current_scenario.playable_units, and HQTable.generate_playable_units() hydrates new ScenarioUnits from Game.current_save, so playable units’ strength/injury/equipment/ammo survive between missions. Note restore_unit_states_from_save() still only touches scenario.units, but the loadout/HQ path restores state via generate_playable_units, so the earlier “always reset to defaults” problem is addressed for the player roster.

Pre-mission persistence: Fixed. HQTable.generate_playable_units() now pulls saved state (including ammo/equipment) from Game.current_save, and _save_temp_unit_states() persists edits, so resupply/reinforcement changes made before deploy carry into the mission.

Reinforcement pool: Your intent is per-mission pools, and the code matches that: UnitSelect reads/writes Game.current_scenario.replacement_pool and nothing persists a campaign-wide pool.

Experience: Implemented and awarded (Game._award_experience_to_units, medal handling, UnitSelect displays it), but there’s a regression: save_campaign_state() writes unit states without the experience field, so any XP gained in _award_experience_to_units() gets overwritten when the save happens. Add experience to the state dictionary in save_campaign_state() to preserve XP between missions.

@Tapawingo
Copy link
Contributor Author

pushed a fix for the unit xp regression issue.

@GianRathgeb
Copy link
Contributor

aproved

@Tapawingo Tapawingo merged commit e384d0b into main Nov 24, 2025
3 checks passed
@Tapawingo Tapawingo deleted the feature/campaign-persistence branch November 24, 2025 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants