1050 lines
49 KiB
Markdown
1050 lines
49 KiB
Markdown
# Aetherbound Guild: Systems And Battle Authority
|
|
|
|
> Authority: generated-Recruit state, Profession grammar, Market/run handoffs,
|
|
> ordered Party-line geometry, deterministic auto-battle, equipment and Artifact
|
|
> hooks, targeting, movement, death, replacement, and causal diagnosis.
|
|
>
|
|
> Revision: recruit-line-design-r2 / 2026-08-10
|
|
>
|
|
> Product intent is defined in
|
|
> [GAME_PRODUCT_CONTRACT.md](GAME_PRODUCT_CONTRACT.md). Prices, rewards,
|
|
> progression rates, capacity selection, and pacing are defined in
|
|
> [ECONOMY_AND_BALANCE.md](ECONOMY_AND_BALANCE.md). Durable commit and recovery
|
|
> semantics are defined in
|
|
> [SAVE_AND_FAILURE_CONTRACT.md](SAVE_AND_FAILURE_CONTRACT.md).
|
|
|
|
## 1. System Invariants
|
|
|
|
1. Each side occupies one ordered horizontal line. Position zero is front; a
|
|
larger position is farther rearward. There is no second spatial axis.
|
|
2. Allied simultaneous footprint begins at four and reaches ten. Reserve and
|
|
cumulative hires are separate and never redefine this limit.
|
|
3. Battle is automatic. The player may start, pause, change speed, inspect, or
|
|
retreat, but cannot activate attacks/skills, reorder, equip, or promote while
|
|
resolving.
|
|
4. A Recruit has one generated identity, one current fixed Profession, five
|
|
rolled attributes from an equal level budget, exactly one Trait, equipment,
|
|
level, and survival history.
|
|
5. Zero HP means Fallen. The Recruit leaves the resolving line immediately,
|
|
never respawns in that battle, and is never replaced by Reserve during that
|
|
battle. At outcome commit, that Recruit is permanently removed from the run
|
|
and its equipment returns to run inventory.
|
|
6. The same start state, ruleset, content revision, seed, and retreat timestamp
|
|
produces the same state hashes and result.
|
|
7. Display frame rate and pause/1x/2x/4x do not change simulation time or draws.
|
|
8. Every targeting exception, failed action, movement conflict, retarget,
|
|
immunity, proc suppression, and outcome has one inspectable reason.
|
|
9. All damage has a declared type, power source, defense, rounding boundary,
|
|
critical rule, modifier groups, and floor/nullification behavior.
|
|
10. No standard battle exceeds 150 simulation seconds.
|
|
|
|
## 2. Authoritative State Model
|
|
|
|
```text
|
|
profile
|
|
settings, accessibility, language, input mappings
|
|
Renown, unlock breadth, Region/Contract progress, Records, collection facts
|
|
|
|
run
|
|
run_id, contract_id, difficulty_id, ruleset_version, content_revision
|
|
generation_seed, Market index, cleared Rounds, Line capacity
|
|
Coin, Replacement Credit, refresh/lock counters
|
|
living Recruits, Reserve, inventory, Artifacts
|
|
hired/fallen/dismissed totals, boss state, run result
|
|
|
|
Recruit
|
|
recruit_id, generated_name_parts, rendered_name_snapshot, appearance_seed
|
|
origin_profession_id, current_profession_id, promotion_state
|
|
level, xp, five base attributes, Trait id
|
|
equipment ids, effective stats, survived battles, victories, hire receipt
|
|
|
|
encounter
|
|
encounter_id, battle_offer_id, root_seed, phase, tick
|
|
ordered allied/enemy actor sequences and footprints
|
|
HP, resources, readiness, cooldowns, casts, statuses, barriers
|
|
event queue, draw counters, retreat state, objective, outcome, event journal
|
|
|
|
presentation only
|
|
camera, interpolation, animation frame, particles, selected inspector,
|
|
expanded tooltip, pointer, audio playback cursor
|
|
```
|
|
|
|
Presentation never authors state. Battle arithmetic uses signed 64-bit integer
|
|
fixed point with 100 units per displayed point. Percentages use basis points
|
|
(`10,000 = 100%`). A formula rounds only where this document says `floor`,
|
|
`ceil`, or `round_half_up`.
|
|
|
|
## 3. Run And Market State Machine
|
|
|
|
```text
|
|
run_created
|
|
-> Market_open
|
|
-> battle_offer_committed
|
|
-> countdown
|
|
-> resolving
|
|
-> outcome_locked
|
|
-> diagnosis
|
|
-> reward_or_failure_applied
|
|
-> next_Market | boss_Muster | run_closed
|
|
```
|
|
|
|
The Market snapshot contains three Recruit offers, four equipment offers, and
|
|
three battle offers. Offer generation, prices, locks, and refreshes are owned by
|
|
the economy authority. This document owns these system rules:
|
|
|
|
- leaving and reopening a Market preserves all offer IDs and generated values;
|
|
- buying removes exactly that offer and never silently fills the empty slot;
|
|
- locked unbought offers persist to the next Market as declared;
|
|
- equipment, order, promotion, and dismissal are legal only while Market is
|
|
open or during boss Muster;
|
|
- battle commit stores an immutable deployed lineup, inventory ownership,
|
|
effective-stat snapshot, enemy lineup, seed, risk, and result rules;
|
|
- no Market edit after commit can affect that encounter;
|
|
- result inspection never applies or skips a reward operation.
|
|
|
|
## 4. Generated Recruit Contract
|
|
|
|
### 4.1 Generation
|
|
|
|
Recruit generation uses labeled deterministic streams so a name draw cannot
|
|
change attributes or Trait:
|
|
|
|
```text
|
|
recruit_name, recruit_appearance, recruit_profession,
|
|
recruit_attributes, recruit_trait
|
|
```
|
|
|
|
For offer level `L` from 1 through 10:
|
|
|
|
```text
|
|
attribute_budget(L) = 30 + 5*L
|
|
attribute_floor(L) = 3 + L
|
|
attribute_cap(L) = 12 + 3*L
|
|
```
|
|
|
|
`Might + Finesse + Insight + Vigor + Resolve` equals the exact budget. Every
|
|
attribute stays within floor/cap. The generator first assigns the floor to all
|
|
five, then distributes the remaining points one at a time by the labeled stream
|
|
without exceeding cap. Because totals are equal at a level, no Recruit is
|
|
strictly superior only because its random total is larger.
|
|
|
|
Every Recruit row stores its inputs and output hash. Generated name components
|
|
and modular visual parts create identity and readable variation but no hidden
|
|
mechanical modifier.
|
|
|
|
### 4.2 Trait
|
|
|
|
Each Recruit receives exactly one of 36 authored Traits. A Trait row has one
|
|
visible benefit and one visible cost, both mechanical. It cannot be removed,
|
|
stacked, upgraded, rerolled, or suppressed by changing language or appearance.
|
|
|
|
A Trait is invalid if its cost never changes a decision in either of its two
|
|
fixed fixtures, or if its benefit is only a larger unconditional value. Trait
|
|
tags may participate in hidden-hybrid eligibility only when that condition is
|
|
shown after discovery.
|
|
|
|
### 4.3 Survival History
|
|
|
|
The run records battles entered, victories, retreats survived, allies ahead at
|
|
commit, first Fallen ally witnessed, promotion, and final disposition. History
|
|
may unlock a run-local title or catalog fact but cannot grant a hidden stat.
|
|
After run close, only the immutable summary Record remains; the Recruit is no
|
|
longer playable.
|
|
|
|
## 5. Profession Catalog And Promotion
|
|
|
|
The fixed catalog contains 12 base, 24 regular advanced, and 6 hidden hybrid
|
|
Professions. Content owns identities and instances; this document owns schema
|
|
and topology.
|
|
|
|
### 5.1 Topology
|
|
|
|
- Every base Profession has exactly two regular advanced descendants.
|
|
- Every regular advanced Profession has exactly one parent base.
|
|
- Every hidden hybrid declares exactly two compatible base-family IDs and an
|
|
original battlefield responsibility distinct from both parents.
|
|
- A Recruit has exactly one current Profession. Equipment never changes the
|
|
stored Profession ID.
|
|
- A Recruit's origin base is immutable even after promotion.
|
|
|
|
### 5.2 Promotion
|
|
|
|
A base Recruit becomes eligible after reaching level 4 and surviving three
|
|
completed battles. Promotion is one-way and can happen once. The Market review
|
|
shows new action rules, lost rules, target/reach changes, resource loop, price
|
|
or opportunity cost, and the two validation fixtures before confirm.
|
|
|
|
The two regular descendants are always deterministic choices once eligible.
|
|
A hidden hybrid appears as an additional choice only when its revealed catalog
|
|
predicate is satisfied. Allowed predicate inputs are origin base, Trait tags,
|
|
equipped behavior tags, current Artifact tags, adjacent deployed Profession
|
|
families, and cleared Contract facts. A predicate cannot read generated name,
|
|
appearance, playtime, wall clock, or social state.
|
|
|
|
Promotion preserves level, HP percentage outside battle, Trait, equipment,
|
|
survival history, and recruit ID. It replaces current Profession, action table,
|
|
resource meter, and derived Profession bases atomically. It is not a free job
|
|
switch or reversible respec.
|
|
|
|
### 5.3 Automatic Action Unlocks
|
|
|
|
A Profession action kit unlocks by Recruit level:
|
|
|
|
| Recruit level | Available automatic rules |
|
|
|---:|---|
|
|
| 1 | basic action, resource rule, identity passive |
|
|
| 2 | first technique and its priority row |
|
|
| 3 | second technique and its priority row |
|
|
| 4 | signature and its priority row; promotion becomes possible after the survival requirement |
|
|
|
|
Promoting replaces the action kit with the promoted Profession's level-valid
|
|
kit. A direct regular-advanced hire uses the same level schedule. Falling below
|
|
an unlock level is impossible, and equipment cannot unlock a later action
|
|
early. Every unlocked action is automatic; the player prepares through hire,
|
|
equipment, deployment, and order rather than selecting it during battle.
|
|
|
|
### 5.4 Profession Row
|
|
|
|
```text
|
|
profession_id, tier (base | regular_advanced | hidden_hybrid)
|
|
parent_base_ids, unlock/promotion predicate
|
|
battlefield responsibility, preferred depth, failure mode, counter tags
|
|
base HP, base Tempo, base defenses, resource schema
|
|
basic action, two techniques, signature, passives
|
|
automatic priority table and target policies
|
|
movement/reach/protection/projectile/healing rules
|
|
two decision-opposed validation fixtures
|
|
presentation and accessibility event requirements
|
|
```
|
|
|
|
An advanced or hidden Profession must transform target, timing, position,
|
|
resource flow, protection, or risk ownership. A stronger scalar copy fails.
|
|
|
|
## 6. Party-Line Geometry
|
|
|
|
### 6.1 Ordered Footprint
|
|
|
|
Each actor declares footprint 1 or 2. Standard Recruits use footprint 1. An
|
|
actor with footprint 2 is one unit ID, one HP pool, and one action state
|
|
occupying a contiguous block.
|
|
|
|
The authoritative line is an ordered actor sequence with no interior empty
|
|
space after normalization. For actor `A`:
|
|
|
|
```text
|
|
depth(A) = sum(footprint(X) for every living actor X ahead of A)
|
|
front_cell(A) = depth(A)
|
|
rear_cell(A) = depth(A) + footprint(A) - 1
|
|
```
|
|
|
|
Allied deployed footprint cannot exceed current Line capacity. Recruits left
|
|
out of the sequence are Reserve. Order ties and simultaneous insertion use
|
|
stable actor ID only after all player-visible rules are equal.
|
|
|
|
### 6.2 Cross-Line Distance And Same-Line Distance
|
|
|
|
For opposing source `S` and target `T`:
|
|
|
|
```text
|
|
cross_line_distance(S,T) = 1 + depth(S) + depth(T)
|
|
```
|
|
|
|
For allied actors:
|
|
|
|
```text
|
|
same_line_distance(S,T) =
|
|
max(0, max(front_cell(S), front_cell(T)) -
|
|
min(rear_cell(S), rear_cell(T)) - 1)
|
|
```
|
|
|
|
Adjacent footprints therefore have same-line distance zero. Every action
|
|
declares a maximum cross-line or same-line reach. No visual closeness overrides
|
|
the integer distance.
|
|
|
|
### 6.3 Protection
|
|
|
|
```text
|
|
protection_stacks(T) = min(2, depth(T))
|
|
```
|
|
|
|
Each occupied footprint ahead contributes one stack up to two. Protection is
|
|
not a generic defense stat; actions use one declared mode:
|
|
|
|
| Mode | Rule |
|
|
|---|---|
|
|
| `frontbound` | Only targets with `depth=0` are candidates |
|
|
| `screened` | Deeper targets may be candidates, but resolved damage is multiplied by `max(0.70, 1 - 0.15*protection_stacks)` |
|
|
| `intercepted_projectile` | Projectile collides with the first eligible footprint in its current path |
|
|
| `lobbed` | Ignores collision but uses screened damage |
|
|
| `bypass_protection` | Ignores stacks; must be declared in preview and telegraph |
|
|
|
|
Healing and boons do not gain a hidden bonus from protection. The inspect view
|
|
shows stacks, contributing actors, target legality, and expected multiplier.
|
|
|
|
## 7. Encounter Lifecycle
|
|
|
|
| Phase | Legal player actions | Commit behavior |
|
|
|---|---|---|
|
|
| Preview | Inspect enemy order, actions, risk, reward, timeout, retreat | Offer is stable; no spend |
|
|
| Prepare | Equip, promote, dismiss, deploy, reorder | Changes remain reversible until battle confirm |
|
|
| Countdown | Pause, speed, inspect | Three simulation seconds; lineup locked |
|
|
| Resolve | Pause, speed, inspect, retreat | Automatic action events and retreat timestamp journaled |
|
|
| Outcome locked | Inspect | Victory, defeat, timeout, or retreat cannot change |
|
|
| Diagnose | Inspect causal timeline | No reward applied by viewing/skipping |
|
|
| Settle | Choose fixed reward if eligible | One atomic result operation |
|
|
| Finalized | Continue to Market/run result | Casualties, equipment return, Coin/Credit, and reward agree |
|
|
|
|
## 8. Deterministic Time, Events, And Draws
|
|
|
|
### 8.1 Fixed Tick And Priority
|
|
|
|
One simulation tick is exactly 100 milliseconds. At each tick:
|
|
|
|
1. accept lifecycle control stamped for this tick, including retreat start;
|
|
2. expire statuses and barriers whose end tick equals this tick;
|
|
3. resolve periodic status events due this tick;
|
|
4. complete casts, channels, projectile arrivals, and summon expiries;
|
|
5. select actions for actors already ready and legal;
|
|
6. resolve voluntary and forced movement intents;
|
|
7. apply simultaneous damage, healing, barrier, and resource deltas by batch;
|
|
8. finalize action-outcome records, mark zero-HP actors Fallen, and run declared
|
|
outcome/death triggers once;
|
|
9. compact lines, insert legal summons, and evaluate objective/retreat/phase;
|
|
10. advance readiness, cooldown, cast, status, timeout, and retreat clocks.
|
|
|
|
Events in the same numeric batch read one pre-batch state and apply together. An
|
|
actor alive at batch start completes its already-scheduled event even if the
|
|
same batch makes it Fallen. A death trigger cannot restore the source above
|
|
zero HP and cannot recursively produce another death trigger in the same tick.
|
|
An outcome-triggered derived action is queued no earlier than priority 4 of the
|
|
next tick; it cannot join or reopen the batch that produced its outcome.
|
|
|
|
### 8.2 Labeled Determinism
|
|
|
|
The encounter root seed supplies independent labels:
|
|
|
|
```text
|
|
target_tie, critical, status_apply, proc_choice,
|
|
summon_variant, reward
|
|
```
|
|
|
|
For a draw:
|
|
|
|
```text
|
|
roll_bp = hash64(root_seed, label, actor_id, action_sequence,
|
|
target_id, draw_index) mod 10,000
|
|
```
|
|
|
|
The event journal records label and draw index. Adding an equipment proc cannot
|
|
shift target, critical, status, or reward results in another stream. There is
|
|
no random damage variance or hidden miss chance.
|
|
|
|
## 9. Attributes And Derived Statistics
|
|
|
|
| Attribute | Primary responsibility |
|
|
|---|---|
|
|
| Might | physical power and Guard contribution |
|
|
| Finesse | Tempo, physical precision, and critical pressure |
|
|
| Insight | arcane power and status Potency |
|
|
| Vigor | maximum HP, Guard, and movement stability |
|
|
| Resolve | healing power, Ward, and status Tenacity |
|
|
|
|
At level `L`:
|
|
|
|
```text
|
|
PhysicalPower = WeaponPower + 2.00*Might + 0.50*Finesse
|
|
ArcanePower = FocusPower + 2.00*Insight + 0.50*Resolve
|
|
HealingPower = FocusPower + 1.20*Insight + 1.20*Resolve
|
|
MaxHP = ProfessionBaseHP + 8*L + 10*Vigor
|
|
Guard = ArmorGuard + 1.20*Vigor + 0.60*Might
|
|
Ward = ArmorWard + 1.20*Resolve + 0.60*Insight
|
|
Potency = Insight + 0.50*Finesse + FlatPotency
|
|
Tenacity = Resolve + 0.50*Vigor + FlatTenacity
|
|
Tempo = clamp(ProfessionBaseTempo + 0.40*Finesse + FlatTempo, 20, 100)
|
|
Initiative = clamp(ProfessionBaseInitiative + 0.25*Finesse + FlatInitiative,
|
|
0, 95)
|
|
```
|
|
|
|
Derived values round down to 1/100 after the full expression. Profession bases
|
|
must stay within `BaseHP 140-420`, `BaseTempo 24-55`, and `BaseInitiative 0-45`
|
|
unless a fixed exception fixture is approved. A MaxHP change outside battle
|
|
preserves current HP percentage and does not heal.
|
|
|
|
## 10. Readiness And Automatic Action Selection
|
|
|
|
At battle start, `Readiness = Initiative`. Each tick while an actor can act:
|
|
|
|
```text
|
|
Readiness = min(150, Readiness + Tempo*0.1)
|
|
```
|
|
|
|
At `Readiness >= 100`, the actor scans its Profession priority rows from top to
|
|
bottom. The first row with a legal action, true visible condition, and legal
|
|
target starts. It subtracts 100 Readiness and retains overflow. If none is
|
|
legal, readiness remains capped and the actor checks again next tick.
|
|
|
|
Priority conditions may read only current HP bands, resource, status, casts,
|
|
depth, protection, ally/enemy counts, summon space, cooldown, phase, and preview
|
|
tags. They cannot read future draws. Every Profession has a legal fallback or
|
|
an explicit `NO_REACHABLE_TARGET` idle result.
|
|
|
|
| Timing field | Boundary |
|
|
|---|---|
|
|
| Wind-up | 0.1-1.5 s |
|
|
| Major telegraph | at least 1.5 s; first boss use at least 2.5 s |
|
|
| Channel/cast | 0.3-4.0 s |
|
|
| Recovery | 0-2.0 s |
|
|
| Cooldown | 0-30 s |
|
|
|
|
The automatic table is part of Profession identity. Players compare it but do
|
|
not script arbitrary condition programs.
|
|
|
|
## 11. Target Selection, Reach, And Retarget
|
|
|
|
An action constructs candidates in this order:
|
|
|
|
1. required side and living/Fallen/summon state;
|
|
2. cross-line or same-line reach;
|
|
3. protection mode;
|
|
4. required status, cast, HP band, or tag;
|
|
5. exclusion, immunity, and maximum targets;
|
|
6. target policy.
|
|
|
|
Core target policies are `frontmost`, `rearmost`, `lowest_hp_ratio`,
|
|
`highest_power`, `active_cast`, `marked`, and `self`. Numeric ties use depth in
|
|
the policy's natural direction, then `target_tie`. The default hostile policy is
|
|
frontmost. Enemy-specific score tables must be shown in preview when they can
|
|
select something other than the declared policy result.
|
|
|
|
At action start the target unit ID is reserved. At completion, the action uses
|
|
one declared invalid-target policy:
|
|
|
|
- `retarget_same_policy`: rebuild candidates and choose again;
|
|
- `fizzle`: apply no primary effect and use the stated cooldown refund;
|
|
- `ground_resolve`: resolve at the stored depth and affect current occupants.
|
|
|
|
A target moving to another depth remains the same target if still legal. Every
|
|
retarget or fizzle logs the first rejecting filter.
|
|
|
|
### 11.1 Forecast Is Not Resolution
|
|
|
|
A forecast is a diagnostic prediction made from the committed preview or the
|
|
state at automatic action selection. It stores predicted target IDs, depth,
|
|
timing, and the rules that could change them. It never reserves a target and
|
|
never fires a battle trigger.
|
|
|
|
At action start, target selection creates the authoritative reservation. If its
|
|
target differs from forecast because an earlier action, movement, collapse, or
|
|
status changed state, the journal records `FORECAST_DIVERGED` with the first
|
|
changed input. That is not a hit, miss, dodge, resistance, or action outcome.
|
|
The reserved action then resolves normally.
|
|
|
|
Likewise, if a reserved target moves before completion but remains targetable
|
|
and inside all declared reach/protection filters, the action follows the same
|
|
unit ID. Its terminal component outcome can be `AO_APPLIED`; the detail reason
|
|
is `TARGET_MOVED_STILL_LEGAL`. Movement alone never creates an avoidance roll.
|
|
|
|
### 11.2 Terminal Outcome IDs
|
|
|
|
Every started action produces one or more terminal outcome records. Records are
|
|
per effect component and actual recipient; routing/invalidity records can name
|
|
the intended target, and action-level cancellation records have no recipient.
|
|
An area or multi-component action can therefore produce mixed outcomes without
|
|
collapsing them into an invented accuracy value.
|
|
|
|
| Outcome ID | Exact precondition | Ordering point | Player-visible causal label |
|
|
|---|---|---|---|
|
|
| `AO_APPLIED` | Legal component changes HP, barrier, status, resource, order, or another declared authoritative field on its actual recipient | Finalized after priority-7 deltas | `Applied`; use `Followed target` detail for `TARGET_MOVED_STILL_LEGAL` |
|
|
| `AO_NO_CHANGE` | Component reaches a legal recipient but caps/current state yield zero primary change | Finalized after priority-7 deltas | `No change` plus cap/current-state reason |
|
|
| `AO_INVALID_REACH` | Reserved target is living/targetable but current reach or protection filter is illegal | Completion validation at priority 4 | `Out of reach` plus old/current depth and required reach |
|
|
| `AO_INVALID_UNTARGETABLE` | Reserved target is living but a declared Untargetable rule excludes it | Completion validation at priority 4 | `Untargetable` plus rule ID and remaining duration |
|
|
| `AO_INVALID_FALLEN` | Reserved target is absent from the living line because it became Fallen before completion | Completion validation at priority 4 | `Target already Fallen` plus death event ID |
|
|
| `AO_INVALID_FILTER` | Reserved target fails another declared side/state/tag candidate filter after the three specific invalid checks | Completion validation at priority 4 | `Target no longer eligible` plus filter ID |
|
|
| `AO_INTERCEPTED` | Current projectile/protection path deterministically redirects the intended target's component to an eligible interceptor | Routing after target validation at priority 4 | `Intercepted by {actor}` plus path/protection rule ID |
|
|
| `AO_BLOCKED` | An explicit Block charge or named deterministic component blocker nullifies the component before its primary delta | Defense allocation at priority 4; charge/delta commits in priority 7 | `Blocked` plus blocker actor/rule ID |
|
|
| `AO_IMMUNE` | A declared immunity tag fully rejects the component before any resistance draw | Component defense at priority 4 | `Immune` plus immunity tag/source ID |
|
|
| `AO_RESISTED` | A resistible status component is not immune and its stored `status_apply` roll is at/above `ApplyChanceBp` | Component defense at priority 4 | `Resisted` plus roll, threshold, Potency, and Tenacity |
|
|
| `AO_FIZZLED` | Invalid-target policy is `fizzle`, retarget finds no legal candidate, or ground resolution has no eligible occupant | After invalid-target policy at priority 4 | `Action fizzled` plus invalid outcome/filter and refund |
|
|
| `AO_INTERRUPTED` | A started wind-up/channel is cancelled by a declared interrupt before completion | When interrupt commits at priority 4 | `Interrupted` plus interrupter/rule and refund |
|
|
|
|
`AO_BLOCKED` is not generic zero damage: barrier absorption is `AO_APPLIED`
|
|
because barrier state changes. `AO_IMMUNE` requires a named immunity. A legal
|
|
heal into full HP is `AO_NO_CHANGE`, not resistance. `AO_RESISTED` is limited to
|
|
the existing deterministic status-application check and never implies an
|
|
accuracy/evasion stat or a general attack miss.
|
|
|
|
An action summary is derived only for display:
|
|
|
|
```text
|
|
APPLIED_ALL = every primary component record is AO_APPLIED
|
|
APPLIED_PARTIAL = at least one primary component is AO_APPLIED and at least one is not
|
|
APPLIED_NONE = no primary component is AO_APPLIED
|
|
```
|
|
|
|
Summary values are not trigger IDs. The terminal records remain authoritative.
|
|
|
|
### 11.3 Resolution And Routing Order
|
|
|
|
At priority 4, each completing action uses this order:
|
|
|
|
1. If a committed interrupt already cancelled the action, emit one
|
|
`AO_INTERRUPTED` action record and stop.
|
|
2. Revalidate each reserved target against current state in this first-failure
|
|
order: Fallen/absent, Untargetable, other declared candidate filter, then
|
|
reach/protection. Emit the corresponding `AO_INVALID_*` reservation record.
|
|
3. Apply the skill's declared invalid-target policy. A successful
|
|
`retarget_same_policy` reserves a new target and continues without refund;
|
|
`ground_resolve` snapshots eligible current occupants at the stored depth;
|
|
otherwise emit `AO_FIZZLED` and stop that action.
|
|
4. Resolve current projectile/protection paths. Emit `AO_INTERCEPTED` for each
|
|
redirected intended target, then create component records for the actual
|
|
interceptor. Interception itself never counts as an applied component.
|
|
5. Expand components and area recipients in current depth then stable-ID order.
|
|
A footprint-2 actor is expanded once unless the skill explicitly says once
|
|
per footprint.
|
|
6. Allocate finite Block charges and deterministic blockers. Same-tick claims
|
|
use completion tick, target depth, source stable ID, then action sequence; one
|
|
charge cannot block two components. Emit `AO_BLOCKED` for each allocation.
|
|
7. Check declared immunity before consuming a resistance or critical draw. Emit
|
|
`AO_IMMUNE` on rejection.
|
|
8. For remaining resistible status components, consume and record exactly one
|
|
`status_apply` draw. Emit `AO_RESISTED` when the roll fails the threshold.
|
|
9. Queue remaining numeric/status/movement deltas for priority 7. After the
|
|
simultaneous batch, emit `AO_APPLIED` when primary state changed or
|
|
`AO_NO_CHANGE` when it did not.
|
|
10. At priority 8, derive the action summary, apply at most one declared refund,
|
|
claim outcome triggers, log suppressed duplicates, and queue derived actions
|
|
for the next tick.
|
|
|
|
An invalid reservation record remains terminal evidence even when retarget or
|
|
ground resolution continues. The redirected/new recipient receives its own
|
|
terminal component record, so diagnosis can say both why the original target
|
|
was not affected and what actually happened.
|
|
|
|
### 11.4 Journal, Refund, And Proc Contract
|
|
|
|
Every outcome record stores:
|
|
|
|
```text
|
|
root_action_id, action_instance_id, action_sequence, skill_id, source_id
|
|
selection_tick, completion_tick, effect_component_id, component_tags
|
|
forecast_target_ids, reserved_target_id, reserved_depth
|
|
actual_recipient_id, current_depth, outcome_id, reason_id
|
|
retarget_policy, resolution_disposition, redirected_action_or_component_id
|
|
interceptor_id, blocker_id, immunity_tag as applicable
|
|
roll_label, draw_index, roll_bp, threshold_bp as applicable
|
|
raw_delta, effective_delta, barrier_delta, status_or_movement_delta
|
|
resource_spent, cooldown_committed, refund_resource, refund_cooldown_ticks
|
|
trigger_claim_keys, fired_trigger_ids, suppressed_trigger_ids
|
|
parent_action_id, derived_depth
|
|
```
|
|
|
|
Resource cost, Readiness, and cooldown are committed when the action starts.
|
|
Default refund/proc behavior is:
|
|
|
|
| Outcome/disposition | Default refund | Primary effect procs |
|
|
|---|---|---|
|
|
| Invalid record followed by successful retarget/ground resolution | none | evaluate only the new actual recipient's component outcomes |
|
|
| `AO_FIZZLED` | skill's declared `fizzle_resource_refund_bp` and `fizzle_cooldown_refund_bp` | no on-hit/on-damage/on-heal/on-status proc |
|
|
| `AO_INTERRUPTED` | skill's declared interrupt refund fields | `on_interrupt` and matching `on_outcome` only |
|
|
| `AO_INTERCEPTED` | none | intended target can observe `AO_INTERCEPTED`; primary procs evaluate on actual recipient only |
|
|
| `AO_BLOCKED`, `AO_IMMUNE`, `AO_RESISTED` | none unless exact ID appears in `refund_on_outcome_ids` | matching defensive hook and `on_outcome` only; no primary effect proc |
|
|
| `AO_NO_CHANGE` | none | `on_outcome` only; no effective-delta proc |
|
|
| `AO_APPLIED` | none | only hooks whose required effective delta/status/movement actually occurred |
|
|
|
|
An outcome refund is evaluated once per root action after every component record
|
|
is final. The skill declares `refund_match = all_primary | any_primary`; default
|
|
is `all_primary`. Refund totals clamp to the originally committed cost/cooldown
|
|
and never multiply by targets, components, or repeated outcome records.
|
|
|
|
Outcome triggers use:
|
|
|
|
```text
|
|
trigger_id, observed_role (source | intended_target | actual_recipient)
|
|
outcome_ids[], component_tags[], once_scope (action | recipient | component)
|
|
allow_derived (default false), resulting_action_or_hook
|
|
```
|
|
|
|
Default `once_scope` is `action`. Before firing, create:
|
|
|
|
```text
|
|
trigger_claim_key = hash(root_action_id, trigger_id,
|
|
scope_recipient_or_component)
|
|
```
|
|
|
|
The first claim fires in outcome-record order; later identical claims log
|
|
`DUPLICATE_TRIGGER_CLAIM` and do nothing. Derived actions keep the same
|
|
`root_action_id`, increment `derived_depth`, and cannot trigger a row with
|
|
`allow_derived=false`. No derived chain can exceed depth 4 or the hook's declared
|
|
per-action cap.
|
|
|
|
## 12. Projectile And Area Resolution
|
|
|
|
A projectile declares speed in footprints per second, collision mode, pierce
|
|
count, and damage retention. At launch:
|
|
|
|
```text
|
|
arrival_ticks = max(1, ceil(cross_line_distance / projectile_speed / 0.1))
|
|
```
|
|
|
|
At arrival, an intercepted projectile traverses the **current** opposing order
|
|
from front to its reserved target and collides with the first eligible actor.
|
|
After each pierced actor, remaining damage is multiplied by the declared
|
|
retention in `0.50-0.90`. A reserved target that moved behind a new protector
|
|
can therefore be intercepted. Lobbed and bypassing projectiles follow their
|
|
declared protection mode instead.
|
|
|
|
Areas are contiguous footprint intervals, not visual circles. An area row
|
|
declares start policy, length, falloff, and whether a footprint-2 actor is hit
|
|
once or once per footprint; default is once per actor.
|
|
|
|
## 13. Healing, Support, And Protection Access
|
|
|
|
Support actions use same-line distance. Default heal selection is lowest HP
|
|
ratio among legal allies; exact ratio ties choose the frontmost, then
|
|
`target_tie`. A heal cannot pass its declared same-line reach because the
|
|
animation appears to span the line.
|
|
|
|
Barrier applies after healing in the same batch and is capped at 40% of target
|
|
MaxHP across all generic barriers. Excess is logged as waste. `Block` is an
|
|
explicit charge that nullifies one eligible hit after interception and before
|
|
barrier. Area, true, or `unblockable` events must declare ineligibility.
|
|
|
|
Protection stacks do not redirect heals. A support Profession may explicitly
|
|
target `nearest_ally_ahead`, `nearest_ally_behind`, or a contiguous interval;
|
|
the predicted support path updates when order changes.
|
|
|
|
## 14. Movement, Push, Pull, And Summons
|
|
|
|
### 14.1 Reordering Actions
|
|
|
|
Battle movement is an automatic action, never free dragging:
|
|
|
|
- `advance`: swap the actor block with the adjacent actor block ahead;
|
|
- `withdraw`: swap with the adjacent actor block behind;
|
|
- `push N`: move the target toward rear through up to `N` adjacent block swaps;
|
|
- `pull N`: move the target toward front through up to `N` swaps;
|
|
- `insert`: add a legal summon before/after its source;
|
|
- `return`: remove a temporary summon or restore an explicitly stored order.
|
|
|
|
Footprint-2 actors move as indivisible blocks. Simultaneous conflicting intents
|
|
resolve larger declared movement priority first, then higher source Potency,
|
|
then stable source ID. Losing intents fail with `DESTINATION_RESERVED`.
|
|
|
|
Forced movement stops before an `Immovable` actor. Each unresolved forced step
|
|
at a line boundary or blocker deals:
|
|
|
|
```text
|
|
collision_damage = max(1, floor(0.08 * source_PhysicalPower))
|
|
```
|
|
|
|
once per action, not once per blocked step. `Rooted` blocks voluntary movement;
|
|
`Immovable` blocks forced movement. Rejections name `ROOTED`, `IMMOVABLE`,
|
|
`NO_ADJACENT_ACTOR`, `DESTINATION_RESERVED`, or `CAST_LOCKED`.
|
|
|
|
### 14.2 Summon Footprint
|
|
|
|
Each side has temporary summon allowance of two footprint beyond its committed
|
|
deployment. A summon declares footprint 1 or 2 and insertion side relative to
|
|
its source. It is legal only when:
|
|
|
|
```text
|
|
current_living_footprint + summon_footprint
|
|
<= committed_deployment_footprint + 2
|
|
```
|
|
|
|
A failed insertion spends no summon resource and returns `NO_SUMMON_SPACE`.
|
|
Summons never enter Reserve, hold equipment, create Replacement Credit, count
|
|
as cumulative hires, or persist after battle.
|
|
|
|
### 14.3 Death Collapse
|
|
|
|
After every death batch, Fallen actors are removed and both lines compact while
|
|
preserving the relative order of survivors. New depths become authoritative
|
|
before summon insertion and objective checks at priority 9. A scheduled action
|
|
that reserved a Fallen target follows its retarget policy; it does not target
|
|
the actor that happened to collapse into the old depth unless it uses
|
|
`ground_resolve`.
|
|
|
|
Reserve Recruits never fill a collapsed position during battle. At the next
|
|
Market the player explicitly chooses any replacement and new order.
|
|
|
|
## 15. Damage, Critical, Healing, And Floors
|
|
|
|
### 15.1 Damage
|
|
|
|
Skills declare `Base`, `Coefficient`, `PowerSource`, type, pierce, protection
|
|
mode, and whether critical is legal.
|
|
|
|
```text
|
|
RawDamage = max(0, Base + Coefficient * selected_power)
|
|
EffectiveDefense = clamp(relevant_defense - pierce, -75, 500)
|
|
|
|
if EffectiveDefense >= 0:
|
|
DefenseMultiplier = 100 / (100 + EffectiveDefense)
|
|
else:
|
|
DefenseMultiplier = 2 - 100 / (100 - EffectiveDefense)
|
|
|
|
CritChanceBp = clamp(skill_base_crit_bp
|
|
+ 20*(source_Finesse - target_Resolve)
|
|
+ explicit_crit_bp,
|
|
0, 5000)
|
|
crit = can_crit and critical_roll_bp < CritChanceBp
|
|
CritMultiplier = clamp(declared_crit_multiplier, 1.25, 2.00) if crit else 1.00
|
|
|
|
OutgoingGroup = clamp(1 + sum(outgoing_modifiers), 0.25, 3.00)
|
|
IncomingGroup = clamp(1 + sum(incoming_modifiers), 0.25, 3.00)
|
|
EncounterGroup = clamp(1 + sum(encounter_modifiers), 0.25, 3.00)
|
|
GroupProduct = clamp(OutgoingGroup * IncomingGroup * EncounterGroup, 0.10, 4.00)
|
|
|
|
Mitigated = RawDamage * DefenseMultiplier * CritMultiplier * GroupProduct
|
|
Screened = Mitigated * max(0.70, 1 - 0.15*protection_stacks)
|
|
DamageFloor = ceil(0.04 * RawDamage)
|
|
FinalDamage = 0 if explicit_nullification else
|
|
max(1, DamageFloor, floor(Screened))
|
|
HPDamage = max(0, FinalDamage - barrier_absorbed)
|
|
```
|
|
|
|
Use `Screened=Mitigated` for non-screened modes. Guard defends physical, Ward
|
|
defends arcane, and true damage uses zero defense, cannot critical, ignores
|
|
screening, and is capped at 25% target MaxHP per non-boss event. Barrier absorbs
|
|
after the floor; an explicit nullification can produce zero. No other ordinary
|
|
reduction bypasses the four-percent floor.
|
|
|
|
Fixed boundary: `RawDamage=125`, defense `500`, GroupProduct `0.10`, no critical,
|
|
and no screening yields `2.083...` before the floor. `DamageFloor=5`, so the
|
|
resolved damage is `5` before barrier. Explicit nullification yields zero.
|
|
|
|
### 15.2 Healing
|
|
|
|
```text
|
|
RawHeal = max(0, Base + Coefficient * HealingPower)
|
|
FinalHeal = floor(RawHeal * OutgoingHealGroup * ReceivedHealGroup)
|
|
EffectiveHeal = min(FinalHeal, MaxHP - current_HP)
|
|
```
|
|
|
|
Healing does not critical unless the skill declares a visible healing-critical
|
|
rule. Overheal has no effect unless one named hook converts it; conversion is
|
|
capped at 50% of overheal and still respects the barrier cap.
|
|
|
|
## 16. Status Effects And Resolution Order
|
|
|
|
Each status declares:
|
|
|
|
```text
|
|
status_id, category, source_id, target_id
|
|
base_chance_bp, potency_source, resist_stat
|
|
duration_ticks, interval_ticks, max_stacks
|
|
stack_rule (add | refresh | replace | independent)
|
|
dispel/immunity tags, on_apply, on_tick, on_expire
|
|
presentation and causal-report events
|
|
```
|
|
|
|
For a resistible status:
|
|
|
|
```text
|
|
ApplyChanceBp = clamp(BaseChanceBp + 25*(Potency - Tenacity), 500, 9500)
|
|
applies = status_apply_roll_bp < ApplyChanceBp
|
|
```
|
|
|
|
Guaranteed effects bypass the roll but not declared immunity. If simultaneous
|
|
effects apply the same status, resolve `replace`, then `add`, then `refresh`,
|
|
then independent instances by source ID. Expiry occurs before periodic ticks,
|
|
so a status with `end_tick == current_tick` does not tick again.
|
|
|
|
Hard control effective duration is:
|
|
|
|
```text
|
|
duration = clamp(BaseDuration * 100/(100 + Tenacity), 0.2, 3.0)
|
|
```
|
|
|
|
After hard control ends, the actor gains four seconds of Control Guard, reducing
|
|
new hard-control duration by 75%. No actor may be unable to act for more than
|
|
50% of any rolling ten-second window. Boss caps and immunities are previewed.
|
|
|
|
## 17. Equipment, Artifacts, And Hooks
|
|
|
|
Each Recruit has three equipment slots:
|
|
|
|
| Slot | Main scope |
|
|
|---|---|
|
|
| Weapon | Power source, basic/technique behavior, reach or projectile rule |
|
|
| Guard | HP, defense, protection, movement, or death-risk tradeoff |
|
|
| Charm | Status, resource, timing, target, healing, or promotion interaction |
|
|
|
|
All 320 equipment rows must alter a decision and declare one named hook. Scalar
|
|
budget may support the hook but cannot be the row's only identity. A Recruit
|
|
cannot equip duplicate stable IDs. Company-unique effects declare a unique
|
|
group; later copies retain local behavior but show the shared portion dormant.
|
|
|
|
Artifacts are shared run rules. A run holds at most three active Artifacts. A
|
|
fourth acquisition requires replacing one or declining the new row after an
|
|
exact before/after preview. All 60 must change formation, targeting, market,
|
|
risk, resource, promotion, summon, or reward valuation and must name a conflict.
|
|
|
|
Legal battle hooks are:
|
|
|
|
```text
|
|
before_target, after_target, before_cast, on_cast_complete, on_interrupt,
|
|
before_damage, after_damage, on_critical, before_heal, after_heal,
|
|
on_barrier_break, on_status_apply, on_status_expire,
|
|
on_advance, on_withdraw, on_push, on_pull, on_protection_change,
|
|
on_resource_gain, on_signature, on_summon, on_fallen, after_collapse
|
|
```
|
|
|
|
Each hook has a trigger limit, minimum 0.5-second cooldown unless a fixed loop
|
|
proof allows otherwise, and recursion declaration. Derived events cannot
|
|
retrigger their source by default.
|
|
|
|
## 18. Death, Dismissal, And Replacement
|
|
|
|
### 18.1 Battle Death
|
|
|
|
At zero HP, a non-summon Recruit becomes Fallen:
|
|
|
|
- it cannot act, target, protect, receive healing, or be promoted;
|
|
- its death trigger resolves once at priority 8;
|
|
- it is removed for line collapse;
|
|
- no timer, item, Profession, Artifact, difficulty rule, or Reserve state can
|
|
respawn, resurrect, or substitute for it during the encounter;
|
|
- its recruit ID and equipment IDs enter the pending outcome casualty set;
|
|
- it remains visible in diagnosis with the preceding five seconds of causes.
|
|
|
|
At outcome application, each casualty and all returned equipment commit with
|
|
Replacement Credit as one transaction. Victory, defeat, timeout, and retreat
|
|
do not change the permanence of already Fallen Recruits.
|
|
|
|
### 18.2 Dismissal
|
|
|
|
Dismissal is a Market-only operation. It is illegal for a deployed Recruit in a
|
|
committed battle, a Fallen Recruit awaiting outcome, or a Recruit referenced by
|
|
a pending promotion. It also uses the product authority's canonical count:
|
|
|
|
```text
|
|
live_recruit_count = count(unique Recruit IDs owned by the current run
|
|
whose state is living,
|
|
across deployed party and Reserve)
|
|
dismissal_legal = Market_open and target_is_living and
|
|
live_recruit_count >= 2
|
|
```
|
|
|
|
The preview and commit independently evaluate `dismissal_legal`. Review shows
|
|
equipment return, rebate, lost level/history, and resulting deployable
|
|
footprint. A legal confirm removes the Recruit once and asserts the post-state
|
|
has `live_recruit_count >= 1`.
|
|
|
|
If the count is one, or a once-valid preview becomes stale after another
|
|
serialized operation leaves one living Recruit, reject `FINAL_LIVE_RECRUIT`.
|
|
The rejection removes no Recruit or equipment, grants no Coin or Replacement
|
|
Credit, changes no counters, and creates no protected recovery offer. Repeated
|
|
confirm returns the same rejection. An interrupted pending dismissal must
|
|
revalidate the active count before it can apply and is rejected without mutation
|
|
when that count is one.
|
|
|
|
Dismissal never creates Replacement Credit or a Meta reward. Explicit run
|
|
abandonment is a distinct Market/result transaction, and casualty-driven
|
|
replacement/Company collapse remains exclusive to casualty settlement.
|
|
|
|
### 18.3 Replacement
|
|
|
|
Replacement is an ordinary hire using Coin and eligible Replacement Credit.
|
|
After a casualty, the next Market protects one base-Profession recovery offer
|
|
from refresh until bought or explicitly declined. Reserve never fills the line
|
|
automatically. A run closes only when the player cannot legally deploy one
|
|
living Recruit after all available recovery purchases or explicitly abandons.
|
|
A blocked final dismissal never creates or refreshes this offer and never invokes
|
|
the casualty recovery predicate.
|
|
|
|
## 19. Battle Control, Retreat, Timeout, And Outcome
|
|
|
|
Pause, 1x, 2x, and 4x affect presentation only. Inspection while paused can
|
|
open actor state, target reasoning, current action, queued major event, line
|
|
depths, protection, status order, and causal log.
|
|
|
|
Retreat becomes legal at tick 50 (5.0 seconds). Confirm begins a 20-tick global
|
|
withdrawal. Automatic actions continue and Recruits can fall during it. At the
|
|
end of the 20th tick, living allied non-summon actors escape and outcome becomes
|
|
retreat. Repeating retreat confirm returns the same command receipt.
|
|
|
|
At 120 seconds, Overtime begins:
|
|
|
|
```text
|
|
for each completed 10-second Overtime band:
|
|
all damage dealt multiplier += 0.25
|
|
all healing and new barrier multiplier -= 0.20
|
|
damage bonus caps at +0.75; healing/barrier penalty caps at -0.60
|
|
```
|
|
|
|
At tick 1500, if the objective is not satisfied, the result is timeout defeat.
|
|
Living Recruits survive; Fallen Recruits remain lost. Timeout grants no battle
|
|
reward and applies the failure transaction in the save authority.
|
|
|
|
Victory is evaluated after simultaneous damage, death, collapse, and summon
|
|
events. If both victory and all-allied-Fallen predicates become true in the same
|
|
batch, the declared objective decides: elimination objectives are a mutual
|
|
defeat; survival/objective-complete battles are victory with zero living
|
|
deployed Recruits and can close the run if no Reserve remains.
|
|
|
|
## 20. Enemy And Battle-Offer Contract
|
|
|
|
Every ordinary/elite enemy and boss row declares:
|
|
|
|
```text
|
|
enemy_id, ordinary | elite | boss, Region/Contract placement
|
|
footprint, preferred depth, movement rules
|
|
basic/technique/signature actions and automatic priority
|
|
target/protection/reach/projectile/heal/summon rules
|
|
first-major-action window and telegraph
|
|
phase predicates, immunities, counter tags, two rational responses
|
|
interaction with at least two older mechanics
|
|
first-failure contribution and fixed fixtures
|
|
```
|
|
|
|
Before commitment, a battle offer shows exact enemy order and footprint, target
|
|
policies, protection bypass, earliest major windows, movement, summon allowance,
|
|
resistances, objective, timeout, retreat consequence, Coin reward, and reward
|
|
family. A hidden visual identity may remain concealed for discovery; a mechanic
|
|
needed for a fair choice may not.
|
|
|
|
The complete envelope is 100 ordinary/elite identities plus 16 bosses across 8
|
|
Regions. Presentation variants do not count toward those totals.
|
|
|
|
## 21. Causal Diagnosis
|
|
|
|
The result report presents, in order:
|
|
|
|
1. committed allied and enemy order;
|
|
2. predicted and actual first targets;
|
|
3. first divergence from predicted action/target/timing;
|
|
4. first protection change, projectile interception, or reach failure;
|
|
5. first decisive major action and available pre-battle counter categories;
|
|
6. every Fallen Recruit with the preceding five simulation seconds;
|
|
7. collapse, displacement, summon-space, retarget, and proc-suppression events;
|
|
8. effective damage, prevention, healing, control, and resource totals;
|
|
9. reward/failure/casualty operation IDs in technical details.
|
|
|
|
The report can compare one alternate order or equipment removal against the same
|
|
seed in a no-reward rehearsal. It may explain categories but cannot auto-equip a
|
|
supposed universal answer.
|
|
|
|
## 22. Content Schemas
|
|
|
|
### 22.1 Skill Row
|
|
|
|
```text
|
|
skill_id, owner_profession_id, tags, timing
|
|
candidate filters, target policy, protection mode, retarget policy
|
|
invalid-target outcome mapping, fizzle/interrupt refund fields
|
|
reach, projectile/area/movement/summon fields
|
|
Base, Coefficient, PowerSource, type, pierce, critical rule
|
|
resource cost/gain, cooldown, status rows, proc hooks
|
|
refund_on_outcome_ids, refund_match
|
|
outcome triggers (trigger_id, observed_role, AO_* outcome_ids,
|
|
component_tags, once_scope, allow_derived, resulting action/hook)
|
|
automatic priority condition, illegal reasons, causal labels
|
|
animation/VFX/SFX/caption/reduced-motion requirements
|
|
fixed input and expected event output
|
|
```
|
|
|
|
### 22.2 Equipment Row
|
|
|
|
```text
|
|
equipment_id, slot, acquisition band, list-price inputs
|
|
eligible Profession/action tags
|
|
changed decision and named behavior hook
|
|
stat support budget, trigger, cooldown, recursion
|
|
order/target/timing/resource/risk tradeoff
|
|
two interaction fixtures and one loss/comparison fixture
|
|
presentation/accessibility/localization needs
|
|
```
|
|
|
|
### 22.3 Artifact Row
|
|
|
|
```text
|
|
artifact_id, unlock/offer placement, shared hook
|
|
run rule changed, conflict group, replacement comparison
|
|
Market/battle/risk inputs and outputs
|
|
two builds whose valuation changes in opposite directions
|
|
fixed seed fixture and causal event
|
|
```
|
|
|
|
### 22.4 Battle Offer Row
|
|
|
|
```text
|
|
battle_offer_id, Region, Contract, Round, risk tier
|
|
enemy lineup/order/levels, seed labels, objective
|
|
preview fields, Coin reward, reward family, retreat/failure receipt
|
|
expected duration, profile assertion, causal-report requirements
|
|
```
|
|
|
|
## 23. Static Validation Gates
|
|
|
|
- all Profession topology counts and parent links reconcile to 42;
|
|
- all 36 Traits have one benefit, one cost, and two decision fixtures;
|
|
- all 320 equipment and 60 Artifact rows name a behavior change;
|
|
- all 100 ordinary/elite and 16 boss rows create a distinct counter question;
|
|
- no deployed footprint exceeds current Line capacity;
|
|
- target preview equals the first simulated target for fixed fixtures;
|
|
- identical state/seed/retreat inputs yield identical hashes at every tick;
|
|
- all actions stay inside reach, critical, defense, barrier, control, proc, and
|
|
timeout bounds;
|
|
- every projectile and movement conflict produces the declared collision/order;
|
|
- every death returns the exact owned equipment once and never introduces a
|
|
Reserve automatically;
|
|
- invalid actions spend no resource and return one enumerated reason;
|
|
- every started action/component has a declared terminal `AO_*` record and every
|
|
outcome trigger references only IDs in Section 11.2;
|
|
- duplicate trigger claims are journaled and cannot fire twice;
|
|
- all standard fixtures resolve or timeout at/before tick 1500.
|
|
|
|
## 24. Required Fixed Test Vectors
|
|
|
|
| Vector | Setup | Expected result |
|
|
|---|---|---|
|
|
| Frontbound | Three enemies; target policy frontmost | Only depth-zero enemy is a candidate |
|
|
| Screened rear | Target has two footprint ahead | Legal screened hit uses `0.70` multiplier |
|
|
| Cross-line reach | source depth 1, target depth 2, reach 4 | distance `1+1+2=4`, legal; reach 3 is illegal |
|
|
| Heal tie | Two allies at equal HP ratio in reach | Frontmost wins, then deterministic tie draw |
|
|
| Projectile intercept | Reserved rear target gains a new front summon before arrival | Current front summon is hit unless bypass/lobbed |
|
|
| Push footprint | Push a footprint-2 target one step | Whole block swaps; it never splits |
|
|
| Blocked push | Forced move has two remaining steps at boundary | One collision event, not two |
|
|
| Summon full | committed footprint 10 plus temporary footprint 2 | another footprint-1 summon fails `NO_SUMMON_SPACE` |
|
|
| Simultaneous lethal | Two actors complete lethal actions in one batch | Both events apply, both actors become Fallen |
|
|
| Death collapse | Front actor falls before a reserved cast completes | Survivors compact; cast follows its declared retarget rule |
|
|
| Reserve behavior | Deployed actor falls while living Reserve exists | Reserve does not enter until next Market preparation |
|
|
| Damage floor | Raw 125, defense 500, group product 0.10 | damage 5 before barrier; explicit nullification 0 |
|
|
| Critical boundary | roll 2499 with chance 2500 bp | critical; roll 2500 is not |
|
|
| Status expiry | periodic tick equals end tick | expiry occurs; no final periodic tick |
|
|
| Retreat | confirm at tick 50, no terminal predicate | outcome retreat after tick 70 batch; later duplicate has no effect |
|
|
| Speed parity | identical battle at 1x and 4x | all authoritative hashes equal |
|
|
| Timeout | objective incomplete at tick 1200/1500 | Overtime applies, then timeout defeat at tick 1500 |
|
|
| Casualty equipment | Fallen Recruit owns three items | Recruit removed and all three item IDs returned exactly once |
|
|
| Final dismissal | one living Recruit across deployed plus Reserve | preview/commit reject `FINAL_LIVE_RECRUIT`; no state or recovery-offer change |
|
|
| Moved target remains legal | Reserved target changes depth but remains targetable and in reach | same ID receives `AO_APPLIED`; detail `TARGET_MOVED_STILL_LEGAL`; no refund |
|
|
| Moved target leaves reach | Reserved target moves from distance 2 to 3 against reach 2; policy `fizzle` | `AO_INVALID_REACH` then `AO_FIZZLED`; declared fizzle refund once |
|
|
| Target becomes Untargetable | Living reserved target gains declared Untargetable before completion | `AO_INVALID_UNTARGETABLE`; row retarget/fizzle policy applies; no resistance draw |
|
|
| Target falls first | Reserved target becomes Fallen in an earlier tick | `AO_INVALID_FALLEN` names death event; collapsed-depth actor is not substituted |
|
|
| Interception | New front protector intercepts projectile aimed at legal rear target | intended target `AO_INTERCEPTED`; protector gets its own component outcome |
|
|
| Explicit Block | Actual recipient owns one eligible Block charge | `AO_BLOCKED`; one charge consumed; no primary proc or default refund |
|
|
| Immunity | Status target has matching immunity tag | `AO_IMMUNE`; no `status_apply` draw and no status proc |
|
|
| Resistance | No immunity; stored roll 7000, threshold 6500 | `AO_RESISTED` with roll/threshold; no general attack miss |
|
|
| Mixed area | Three recipients: one changed, one immune, one already capped | `AO_APPLIED`, `AO_IMMUNE`, `AO_NO_CHANGE`; summary `APPLIED_PARTIAL` |
|
|
| Duplicate trigger suppression | Mixed area yields three matching records for one once-per-action trigger | first claim fires; later claims log `DUPLICATE_TRIGGER_CLAIM`; one derived action next tick |
|
|
|
|
## 25. Acceptance Checklist
|
|
|
|
- [ ] One ordered line owns protection, reach, projectiles, healing, movement,
|
|
summon footprint, death collapse, and replacement behavior.
|
|
- [ ] Battle formulas define tick order, random labels, damage floor, critical,
|
|
status order, timeout, and fixed vectors.
|
|
- [ ] Deterministic outcomes distinguish forecast divergence, target
|
|
invalidation, interception, Block, immunity, resistance, application, and
|
|
duplicate trigger suppression without accuracy/evasion.
|
|
- [ ] Generated Recruit and fixed Profession schemas are complete without
|
|
requiring authored individual narrative content.
|
|
- [ ] Fully automatic combat exposes only the approved diagnostic controls and
|
|
retreat.
|
|
- [ ] Content counts and no-filler tests match the product authority.
|
|
- [ ] Save/failure owns durable death and operation recovery; economy owns all
|
|
purchase, reward, capacity, and pacing numbers.
|