# 05 — Legacy Ability Architecture **Status: Draft** - **Scope:** Shared `BP_PlayerCharacterBase` ability architecture (Batch 2) plus per-character Ability 001–004 connected-path reconstruction (Batch 3 Pass 6), qualified by animation-notify wiring (Batch 4A Pass 8) and Pass 7 legacy/GAS boundary clarification. - **Inspection method:** BlueprintTools connected subgraphs (Pass 6); AnimNotify `Received_Notify` DSL + montage dependency/referencer graphs (Pass 8); Pass 7 GAS GE/ASC inventory correlation. - **Evidence classifications used:** Observed Implementation, Documented Intent, Observed Runtime Behavior, Inferred, Unknown. - **Tool or visibility limitations:** CustomEvent Reliable flags not exposed; Montage Notifies array / trigger times unreadable via ObjectTools; AnimGraph DSL empty. - **Last updated:** 2026-07-16 - **Current phase:** Phase 1 — Static Architecture - **Last completed pass:** Pass 7 (Batch 4B) — boundary clarification only; ability tables unchanged - **Next pass expected to contribute:** Pass 11 migration matrix / other Batch 4 passes when authorized ## Draft tracking ### Completed sections - Shared input → Server RPC routing on base - Base Server_Ability_* stubs - Multicast FX helpers - Death / respawn / HUD (DEPRECATED floats) - Per-character Ability 001–004 connected paths for all five playables - Parent-call inventory - Resource / damage / projectile inventories - Montage dependency seeds - **Pass 8:** UseAbility* callers resolved (`AN_Ability_001–004`); `AN_AttackComplete` cleanup; Pass 6 reclassification table in `10` - **Pass 7:** Legacy vs GAS dual-resource boundary clarified (no ability-graph GE/ASC usage) ### Pending sections - Cross-character migration matrix (Pass 11 → doc 07) - Runtime verification of CDO damage/mana values (PIE) - Interrupt cleanup if `AN_AttackComplete` skipped ### Evidence still required - Notify trigger times (Manual Editor Inspection) - FCanUseMana implementation body (call sites only) - Client_Charge timeline numeric details - PIE: potion ASC Health vs DEPRECATED_CurrentHealth divergence --- ## Shared architecture (Batch 2 baseline — verified) ```mermaid flowchart TD IA[IA_Ability_001to004] -->|Started| SBegin[Server_Ability_N_Begin] IA -->|Completed_or_Canceled| SEnd[Server_Ability_N_End] SBegin -->|base| Print[PrintString Override] SBegin -->|child override| Child[Character body] Child --> MC[Multicast_PlayMontage] MC --> AN[AN_Ability_00N notify] AN --> Use[UseAbilityN Authority] Use --> Dmg[ApplyDamage or RecoverHealth] MC --> ANC[AN_AttackComplete] ANC --> Clear[SetIsAttacking clears CurrentlyAttacking] ``` **Observed Implementation:** No `UGameplayAbility` activation. Reliability: **Unknown — MCP property visibility limitation**. **Pass 8:** `UseAbility*` is invoked from AnimNotify Blueprints (`AN_Ability_001–004`), not from AnimBP EventGraphs. `Multicast_PlayMontage` completion pins are unwired — cleanup for notify-driven attacks uses `AN_AttackComplete` → `SetIsAttacking`. Full animation tables: `10-AnimationDependencies.md`. | Base event | Body | |---|---| | Server_Ability_*_Begin | PrintString `"Override Ability N"` | | Server_Ability_*_End | then unconnected | | Multicast_PlayMontage / PlaySFX / Multi_SpawnParticle | Active helpers | --- ## Parent-call inventory (Pass 6) | Character | Ability overrides call Parent? | Other Parent calls | |---|---|---| | Paladin | **No** on Ability Begin/UseAbility | Tick/Overlap call Parent; BeginPlay does **not** (leader-pose style local) | | Amazonian | **No** | — | | Cleric | **No** on any ability override | BeginPlay no Parent (leader pose) | | Wizard | N/A (no ability overrides) | BeginPlay **no Parent**; Tick/Overlap **call Parent** | | Gunslinger | N/A | BeginPlay/Tick/Overlap **call Parent** | --- ## Player_Paladin **Path:** `/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterClasses/Paladin/Player_Paladin` | Slot/System | Entry point | Parent called | Server path | Multicast/client path | Validation | Resource | Damage/effect | Animation | End/cleanup | Status | Evidence | |---|---|---|---|---|---|---|---|---|---|---|---| | Ability 001 | Server_Ability_001_Begin; UseAbility001 | No | Gate !attacking && !dead → CurrentlyAttacking → SetPlayerCanMove(true) → Multicast_PlayMontage(random Ability001Montages) | Multicast_PlayMontage | Gate only | None | UseAbility001 Authority BoxOverlap ApplyDamage — **caller: AN_Ability_001** | Attack_A/B/C/D_Fast_Montage | **AN_AttackComplete** → SetIsAttacking (no local End) | **Implemented** (Pass 8 qualified) | Pass 6 + Pass 8 | | Ability 002 | Server_Ability_002_Begin; Server_Ability_002_End | No | Begin: gate → CurrentlyAttacking → CanMove false → IsBlocking true | ABP Block (no Montage) | Gate | None | Block state only | ABP_Paladin Block via IsBlocking | End clears attacking/CanMove/IsBlocking | **Partial** | Pass 6 + Pass 8 | | Ability 003 | Server_Ability_003_Begin; Charge; Client_Charge; ChargeBox overlap | No | Gate → FCanUseMana → Charge + Client_Charge | Client_Charge | Gate + mana | DEPRECATED_Ability003ManaCost | ChargeBox Authority ApplyDamage | ChargeTimeline (not Montage) | Not notify-driven | **Implemented** | Pass 6 | | Ability 004 | Server_Ability_004_Begin; UseAbility004 | No | Gate → FCanUseMana → Multicast_PlayMontage(Paladin_Ability004_Montage) | Multicast_PlayMontage | Gate + mana | DEPRECATED_Ability004ManaCost | UseAbility004 Authority AoE — **caller: AN_Ability_004**; empty particle | Paladin_Ability004_Montage | **AN_AttackComplete** cleanup | **Implemented** (Pass 8 qualified; FX hole) | Pass 6 + Pass 8 | | Basic attack | Same as Ability 001 | No | Same | Same | Same | Same | Same | Attack_* montages | Same | **Implemented** (=001) | — | | Passive | — | — | — | — | — | — | — | — | — | **Missing** | — | | Death | Inherited PlayerDeath | — | Base | Base | — | DEPRECATED health (if damaged via AnyDamage — Paladin has no local AnyDamage) | Base | Base | Base | **Inherited** | list_events | | Legacy HUD | Inherited Server_UpdateHUD | — | Base DEPRECATED floats | — | — | Reads DEPRECATED health/mana | — | — | — | **Inherited** | Batch 2 | **Paladin montages:** `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Paladin/AnimMontages/Attack_{A,B,C,D}_Fast_Montage` `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Paladin/AnimMontages/Abilities/Paladin_Ability004_Montage` --- ## Player_Amazonian **Path:** `/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterClasses/Amazonian/Player_Amazonian` | Slot/System | Entry point | Parent called | Server path | Multicast/client path | Validation | Resource | Damage/effect | Animation | End/cleanup | Status | Evidence | |---|---|---|---|---|---|---|---|---|---|---|---| | Ability 001 | Server_Ability_001_Begin; UseAbility001 | No | Gate → CurrentlyAttacking → CanMove true → Multicast_PlayMontage(random Ability001Montage) | Multicast_PlayMontage | Gate | None | UseAbility001 Authority BoxOverlap ApplyDamage — **caller: AN_Ability_001** | A_Hu_F_Combat_2H_Attack* montages | **AN_AttackComplete** → SetIsAttacking | **Implemented** (Pass 8 confirmed) | Pass 6 + Pass 8 | | Ability 002–004 | Inherited only | N/A | Base PrintString | — | — | — | — | — | Base empty End | **Stub** (inherited) | list_events | | Basic attack | Ability 001 | No | Same | Same | Same | Same | Same | Attack montages | Same | **Implemented** (=001); **Observed Runtime Behavior:** known working melee | parity brief + subgraph | | Passive | — | — | — | — | — | — | — | — | — | **Missing** | — | | Whirlwind | PerformingWhirlwind Get only | — | — | — | Gates AnyDamage | — | — | — | Never Set | **Partial / Present but Unconnected setter** | find_nodes | | Death | ReceiveAnyDamage → PlayerDeath | — | Local health subtract DEPRECATED_CurrentHealth → Server_UpdateHUD → PlayerDeath if ≤0 | Base death | PlayerHitCheck when whirlwind | Writes DEPRECATED_CurrentHealth | ApplyDamage inbound | — | Base | **Partial** (legacy health) | subgraph | | Legacy HUD | Server_UpdateHUD after damage | — | Base | — | — | DEPRECATED health | — | — | — | **Active** | subgraph | **Amazonian montages:** `/Game/_Main/Animations/PlayerCharacters/Human/CharacterClasses/Amazon/AnimMontages/A_Hu_F_Combat_2H_Attack01_Montage` (+ Attack02, Attack_Base, Attack) --- ## Player_Cleric **Path:** `/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterClasses/Cleric/Player_Cleric` | Slot/System | Entry point | Parent called | Server path | Multicast/client path | Validation | Resource | Damage/effect | Animation | End/cleanup | Status | Evidence | |---|---|---|---|---|---|---|---|---|---|---|---| | Ability 001 | Server_Ability_001_Begin | No | Gate → CurrentlyAttacking → CanMove false → Multicast_PlayMontage(random Ability001Montages) | Multicast_PlayMontage | Gate | None | **AN_Ability_001 present but UseAbility001 unimplemented** — no hit | Cleric_PrimaryAttack_* | AN_AttackComplete still clears attacking | **Partial** (montage + dead notify) | Pass 6 + Pass 8 | | Ability 002 | Server_Ability_002_Begin; UseAbility002 | No | Gate → FCanUseMana → Multicast_PlayMontage(Cleric_Ability002_Montage) | Multicast_PlayMontage | Gate + mana | DEPRECATED_Ability002ManaCost | UseAbility002 Authority heal — **caller: AN_Ability_002**; empty particle | Cleric_Ability002_Montage | AN_AttackComplete | **Partial** (notify-driven heal; FX hole) | Pass 6 + Pass 8 | | Ability 003 | Server_Ability_003_Begin; Server_Ability_003_End; ConcentrateHandle; EndConcentrate | No | Mana≥cost → DivineCircleActive + SetTimer 0.25 ConcentrateHandle | ConcentrateHandle plays montage + ApplyDamage; ABP Divine Circle state | Gate + mana | DEPRECATED_Ability003ManaCost | ApplyDamage in timer; **AN_Ability_003 → UseAbility003 dead/vestigial** | Cleric_Ability003_Montage (timer byproduct) | EndConcentrate | **Implemented** (timer-driven; vestigial notify) | Pass 6 + Pass 8 | | Ability 004 | Server_Ability_004_Begin; UseAbility004 | No | Gate → FCanUseMana called but Branch Condition=**literal true** → montage | Multicast_PlayMontage | Gate; mana bypassed | DEPRECATED_Ability004ManaCost unused | UseAbility004 — **caller: AN_Ability_004**; SpawnActor Class empty | Cleric_Ability004_Montage | AN_AttackComplete | **Partial / Existing Baseline Defect** | Pass 6 + Pass 8 | | Basic attack | Ability 001 montage | No | Same | Same | Same | — | Missing hit | PrimaryAttack montages | — | **Partial** | — | | Passive | — | — | — | — | — | — | — | — | — | **Missing** | — | | Death / HUD | Inherited | — | Base | Base | — | — | — | — | — | **Inherited** | — | **Cleric GE** `GE_Cleric_DefaultAttributes` exists but **0 referencers**; not in ability graphs. --- ## Player_Wizard **Path:** `/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterClasses/Wizard/Player_Wizard` | Slot/System | Entry point | Parent called | Server path | Multicast/client path | Validation | Resource | Damage/effect | Animation | End/cleanup | Status | Evidence | |---|---|---|---|---|---|---|---|---|---|---|---| | Ability 001–004 | Inherited Server_Ability_* only | N/A | Base PrintString | — | — | — | — | — | Base empty End | **Stub** (inherited PrintString) | list_events + EventGraph walk | | Basic attack | Same | N/A | Stub | — | — | — | — | — | — | **Stub** | — | | Passive | — | — | — | — | — | — | — | — | — | **Missing** | — | | Death / HUD | Inherited | Tick/Overlap Parent yes; BeginPlay **no Parent** | Base | Base | — | — | — | — | — | **Inherited** | subgraph | | Alternate paths | UseAbility* false; no Input/Montage/spell nodes | — | — | — | — | — | — | — | — | **Missing** | find_nodes | | Unwired assets | NS_Wizard_Ability001; GE_Wizard_DefaultAttributes; BP_PlayerProjectile | — | — | — | — | — | — | — | — | **Present but Unconnected** | deps/referencers | Local vars `EnemyFound`, `IsBlocking`, `ClosestEnemy`: **declared, zero EventGraph uses**. --- ## Player_Gunslinger **Path:** `/Game/_Main/Blueprints/Characters/PlayerCharacters/PlayerCharacterClasses/Gunslinger/Player_Gunslinger` | Slot/System | Entry point | Parent called | Server path | Multicast/client path | Validation | Resource | Damage/effect | Animation | End/cleanup | Status | Evidence | |---|---|---|---|---|---|---|---|---|---|---|---| | Ability 001–004 | Inherited only | N/A | Base PrintString | — | — | — | — | — | Base empty End | **Stub** (inherited) | IsDataOnly + deps | | Basic attack | Inherited stub | N/A | Stub | — | — | — | — | — | — | **Stub** | — | | Passive | — | — | — | — | — | — | — | — | — | **Missing** | — | | Death / HUD | Inherited; BeginPlay Parent | Yes | Base | Base | — | — | — | — | — | **Inherited** | subgraph | | Weapon/projectile | None | — | — | — | — | — | — | — | — | **Missing** | deps only base | **IsDataOnly=True.** No GE_Gunslinger. Referencers registry []. --- ## Cross-character RPC inventory (ability-related) | Event | Paladin | Amazonian | Cleric | Wizard | Gunslinger | |---|---|---|---|---|---| | Server_Ability_001_Begin | Local override | Local | Local | Inherit stub | Inherit stub | | Server_Ability_001_End | Inherit empty | Inherit empty | Inherit empty | Inherit | Inherit | | Server_Ability_002_Begin | Local (block) | Inherit stub | Local | Inherit | Inherit | | Server_Ability_002_End | Local | Inherit | Inherit empty | Inherit | Inherit | | Server_Ability_003_Begin | Local (charge) | Inherit | Local (DivineCircle) | Inherit | Inherit | | Server_Ability_003_End | Inherit | Inherit | Local → EndConcentrate | Inherit | Inherit | | Server_Ability_004_Begin | Local | Inherit | Local (mana bypass) | Inherit | Inherit | | Server_Ability_004_End | Inherit | Inherit | Inherit | Inherit | Inherit | | UseAbility001 | Local Authority damage | Local Authority damage | Missing | Missing | Missing | | UseAbility002 | Missing | Missing | Local Authority heal | Missing | Missing | | UseAbility004 | Local Authority AoE | Missing | Local Authority spawn broken | Missing | Missing | | Charge / Client_Charge | Local | — | — | — | — | | ConcentrateHandle / EndConcentrate | — | — | Local | — | — | Reliability: **Unknown — MCP property visibility limitation** for all CustomEvents. --- ## Resource and legacy-state inventory | Symbol | Readers/Writers | Notes | |---|---|---| | DEPRECATED_Ability001Damage | Paladin UseAbility001; Amazonian UseAbility001 | ApplyDamage BaseDamage | | DEPRECATED_Ability003Damage | Paladin ChargeBox | ApplyDamage | | DEPRECATED_Ability004Damage | Paladin UseAbility004 | ApplyDamage | | DEPRECATED_Ability002Damage | Cleric UseAbility002 | Heal amount via RecoverPlayerHealth | | DEPRECATED_Ability00{2,3,4}ManaCost | Paladin 003/004; Cleric 002/003/004 | FCanUseMana / compare | | DEPRECATED_CurrentHealth | Amazonian AnyDamage | Subtract + death check | | DEPRECATED_RecoverPlayerHealth | Cleric UseAbility002 | Interface message | | CurrentlyAttacking / IsDead | All ability gates | Replicated on base | | IsBlocking | Paladin 002 Begin/End | Local; **ABP_Paladin Block state** (Pass 8 Observed Implementation) | | PerformingWhirlwind | Amazonian AnyDamage | Get only — never Set; **not in AnimBP/montages** (Pass 8) | | DivineCircleActive / TimerHandle | Cleric 003 | Timer loop; **ABP_Cleric Divine Circle state** reads flag (Pass 8) | **No ASC attribute reads/writes in ability graphs.** No GameplayAbility grant/activate. ### Pass 7 — Legacy vs GAS boundary (clarification) | Concern | Legacy ability path | GAS path | Sync | |---|---|---|---| | Combat damage / heal | ApplyDamage / DEPRECATED_Recover* | Consumable GEs only (potions/food) | **None observed** | | Mana cost | DEPRECATED floats + FCanUseMana | Attribute Mana modified by potions only | **None observed** | | Default spawn resources | Not from abilities | Orphan `GE_*_DefaultAttributes`; native AttributeSet Init* used | Defaults unreachable via GE | | UI | Server_UpdateHUD DEPRECATED % | OverlayWidgetController ASC | Dual, unsynchronized | ### Pass 9 — Player ApplyDamage vs enemy reception Playable Paladin/Amazonian/Cleric attacks apply `ApplyDamage` (Pass 6). Enemy Blueprints implement **no** `ReceiveAnyDamage` / health mutation / death. Enemy ASC Health is not bridged from ApplyDamage. **Static implication:** player attack damage paths have **no observed enemy health/death consumer** — Existing Baseline Defect on the enemy side; player attack graph status unchanged. Full matrices: `06-PartialGASArchitecture.md`, `09-EnemyAI-StaticAnalysis.md`. Ability status labels from Pass 6/8 are **unchanged** by Pass 7/9. --- ## Authority / networking findings (flags, no fixes) - Client IA → Server Begin: Observed Implementation - Damage on UseAbility* / ChargeBox: Authority SwitchHasAuthority — Observed Implementation - Multicast used for montage/SFX/particle presentation — Observed Implementation - **Pass 8:** Multicast montage → AnimNotifies fire on evaluating machines; gameplay still Authority-gated inside UseAbility* / SetIsAttacking - **Pass 8 static risk:** hit windows depend on server evaluating Multicast montage notifies; interrupt may skip `AN_AttackComplete` (completion pins unwired) - Cleric Ability 004: mana CanUse **unwired** (literal true) — Existing Baseline Defect - Cleric Ability 004: SpawnActor Class empty — Existing Baseline Defect - Multi_SpawnParticle EmitterTemplate empty (Paladin 004, Cleric 002) — Partially Implemented - End events missing for most slots — Incomplete Refactor (cleanup often via `AN_AttackComplete` instead) - Amazonian/Paladin Ability 001: no mana cost — Observed Implementation - Dual HUD still uses DEPRECATED floats on Server_UpdateHUD — Incomplete Refactor (Batch 2) --- ## Status rollup | Classification | Characters / slots | |---|---| | **Implemented** | Paladin 001, 003, 004 (FX hole on 004); Amazonian 001; Cleric 003 (timer; vestigial AN_Ability_003) | | **Partial** | Paladin 002; Cleric 001 (dead notify), 002 (heal + FX hole), 004 (broken spawn); Amazonian whirlwind | | **Stub** | Wizard 001–004; Gunslinger 001–004 (inherited PrintString) | | **Missing** | Wizard/Gunslinger combat bodies; most Server Ends | | **Present but Unconnected** | NS_Wizard_Ability001; GE_* orphans; BP_PlayerProjectile; PerformingWhirlwind setter; Cleric_Hu_M_Spell_Staff_Up_Impact_Montage (0 refs) | | **Deprecated connected** | All DEPRECATED_* damage/mana/health in active paths | | **Notify Present; Receiver Unimplemented** | Cleric AN_Ability_001 → UseAbility001; Cleric AN_Ability_003 → UseAbility003 | --- ## Pass 8 animation callback note Full tables and reclassification: `10-AnimationDependencies.md`. Primary status labels unchanged except qualifications above; no silent rewrites. --- ## Migration relevance (inventory only) Replacement targets: IA→Server custom events; AnimNotify→UseAbility timing; ApplyDamage/RecoverPlayerHealth; FCanUseMana + DEPRECATED costs; Multicast_PlayMontage; Charge timeline; DivineCircle timer; dual HUD floats; `AN_AttackComplete` lockout cleanup.