Add branch-aware camp conversations

This commit is contained in:
2026-06-18 18:16:38 +09:00
parent 87e75ea018
commit 4bd18a3f53
8 changed files with 155 additions and 10 deletions

View File

@@ -488,7 +488,7 @@ Scenario deployments may override `move_type` for special units. For example, a
`objectives` are display text. `conditions` drive the actual victory and defeat checks. Defeat is evaluated before victory, matching Cao Cao Zhuan-style commander-loss rules. If `conditions` is omitted, battles fall back to defeating all enemies for victory and losing all player units for defeat.
`briefing.camp_conversations` drives the pre-battle Talk menu. Each entry needs a stable lowercase `id`, a non-empty `label`, a `group` of `officer` or `topic`, and non-empty dialogue `lines`. Officer conversations also need an `officer_id` that exists in `officers.json`; `BattleState` normalizes their dialogue lines so speaker portraits can be filled from officer defaults. Optional `effects` can currently include `grant_item` entries with an `item_id`, optional positive `count`, and optional non-empty `text`. Camp conversation supplies are claimed once per scenario/conversation, saved immediately to campaign inventory through `CampaignState`, and copied into the already-loaded battle inventory; completed-scenario replays cannot claim them. If `camp_conversations` is absent, the older `briefing.camp_dialogue` array is still exposed as one fallback War Council conversation.
`briefing.camp_conversations` drives the pre-battle Talk menu. Each entry needs a stable lowercase `id`, a non-empty `label`, a `group` of `officer` or `topic`, and non-empty dialogue `lines`. Officer conversations also need an `officer_id` that exists in `officers.json`; `BattleState` normalizes their dialogue lines so speaker portraits can be filled from officer defaults. Optional `campaign_flags`, such as `"campaign_flags": { "regrouped_after_sishui": true }`, can hide a conversation unless saved flags match exactly. Optional `effects` can currently include `grant_item` entries with an `item_id`, optional positive `count`, and optional non-empty `text`. Camp conversation supplies are claimed once per scenario/conversation, saved immediately to campaign inventory through `CampaignState`, and copied into the already-loaded battle inventory; completed-scenario replays cannot claim them. If `camp_conversations` is absent, the older `briefing.camp_dialogue` array is still exposed as one fallback War Council conversation.
`BattleState` also exposes condition progress and defeat-risk text for presentation. The active HUD and briefing panels split objective, progress, and risk details while showing defeated enemy counts, destination reach status, named commander or protected-unit safety, and turns remaining from the same `conditions` data. Conditions gated by `after_event` stay marked as pending; when the referenced event is a `unit_reaches_tile` or `turn_start` trigger, the tracker can surface that prerequisite as the next visible objective, and `unit_reaches_tile` prerequisites can also draw objective markers while the gated condition is still locked.
@@ -632,7 +632,7 @@ Movement-triggered gold caches can use `grant_gold` with a positive `amount`. Th
}
```
`briefing.conditional_lines`, `shop.conditional_items`, and `when.campaign_flags` all use exact flag matching. When present, every listed flag must match the saved campaign flag value for that block or event to apply. Use separate blocks or events for OR-style branches. The validator requires referenced flags to have been introduced by an earlier `post_battle_choices.set_flags` entry in campaign order.
`briefing.conditional_lines`, `briefing.camp_conversations[].campaign_flags`, `shop.conditional_items`, and `when.campaign_flags` all use exact flag matching. When present, every listed flag must match the saved campaign flag value for that block, conversation, or event to apply. Use separate blocks, conversations, or events for OR-style branches. The validator requires referenced flags to have been introduced by an earlier `post_battle_choices.set_flags` entry in campaign order.
Event-spawned units use the same compact deployment shape as scenario starting units. Spawn attempts are skipped if the unit id already exists, the target cell is occupied, the cell is outside the map, or the unit cannot stand on that terrain. Reinforcements that arrive during their own team's phase wait until their next phase before acting.
@@ -650,8 +650,8 @@ During a battle, item consumption, event item pickups, equipment swaps, and uneq
Physical attacks grant normal attack/counter EXP only on hit after the attack/counter exchange resolves. A missed physical attack or counter grants a small miss EXP value, while defeat bonuses still require the attack to hit and defeat the target.
Before a battle starts, `BattleScene` can buy priced items through `CampaignState.try_buy_item()` and sell unequipped inventory through `CampaignState.try_sell_item()`. Successful shop transactions update campaign gold, inventory, and finite-stock purchase counts in the save file immediately, then call `BattleState.set_inventory_snapshot()` so the upcoming battle sees the new stock. Pre-battle Talk can claim `briefing.camp_conversations[].effects` through `CampaignState.try_claim_camp_conversation_effects()`, which saves the supply reward and conversation ledger immediately before refreshing the loaded battle inventory copy. Pre-battle Armory changes call `CampaignState.try_save_prebattle_loadout()`, which merges the currently deployed roster snapshot into the saved roster and saves the adjusted inventory in the same operation. Pre-battle Roster calls `BattleState.try_set_unit_deployed()` to toggle optional player units while enforcing required officers and sortie limits. Pre-battle Formation calls `BattleState.try_set_prebattle_formation()`, which can move a player unit to an open formation cell or swap two player units inside the formation area. Roster and Formation choices are battle setup state, so the manual checkpoint stores campaign progression and saved loadout state but not unsaved sortie or starting-cell edits. Matching `briefing.conditional_lines` and `shop.conditional_items` are merged while the scenario loads, before the briefing panel opens. During battle, item previews can show HP/MP recovery, status cures, and debuff cleanses, and no-effect item use is rejected without consuming stock. `post_battle_dialogue` is rendered by the battle scene after victory and before rewards/choices are shown in the result panel. Post-battle choices call `CampaignState.try_apply_post_battle_choice()`, which saves selected flags and rolls back flags, gold, and inventory if the save write fails.
Before a battle starts, `BattleScene` can buy priced items through `CampaignState.try_buy_item()` and sell unequipped inventory through `CampaignState.try_sell_item()`. Successful shop transactions update campaign gold, inventory, and finite-stock purchase counts in the save file immediately, then call `BattleState.set_inventory_snapshot()` so the upcoming battle sees the new stock. Pre-battle Talk can claim `briefing.camp_conversations[].effects` through `CampaignState.try_claim_camp_conversation_effects()`, which saves the supply reward and conversation ledger immediately before refreshing the loaded battle inventory copy. Pre-battle Armory changes call `CampaignState.try_save_prebattle_loadout()`, which merges the currently deployed roster snapshot into the saved roster and saves the adjusted inventory in the same operation. Pre-battle Roster calls `BattleState.try_set_unit_deployed()` to toggle optional player units while enforcing required officers and sortie limits. Pre-battle Formation calls `BattleState.try_set_prebattle_formation()`, which can move a player unit to an open formation cell or swap two player units inside the formation area. Roster and Formation choices are battle setup state, so the manual checkpoint stores campaign progression and saved loadout state but not unsaved sortie or starting-cell edits. Matching `briefing.conditional_lines`, `briefing.camp_conversations[].campaign_flags`, and `shop.conditional_items` are resolved while the scenario loads, before the briefing panel opens. During battle, item previews can show HP/MP recovery, status cures, and debuff cleanses, and no-effect item use is rejected without consuming stock. `post_battle_dialogue` is rendered by the battle scene after victory and before rewards/choices are shown in the result panel. Post-battle choices call `CampaignState.try_apply_post_battle_choice()`, which saves selected flags and rolls back flags, gold, and inventory if the save write fails.
When every campaign scenario id is present in `completed_scenarios`, the battle scene shows a campaign completion panel. Starting a new campaign clears the automatic save file and resets `current_scenario_id` to `start_scenario`; the manual checkpoint is left alone until overwritten from the Save menu.
Run `tools/validate_data.ps1` after data edits to check campaign paths, chapter ranges, map dimensions, terrain keys, class/officer/item/skill references, skill area shapes, skill status/action-lock effect shapes, item effect names, cure statuses, debuff cleanse effects, class sprites, item icons, map backgrounds, officer and deployment portraits/sprites, officer and deployment equipment slot compatibility including accessory types and weapon effectiveness fields, promotion routes and promotion equipment compatibility, condition/event names, event `after_event` references, event trigger unit/officer filters, event item/gold grants, event withdrawal unit ids, event AI target-priority unit ids, condition unit references, destination `pos`/`cells` coordinates, campaign flag references, joined-officer gates, briefing line blocks, camp dialogue, camp conversations and camp conversation effects, deployment ids, deployment bounds, impassable spawn cells, shop stock, shop merchant lines, roster rules, formation cells, post-battle dialogue, post-battle choices, and reward item ids.
Run `tools/validate_data.ps1` after data edits to check campaign paths, chapter ranges, map dimensions, terrain keys, class/officer/item/skill references, skill area shapes, skill status/action-lock effect shapes, item effect names, cure statuses, debuff cleanse effects, class sprites, item icons, map backgrounds, officer and deployment portraits/sprites, officer and deployment equipment slot compatibility including accessory types and weapon effectiveness fields, promotion routes and promotion equipment compatibility, condition/event names, event `after_event` references, event trigger unit/officer filters, event item/gold grants, event withdrawal unit ids, event AI target-priority unit ids, condition unit references, destination `pos`/`cells` coordinates, campaign flag references, joined-officer gates, briefing line blocks, camp dialogue, camp conversations, camp conversation campaign flags and camp conversation effects, deployment ids, deployment bounds, impassable spawn cells, shop stock, shop merchant lines, roster rules, formation cells, post-battle dialogue, post-battle choices, and reward item ids.