Add battlefield visuals and camp talk slice

This commit is contained in:
2026-06-18 16:45:46 +09:00
parent 909d497df0
commit d723d34a32
25 changed files with 604 additions and 35 deletions

View File

@@ -200,6 +200,7 @@ Classes provide movement, min/max attack range, skill access, growth grades, cla
{
"cavalry": {
"name": "Cavalry",
"sprite": "res://art/units/cavalry.png",
"tier": 1,
"move_type": "mounted",
"move": 5,
@@ -218,6 +219,7 @@ Classes provide movement, min/max attack range, skill access, growth grades, cla
```
`attack_range` is `[min, max]` in Manhattan distance. A range of `[2, 2]` means the unit cannot attack adjacent targets.
`sprite` is an optional class-level board token image used by hydrated units unless an officer or deployment overrides it.
`promotion.level` and `promotion.to` define an automatic class promotion route. When a unit reaches the threshold during battle, the runtime updates class name, movement, movement type, growth, class skills, attack range, and class base-bonus deltas. The promoted `class_id` and derived roster fields are captured in the campaign roster snapshot, and the next battle rehydrates class-derived fields from the saved `class_id`. Promotion targets must be higher-tier classes and must keep all source equipment slot permissions unless runtime auto-unequip logic is added later. The current core routes cover hero, cavalry, infantry, archer, warrior, and strategist first-tier classes.
@@ -310,6 +312,7 @@ Items start as static bonuses and consumable effects. Equipment leveling should
"bronze_sword": {
"name": "Bronze Sword",
"kind": "weapon",
"icon": "res://art/items/sword.png",
"weapon_type": "sword",
"range": [1, 1],
"bonuses": { "atk": 3 },
@@ -320,6 +323,7 @@ Items start as static bonuses and consumable effects. Equipment leveling should
```
Weapon `range` also uses `[min, max]`. When class and equipment both provide range, the runtime unit keeps the lowest minimum and highest maximum. Weapons can optionally define `effective_vs_move_types` plus `effective_bonus_damage` to add a small physical damage bonus during combat against targets with a matching runtime `move_type`; this is shown in attack forecasts, combat logs, shop stock, and equipment menus, but it does not mutate saved unit stats. The first examples are spear vs mounted, bow vs water, and axe vs foot. Accessories use `kind: "accessory"` with an `accessory_type` checked against the class `equipment_slots.accessory` list; `war_drum` and `imperial_seal` are the first branch-choice accessory rewards. Current equipment inventory is stackable stock only; unique equipment instances, durability, and enhancement are planned later. `war_axe` is a stronger axe reward for the Warrior/Bandit weapon family. The first named rewards are `yitian_sword`, `dragon_spear`, `wind_chaser_bow`, and `black_tortoise_robe`; their `rarity` tag is presentation-only and does not enforce uniqueness.
`icon` is an optional item UI image shown in shop, item, and equipment buttons when present.
Consumables use `kind: "consumable"` with effect records. `heal_hp` restores HP, `heal_mp` restores MP, `cure_status` removes active battle-only effects with a matching `status` from a valid target, and `cleanse_debuffs` removes only negative `stat_bonus` effects while leaving positive buffs intact; `Bean`, `Wine`, `Antidote`, and `Panacea` are the first examples. Item use consumes the acting unit's action and only commits to the save file on victory. Weapons, armor, and accessories can be granted through `rewards.items`; they are shown in inventory, can be equipped through the Equip menu before the unit moves or acts, and are not usable from the battle item menu.
@@ -343,7 +347,7 @@ Consumables use `kind: "consumable"` with effect records. `heal_hp` restores HP,
}
```
Scenario `shop.items` controls which positive-price items appear in the current pre-battle shop. `shop.conditional_items` can append extra stock when saved campaign flags match. Entries can be plain item ids or objects with `id` and optional non-negative `stock`; `shop.stock` and conditional block `stock` objects can also set finite limits by item id. Items omitted from stock data are unlimited. Finite stock is tracked as per-scenario purchase counts in the campaign save, so buying an item decrements that scenario's remaining stock and manual checkpoint saves preserve it. Purchases spend campaign gold, increment the campaign inventory count, save immediately, and then refresh the battle inventory copy if a scenario briefing is already loaded. The shop can also sell unequipped inventory stock back for 50% of base `price`, saving immediately and refreshing the loaded battle inventory copy. Later campaign data should add broader unlock flags.
Scenario `shop.items` controls which positive-price items appear in the current pre-battle shop. `shop.merchant` can provide a `name` and `lines` that are shown above buy stock as a lightweight camp event. `shop.conditional_items` can append extra stock when saved campaign flags match. Entries can be plain item ids or objects with `id` and optional non-negative `stock`; `shop.stock` and conditional block `stock` objects can also set finite limits by item id. Items omitted from stock data are unlimited. Finite stock is tracked as per-scenario purchase counts in the campaign save, so buying an item decrements that scenario's remaining stock and manual checkpoint saves preserve it. Purchases spend campaign gold, increment the campaign inventory count, save immediately, and then refresh the battle inventory copy if a scenario briefing is already loaded. The shop can also sell unequipped inventory stock back for 50% of base `price`, saving immediately and refreshing the loaded battle inventory copy. Later campaign data should add broader unlock flags.
The pre-battle Armory operates on the currently loaded player deployments and the copied battle inventory, then saves the changed roster entries and inventory counts back into `CampaignState`. Gear can also be unequipped back into inventory stock before combat, making it available for later Armory swaps or shop selling. Unlike in-battle equipment swaps, Armory changes persist immediately and survive defeat or restart. Completed-scenario replays keep Shop and Armory disabled so replay setup cannot alter the campaign save.
@@ -355,9 +359,9 @@ Scenario `formation.cells` controls the highlighted starting cells available dur
## Scenarios
Scenarios should use deployments rather than full inline unit stat blocks. `DataCatalog` will resolve officer, class, and item references into runtime unit dictionaries. Scenarios may also define briefing text, visible objective text, battle conditions, and victory rewards.
Scenarios should use deployments rather than full inline unit stat blocks. `DataCatalog` will resolve officer, class, and item references into runtime unit dictionaries. Scenarios may also define briefing text, camp dialogue, visible objective text, battle conditions, map background art, and victory rewards.
Scenario deployments may override `move_type` for special units. For example, a river boat can keep an existing combat class but set `"move_type": "water"` so it can deploy and path on `W` water tiles while normal foot, mounted, and archer units treat those cells as impassable. Deployments can also override `portrait` and `equipment`; the validator checks portrait files and equipment against class equipment slots, and `DataCatalog` applies their presentation paths, stat bonuses, and weapon ranges when hydrating the unit.
Scenario deployments may override `move_type` for special units. For example, a river boat can keep an existing combat class but set `"move_type": "water"` so it can deploy and path on `W` water tiles while normal foot, mounted, and archer units treat those cells as impassable. Deployments can also override `portrait`, `sprite`, and `equipment`; the validator checks image files and equipment against class equipment slots, and `DataCatalog` applies their presentation paths, stat bonuses, and weapon ranges when hydrating the unit.
```json
{
@@ -375,6 +379,9 @@ Scenario deployments may override `move_type` for special units. For example, a
"title": "Yingchuan Skirmish",
"location": "Yingchuan, 184 CE",
"lines": ["Yellow Turban rebels have gathered near Yingchuan."],
"camp_dialogue": [
{ "speaker": "Cao Cao", "side": "left", "text": "We settle this before the revolt spreads." }
],
"conditional_lines": [
{
"campaign_flags": { "pursued_dong_zhuo": true },
@@ -383,6 +390,10 @@ Scenario deployments may override `move_type` for special units. For example, a
]
},
"shop": {
"merchant": {
"name": "Camp Merchant",
"lines": ["I saved beans and antidotes for your column."]
},
"items": ["bean", { "id": "cloth_robe", "stock": 1 }],
"stock": { "bean": 3 },
"conditional_items": [
@@ -401,6 +412,21 @@ Scenario deployments may override `move_type` for special units. For example, a
"formation": {
"cells": [[1, 3], [1, 4], [2, 3], [2, 4]]
},
"map": {
"width": 10,
"height": 8,
"background": "res://art/backgrounds/battlefield_frontier.png",
"terrain": [
"GGGGGGGGCC",
"GGGFFFFGCC",
"GGGFFFGGGG",
"GGGRRGGGGG",
"GGGRRGGHHG",
"GGGGGGGHHG",
"GGGWWGGGGG",
"GGGWWGGGGG"
]
},
"deployments": [
{ "unit_id": "cao_cao", "officer_id": "cao_cao", "team": "player", "pos": [1, 3] },
{ "unit_id": "protected_envoy", "name": "Protected Envoy", "class_id": "infantry", "team": "player", "controllable": false, "persist_progression": false, "ai_target_priority": 6, "pos": [1, 4] },
@@ -601,4 +627,4 @@ Before a battle starts, `BattleScene` can buy priced items through `CampaignStat
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, officer and deployment portraits, 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, deployment ids, deployment bounds, impassable spawn cells, shop stock, 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, 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.