Skip to content

Track war losses as wounds and settle them when the war ends - #239

Merged
Drefvelin merged 1 commit into
mainfrom
feat/war-wounds
Nov 11, 2026
Merged

Drefvelin merged 1 commit into
mainfrom
feat/war-wounds

Conversation

@Drefvelin

Copy link
Copy Markdown
Contributor

Battles no longer shrink regiments when they end. Losses are now wounds that staff can correct during the war, and they are settled when the war ends.

What changes for players

  • Forces at battle start: when a campaign field battle or siege starts, each force on a side puts lives into the side's shared pool (5 per slot). The battle records what each force brought.
    • Fighting factions: the regiments allowed in that battle.
    • Non-fighting subjects: their levy, which is the levy % of every regiment, militia included. On a subject's own province its whole militia defends instead.
    • Hired mercenaries: the members on the roster, up to their healthy slots.
  • Losses at battle end: the side's deaths become wounds. They are split between forces by the lives each brought, militia first inside a force, then between law and paid slots in proportion. No force takes more than it brought, so lives staff add cost nobody.
  • Law slots are full again after every battle.
  • Wounded paid slots cannot fight, cost no upkeep and cannot be disbanded. They are lost when the war ends, once.
  • Mercenary companies never lose slots. Their wounds are shared by all their contracts and heal by mercenary_heal_percent every mercenary_heal_hours, counted from the latest new wound.
  • One army per faction across all its wars. Recruiting during a war reinforces it.
  • Regiment screen: shows wounded slots.

Staff tools

  • /war admin losses <war> lists recorded battles and what the war's end will take. /war admin losses <war> <battle#> attacker|defender set|add|remove <deaths> [reason] corrects a battle's deaths.
  • /war admin army <faction> shows each regiment's slots, wounds per war and what can fight.
  • /war admin wounds <war> <faction> <regiment> add|remove <lives> and /war admin wounds company <guild> [set <lives>] change wounds directly.
  • /battle lives <battle> <side> set|add|remove <n> now works before a campaign battle starts, and auto resets it. Before, it was refused until the battle started, and /battle setlives refused campaign battles.

Under the hood

  • Each war keeps a WarLedger (saved in WarData.ledger).
  • Faction wounds are worked out from the ledger every time, so a corrected battle changes them exactly.
  • The war commitment snapshot (WarCommitment, WarCommitmentService, LevySnapshotCalculator, BattlePoolService) is gone. Everything reads the live armies through BattleForces.
  • Settlement runs in WarManager.endWar before the civil war untangle, and is marked settled before any slots change.
  • New war.yml keys: war.battle_military.mercenary_heal_percent (25) and mercenary_heal_hours (6).

Not in this PR

The website's war pages keep the losses originally reported for a battle. They do not show staff corrections yet.

Testing

  • Unit tests: mvn verify locally. All pass except the two known local-only failures, and the only uncovered lines are the known environment-only ones.
  • Dev:
    • Declared AIRPLANE vs Rat_Hill. /battle lives campaign_w1_p244 attacker set 95 before the start applied 95; the defender went back to 44 with auto.
    • Killed bots in the battle: 2 attacker and 3 defender deaths. Rat_Hill's 3 landed on its paid militia.
    • Corrected the defender to 20 deaths, which wounded 4 militia slots, and added 8 wounded lives to AIRPLANE professional.
    • /war admin end took exactly the previewed slots: militia 5 → 1, professional 100 → 98. Law slots were untouched.
    • Dev data was restored afterwards.

🤖 Generated with Claude Code

Battles no longer shrink regiments as they end. Each campaign battle side
records what every force brought (faction regiments, subjects' levies
including militia, a subject's whole militia on its own province, and
mercenaries on the roster) and its deaths. The deaths become wounds:
shared between forces by lives brought, militia first inside a force,
then law and paid slots in proportion. Law slots are full after every
battle; wounded paid slots cannot fight, cost no upkeep and are lost
when the war ends. Mercenary companies heal a percentage every few
hours and never lose slots. Each faction has one army over all its
wars, and recruiting during a war reinforces it.

Each war keeps a ledger of its battles, so staff can fix losses with
/war admin losses, /war admin army and /war admin wounds, and set a
campaign battle's starting lives with /battle lives before it starts.
The war commitment snapshot is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 108 files, which is 8 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 10c84489-3720-4a89-93e6-2013f13f667a
Commits

Reviewing files that changed from the base of the PR and between d36d394 and 6461b2d.

Files selected for processing: 108

  • README.md
  • src/main/java/net/tfminecraft/simplefactions/Cache.java
  • src/main/java/net/tfminecraft/simplefactions/army/Military.java
  • src/main/java/net/tfminecraft/simplefactions/army/Regiment.java
  • src/main/java/net/tfminecraft/simplefactions/database/BattleSideData.java
  • src/main/java/net/tfminecraft/simplefactions/database/CommitmentData.java
  • src/main/java/net/tfminecraft/simplefactions/database/MercenaryCompanyData.java
  • src/main/java/net/tfminecraft/simplefactions/database/WarData.java
  • src/main/java/net/tfminecraft/simplefactions/economy/settlement/FactionUpkeepPlan.java
  • src/main/java/net/tfminecraft/simplefactions/espionage/EspionageService.java
  • src/main/java/net/tfminecraft/simplefactions/loaders/ConfigLoader.java
  • src/main/java/net/tfminecraft/simplefactions/managers/InventoryManager.java
  • src/main/java/net/tfminecraft/simplefactions/managers/RelationManager.java
  • src/main/java/net/tfminecraft/simplefactions/managers/WarManager.java
  • src/main/java/net/tfminecraft/simplefactions/managers/inventory/MilitaryCreator.java
  • src/main/java/net/tfminecraft/simplefactions/mercenary/company/MercenaryCompany.java
  • src/main/java/net/tfminecraft/simplefactions/mercenary/contract/MercenaryEngagements.java
  • src/main/java/net/tfminecraft/simplefactions/mercenary/contract/MercenaryLoyaltyWatcher.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/campaign/CampaignBattleOutcomeService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleSide.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleSideSetupService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleStaffService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/military/BattleCasualtyService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/military/BattleForces.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/military/BattleLivesService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/military/BattlePoolService.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/persistence/BattleMapper.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/ui/BattleCommandManager.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/ui/BattleInventoryManager.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/ui/BattleLivesEditor.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/ui/BattleStaffCommands.java
  • src/main/java/net/tfminecraft/simplefactions/war/battle/ui/BattleTabCompletion.java
  • src/main/java/net/tfminecraft/simplefactions/war/campaign/progression/CampaignCapabilityService.java
  • src/main/java/net/tfminecraft/simplefactions/war/campaign/runtime/BattleAutoresolveService.java
  • src/main/java/net/tfminecraft/simplefactions/war/campaign/ui/CampaignBattleIconLore.java
  • src/main/java/net/tfminecraft/simplefactions/war/commitment/LevySnapshotCalculator.java
  • src/main/java/net/tfminecraft/simplefactions/war/commitment/WarCommitmentService.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/CallToArmsService.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/War.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarCommandManager.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarCommitment.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarDebugFormatter.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarDevMode.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarMapper.java
  • src/main/java/net/tfminecraft/simplefactions/war/core/WarTabCompletion.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/BattleForce.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/CompanyWounds.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/ForceKind.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/ForcePart.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/WarArmyAdmin.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/WarLedger.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/WarWounds.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/Wound.java
  • src/main/java/net/tfminecraft/simplefactions/war/wounds/WoundAllocator.java
  • src/main/resources/war.yml
  • src/test/java/net/tfminecraft/simplefactions/diplomacy/RealmRelationsBoundaryCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/economy/settlement/FactionUpkeepWoundsTest.java
  • src/test/java/net/tfminecraft/simplefactions/managers/InventoryManagerCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/managers/WarManagerCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/managers/WarManagerStartCivilWarTest.java
  • src/test/java/net/tfminecraft/simplefactions/managers/inventory/ArmyMenusCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/mercenary/company/MercenaryCompanyPersistenceTest.java
  • src/test/java/net/tfminecraft/simplefactions/mercenary/contract/MercenaryLivesTest.java
  • src/test/java/net/tfminecraft/simplefactions/mercenary/contract/MercenaryRosterTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/actions/WarActionApplierTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/campaign/CampaignBattleJoinServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/campaign/CampaignBattleOutcomeServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/campaign/CampaignBattleRosterServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/campaign/WarbandCampaignSignupTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/campaign/warband/CampaignWarbandSignupServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleEngineListenersCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleJoinServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/engine/core/BattleStaffServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/engine/core/CampaignBattleRuntimeBoundaryCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattleCasualtyLifecycleCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattleCasualtyServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattleForcesTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattleLivesServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattleMilitaryBoundaryCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/military/BattlePoolServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/ui/BattleCommandsCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/ui/BattleInventoryCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/ui/BattleStaffUiTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/battle/warband/BattleRosterBoundaryCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/admin/WarScheduleAdminServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/progression/CampaignCapabilityServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/runtime/BattleAutoresolveCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/runtime/BattleAutoresolveServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/runtime/BattleScheduleServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/campaign/runtime/BattleScheduleTickServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/civilwar/CivilWarLifecycleCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/commitment/LevySnapshotCalculatorTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/CallToArmsServiceTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarCommandsCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarCommitmentTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarDataRoundTripTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarDebugFormatterTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarDevModeTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/core/WarPersistenceCoverageTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/history/WarHistoryEventsTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/resolution/PillageMissingBankRegressionTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/CompanyWoundsTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/TestForces.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/WarArmyAdminTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/WarLedgerTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/WarWoundsTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/WoundAllocatorTest.java
  • src/test/java/net/tfminecraft/simplefactions/war/wounds/WoundFixture.java

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions github-actions Bot added the size:XXL 1,000+ effective changed lines (tests excluded in mixed PRs). label Nov 11, 2026
@Drefvelin
Drefvelin merged commit 6e60c40 into main Nov 11, 2026
3 checks passed
@Drefvelin
Drefvelin deleted the feat/war-wounds branch November 11, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ effective changed lines (tests excluded in mixed PRs).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant