Skip to content

Ability modules and gameplay extension points

Status: This is a historical migration and behavior record, not the current ability API. Individual Ability ScriptableObjects and AbilityHolder have been retired; data and behavior are now code-owned. Use the current hook reference, roadmap, and source for current identity, lifecycle and verification status.

The following early migration summary is historical: later sections contain dated notes and source baselines; confirm their status before use.

Current cooldown and progress behavior

The runtime owns timed work and private copies of ability assets. UseAbility normally checks isOnCooldown, starts a timed admission and a separate display countdown, and then runs the ability work. The admission starts with a half-second wait and reads the copy's cooldown for the remaining wait; the display updates independently. Bypassing admission is used by abilities that count events instead of waiting for this timer.

Luster Burst updates its displayed currentCooldownTime and cooldownTime from its shot count and threshold. Ground Breaker displays its critical count and threshold, then uses timed cooldown work for its burst recovery. These fields therefore serve as display progress as well as timed cooldown data; changing their interpretation globally would affect both styles. The existing overlapping timer and display behavior, pause, removal, suspension, and upgrade timing are not yet verified in gameplay.

2026-10-28, batch 59. Source/design review at 0a150f7c, implementation 56f764c9. This refines the combat contract, whose original formulas, ordered traces, serialized callbacks and acceptance gates remain authoritative. No ability behavior is implemented by this document. Continue the existing R3 work order; concrete modules follow their required capability/attack owners.

Later owner direction: plan the complete connected rework first, then defer tests during implementation for now. Compilation is a separate check and does not establish gameplay behavior. The evidence checklist below remains the eventual verification target, not a requirement to run checks in each current implementation group. Clearly mark new work unverified and retain all runtime acceptance gates until verification resumes.

Evidence and coverage

The runtime reference index contains all 101 AbilityType members in ordinal order. A comment-excluded literal enum scan finds candidates for 92 types across 17 non-Editor scripts. This is a discovery index, not a compiled call graph, reachability test or semantic certification of every combination. Carrier, evolution, HUD and projectile code can use transferred fields or serialized callbacks without naming AbilityType. The nine names without literal sites include Armored, whose ARMORED UpgradeFunction branch still performs work; absence of a literal check does not mean unused content.

Reuse the 121 authored-definition inventory, upgrade routes, bindings, persistent calls and equivalence cases. This page supplies mechanism-level decisions rather than duplicating their raw catalogs. Review traces AbilityHolder, ability clocks, PlayerWeapon/Attack/Carrier, damage hooks/resolver, stat input/projection, companions, enemy marks, pickup/item behavior, evolution/upgrade adapters and HUD readers. Fresh/reused objects, imported overrides, actual late-run combinations and Windows/physical acceptance remain unverified here.

Mechanisms the design must support

Mechanism and source examples Observed behavior Required boundary
ProtoBarrier (historical script) and incoming shield resolution Capacity depends on live max HP and an evolution bonus; regeneration rewrites cooldown from reload speed, waits, then polls stamina. Reflection precedes immunity. Sprite color reads accumulated damage, while activeSelf currently gates absorption. Barrier runtime owns capacity, accumulation and regeneration phase; ordered defense hooks own absorption/early return; a bound view renders state. Preserve all sampling points, raw-hit thresholds, reflection order and explosion minimum.
StellarShield, EmergencyShield, ReloadShield, TidalVeil Different block counts, capacity subtraction, lethal/low-health triggers, timed reset and dash-generated stacks. TidalVeil has an animation wait and readiness-dependent break. Specialized state/policies share presentation/spawn/lifecycle services. A universal shield default must not introduce spillover, change priority or make every break a timed cooldown.
LusterBurst and GroundBreaker Ability cooldown fields also carry attack/crit counts. GroundBreaker switches between count accumulation, empowered attacks and reload-derived cooldown. Explicit time/count/phase state and display kind; UI reads the right meter. Preserve decrement/reset ordering and the existing count arithmetic.
Frenzy and RocketBarrage Automatic eligibility with per-character cooldown modifiers; Frenzy duration uses max stamina. RocketBarrage captures enemy count before a wait but reads other values later. Owned automatic scheduler, ability-specific readiness and sampling policy, attributed carrier service. No requirement for a manual activation button.
StarBurst Charges only after target/range admission and while stationary; reads attack speed continuously, changes projectile and later attack damage/hit budget, then resets charge. Movement/target observation plus weapon admission, selection and attack-construction stages. A dash-only or timer-only ability interface is insufficient.
ArtemisBurst and Airstrike Delayed sequences, captured origin versus later positions, repeated live stat reads, random offsets, camera-relative carrier launch and delayed child attacks. Owned sequence with explicit camera/target/spawn dependencies; declare captured versus live values at each step. Preserve integer Random.Range calls and ordering.
Wu Ran swords and Tiamra orbs Persistent owned entities reuse weapon AttackModify and FireWeapon(false), with live stats, orbit/target state, contact/return timing and extra splash attacks. Multishoot acquisition and summon acquisition each affect counts. Summon instance plus weapon/attack hooks; preserve ornament weapon data and both acquisition orders. A persistent companion is distinct from a one-shot projectile.
RunandGun and dash perks Several ordered effects run before launch, after stamina eligibility. Some mutate HP/stats or add TidalVeil stacks; cooldown and effect duration are separate. Per-player ordered dash hook; owner handles admission, module handles its effect and contributions. Registration order must preserve existing execution, independent of purchase order.
CCombo, Assassination, SureFire, UnsteadyHand, BloodThirst, Rebuke Weapon-fire hooks run before spawning. Some counters advance even in FireWeapon(false), while each multishot projectile separately calls AttackModify. Distinguish weapon-fire attempt/hooks, each constructed projectile and each resolved critical. One generic OnAttack notification changes counts and random consumption.
FreezingPendant, PoisonVial, VampireBE, CImpact, PiercingBullet Weapon construction transfers eligibility/proc results; impacts use a mix of captured damage/amplification and live owner values. Ordered attack construction and attributed impact processing; payload state belongs to each attack. Preserve fixedModifier guards at their actual stages, including currently unconsulted fields.
Ricochet, ExplodingEnchantment, HydraBarrage Impact creates child attacks with different copied flags, damage formulas, target rules and hit history. First-hit restrictions and child position differ for direct attacks/swords/orbs. Explicit child-attack policies and lineage; never automatically reapply every acquired perk to every child. Resolve fresh/reused differences before asserting chain behavior.
ThornArmor/ETArmor, AdrenalineRush, FirstAid, FinalForm, LastStand Reflection, immunity, shields, HP changes, reactions and lethal handling are different stages with early exits. Some HP costs/heals bypass incoming-damage processing. Ordered synchronous damage/defense capabilities with distinct result stages; UI/feedback observes results. An undifferentiated GotHit event cannot reproduce this sequence.
SurvivalInstinct, TranscendEclipse, Meditate, StaminaBoost, Strafe Conditions read current HP/max HP, stamina, movement, attack speed or derived stats. Remaining below a threshold differs from crossing it once. Explicit observation inputs and evaluation policy. Keep needed polling until every state/stat invalidation is known; event-driven refresh is a separate change requiring evidence.
Pickup modifiers: AlchemistTouch, Opportunist, Invigorate, SWBody Affect potion application count, rerolls, permanent gains, counters and full-resource pickup eligibility. Pickup/upgrade participation hooks; once-only application and collection gates remain with their existing owners. These are ability interactions outside combat firing.
Evolution callbacks and upgrade application Serialized UnityEvents change ability parameters, acquire definitions, summon entities and create extra weapons. Some upgrades apply values immediately rather than maintaining an active skill. Explicit acquire/parameter/weapon operations plus temporary compatibility callbacks. Preserve GUID/type/ordinal identity and arguments until all serialized consumers migrate.
Potion/effect work Potion work is keyed by ItemType globally; the visual queue serializes full durations across players. Per-player effect work and explicit refresh/cleanup. Resolve unintended cross-player ownership under CA-01; do not copy global workers into each module.
HUD readers and StatusPanel Icons are discovered via Upgrade asset-reference equality, list offsets and character index; status colors inspect Holder flags. Private runtime clones cannot satisfy the current upgrade.ability equality lookup. Stable definition-to-presentation mapping, explicit acquired-state/meter view. Keep the legacy HUD out of the owned arena until migrated; this is a known integration boundary, not a newly reproduced shipped HUD defect.
Target-side sword marks and lifecycle Enemy has one IsGotMarkedHeavenSkySword flag; later hits trigger lightning using the passed player. Attacks carry hit history; companions have separate master/death/revive state. State lives on the entity that owns it: target marks, attack hit sets, summon lifecycle and player ability state differ. Preserve/characterize cross-player mark semantics before changing ownership keys.

Asset and object loading

The current shield methods do not load images by filename. Player.prefab serializes object references. Its knightProtoBarrier points to a stripped nested prefab instance, resolved through GUID/fileID to ProtoBarrier.prefab, whose root SpriteRenderer uses Knight_ProtoBarrier_Idle.png and whose Animator references Knight_Skill_ProtoBarrier_Animator.controller. stellarShieldObject points to the local StellarShield child with its own SpriteRenderer and Animator. That controller is under Animation/Unused Animation but is referenced; the folder label is not evidence for deletion. Explosion fields reference separate attack prefabs.

Eight selected bindings were followed in the correct file scope: both shields, both explosions, ArtemisBurst carrier, StarWanderer rocket, Celestial Yin sword and Priestess AbyssOrb. This resolves those YAML targets and root visual references, not every imported override or descendant. Prefab fileIDs can repeat across different files, so resolving a GUID reference against the current file would be incorrect.

Target authoring uses typed definition references for icons, optional bound views, attack/carrier/companion prefabs, animation/audio and effect parameters. Prefabs retain their sprites/controllers/components. A module receives its prepared view/attachment and spawn services from player assembly; shared definition assets must not store a live player GameObject. Preserve existing child views through explicit binding during migration; reusable prefab views can replace them when bindings and behavior are accounted for. Validate requirements by ability kind: an orbital summon need not supply an ordinary gun projectile.

Upgrade/character assets currently supply icon metadata; Ability itself contains only type/cost/cooldown and mutable cooldown fields. Maintain a stable definition link through runtime copies, then migrate presentation mapping. A new icon field on an unpopulated asset would not repair existing content by itself. Direct serialized references are sufficient for this rebuild; no new Addressables catalog or Resources.Load-per-trigger system is required.

Use a focused C# runtime implementation per distinct ability behavior, with ScriptableObject configuration and small explicit player/attack services. Ability-specific state stays with that runtime; shared admission/work stays with the player ability owner. Data-only variations can reuse an implementation. A module may participate in multiple hooks and hold handles to its views and owned entities. The owner's two-part stat design centralizes named stat-source calculations for inspection: modules expose authoritative state; the central calculation reads it and owns the formulas. A module must not become a second player/weapon/pool implementation.

Boundary Required information and authority
Definition Stable definition identity, display metadata link, typed prefab/view/audio references, authored values and behavior factory. No live counters or player pointers. Preserve distinct definitions that share AbilityType.
Runtime module Owning player/run, private counters/phases and contribution/registration handles. Preserve same-definition duplicate-acquisition policy; do not accidentally introduce stacking through extra module instances.
Activation Existing eligibility, cost and cooldown policy, trigger context and bypass/refresh rules. Distinguish charge/count meters and effect duration from admission/display clocks.
Gameplay hooks Explicit stage, context and deterministic legacy order. A hook may modify an attack, intercept damage or start owned work. Gameplay decisions execute synchronously at the required stage.
Stats/conditions Modules expose their own authoritative state. A central stat calculation explicitly reads named sources and applies their rules, preserving live/captured read points and existing arithmetic. Declare replacement/stacking and cleanup; do not duplicate calculation authority or state flags.
Spawned execution Prepare inactive with owner, credit, payload, target, transform, child policy and reset state; then activate. An in-flight object can outlive its creator only under an explicit existing lifetime policy. Run retirement invalidates stale targets/owners.
Presentation Render authoritative state; publish completed-result notifications to UI/audio. Hiding a shield image must not itself decide damage absorption in the target architecture.
Teardown Revoke registrations, cancel owned work, release only owned contributions/entities/views exactly once. Actor suspend, death/revive, acquisition removal and new run have distinct policies.

Common services handle small concrete needs: attack/carrier spawning, persistent summon ownership, target queries, scoped work, stat/resource transactions, defense resolution and presentation. Add them with their first real consumer; avoid a universal service locator, a giant ability switch or hundreds of independent Update components. A per-player scheduler may drive the abilities requiring continuous observation. A separate global broadcast system is not needed for every internal gameplay hook.

Proposed assembly and registration flow

These names and interfaces describe a design to implement, not an existing API. A small ability-runtime base may supply identity, context, activation access, owned work and registration cleanup. Optional interfaces describe capabilities such as participating in a weapon-fire or dash stage; an ability implements only the stages it uses. The player ability owner creates the runtime from its authored definition, registers its supported contracts once for that player's run and stores revocation handles. Registering a contract must not require a branch naming each individual ability in the weapon or dash owner.

An existing gameplay owner publishes a narrow, ordered hook and context at the actual execution point. The dispatcher calls only this player's registered participants; a handler makes its own eligibility/proc decision and requests shared cooldown admission when appropriate. Stateful damage interception needs an explicit synchronous result and existing early-return order. Presentation notifications may consume the result after gameplay is resolved. A unique ability may publish an extension point for another ability when a real consumer needs it; otherwise reuse the existing weapon, attack, damage, dash or other capability stage.

Registration order must reproduce legacy behavior independently of acquisition order. During migration, combine old and new behavior in the same explicit stage sequence: each existing effect has exactly one active route, and a migrated participant replaces its old slot rather than executing twice or being appended after unrelated perks. Preserve conditional/random evaluation and all early returns. Specify reentrant calls, listener addition/removal during dispatch and exception behavior before implementing a stage; these details are open design work, not claims that a generic event bus already handles them.

The existing Ability asset type, character references, Upgrade assets and serialized evolution callbacks are integration inputs. Keep definition identity separate from mutable runtime copies; distinct definitions sharing an enum are not one ability. Preserve the current within-player same-definition duplicate alias/reset and first-match behavior until intentionally changed. EQUIPABILITY means acquiring an existing run ability in this context; it does not authorize a new equipment/loadout feature. Ability UI metadata currently comes from existing character/Upgrade assets; map it to the owning definition and player state without comparing a runtime clone to an authored asset by reference. Maintain existing callback signatures and GUIDs while callers migrate.

Initial character ability state · 2026-10-28

AbilityHolder.PrepareInitialState(bool requireViews) now holds the existing defaults formerly initialized directly in Start. The legacy Start still prepares them before starting its original character-acquisition coroutine. The inactive PlayerAbilityRuntime prepares the same state before acquiring its private definitions, without running the legacy coroutine or enabling legacy updates. The owned route allows a missing Knight barrier view during this preliminary preparation; the legacy route still requires its original binding. This supplies, among other values, Tidal Veil's initial maximum of three and ready flag, Soldier reload defaults and the Archer/Miner counters. This is a foundation, not migration of those abilities, their character initialization, damage behavior or views. It has not been compiled or runtime-tested; initialization timing and all seven characters remain open comparisons.

Authored identity and HUD bridge · 2026-10-28

PlayerAbilityRuntime.TryGetDefinition(Ability runtime, out Ability definition) maps an owned runtime copy back to its authored definition. Duplicate entries for the same definition continue to alias the same copy; different definitions remain distinct. AbilityPanel.IconUpdate uses that mapping for Upgrade icon lookup and reads the selected runtime entry's own cooldown and display time. Without an owned runtime it continues to use the existing asset reference and values. The map is cleared with the owner. This source change has not been compiled or runtime-tested; the shared arena still does not enable the full HUD/gameplay loop.

UpgradeFunction EQUIPABILITY and WeaponEvoData.AddAbility now call the player-aware AbilityFunction.AddAbility overload; UpgradeEvoFunction uses its corresponding removal overload. If the player has an owned runtime, acquisition uses Acquire and removal maps the authored definition to its runtime copy and removes the first matching entry. The copy stays owned until runtime disposal; reacquisition retains the existing alias/reset policy. Removal does not cancel work, matching the old list removal rather than specifying future module revocation. Without an owned runtime the existing list operations remain in use. The serialized evolution callback signatures and Multishoot follow-up ordering are unchanged. This slice has not been compiled or runtime-tested.

This is not complete presentation or production integration. RewardRoller still tests authored-reference membership, and GameManager compares ability entries with Upgrade references for display/result paths. The owner has deferred those domains; migrate their consumers to definition-aware identity before enabling owned copies in their production paths. No runtime acceptance gate is closed.

Trigger stages and interactions

Hook names below describe required semantics, not implemented APIs. Extend the existing dash/damage owners rather than building a parallel route.

Trigger family Required distinctions
Acquisition/evolution Initial acquire, same-definition reacquire, parameter upgrade, summon count change and removal.
Dash Admission, ordered pre-launch effects, launched phase and completion/cancellation. Preserve the current point at which perks run.
Weapon Target/range/charge admission, reload start/captured wait/refill, pre-fire hooks, projectile selection, each attack payload, critical processing and fire completion.
Attack impact Eligible contact, damage attempt/result, ordered status/proc work, first-hit children and return/despawn. Current status/proc work may run after the damage budget branch; retain that distinction.
Incoming hit Pre-immunity reflection, immunity, ordered shields/absorption, health application, reactions, lethal replacement and immunity tail.
Observation/timers Timed eligibility, current resource thresholds, movement/stationary state, available targets and count/charge progress.
Pickup/progression Eligibility, committed item effect, chest/reroll participation, weapon evolution and legacy callbacks.
Lifecycle Prepare/activate, suspend, death, revive, revoke and run retirement. A pooled attack or summon has its own lifecycle.

Each registration needs deterministic order, explicit owner/lifetime, a revocation handle and the correct trigger context. Inspectable registration/state is useful for tracing; it is a later implementation detail, not permission for new menus. Save identity and content discovery stay with existing contracts. Events can report outcomes to presentation; synchronous ordered hooks carry gameplay decisions and early returns.

Publishing and documenting a hook

Owner clarification, 2026-10-28: when changing a capability or splitting an ability, identify its real consumers and supply the required registration point in that same coherent change. Migrate the related caller as well as the ability body. Merely relocating named ability checks into another adapter does not complete this work. Existing PlayerDashHooks.ApplyBeforeDash still lists the perks and their checks; it is a compatibility bridge, not an implemented registration dispatcher. IPlayerDashHooks is an executor adapter interface and must not be presented as a public ability registration API.

Each implemented hook must have a catalog entry in this contract or an owning contract linked here. Proposed names remain marked proposed until their source/API and real consumer exist. The entry must include:

Required field What to document
Identity and owner Exact public name, source path and responsible capability; player/run/attack scope.
Purpose and firing point The actual action/stage; admission/resource ordering, frequency and per-weapon versus per-projectile/per-hit semantics.
Registration example Actual signature, required context, where the module registers and a real migrated consumer. Report compilation status; do not label pseudocode as an existing API.
Context and authority Readable inputs, permitted mutations/results and live/captured values; which owner commits resources/damage.
Ordering Stable phase/priority and tie policy reproducing the prior order; acquisition order must not silently become gameplay order.
Lifetime and removal Returned revocation handle, duplicate/same-definition acquisition policy, revoke/dispose behavior and distinct suspend/death/revive rules.
Dispatch semantics Synchronous/owned work, exceptions, reentrancy and registration/removal during dispatch; define rejection/early-return behavior where relevant.
Activation and clock policy The owner's admission/cooldown path, skill eligibility/proc order, start/refund/refresh rules and display kind.
Evidence Checks for a real registered ability, ordering, two-player isolation and cleanup; remaining native/content qualification.

A capability invokes its registered handlers at the specified stage. Modules own their conditions and effect execution; the ability owner supplies shared admission/work policies. Common weapon/dash/impact stages belong to those capabilities. An ability may expose a specific extension point when a real second behavior needs it; reuse an existing stage when it already has the required semantics. Add a hook for an identified consumer, rather than prebuilding registration methods on every script. Conditional gameplay rules remain necessary; removing named cross-ability branches and duplicate authority is the completion criterion.

Implemented pre-dash ability hook · 2026-10-28

Source: PlayerDashAbilityModules.cs (historical script), PlayerAbilityRuntime.cs, PlayerDashHooks.cs, UnyieldingMalice.cs and CurseOfMalice.cs. This is an internal player/run-scoped registration point for actual modules, not a general public API or migration of all dash abilities.

  • IBeforeDashAbility exposes int Order and synchronous void BeforeDash(PlayerDashFeedback feedback); PlayerBeforeDashHooks.Register(IBeforeDashAbility) returns an IDisposable registration. PlayerAbilityRuntime.Acquire creates and registers the first module for an acquired matching type. The owned dash controller supplies PlayerAbilityRuntime.DispatchBeforeDash(int firstOrder, int lastOrder, PlayerDashFeedback feedback) to the existing dash capability; the capability invokes ordered ranges at their original positions around unmigrated slots. No generic hook is published for abilities without a consumer.
  • The executor invokes the hook only after pause and stamina admission. The first range contains Band Aid Roll and both Malice effects; the second runs TacticalFire, RunandGun, FocusDodge, Bomb Roll, Vacuum Dodge, Airstrike, TidalVeil and Frenzy dash reload in that order. BandAidRoll has order 50, before both Malice modules; it checks SuddenDeath before requesting normal first-match BARoll admission from the per-player owner. On admission it immediately adds 5 × live final maximum health / 100, with no cap in this operation, and its owned work waits the ability cooldown as the old body did. Admission/display clocks retain their existing separate policy. Unyielding Malice has order 100 and Curse of Malice 200 regardless of acquisition order. Equal orders are rejected; registration is once per type even if multiple entries/definitions share that type, matching the old presence checks. The two modules mutate their own player's current health and existing permanent modifier inputs with the original thresholds and values. The second observes the health left by the first. Neither Malice module uses cooldown admission, random work or a separate display meter.
  • Removing an entry unregisters the module only when no entry of that type remains; runtime disposal unregisters all. Suspension retains registrations for the same runtime. Existing direct stat contributions are permanent and are not reversed on removal, as before. Production without the owned runtime executes the old named checks; the owned route dispatches the modules instead, so the migrated slots do not run twice.
  • BombRollAbility (order 600) and VacuumDodgeAbility (700) use normal owned admission. Their bodies preserve the old pooled spawn, immediate payload writes, live values, sound order and cooldown wait. They still use legacy PoolManager and carrier/attack initialization; preparation before activation and fresh/recycled payload equivalence remain open under CA-02. The old bodies are retained for production and possible serialized callers.
  • TacticalFireAbility (order 300) and RunAndGunAbility (400) request normal owned admission and share the existing duration/work policy with Focus Dodge via TimedDashAbility. Their module state is authoritative on the owned path. The central PlayerStatProjection selects the original TacticalFire damage ×2 and skill amplification +50, and RunAndGun movement ×1.5 and attack interval factor ×1/2 at the existing formula positions. PlayerModifier supplies the module flags; AbilityHolder exposes those flags to the existing status panel. The old modifier fields and holder bodies remain the production fallback when no owned module exists. Existing input values and operation order remain for that fallback. Module instances persist until runtime disposal, including after removal, to allow started work to finish.
  • FocusDodgeAbility (order 500) owns the active flag, uses normal owned admission and reads the existing run level when its effect starts. Its duration and subsequent cooldown wait retain the source formula. AbilityHolder.IsFocusDodge is a compatibility reader that returns the module state when that module exists; the central projection and existing status view therefore read the same player-owned state. The module is retained after removal so an already-started effect can finish, and is reused on reacquisition. On normal expiry, the flag clears as in the old body; on cancellation a work item removes only its own contribution and clears the flag when no work remains. Cancellation cleanup is an owned-lifetime change from the old global worker and is unverified, especially for overlapping/re-entry, death and revive. Legacy production keeps the existing holder flag and body.
  • AirstrikeAbility (order 800) retains normal admission, its initial position, 0.2-second scaled wait, second position and subsequent live spawn position/damage, carrier owner and magic type. Carrier and pool ownership are still legacy, and its existing delayed work now follows the actor/run owner. The asset is not established as released content by the inventory; the migration does not introduce it to any catalog.
  • Each range dispatch takes a synchronous ordered snapshot. Registration or removal during dispatch affects the next dispatch, including a reentrant dispatch; an already snapshotted handler still runs in the current dispatch. Exceptions propagate and stop remaining handlers. A reentrant dispatch takes a fresh snapshot. A later range takes a fresh snapshot; current consumers do not themselves alter registrations or reenter; these semantics are documented, not runtime-qualified.
  • No tests, compilation or gameplay check were performed for this slice. Validate the two-player, duplicate/removal, death/revive, dispatch and health-boundary cases when verification resumes. Production composition and other shield abilities remain legacy; the owned cooldown is not yet the complete module policy; this hook does not close player or combat acceptance.

C Combo weapon-fire stage · 2026-10-28

CComboAbility implements IPlayerWeaponFireAbility at order 100. Hooks_WeaponFire.Register(IPlayerWeaponFireAbility) returns an IDisposable; the weapon calls PlayerAbilityRuntime.DispatchWeaponFire(int firstOrder, int lastOrder, PlayerWeapon weapon, bool fireWeapon) at the original C Combo slot, after the character fire handlers and before Assassination. The context supplies the actual weapon and whether the caller will spawn an ordinary shot. The handler checks that weapon's existing ignoreCCombo, consumes the original integer random roll before asking the player owner for first-match cooldown admission, and starts the effect on success. It runs once per fire call, including FireWeapon(false) from swords/orbs, not once per projectile. A registered handler replaces the old slot; absent registration falls back to the legacy check and body.

The module owns its active flag and samples 1 + finalMaxStamina / 50 on activation. AbilityHolder.isCCombo bridges the central projection and existing status view; the projection retains the attack/reload interval factors and operation order. Removal revokes the fire registration only after the last matching entry; the module remains to finish owned work. On normal expiry the flag clears as before; cancellation releases its contribution and only clears when no other work remains. This cancellation policy differs from the global worker and requires comparison. Dispatch uses an ordered snapshot, rejects equal orders, applies registration changes to later dispatches, takes a fresh snapshot for reentry and propagates exceptions. The weapon and actor/run own their respective contexts. No compilation or gameplay check was run; random ordering, cooldown/re-entry, companion fire, extra weapons, co-op and death/revive remain open.

Assassination weapon-fire stage · 2026-10-28

AssassinationAbility uses the same IPlayerWeaponFireAbility contract at order 200. PlayerWeapon.FireWeapon dispatches its own range immediately after C Combo and before Berserker Blood; the actual weapon's ignoreAssassination is checked before any roll. On eligible fire the module takes the existing integer 10% roll before normal first-match cooldown admission, and a successful admitted coroutine adds one charge synchronously. The same fire then consumes one charge if available and sets the module's active flag; otherwise it clears the flag. This also occurs on FireWeapon(false), before that method returns. AbilityHolder properties bridge the active flag and counter to existing readers, including the central stat projection's ×15 damage factor. Removal revokes the hook after the last matching entry; module state and already started work remain owned until disposal. Legacy callers retain their prior path when no owned handler is registered.

The hook uses the dispatch, lifecycle and reentry rules documented for C Combo. Random order, same-frame coroutine execution, companion and extra-weapon calls, cooldown/reacquisition, stat projection timing and death/revive remain uncompiled and untested. The damage factor is still sampled through the existing projection timing; this change does not force immediate recalculation.

Berserker Blood weapon-fire stage · 2026-10-28

BerserkerBloodAbility implements IPlayerWeaponFireAbility at order 300, immediately after Assassination and before SureFire. It checks the current weapon's ignoreBBlood and samples current HP / projected maximum HP × 100 only on eligible fire, including FireWeapon(false). For a sample above 20 and below 50 it records that percentage and activates its existing view; below 20 it records the sample and activates the view; at or above 50 it records the sample and deactivates the view. Exactly 20, and values for which none of the comparisons hold, leave the preceding state and sample intact. The module owns the sampled state and view flag. The central PlayerStatProjection applies the original 1 + ((50 − sampled percentage) / 20), 2.5 or 1 factor at the existing damage and attack-interval positions. Before the first valid sample, or on the legacy path, it reads the existing modifier input. This keeps sampling at fire time and projection at the existing calculation time rather than using current HP on each stat update.

AbilityHolder.isBerserk bridges the existing status view. Removal revokes the fire hook after the last matching entry but retains the module's sample and state until runtime disposal, matching the old persistent modifier after removal. The existing berserkEffect binding remains in use. Hook ordering, snapshots, reentry and exceptions follow the C Combo contract. The 20% boundary, zero/invalid maximum HP, cross-weapon calls, status view, projected stat timing, removal and co-op remain uncompiled and untested. Production retains the legacy route.

Sure Fire weapon-fire and critical stages · 2026-10-28

SureFireAbility implements IPlayerWeaponFireAbility at order 400 and IPlayerCriticalAbility at critical order 100. The fire hook runs after Berserker Blood and before Unsteady Hand, checks the current weapon's ignoreSurefire, and increments the player-owned counter once per fire call, including FireWeapon(false). The new critical hook (historical script) runs for each critical AttackModify after critical damage/type assignment and before the Miner assured-crit reset and GroundBreaker/FatalFK work. It resets that counter regardless of the weapon's SureFire ignore flag. Both dispatchers have unique ordered registrations, synchronous snapshot dispatch, fresh snapshots on reentry and propagated exceptions; the fire registration is revoked after the last matching entry. The critical registration and module remain until owner disposal because the old weapon resets this counter on critical even after the ability is removed. If no owned handler exists the original legacy operations remain active.

PlayerModifier.sureFireCCHCount is a compatibility property backed by the module when present; its legacy serialized field uses FormerlySerializedAs to retain the existing prefab value. The central projection still reads the same counter for critical chance and Late Bloomer critical damage. No stat formula or random roll was moved. Multi-projectile ordering, first critical reset, companion and extra-weapon calls, ability removal, serialized prefab migration, projection timing and two-player isolation remain uncompiled and untested. The critical hook is an internal first consumer, not a completed attack-construction migration.

Unsteady Hand weapon-fire stage · 2026-10-28

UnsteadyHandAbility implements IPlayerWeaponFireAbility at order 500, after Sure Fire and before Blood Thirst. On each eligible fire call it respects the actual weapon's ignoreUnsteadyHand, then takes the existing floating-point Random.Range(0.5f, 2f) draw once. The player-owned module stores the result; PlayerModifier.unsteadyModifier bridges the existing PlayerWeapon.DamageCalculation read for each constructed attack. It also runs for companion FireWeapon(false) calls and is not rerolled per projectile. The modifier and resulting damage operation retain their existing order. Removing the ability removes its fire registration after the last matching entry but retains the last module value until owner disposal, as the old field did. The legacy modifier field is preserved with FormerlySerializedAs; absent an owned handler the original fire path remains active.

Hook ordering, snapshots, reentry and exceptions follow the C Combo contract. Serialized prefab migration, random call order, companion/extra-weapon interactions, multiple projectile damage, removal and two-player behavior remain uncompiled and untested.

Blood Thirst damage, fire and attack stages · 2026-10-28

BloodThirstAbility participates in three ordered contracts. IPlayerDamageReactionAbility.OnDamageReaction(in PlayerDamageHit hit) is dispatched at the original post-health reaction slot after Rebuke and before Final Form. It checks live current HP / projected maximum HP ≤20% and requests normal owned admission with replacement work. Its active phase lasts 10 scaled seconds, followed by the original cooldown-length work wait. The module owns the active flag; AbilityHolder.isBloodThirst bridges the existing status reader. Owned cancellation releases its own contribution, a lifecycle change from the legacy global worker that remains unverified.

IPlayerWeaponFireAbility.OnWeaponFire(PlayerWeapon weapon, bool fireWeapon) runs at order 600 after Unsteady Hand and before Rebuke. It respects ignoreBloodThirst and records live health percentage and active state once per eligible fire, including FireWeapon(false). The central stat projection applies the original +10 vampiric power while active, and uses the last fire sample for chance and movement: while active at that fire, chance is 100 − sampled HP% and movement factor is 1 + chance / 100; otherwise they are 0 and 1. These two fire-derived values remain at the last sample after expiry until another eligible fire, as the original fields did. Until the first fire sample, the old inputs remain the fallback.

IPlayerAttackConstructionAbility.OnAttackConstruction(PlayerWeapon weapon, PlayerAttack attack) for Blood Thirst runs after VampireBE's roll and before character flags, once per constructed attack. It checks that weapon's ignoreBloodThirst and the current active flag, then consumes the original integer vampiric roll against the already projected final chance. The current attack is marked vampiric on success. The reaction and fire registrations are revoked after the last matching acquisition; the attack-construction registration and module persist until runtime disposal because the original construction check depends on active state rather than acquired ability presence. All three dispatchers are synchronous ordered snapshots, reject equal orders, apply mutations to later dispatches, take a fresh snapshot on reentry and propagate exceptions. The damage and attack contexts provide their actual owner and stage; no unrelated attack effect is reapplied.

No compilation or gameplay checks were run. Damage reaction ordering, first-frame admission, refresh/replacement, cancellation, live versus projected values, random order, multishot, companion calls, removal, death/revive and co-op remain open. Legacy production uses its previous paths; this is not a completed attack or life migration.

Rebuke damage and weapon-fire stages · 2026-10-28

RebukeAbility implements IPlayerDamageReactionAbility at order 50 and IPlayerWeaponFireAbility at order 700. The reaction runs after Adrenaline Rush and before Blood Thirst in the existing post-health damage sequence. It requests the existing bypassed, replacement-style owned work; execution adds three charges and activates the flag before yielding. The fire hook runs after Blood Thirst, including FireWeapon(false), and has no fixed-weapon ignore guard because the source has none. It decrements a positive count; only a later fire that begins with no charges clears the active flag. It therefore does not clear the flag on the same call that spends the last charge.

The module owns the counter and active flag. AbilityHolder compatibility properties supply the existing critical eligibility check, central +200 critical-damage projection and status view without changing their evaluation points. When the last entry is removed, reaction and fire registrations are revoked but module state and already-started work remain until disposal; the original code likewise leaves the flag/counter unchanged on list removal. Absent owned registration, production uses the legacy paths. The existing ordered-snapshot, reentry and exception policies apply. Repeated hits/replacement, last-charge timing, multishot/companion calls, critical/stat projection timing, removal, cancellation and co-op remain uncompiled and untested.

Vampire and Concussive Impact attack construction · 2026-10-28

VampireBEAbility uses IPlayerAttackConstructionAbility at order 50, at the original VampireBE slot before Blood Thirst's order 100. For each constructed attack it checks that weapon's ignoreVampireBE, takes the original integer random roll and marks the attack vampiric when it is below the already projected chance. The player attack's existing vampiric hit/heal behavior remains shared with Blood Thirst and child attacks; it is not rerolled here. The construction hook is revoked after the last VampireBE entry. Blood Thirst explicitly retains its hook after removal because its existing construction condition is active state rather than acquired presence. RetainAttackHookAfterRemoval records that difference; absent a registered handler each slot keeps its legacy fallback.

ConcussiveImpactAbility uses attack-construction order 200 at the existing point after character flags and SpellAmp but before the critical roll. It respects ignoreCImpact, rolls the same integer range and stores the result on the actual weapon, preserving the old per-weapon CImpactProc and its unchanged value when ignored. At critical order 300, after the existing Piercing Bullet slot, it records CImpactCritCount and sets the attack's concussive flag. This critical stage intentionally does not consult ignoreCImpact, matching the original. Its construction and critical hooks are revoked after the last entry; RetainCriticalHookAfterRemoval distinguishes this from Sure Fire's unconditional post-removal counter reset. The existing attack still applies stun on impact and copies the flag into the same child routes. These are not yet migrated impact or pooled-payload owners.

Both hook families retain synchronous ordered snapshots, fresh reentrant snapshots, unique order and propagated exceptions. Random ordering, stale per-weapon proc values, ignore combinations, multi-projectile and companion cases, inherited effects, fresh/recycled payloads and co-op remain uncompiled and untested. Legacy routes remain active without an owned handler; no impact or combat gate is closed.

Thorn Armor, Electrical Thorn Armor and Judgement · 2026-10-28

ThornArmorAbility and ElectricalThornArmorAbility register with IPlayerDamageReflectionAbility.Reflect(in PlayerDamageHit hit) at the first post-health reaction stage, before Survival Fitness. Hooks_DamageReflection selects the first registered handler from an ordered snapshot, with Electrical Thorn Armor at 100 and Thorn Armor at 200. This stage deliberately selects one handler: with both abilities present Electrical Thorn Armor takes precedence, preserving one reflection and one ReflectedDamageCount event. Reflection retains the original raw-hit and missing-HP formulas, run-level read for Electrical Thorn Armor, source argument, event ordering and null-source behavior. This stage is distinct from Proto Barrier's earlier pre-immunity reflection. Registration changes affect a later dispatch, a reentrant dispatch takes a fresh snapshot, duplicate orders are rejected and exceptions propagate. The last matching removal revokes the reflection registration; without an owned handler the legacy combined branch remains.

Electrical Thorn Armor also implements damage reaction order 500, after Panic Frenzy and before Jet Propulsion. When its own cooldown flag is false it requests normal replacement-style admission, then performs the existing explosion/audio work even if admission was rejected. Its player-owned cooldown flag is bridged through AbilityHolder.isETArmorCD; normal expiry waits the ability's sampled cooldown and clears it, while cancellation releases only its owned work. The pooled explosion still uses the legacy preparation/activation path. The existing 30% Judgement check happens after that explosion and sound.

JudgementAbility implements IThornRetaliationAbility at order 100 as a real consumer of Electrical Thorn Armor's retaliation stage. It takes the original integer roll before normal first-match admission, waits 0.2 scaled seconds, then uses the existing prefab, live position, damage/max-health values, attribution and magic type. Its registration is revoked after the last matching entry; already-started owned work may finish. The old Judgement body and fallback remain for legacy callers. Its in-progress asset is not added to a release catalog or otherwise completed by this migration.

All stages remain uncompiled and untested. Reflection reentry, simultaneous acquisition/removal, effect cooldown rejection and cancellation, Judgement timing/random order, pooled payload/reset, source attribution, co-op and death/revive remain open. These modules do not close the damage or attack gates.

Survival Fitness and First Aid reactions · 2026-10-28

SurvivalFitnessAbility implements IPlayerDashCostAbility.ModifyDashCost(float cost) at order 100 and IPlayerDamageReactionAbility at order −100. The executor applies the owned cost hooks after pause admission and before its stamina comparison; the module subtracts 5 without clamping, matching the original rule. IPlayerDashCostHooks is the executor adapter, while Hooks_DashCost.Register returns a per-player revocation handle. Legacy executor adapters without the new interface retain their old HasSurvivalFitness behavior. The reaction executes after Thorn/ETArmor reflection and before Adrenaline Rush, adding 20 stamina directly without an immediate cap. Both hooks revoke on last matching removal, use synchronous ordered snapshots, reject equal orders and propagate exceptions.

FirstAidAbility is damage reaction order 200, after Final Form and before Flee Boots. It requests normal first-match admission and adds 20 potion charge directly on execution before yielding, without a new health heal or cap. The reaction registration is revoked after the last matching entry; already-started work belongs to the player runtime. Unregistered production actors keep the old checks and bodies. These paths are uncompiled and untested, including negative dash costs, insufficient stamina, rejected cooldown, simultaneous reactions, co-op and death/revive.

Adrenaline Rush damage reaction · 2026-10-28

AdrenalineRushAbility implements IPlayerDamageReactionAbility at order −50, after Survival Fitness and before Rebuke. The player owner requests normal first-match cooldown admission on each eligible damage reaction. An admitted operation marks the owned flag active, adds 4 to the existing stamina-regeneration bonus, waits the then-current ability cooldown, clears the flag on normal expiry and removes its own 4. The addition/removal uses PlayerStatProjection.ApplyAdrenalineRegen through PlayerModifier, retaining the original mutation point and arithmetic order relative to upgrades that also change the bonus; the central projection still calculates final regeneration and the ×1.2 movement/attack interval factors. AbilityHolder.isADRush bridges existing stat and status readers. No immediate resource refill or new stacking policy is introduced.

Each owned work item releases its own regeneration contribution on cancellation; a cancelled item does not clear the active flag while another remains. Normal expiry retains the old flag-clear behavior even when work overlaps. Last-entry removal revokes the reaction registration but allows started work to finish; legacy production uses the old body when no owned handler exists. This cancellation policy differs from the old global worker. Overlapping work, intervening upgrades, floating-point order, timer and display interactions, status and regen update timing, death/revive and co-op remain uncompiled and untested.

Flee Boots damage reaction · 2026-10-28

FleeBootsAbility implements IPlayerDamageReactionAbility at order 300, after First Aid and before Panic Frenzy. It consumes the original integer random roll before cooldown admission and compares it with 50 + the live run level. On admission it samples the current projected movement speed. PlayerStatProjection.FleeBootsBonus owns the source calculation: below 4.9 the integer bonus is 600 − int(speed × 100), otherwise 100. The module stores that bonus and active flag; PlayerModifier.fleeBootsBonus and AbilityHolder.isFleeBoots bridge the existing central movement calculation and status view, with FormerlySerializedAs fields preserving prefab data. Normal expiry after three scaled seconds clears both values as before. On cancellation, the module restores the most recent remaining owned contribution, or clears when none remains; this is a distinct owned cleanup policy, not a claim of legacy cancellation equivalence.

Last-entry removal revokes the reaction but lets started work complete; the module and last state persist until disposal. The legacy route remains for unowned actors. Roll/cooldown order, sampled movement and integer conversion, overlapping/cancelled work, serialized migration, UI, death/revive and co-op remain uncompiled and untested.

Final Form and Panic Frenzy damage reactions · 2026-10-28

FinalFormAbility implements IPlayerDamageReactionAbility at order 150, after Blood Thirst and before First Aid. At live HP / projected maximum HP ≤10% with a remaining count, it decrements that count, restores HP to the projected maximum unless Sudden Death is present, restores stamina to its projected maximum, and only then requests normal first-match ability admission. Those resource changes and count consumption still happen if the buff's cooldown rejects admission. An admitted buff sets the owned flag and existing view for the ability's current cooldown wait; central stat projection retains its ×1.25 damage, movement and attack-speed factors. AbilityHolder bridges the existing count and flag readers. Owned cancellation removes its own view contribution; normal expiry preserves the old clear behavior.

PanicFrenzyAbility handles reaction order 400, after Flee Boots and before ET Armor. If its existing isPFrenzyCD state is false it starts actor-owned work without normal ability cooldown admission, as the old body did; no new cooldown is invented. It activates the shared Soldier Frenzy view, samples 2 + finalMaxStamina × 1 / 100, waits that scaled duration, then clears the view and active flag. The current source has no writer that starts a Panic Frenzy cooldown; the compatibility property is retained rather than silently adding one. On cancellation, the owned view is left visible if Soldier Frenzy still owns it; normal expiry retains the old unconditional hide. Both modules revoke their reaction registration after the last matching entry while already-started work and state remain until disposal. Production without owned handlers retains the original bodies.

Both use synchronous ordered damage-reaction snapshots. Threshold and cooldown rejection, Sudden Death, resource caps, shared-view overlap, repeated hits, cancellation, stat update timing, death/revive and co-op remain uncompiled and untested.

Jet Propulsion damage reaction · 2026-10-28

JetPropulsionAbility implements IPlayerDamageReactionAbility at order 550, after Electrical Thorn Armor and before Enrage. On an eligible reaction it clears its active indicator and requests bypassed replacement work for the crash. Crash sets the owned movement bonus to −0.5, starts the existing additional owned cooldown/display cycle and waits the ability's current cooldown. It then requests separate bypassed replacement work for acceleration: the bonus resets to zero, waits 0.1 scaled seconds, marks the indicator active and adds 0.025 every 0.5 scaled seconds while the bonus is below 0.99. Crash and acceleration remain distinct operation keys; a new crash does not itself cancel an already-running acceleration. The central stat projection continues to apply 1 + jetPropulsionBonus at the original movement calculation point.

AbilityHolder.isJetProp and PlayerModifier.jetPropulsionBonus bridge existing status/stat readers; the latter uses FormerlySerializedAs for the existing prefab field. isJetCrash remains its separate legacy state because this source path does not write it. On last-entry removal the reaction hook is revoked but already-started work/state remain until disposal. The old unconditional damage-stage reset and activator remain the fallback when no owned handler is present.

IPlayerAbilitySuspension.OnAbilitySuspended is a new internal owner lifecycle contract with Jet Propulsion as its first consumer. After cancelling owned work, the runtime calls each present suspension participant and collects cleanup failures; Jet Propulsion clears its active indicator and movement bonus on suspension. This is an owned cancellation policy, not evidence of legacy equivalence. Repeated hits, crash/acceleration overlap, cooldown/display timing, suspension/revive, serialized migration, status and two-player behavior remain uncompiled and untested. The damage and player acceptance gates remain open.

Enrage damage reaction · 2026-10-28

EnrageAbility implements IPlayerDamageReactionAbility at order 600, after Jet Propulsion and before the low-health Emergency Shield check. When not already enraged, each eligible reaction subtracts one from the owned hit counter. At zero or below it sets the owned active flag and starts actor-owned work without introducing ability cooldown admission. The work activates the existing view/audio and starts the original 30-step counter: while active, it stops and resets the counter to five when stamina is ≤1 or the counter is ≤0; otherwise it spends one stamina, decrements the counter and waits 0.5 scaled seconds. The direct stamina cost and its source order are unchanged.

AbilityHolder.isEnraged and rageCount bridge the existing central stat and status readers to module state; the projection retains the named movement, damage, crit chance and damage-taken factors. Normal external clearing of the flag retains the original loop exit behavior. Cancellation of owned work clears its own state and view and resets the count; that is a lifecycle policy change from the old actor coroutine and remains unverified. Last-entry removal revokes the reaction while already-started work and state remain until disposal. Legacy production retains the old branch. Timing, threshold, stamina interaction, health/stat projection, cancellation, removal, death/revive and co-op are uncompiled and untested.

Light Blessing automatic cycle · 2026-10-28

LightBlessingAbility implements the existing owned IPlayerAbilityTick at order 600, after the currently migrated character ticks. Each active-owner tick requests normal first-match cooldown admission. As in the source, Sudden Death and Last Stand are checked inside the admitted work, before the random draw; the cooldown may therefore already have started when either blocks healing. The integer 0–99 roll succeeds at ≤25 or when the owned failure count is at least four. Success adds 10 + temporaryAmp × finalMaxHealth / 200 directly to health, resets the count and shows the existing success view/audio for one scaled second. Failure increments the count and shows the fail view for one scaled second. AbilityHolder.LightBlessingCount bridges existing readers; removal revokes the tick after the final matching entry and retains already-started work and module state until disposal. Owned cancellation releases its own view work without hiding another still-owned instance; normal expiry retains the old hide behavior. Frame ordering with unmigrated automatic effects, view overlap, cooldown/re-entry, random order, health caps, pause, death/revive and co-op are uncompiled and untested; production retains the legacy cycle.

Frenzy automatic cycle and dash stage · 2026-10-28

FrenzyAbility implements both the ordered pre-dash stage (order 1000) and IPlayerAbilityTick (tick order 100). The ability owner registers IPlayerAbilityTick.Tick() via Hooks_AbilityTick.Register, which returns a revocation handle; the active PlayerAbilityHost.Update dispatches one synchronous, ordered snapshot each frame. Equal orders are rejected, additions/removals affect the next snapshot, reentrant calls take a fresh snapshot, and exceptions stop propagation. It does not gate the tick on pause, matching the old holder Update's admission point; waits remain scaled. Frame ordering relative to the separate movement driver and other player updates is not established and must be compared.

When not already in Frenzy, the module requests first-match normal admission using its live cooldown modifier. On admission it activates the existing bound effect, samples 2 + finalMaxStamina * 2 / 100 and waits that scaled duration. The active flag and the cooldown modifier, attack speed bonus and dash reload percentage are module-owned; AbilityHolder bridges existing upgrade callbacks, central stat projection, reload UI and status readers. On a dash with Frenzy acquired, the module runs after TidalVeil independently of whether the buff is active. It preserves the not-reloading condition, integer ammo addition, cap and sound gate; PlayerDashFeedback supplies the actual feedback callback. On removal the tick and dash registrations are revoked only after the last matching entry, while existing owned work and module state remain until its normal completion or runtime suspension. Production without an owned runtime retains its old holder Update and dash slot.

On owned work cancellation, the active state clears and the view is hidden unless the legacy Panic Frenzy flag is still active. Normal expiry retains the old unconditional view hide, including its shared-view interaction. Cancellation policy, duplicate/reacquisition, cross-effect visual overlap, time-scale and frame ordering, death/revive, stats and reload behavior remain uncompiled and untested. This is not a completed production player loop.

Proto Barrier recharge and damage stages · 2026-10-28

ProtoBarrierAbility implements IPlayerAbilityTick (order 300), IPlayerPreImmunityAbility (order 100) and IPlayerShieldAbility (order 100). The ability factory now creates modules independently of dash participation; the player owner registers each supported contract. Hooks_BeforeImmunity.Register returns an IDisposable; Dispatch(firstOrder, lastOrder, in PlayerDamageHit hit) runs synchronously at the existing reflection point, before the immunity check. Registration uses a stable unique order, dispatch takes a snapshot, additions/removals affect later dispatches, reentry takes a fresh snapshot, and exceptions propagate. The damage owner uses the legacy reflection only when the owned stage has no handler. Shield dispatch receives the same hit context and retains Proto Barrier's first-shield position and early return. Legacy production continues through its previous body.

The module owns using/visible state, capacity, accumulated raw damage and evolution modifiers. Existing AbilityHolder properties bridge weapon evolution and PlayerModifier.ModifHP threshold adjustment to those fields; the projection's ability-presence attack-speed factor remains central. Its tick samples final maximum HP, computes the original threshold and color, and requests bypassed first-match activation when not using the barrier. Recharge sets the cooldown from live reload interval, starts the existing owned admission/display cycle, captures currentCooldownTime + 0.5 for its first wait, polls live stamina and live cost modifier at 0.5-second intervals, spends the same amount, triggers the existing animator/audio and shows the bound view. On a valid hit it adds raw damage, breaks at the original threshold, resets accumulation, hides the view, creates the same pooled explosion with its minimum damage and requests invulnerability. Reflection preserves the source argument and original formula. The tick, reflection and shield hooks are registered independently; on removal the tick and reflection registrations are revoked after the last matching entry, but the shield registration is retained until disposal so a visible shield can continue its old absorption behavior. A cancelled recharge releases its using flag; this is an owned cancellation policy and needs comparison.

The original holder computes barrier capacity/color each Update even before the ability is present; the owned module does so only after acquisition. Interactions with pre-acquisition health modifications and acquisition timing remain an explicit comparison case. Frame order versus player stat updates, cooldown/display sampling, stamina polling, view state on death/revive, retained shield behavior, reflection attribution, pool payload/reset, all characters and co-op remain untested. No compilation or gameplay check was run. This does not close the player or combat gates.

Unique Constitution damage conversion · 2026-10-28

UniqueConstitutionAbility implements IPlayerHealthDamageAbility at order 50. The damage owner dispatches it after damage mitigation and feedback, before Emergency Shield's order 100 adjustment and health subtraction. If current stamina is strictly greater than twice the mitigated damage, it spends twice that damage and subtracts half the original hit amount from the health damage; the result is not clamped. Otherwise it leaves the damage and stamina unchanged. It has no separate cooldown or mutable module state.

Acquisition registers the hook once per ability type, and removal of the last entry revokes it. Dispatch uses the existing health-damage hook's ordered snapshot and propagates exceptions. A missing owned handler leaves the legacy conversion in place; a present handler replaces that slot even when its stamina condition fails. Boundary stamina values, negative damage, duplicate acquisition, removal and interactions with Emergency Shield require comparison when verification resumes. No compilation or gameplay checks were run.

Emergency Shield owned damage stages · 2026-10-28

EmergencyShieldAbility participates in three existing positions. IPlayerShieldAbility order 200 intercepts after Proto Barrier and before Stellar Shield; while its owned visibility state is active, a hit decrements the owned block count, plays the existing sound and returns absorbed without spillover. At ≤0 it creates the existing pooled explosion using final damage ×2 and its original flag, hides the view, clears using state, plays the break sound, adds five to the block count and requests 1.5 seconds of invulnerability.

IPlayerHealthDamageAbility.AdjustHealthDamage(in PlayerDamageHit hit, float damage) is registered at order 100 and dispatched after mitigation and Unique Constitution's stamina conversion but before health application. On damage ≥ current HP while the module's cooldown flag is false, it requests normal first-match activation and returns currentHP − finalMaxHealth / 5. As in the original, this adjustment still occurs if the separate ability admission is rejected; it is not clamped. IPlayerDamageReactionAbility order 700 runs at the later low-health stage after Enrage, and requests normal activation at current HP ≤20% of final max HP when not already using the shield.

Activation sets using/cooldown state, plays the existing spawn sound and enables the bound view, then waits the ability cooldown before clearing the cooldown flag. Its player-owned work clears its own cooldown contribution on cancellation; the shield remains until broken, matching the separation between active shield and recharge. AbilityHolder properties bridge the existing serialized block, using and cooldown fields with FormerlySerializedAs to the module; actual Unity serialization is unverified. Health-damage and reaction registrations revoke after the last entry, while the shield registration remains until owner disposal so an already-visible shield can still absorb as before. Legacy branches remain when no owned handler is registered.

The health-damage hook carries the actual hit and current adjusted damage, uses synchronous ordered snapshot dispatch and returns the next damage value; registration changes affect later dispatches, reentry takes a fresh snapshot and exceptions propagate. Lethal adjustment, cooldown rejection, negative damage, shield priority and repeated hits, serialization, pool payload/reset, cancellation, death/revive and co-op remain uncompiled and untested. No player or damage acceptance gate is closed.

Tidal Veil owned shield stage · 2026-10-28

TidalVeilAbility implements the existing IBeforeDashAbility at order 900 and IPlayerShieldAbility at shield order 400. PlayerAbilityRuntime.Acquire registers both supported interfaces; the damage compatibility owner invokes TryAbsorbShield(400, 499, in PlayerDamageHit hit, out bool hasHandler) at the old Tidal Veil position after Stellar Shield and before Reload Shield. The generic synchronous handler returns whether it absorbed the hit; an absent owned handler leaves the original legacy stage active. A snapshot is taken per dispatch, equal shield orders are rejected, mutations take effect on the next dispatch, reentrant calls take a new snapshot, and exceptions propagate. The shield interface carries PlayerDamageHit; Tidal Veil does not inspect it, while Proto Barrier consumes its raw amount.

The module owns stack count, maximum, readiness and visibility state. The bound existing object and animator render spawn/break; the old AbilityHolder properties bridge legacy evolution and other callers to this state, including PriestessTidalVeilMaxAmountIncrease. When acquired, the module takes its initial values from the prepared holder. Dash uses first-match TidalVeil admission with cooldown bypass, checks readiness and increases the stack with the old clamp. A visible shield consumes one stack, plays the same sound and returns absorbed without overflow; at zero or below and ready it requests normal ability admission, then retains the old break sound and invulnerability even if that admission is rejected. Its break writes live reload interval, starts the second owned cooldown in addition to the admission cooldown, plays the animation, waits 0.8 scaled seconds, hides the view and then waits the then-current cooldown minus 0.8 before resetting count/readiness. The two cooldown operations retain separate waits and the display replacement policy; no normalization is claimed.

Removing the last entry unregisters its dash handler but retains the shield handler and module until owner disposal, so an existing shield can still intercept a hit as the old view-based path did. On cancellation of break work the owned path hides its view and resets stack/readiness; unlike legacy global work, this is explicit cleanup and requires comparison during verification. The shared owner now releases tracked timed admission flags on suspension as described below; count-based states, display reconciliation and TidalVeil death/revive behavior remain open, so the ability is not lifecycle-complete. Death/revive, overlapping cooldowns, short/negative waits, repeated hits during animation, view binding, upgrades and co-op have not been tested. No compilation or gameplay check was run. Other shields and production composition remain legacy.

Cooldown ownership and activation policy

Current source: PlayerAbilityRuntime owns private Ability copies and delegates to AbilityCooldownCycle. Production scenes retain legacy asset ownership/workers. Admission currently starts a display iterator, waits 0.5 scaled seconds, then reads the current cooldown for the second wait. Display ticks separately. This preserves original traces but is not the final module/state API. Zero/short waits, changing cooldown values, bypass, rejected dash admission and stopped work need their existing evidence/policy carried forward.

Owned suspension policy, implemented 2026-10-28: PlayerAbilityRuntime tracks active AbilityCooldownCycle.Admission operations, including TidalVeil's additional admission. Suspension cancels owned work and clears isOnCooldown for the affected runtime copies after cancellation, preventing a stopped timer from permanently blocking later admission. Multiple concurrent admissions are counted; normal completion still uses the original independent timer behavior and timing. Activation is rejected while suspension is releasing work. The existing display value is left as it was when stopped, matching the legacy revive path's flag-only reset; no generic reset is applied to count/charge meters or other ability state. A later activation starts its usual display again. This deliberately defines cancellation behavior for the owned path, not production equivalence. Natural completion versus cancellation, reentrant suspend/activation, overlapping timers, rejected dash, display, death/revive and separate-player behavior remain uncompiled and untested. Ability-specific timers and lifecycle policies still need migration.

The target is one authoritative admission state for each owned definition/ability instance, scoped to its player/run. Definition assets hold authored configuration; the instance holds effective parameters, readiness and clock/phase state. Distinct definitions sharing AbilityType stay distinct; the established duplicate/first-match policies remain explicit. A handler requests activation through that owner and receives a defined result. It does not start its own independent shared cooldown timer or write another skill's readiness flag.

Keep these policies separate:

  • Trigger eligibility and random work: execute at the original stage. For example, CCombo's chance roll currently occurs before UseAbility checks cooldown; moving the roll after a common precheck changes random consumption. An availability query must not consume random state or apply effects.
  • Admission and commit: check/reserve/start through one synchronous Unity-thread owner. Specify whether cooldown starts on request, accepted activation, effect completion or break, including the original rejection/refund behavior. Do not impose one universal start point on all abilities.
  • Effective duration/modifiers: retain the original calculation order and live/captured read points. The existing admission formula is not always simply base cooldown multiplied by a modifier. Evolution changes instance parameters through an explicit operation; it does not rewrite authored shared data.
  • Effect duration: buff lifetime, sequence work, owned entities and activation cooldown are independent. A ready ability may still have active work; preserve or deliberately resolve its existing overlap/refresh policy.
  • Meters and presentation: time remaining, charges, attack/crit counts and phase indicators are distinct. HUD reads a state view. Preserve the existing admission/display discrepancy through an explicit compatibility projection while migrating; unifying the displayed and effective clocks is a separate visible timing correction, not an incidental cleanup.
  • Lifecycle: scaled game pause holds timed work. Revoke, suspend, death/revive and run retirement have defined reset/retain/dispose policies. Retained flags without a surviving timer or defined resume/reset path cannot be called a completed cooldown migration. Actor/run teardown releases work and stale operations cannot release a newer reservation.

Shared cooldown handling is a reusable owner/policy, not a timer implementation duplicated in every ability. Specialized recharge/count/break behavior stays with its module and requests the corresponding owner operations. Original clock and character references remain the comparison baseline; no normalized timer, stacking rule or balance change is implied.

Child attacks: ricochet and explosions

PlayerWeapon.AttackModify enables flags for eligible effects. PlayerAttack then processes damage/hit budget, feedback/status work, explosion, first-hit ricochet, placeholder shrapnel, first-hit hydra, poison/vacuum/eclipse, lifesteal and sword marks in source order. Criticals and random weapon procs happen earlier during construction. Do not collapse these into one unordered collection of effects.

The explosion branch copies poison/freeze/concussive flags and uses 10 + SpellAmp / 4 damage. Ricochet copies a different subset including vampiric, uses 10 + SpellAmp / 2, adjusts hit history/knockback and can change prefab/speed for swords and water projectiles. Neither branch explicitly initializes every owner/amplification/recursive flag. PlayerAttack.Reset/ReturnPool also do not clear the whole payload. Consequently, a pooled child's previous use can matter; current fresh/reused chain behavior is not certified by reading acquisition flags.

The target child-attack request must identify the originating player/weapon/ability, attack kind, permitted inherited effects, source/credit, target policy and chain restrictions using rules derived from each current route. Spawn preparation resets the entire owned payload. Preserve current formulas/proc sites and investigate omitted initialization under CA-02 before declaring expected combo behavior. Reapplying all owner abilities to every explosion/bounce would invent procs, alter random order and could create recursive chains. A blanket ban on all secondary procs would also erase existing interactions.

Required migration evidence and order

  1. Complete the architecture and migration plan across AbilityHolder, hooks, cooldowns, assets, central stat-source calculation, damage, weapons, attacks, summons, upgrades and UI identity. Trace unresolved contracts against the runtime reference index and existing catalogs; do not label lexical coverage as a completed implementation plan for every ability.
  2. Establish the required shared capability and per-player module/registration/state boundaries, with deterministic hook order, acquisition identity, counters/defense state, cooldown policies and stable UI definition mapping. Plan the dash replacement as a real registered-ability path; the current named perk list is a temporary bridge. Reuse useful current owners where they fit.
  3. Integrate the owner's two-part stat design and its existing mutation/upgrade callers. Keep named source formulas centrally inspectable, and ability state authoritative in its module. Establish attack construction/impact and pool preparation with required player/weapon/target owners.
  4. Migrate concrete behavior groups and their related consumers together: timed buffs, shields, count-based character effects, delayed carriers, persistent summons and impact/child interactions. Preserve Wu Ran, Tiamra and Zenova's actual attack routes. Work across the connected implementation as the user's grouped workflow requires, with separate meaningful implementation commits.
  5. Cover the existing catalog, including pickup/stat/evolution participants, and migrate serialized references and compatibility callers. Retire legacy bodies only after their owners/callers/bindings have migrated. Do not introduce new abilities, UI redesign or balance rules.

Tests are deferred for now at the owner's request. Compilation, if run, is reported separately; any implementation without runtime checks remains unverified. When verification resumes, compare fresh/reused payloads, parent/child attribution, original formulas, proc/random ordering, individual characters and full gameplay flows. These are eventual acceptance requirements, not tests to run during the current planning work.

For each migrated behavior record: trigger sites and order; state location; definition/view/prefab bindings; captured/live values; cooldown/duration/count policies; stats/resources; attack/proc inheritance; random calls; attribution; acquisition/evolution and UI readers; fresh/reused reset; pause/disable/death/revive/run teardown; and the relevant isolated/co-op comparisons. Shrapnel's empty impact block, StarBurstShield's yield-only body and Judgement's in-progress label require reachability/disposition checks under existing gates; no placeholder functionality is authorized here.

No catalog-wide performance gain or completed runtime acceptance is claimed. Current ownership/dash checks qualify their recorded scope only. The 27 PC/CA/SE/RP/PS follow-ups remain open; final native/control/Windows campaigns remain later.

External examples and how they apply

  • Unity: ScriptableObject delegate objects demonstrates pluggable behavior. Use the separation principle for ability implementations and keep mutable player state in runtime instances.
  • Unity Chop Chop: configuration and runtime demonstrates ScriptableObject configuration paired with plain C# runtime objects. Borrow that division without importing its full state-machine system.
  • Unity: event channels demonstrates subscription/unsubscription and presentation communication. Typed player hooks with explicit ordering are this project's adaptation for synchronous combat decisions.
  • Unity 6.2: ObjectPool documents creation/get/release/destruction callbacks. A pool supplies reuse; our prepare-before-activate/reset/ownership contract still needs explicit implementation. This design does not choose a pool replacement solely from that example.

These are primary-source examples supporting parts of the recommendation. Their combination and fit to Tiny Chaos are design judgments, not an external framework that has already been integrated or tested here.

Migrated damage branches removed · 2026-10-28

The damage owner now invokes owned hooks for Proto Barrier reflection and absorption, Emergency Shield absorption and lethal adjustment, Tidal Veil absorption, Unique Constitution conversion, and the migrated reflection and reaction stages. Their old fallback branches have been removed from LegacyPlayerDamageHooks; the Electrical Thorn Armor-to-Judgement legacy fallback has also been removed. Existing sections below that describe these fallbacks are historical. Dispatch remains split into the prior ordered ranges so each stage retains its own handler snapshot. Stellar Shield, Reload Shield and Last Stand still have legacy damage logic and need their own migration.

This intentionally leaves a production gap where a player has no active PlayerAbilityHost.Runtime: the removed effects will not run there. The old holder methods and properties, other callers, the no-ability Jet Propulsion reset, initialization, death/revive and serialized routes require further migration or explicit retirement. The owned implementations and asset bindings have not been compiled or tested. Compare the original stage behavior and snapshot/reentry interactions when verification resumes.

Last Stand lethal stage · 2026-10-28

AB_LastStand supplies player-owned active and expired state. Its ILethalDamageAbility order 100 is registered with Hooks_LethalDamage: when health reaches zero after damage reactions, the dispatcher takes a handler snapshot in unique order and stops at the first handler that prevents death. Registration is removed after the last matching ability entry and on owner disposal; exceptions propagate and reentrant dispatch takes a new snapshot. If Last Stand has not expired it marks itself expired, restores full health, requests its existing first-match activation and returns the lethal disposition even if admission rejects the work. Its work shows the bound effect, immediately burns 3% of live final maximum health, then repeats at one-second intervals while health is positive. At completion it hides the effect, clears active state, sets health to zero and sends the original one-damage self-hit.

The authored Last Stand asset now points to the ability script; the old lethal branch and holder coroutine were removed. Holder properties forward active/expired state to the owned module for remaining regeneration, run-manager and old editor callers; without an active owner they read false and writes do nothing. This is a temporary integration access point, not a second ability state. A missing runtime no longer supplies the old survival path. The owned iterator now clears its active state and effect if cancelled; death/revive, suspend, removal, zero health, admission rejection and final recursive damage need explicit lifecycle reconciliation. No compilation, tests, Unity import or gameplay verification was performed.

Stellar Shield and Reload Shield · 2026-10-28

AB_StellarShield supplies an automatic tick at order 700 and shield interception at order 300, after Emergency Shield and before Tidal Veil. Each tick requests normal first-match activation; admitted work resets the block count to five, plays the existing sound and shows the view. Each absorbed hit removes one block; on break it creates the existing pooled attack with 50 * (1 + temporaryAmp / 100), hides the view, plays the sound and requests 1.5 seconds of invulnerability. Block count is owned by the ability; the holder accessor preserves the central stat projection and existing status consumer, and the serialized initial value retains its old field name through FormerlySerializedAs. The old holder activation and damage branch have been removed.

AB_ReloadShield implements IWeaponReloadAbility order 100 and shield interception order 500. Hooks_WeaponReload is invoked before reload audio and reload state changes, takes an ordered snapshot, rejects equal orders, propagates exceptions, and uses disposable registrations removed when the last matching ability is removed or the owner is disposed. Reload refreshes shield amount to 5 + finalMaxHealth * 0.05; if the duration is not active, it requests bypassed activation. Duration captures 0.5 + temporaryAmp / 100 + finalReloadSpeed. A hit subtracts raw damage; on depletion it hides the view, grants 1.5 seconds of invulnerability and clears the amount, while duration state remains active until its wait finishes. Existing shield-hook retention after ability removal applies to both shields. Holder accessors bridge remaining state consumers; the old reload activation, duration and damage branch have been removed.

Both ability assets point to their new scripts. Players without an active owned runtime no longer receive these effects. Tick ordering relative to other unmigrated automatic abilities, pre-acquisition values, removal, interruption, overlapping reloads, shield visuals, serialized field migration and pooled attack reset remain unresolved. Reload Shield now clears its active state and view on cancellation; compare this policy when lifecycle handling is completed. No compilation, Unity import, tests or build were run.

Legacy dash effects removed · 2026-10-28

Both dash routes now invoke the registered before-dash stages and dash-cost hook when a player ability runtime is available. The duplicate ability-name checks and bodies in PlayerDashHooks were removed, as were the old holder coroutines for Band Aid Roll, Tactical Fire, Run and Gun, Focus Dodge, Bomb Roll, Vacuum Dodge, Tidal Veil stacking and Airstrike. The dash executor no longer has its own Survival Fitness cost fallback. Registered before-dash handlers still dispatch in the two existing ordered ranges, each with a separate snapshot.

This intentionally leaves dash effects and the Survival Fitness cost adjustment absent on players without an active ability runtime. Legacy dash admission, character lookup, pause and weapon hiding remain connected to the existing game flow; they are not part of this ability removal. Legacy timed-effect fields, projection inputs, Tidal Veil break work, Unity asset and evolution consumers, cancellation, revive and player composition still require migration. The editor comparison probes and any serialized callers need later reconciliation; no compilation, Unity import, tests or build was run.

Migrated weapon ability fallbacks removed · 2026-10-28

PlayerWeapon now dispatches registered weapon-fire, attack-construction and critical hooks without duplicate branches for C Combo, Assassination, Berserker Blood, Sure Fire, Unsteady Hand, Blood Thirst, Rebuke, Vampire Blood Essence and Concussive Impact. The original ordered dispatch ranges remain separate, including the weapon-fire calls used by companion paths and attack-construction stages around other legacy effects. The old holder activation and coroutine bodies for C Combo, Assassination, Blood Thirst and Rebuke were removed after their call sites moved. The earlier unconditional legacy Sure Fire counter reset on critical has also been removed; the owned critical hook performs it when registered.

An absent ability runtime now means these hooks do not run. This includes random rolls and their effects; the remaining legacy attack abilities, stat/property bridges, held-weapon and companion paths, and the prior behavior of a stale Concussive Impact proc or Sure Fire count still require migration and comparison. Other legacy holder methods and serialized routes remain to be inventoried. No compilation, Unity import, tests or build was run.

Dash buff stat ownership · 2026-10-28

Tactical Fire, Run and Gun and Focus Dodge now expose their active state only from their owned dash abilities; the holder's old writable fallback flags were removed. The central PlayerStatProjection still explicitly calculates Tactical Fire's attack multiplier and skill amplification, and Run and Gun's movement and reload multipliers, using owned active state. Without a runtime the active flags are false, and the projection uses the inactive values rather than old mutable multiplier fields. Focus Dodge's existing central calculations continue to read its owned active flag.

The old serialized modifier fields and stat-input members remain as unused migration data, because their prefab and editor consumers have not yet been retired. Player production setup still does not prepare the owned runtime; its assembly must be connected separately without redesigning the deferred game-flow or input systems. Stat update order, active-duration cancellation, authored assets, HUD, death/revive, and previous behavior with external writes to those legacy fields remain unverified. No compilation, tests, Unity import or build was performed.

Projectile construction abilities · 2026-10-28

Freezing Pendant, Exploding Enchantment, Ricochet, Shrapnel, Hydra Barrage and Poison Vial now have individual AB_ scripts referenced by their authored assets. Their existing attack-construction contract sets each projectile flag when its corresponding weapon ignore option is false. Orders -600 through -100 preserve their former weapon sequence ahead of Vampire Blood Essence; registration and removal follow the existing attack-construction hook policy. The six weapon checks were removed.

The companion's old Freezing Pendant, Exploding Enchantment, Ricochet and Poison Vial checks were removed as requested; their companion application was restored in the subsequent companion hook described below. Impact execution, secondary attacks and inheritance still live in PlayerAttack and require ability-owned migration; the companion Concussive Impact check was subsequently moved to the same companion hook. Players without an active ability runtime do not get the weapon effects. Asset bindings, ordering, pool reuse and all gameplay remain unverified; no compilation, Unity import, tests or build was run.

Companion attack ability stage · 2026-10-28

ICompanionAttackAbility.OnCompanionAttack(Companion, PlayerAttack) and Hooks_CompanionAttack now apply Freezing Pendant, Concussive Impact, Exploding Enchantment, Ricochet and Poison Vial in the former order before companion damage and spell amplification are assigned. These hooks set the original flags unconditionally when their ability is registered: companion attacks do not use weapon ignore options, and Concussive Impact does not roll its weapon proc here. The player ability owner registers supported handlers, removes them after the last matching ability entry and disposes them on owner teardown. Dispatch takes an ordered snapshot, rejects duplicate orders and propagates exceptions; reentry takes a new snapshot. The last companion ability-name check was removed.

This restores the previously removed companion construction effects only for players with an active owned runtime. Other companion classes, projectile impacts, effect inheritance, owner binding, removal and pooling remain to be traced. No compilation, Unity import, tests or build was run.

Generic ability-state lookup · 2026-10-28

Nineteen individual PlayerAbilityRuntime lookups named after abilities have been removed. The existing holder and modifier accessors use TryGetModule<T>; timed dash state uses the same generic operation with its concrete behavior type. This only removes the owner's named lookup list, not the holder bridges, AbilityType keyed storage, or legacy state. The lookup searches retained module objects and returns the first matching type; future cases with multiple definitions or behavior classes need an explicit identity policy. No compilation, Unity import, tests or build was run.

Automatic ability legacy execution removed · 2026-10-28

The old AbilityHolder.Update calls, activators and coroutine bodies for Frenzy, Proto Barrier and Light Blessing have been removed. Their automatic behavior is supplied by their existing player-owned ability tick hooks. As previously recorded, Proto Barrier's old update calculated capacity and view color before the ability was acquired; that legacy behavior no longer runs and its pre-acquisition interactions need review. Without an active owned runtime, none of these automatic effects runs. Holder state bridges, character setup and other unmigrated automatic abilities remain. No compilation, Unity import, tests or build was run.

Retired damage ability holder methods · 2026-10-28

Removed the old holder activators and coroutine bodies for Adrenaline Rush, Electrical Thorn Armor, Emergency Shield, Judgement, Tidal Veil break, Flee Boots, First Aid, Panic Frenzy, Final Form and Enrage. Their previously migrated ability scripts and hooks are the intended execution paths. Source and serialized UnityEvent searches found no remaining references to these removed method names at this checkpoint; this does not prove runtime behavior or rule out dynamic references.

Jet Propulsion's upgrade route and holder methods were subsequently migrated as described below. Holder state bridges, production ability-owner composition, cancellation and lifecycle remain open. No compilation, Unity import, tests or build was run.

Jet Propulsion upgrade route · 2026-10-28

The existing JETPROP upgrade now asks the owned JetPropulsionAbility to begin its crash/recharge sequence and then resets the modifier to zero in the original order. The upgrade's authored route lists EQUIPABILITY before JETPROP, so acquisition can create the module first. The damage reaction still clears active state before starting that same sequence; the upgrade request itself does not add that clear. The old holder activator and crash/acceleration coroutines were removed.

Without an active ability runtime, the upgrade no longer starts the old crash work; production owner composition remains open. Upgrade ordering, admission, timing, repeated acquisition, death/revive and interruption remain unverified. No compilation, Unity import, tests or build was run.

Ultra Magnet automatic cycle · 2026-10-28

AB_UltraMagnet registers automatic tick order 650, between Light Blessing and Stellar Shield, and requests normal first-match ability admission. Its owned work adds 15 to the player's existing pickup radius for one scaled second, then removes that contribution. Each admitted cycle contributes separately, preserving additive overlap and independent upgrade changes to the base radius. The authored asset now references the ability script; the old holder update call, activator and coroutine were removed.

The owned coroutine removes its contribution in finally if cancelled, whereas the old global coroutine had no cancellation cleanup. Confirm the desired suspend, death/revive and removal behavior when lifecycle work is addressed. Pickup ownership, other automatic effects between these stages, upgrade interaction, owner composition and the asset binding remain unverified. No compilation, Unity import, tests or build was run.

Survival Instinct stat state · 2026-10-28

AB_SurvivalInstinct samples the player's current health percentage on automatic tick order 675, after Ultra Magnet and before Stellar Shield. Its previously holder-owned activation has been removed. The central PlayerStatProjection calculates movement and health-regeneration values from the owned sample: between 10% and 50% health use 1 + (50 - percent) / 80 and (50 - percent) / 20; at or below 10% use 1.5 and 2; at or above 50% use 1 and 0. The ability retains its prior sample when the percentage is NaN, matching the former conditional writes. Player health recovery reads the centrally calculated contribution. Its authored asset points to the new script.

Until the first owned tick, or without an active ability runtime, the effect contributes its inactive values. Module removal is checked against the acquired ability list even though module objects may be retained. Old serialized surviveMS and surviveRegen fields remain as unused migration data; the legacy stat input also remains. Frame order, initial sample, ability removal/reacquisition, health recovery timing, NaN, prefab and Unity asset binding remain unverified. No compilation, Unity import, tests or build was run.

War Cry automatic cycle · 2026-10-28

AB_WarCry registers automatic tick order 800 and requests normal first-match admission. Its per-player active state feeds the existing central damage and damage-reduction calculations and status display through the holder accessor. Admitted work sets cooldown to 15, captures duration from final maximum stamina, waits 0.15 scaled seconds, spawns the existing pooled roar at the player, plays its sound and assigns damage, owner and War Cry flag, then waits the captured duration before clearing active state and waiting the live cooldown. The ability asset points to this script; the holder update call, activator and coroutine were removed.

The active state is released on cancellation when no overlapping owned work remains; normal completion clears it even if work overlaps, matching the old normal completion behavior. This cancellation policy needs lifecycle review. Actual impact freezing remains in PlayerAttack, and pooled payload/reset, coroutine admission timing, overlapping work, asset binding, death/revive and players without an active runtime remain unresolved. No compilation, Unity import, tests or build was run.

Transcend Eclipse automatic cycle · 2026-10-28

AB_TranscendEclipse registers automatic tick order 750, after Stellar Shield and before War Cry. It requests normal first-match admission using Transcend when current health is at least half final maximum health, otherwise Eclipse. Transcend prepares the existing pooled carrier with damage 10 + currentHealth * 0.25 and the player; Eclipse prepares the existing pooled attack with its Eclipse flag and player. Both then wait the current ability cooldown. The authored ability asset points to the new script; the old holder update call, activator and coroutines were removed.

Eclipse's impact effects remain in PlayerAttack; attack ownership, pool preparation/reset, attribution, spawn timing, overlapping work and cancellation remain open. Players without an active ability runtime do not receive the automatic cycle. No compilation, Unity import, tests or build was run.

Meditate automatic cycle · 2026-10-28

AB_Meditate owns readiness, active state and the stacking value, and registers automatic tick order 900 after War Cry. While moving and not ready it requests normal cooldown admission; completion sets readiness. When stationary, ready and inactive it marks active before requesting bypassed meditation, shows the existing effect, increases the value once per scaled second up to five, and clears readiness, state, view and value after movement resumes. The existing central stat calculation still applies five damage reduction per value, and player health recovery still uses the value and final maximum health. PlayerModifier.meditateValue now accesses owned state; its unused serialized prefab field was removed. The authored asset points to the new script, and the old holder state, update call, activator and coroutines were removed.

The original active-before-admission ordering is retained even if admission fails. Interruption now clears the owned meditation state and view; death/revive, overlapping cooldown work, ability removal, retained modules, movement timing and prefab asset binding need review. Players without an active owned runtime no longer receive this ability. No compilation, Unity import, tests or build was run.

Artemis Burst automatic volley · 2026-10-28

AB_ArtemisBurst registers automatic tick order 200, between Frenzy and Proto Barrier, and requests normal first-match admission. Its owned volley captures the holder's position before a 0.5-second wait, then reevaluates integer finalWeaponAmmo / 2 on each iteration. Each arrow uses the original integer random offsets, pooled prefab, sound, player, live skill amplification and Luster Burst amplification percentage, magic damage type and 0.25-second spacing; it finishes with the original 0.3-second wait. The authored ability asset now references this script and the old holder update call, activator and coroutine were removed.

Carrier preparation and pooled reset remain legacy. Ability cancellation can stop owned volley work, unlike the old global coroutine; character upgrade bindings, ammo changes during the volley, random ordering, owner composition, ability removal and death/revive require review. No compilation, Unity import, tests or build was run.

Rocket Barrage automatic volley · 2026-10-28

AB_RocketBarrage registers automatic tick order 400, after Proto Barrier and before Light Blessing. It requests normal first-match admission only when the existing nearest-enemy list is nonempty, using its owned cooldown modifier. The volley captures the enemy count before a 0.1-second wait, plays the existing launch sound, reevaluates integer finalWeaponAmmo / 4 per iteration, queries each target by the original modulo priority, and stops if that query returns null. Each missile uses the existing pooled carrier, live holder position and skill amplification, the original magic damage and target fields, and 0.1-second spacing, followed by the existing sound and 0.3-second wait.

Cooldown and skill-amplification modifiers are owned by the module; holder properties bridge existing character initialization and weapon evolution, preserving their pre-acquisition values. The authored asset references the new script and the old holder activator and coroutine were removed. Captured enemy count versus later target changes, pooled missile reset, target lifetime, cooldown sampling, upgrade timing, interruption and runtime composition remain unverified. No compilation, Unity import, tests or build was run.

Heaven Yang Sword automatic summoning · 2026-10-28

AB_HeavenYangSword registers automatic tick order 500 after Rocket Barrage and before Light Blessing. When the bound rotator has fewer swords than the owned maximum, it requests normal first-match admission. Work activates the existing sword object, writes the live final reload interval to its cooldown, starts the additional cooldown, waits the current cooldown display plus 0.5 seconds, and, if base maximum health is positive, gets the existing pooled sword and adds its circular weapon to the rotator. The owned maximum is exposed through the existing holder property for initialization and weapon-evolution callbacks. The authored ability asset references the new script; the old holder update call, activator and coroutine were removed.

Sword lifetime, contact, weapon hooks, attribution, pooled object state and the paired Yin sword remain in their existing owners and need migration. Cooldown overlap, cancellation, initialization, evolution, object activation, destruction and behavior without an active runtime remain unverified. No compilation, Unity import, tests or build was run.

Existing player ability-owner initialization · 2026-10-28

After existing character initialization completes and the holder has added its character ability and set initial cooldowns, the holder now ensures that its player has an active PlayerAbilityHost. The host constructs the player-owned runtime from the collected definitions without repeating holder initial state, then enables it. The existing inactive run-participant initialization retains its separate preparation path. Ability acquisition, removal and hooks can consequently find the runtime on this existing setup path once initialization has completed.

This active-player path presently supplies a new actor-local run context and player ID with no shared run cancellation because the existing scene does not expose the planned run lifetime and roster here. It is not equivalent to a shared run identity. Disable/enable suspends and reactivates the host, and destruction disposes it; compare these policies with death, revive, retry, scene changes and actual run teardown before closing lifecycle work. Existing global ability work, initialization order, player-specific cloned definitions, serialized references, cross-player identity, cooldown/UI behavior and production composition remain unverified. Earlier notes about a missing runtime on this path describe the state before this change. No compilation, Unity import, tests or build was run.

Interrupted ability cleanup · 2026-10-28

Meditate, Last Stand and Reload Shield now release their active state and hide their existing views when their owned coroutine is disposed. Meditate also clears readiness and its stack; Reload Shield retains its remaining amount but no longer treats the shield as visible or active; Last Stand retains its expired flag and does not execute the final self-hit on cancellation. Normal completion retains the existing order. This prevents a disabled or revived actor from retaining those active flags when the owner suspends its work.

This is an explicit lifecycle policy change from the old global coroutine behavior, which did not perform cleanup on cancellation; it is recorded for discussion and later comparison. Admission failure, repeated activation, death versus temporary disable, revival, removal, view bindings and run teardown remain unresolved. No compilation, Unity import, tests or build was run.

Passive stat ability definitions · 2026-10-28

Quick Hand, Sharpshooter, Sniper, Stamina Boost, Strafe, Late Bloomer, Potion Maniac, Potion Overlord, Demonic Pact and Ancient Demon Pact now have individual AB_ definitions referenced by their existing assets. These passive abilities have no separate mutable behavior in the inspected stat path: the player ability owner exposes a generic acquired-definition query, and PlayerModifier uses it to populate the named sources in the existing central stat projection. Demonic Pact and Ancient Demon Pact's health and stamina mutation calculations also use the acquired definitions. The numeric formulas and operation order remain in the central stat calculation.

The generic query searches acquired runtime definitions, rather than retained module objects, so removing the last matching acquired definition removes its passive contribution; duplicate definitions remain present until individually removed. Without an initialized owner these passive effects now read as absent. Asset bindings, initialization ordering, duplicate and removal behavior, health/stamina mutation ordering, other authored variants and cross-player isolation remain unverified. No compilation, Unity import, tests or build was run.

Dash ability admission · 2026-10-28

AB_Dash now supplies each player's dash behavior. Both existing input routes request its module, which uses the player ability owner's first-match cooldown admission and executes the player's scoped dash. Both authored Dash assets reference the new script. The old holder dash coroutine and global ability-service admission were removed; existing input checks, player dash executor, movement hooks and weapon hiding remain. Editor comparison code was updated to call the executor facade after removal of the holder method, but was not run.

The ability cannot start before its player runtime is initialized. Actor-specific run identity, ability duplication, cooldown display, the executor's generation-based cancellation, death/revive, input ownership, weapon presentation and movement timing still need integration and review. No compilation, Unity import, tests or build was run.

Fatal Flow Knowledge and Piercing Bullet critical stages · 2026-10-28

AB_FatalFlowKnowledge and AB_PiercingBullet implement critical hook orders 200 and 250. The weapon dispatches them after its existing Ground Breaker stage and before Concussive Impact order 300. Fatal Flow Knowledge applies its existing damage and critical-damage increments when base critical chance is at least one, then makes the original integer random roll and subtracts critical chance on a roll at or below 30. Piercing Bullet adds four to the attack's enemy-hit budget. Neither old branch checked the corresponding weapon ignore field, so the owned hooks do not add such a check. Both assets now reference their ability scripts; the old weapon checks were removed.

Handler registration is revoked after the last matching ability is removed. Owner composition, stat mutation order, random and reentrant callback behavior, companion attacks, projectile reuse and asset bindings remain unverified. No compilation, Unity import, tests or build was run.

Ground Breaker weapon and critical stages · 2026-10-28

AB_GroundBreaker owns the critical threshold and count, burst amount and count, active state, damage multiplier and cooldown state. Weapon-fire order 50 runs at the previous character-ability position before Star Burst: it updates the separate assured-critical count, chooses the existing weapon projectile, consumes burst count and makes the original Lucky Find roll. Critical order 150 runs after Sure Fire and the existing assured-critical reset, before Fatal Flow Knowledge; it requests bypassed work to update the count and ability display values. The cooldown work keeps its additional cooldown and current-display-based wait. The stat projection reads the acquired Ground Breaker definition, and existing holder properties expose owned values to character initialization, status, revive and weapon-evolution callers. The authored asset points to the new script; the old holder methods and weapon branches were removed.

Assured-critical state, pooled projectiles, character-specific paths and upgrade callbacks remain to be migrated. The ability's cooldown coroutine has no explicit cancellation cleanup. Admission and display timing, random/reentrant ordering, initialization, removal, stat calculations, prefab binding and revive remain unverified. No compilation, Unity import, tests or build was run.

Ground Breaker attack damage stage · 2026-10-28

Ground Breaker now participates in the existing attack-construction contract at order 400, dispatched after the Luster Burst damage stage and before the Long Slash color stage. While Ground Breaker is active, it replaces attack damage with the original final-damage, critical-damage and owned multiplier formula and sets the critical damage type. The old named branch in PlayerWeapon was removed. Its attack-construction registration is retained after the last matching ability is removed, because the former branch depended on active state rather than current ability presence; it is released on owner disposal.

Character weapon behavior, pooled attack payload, retained state and cancellation remain open. Ordering, modifier values and removal behavior are not verified. No compilation, Unity import, tests or build was run.

Lucky Find excavation stage · 2026-10-28

AB_LuckyFind implements IExcavationAbility order 100. Ground Breaker keeps its original chance roll and dispatches Hooks_Excavation when that roll succeeds; the handler requests bypassed first-match Lucky Find admission, plays the original sound, draws the original integer offsets and spawns the existing pooled gem from the first weapon's bullet position. Ground Breaker does not name Lucky Find. Dispatch takes an ordered snapshot, rejects duplicate orders, propagates exceptions and uses registrations removed on last matching ability removal or owner disposal. The authored ability asset points to the new script; the old holder activator and coroutine were removed.

The pickup's lifetime and pool state, player and weapon availability, random sequence, same-frame reentry, cancellation, ability removal, character upgrades and asset binding remain unverified. No compilation, Unity import, tests or build was run.

Luster Burst weapon and attack stages · 2026-10-28

AB_LusterBurst owns the shot threshold and count, active state, skill amplification percentage and pierce settings. Weapon-fire order 40 precedes Ground Breaker order 50 and requests the original bypassed shot advancement; it preserves the existing first-weapon projectile selection, speed multiplier, sound and ability display values. Attack-construction order 350 runs after the Star Burst damage stage and before Ground Breaker order 400, applying the existing magic-damage override when active or making the original integer pierce roll otherwise. The owned attack hook is revoked after the last matching ability entry is removed, as the old branch checked ability presence.

Existing holder properties expose the owned values to initialization, Artemis Burst and weapon evolution, including values set before acquisition. The authored asset points to the new script; the old holder activator and coroutine and the named weapon branches were removed. Weapon ownership, companion use, random order, cooldown display, pooled projectiles, initialization, removal and evolution remain unverified. No compilation, Unity import, tests or build was run.

Neo Sword combo stages · 2026-10-28

AB_NeoSword owns the long-slash chance, active flag and combo count. Weapon-fire order 20 requests bypassed combo work after the existing Proto Sword stage and before Luster Burst and Ground Breaker. It retains the original integer rolls, failure cap, first-weapon projectile changes and combo transitions. Attack-construction order 500 applies the existing combo color after Ground Breaker's damage stage. This construction hook is retained after ability removal because the former color check depended on combo state rather than ability presence. The authored asset points to the new script; the old holder activator and coroutine and named weapon branches were removed.

The holder properties still bridge character initialization, central stats, Proto Sword and evolution; Proto Sword's own legacy execution and its Neo Sword exclusion remain to migrate. Before Neo Sword is acquired, an externally set nonzero legacy combo will not have an owned color handler. Ability removal, combo state, character weapon ownership, projectile pooling, random ordering, shared hook snapshots and Unity asset binding remain unverified. No compilation, Unity import, tests or build was run.

Proto Barrier weapon stages · 2026-10-28

Proto Barrier now handles its former default long-slash projectile roll at weapon-fire order 10 and sets its attack payload flag at construction order 150, after Blood Thirst and before the remaining character attack flags. Neo Sword declares IWeaponProjectileOverride; Proto Barrier queries whether an acquired module implements that contract before making the default roll. This preserves the existing Neo Sword exclusion without referring to Neo Sword by name inside Proto Barrier. The acquired-module query ignores modules retained after their ability is removed. Proto Barrier's attack-construction registration is removed after the last matching entry; its central stat-presence input now comes from its acquired definition. The old holder Proto Sword methods and named weapon branches were removed.

The new override marker currently has one consumer and expresses the existing default-selection relationship; future projectile-selection interactions need explicit ordering rather than automatically assuming they use the same policy. Multishoot spread, drone fire rate, Proto Barrier hit execution, character upgrades and pre-acquisition state remain elsewhere. Asset initialization, random order, ability removal, shared hook snapshots and companion interactions remain unverified. No compilation, Unity import, tests or build was run.

Multishoot weapon stages · 2026-10-28

AB_Multishoot implements the weapon extra-shot contract at order 100 and attack-construction order 325. The weapon invokes extra-shot hooks after its primary attack and before resetting its attack timer; Multishoot generates the original two shots with opposite spread and the existing direct-attack option. Its construction stage applies the original 0.3 damage multiplier after Double Edge and before Star Burst. Both stages respect the existing weapon ignore option. Their registrations are removed after the last matching entry; the extra-shot dispatcher takes an ordered snapshot, rejects equal orders and propagates exceptions.

Proto Barrier implements IExtraShotSpreadOverride with the existing 30-degree value; without an acquired provider Multishoot uses 10 degrees. The generic provider query returns the first matching acquired module, so a policy for multiple spread overrides remains a design question. The authored Multishoot asset now references the new script and the old weapon branches were removed. Existing Yin sword and orb acquisition/upgrade interactions remain in their original callers and need migration; additional-shot projectile preparation, nested random ordering, direct attacks, companion paths, removal and asset binding remain unverified. No compilation, Unity import, tests or build was run.

Star Burst charge and weapon stages · 2026-10-28

AB_StarBurst owns charge time and its upgrade damage multiplier. Its IWeaponChargeAbility order 100 can hold ordinary fire after target/range admission and before the existing companion-weapon checks; while stationary and below four seconds it increments charge by scaled delta time divided by final attack interval. The same charge hook clears the charge after an ordinary FireWeapon call returns. Companion calls that only activate weapon abilities do not perform that reset. Hooks_WeaponCharge uses ordered snapshots, stops at the first hold request, dispatches completion separately, rejects duplicate orders and propagates exceptions. Registration is removed after the last matching ability entry or at owner disposal.

Weapon-fire order 75 preserves first-weapon projectile and speed selection after Ground Breaker. Attack-construction order 340 applies the original damage and hit-budget calculation after Multishoot and before Luster Burst. Holder properties expose the owned values to initialization and the existing evolution callback. The authored asset now references the new script; the old named weapon checks and unused holder shield placeholder were removed.

The charge hook is absent before player ability-owner initialization or after removal; the former unconditional reset of an unused holder value on unrelated shots no longer runs. Target timing, multiple weapons, character projectile ownership, speed and damage order, upgrades, cooldowns and prefab bindings remain unverified. No compilation, Unity import, tests or build was run.

Soul Wager and Double Edge damage stages · 2026-10-28

AB_SoulWager and AB_DoubleEdge implement weapon-damage orders 100 and 200, respectively. The weapon dispatches this stage after the original critical decision and critical hooks, before Multishoot and character damage overrides, supplying the original critical roll. Soul Wager retains the existing health-based damage, live critical conditions, random rolls and integer health changes; Double Edge retains the existing 60% damage addition. Both respect their original weapon ignore settings. Dispatch takes an ordered snapshot, rejects duplicate orders, propagates exceptions and uses registrations removed after the last matching ability entry or at owner disposal. The two authored assets point to their scripts; the named weapon branches were removed.

Soul Wager keeps its failure count per weapon in its player-owned module, initially reading that weapon's preexisting startup value. Weapon Start and destruction now notify retained lifecycle handlers as described below; reuse without a new Start still needs reconciliation. Sudden Death and assured-critical conditions still use existing player interfaces. Random and reentrant ordering, removal/reacquisition, companion attacks, health timing, pooling, owner composition and asset bindings remain unverified. No compilation, Unity import, tests or build was run.

Weapon lifecycle and Soul Wager state · 2026-10-28

IWeaponLifecycleAbility and Hooks_WeaponLifecycle provide ordered weapon-start and weapon-destroy notifications. PlayerWeapon.Start sends its notification after setting the initial Soul Wager count; destruction sends one while the player ability owner is available. Soul Wager removes that weapon's stored count on each event, so the next damage stage reads the weapon's current initial value and destroyed weapons are released from its state. A weapon first used before Start retains the old default until that later start notification. Handlers use ordered snapshots, reject duplicate orders and propagate exceptions. Their registrations are retained after ability removal and disposed with the owner, so a removed ability's retained state can still receive weapon lifecycle events.

This covers Unity Start and destruction only, not pool reactivation, reassignment to another owner or a general weapon reset. Owner teardown order, a destroyed player before weapon destruction, runtime initialization timing, multi-weapon behavior and reentrant callbacks remain unverified. No compilation, Unity import, tests or build was run.

Alchemist Touch, Stalwart Body and Invigorate now have individual ability scripts and authored asset bindings. ICollectibleEffectCountAbility runs at the original effect-count calculation before the null and already-triggered checks; Alchemist Touch changes the count to two. IPotionCollectedAbility runs once after the potion-drink event and before repeated potion applications; Stalwart Body increments its owned count up to four. The holder exposes that count to the central damage and damage-reduction projection and preserves its pre-acquisition value. IPotionAppliedAbility runs after each normal or greater potion's existing resource changes; Invigorate adds one quarter of the potion value to damage and skill amplification. Other potion types do not invoke that applied stage.

The item-following path uses the generic IPotionCapacityBypass contract so Invigorate still permits normal and greater potions to follow at full resources. These hook registrations are removed after the last matching ability and on owner disposal; each dispatcher uses an ordered snapshot, rejects duplicate orders and propagates exceptions. Their old named checks were removed. Interactions among multiple effect-count modifiers, item state and reentry, potion repeat ordering, ability removal, UI, upgrade changes, owner initialization and asset binding remain unverified. Other pickup abilities and reward ownership remain separate work. No compilation, Unity import, tests or build was run.

Super Magnet coin collection · 2026-10-28

AB_SuperMagnet implements ICoinCollectedAbility at order 100. The player pickup path dispatches Hooks_CoinCollected after its existing gold, experience and soul-count operations; Super Magnet emits the existing evolution progress event once per coin pickup, as before. The handler is unregistered when the last matching ability entry is removed and on owner disposal. Dispatch takes an ordered snapshot, rejects equal orders and propagates exceptions. The old named pickup check was removed.

Both the Super Magnet asset and GKCrown.asset currently serialize the SuperMagnet ability type, so both were bound to the same implementation to preserve the existing type-based behavior; whether the latter is intentional is unresolved, not a balance change. Pickup radius still comes from the existing upgrade route, and evolution, reward ownership, duplicate definitions, event timing, capacity and asset bindings remain unverified. No compilation, Unity import, tests or build was run.

Companion attack interval · 2026-10-28

ICompanionAttackIntervalAbility and Hooks_CompanionAttackInterval now provide an ordered interval adjustment after the drone creates and modifies its attack. Proto Barrier implements order 100 and halves the supplied live final attack interval, replacing the drone's named ability check. The dispatcher takes an ordered snapshot, rejects duplicate orders and propagates exceptions. Its registration is removed after the last matching ability entry and on owner disposal. With no handler, the supplied interval is unchanged.

Only the existing drone path invokes this hook; sword and orb timing have different behavior and have not been migrated to it. Master changes, player ownership, attack-speed timing, ability removal and companion lifetime remain unverified. No compilation, Unity import, tests or build was run.

Opportunist chest collection · 2026-10-29

AB_Opportunist provides IChestCollectedAbility; Hooks_ChestCollected dispatches it for both ordinary and boss chests, immediately before the existing reward enqueue. The ability adds two to the existing GameManager.rerollAmount. Triggered collectibles bypass this stage as before. Registration, removal and disposal follow the player ability runtime's existing per-type hook lifecycle; without a prepared runtime there is no fallback. Opportunist.asset retains its authored asset identity and uses the ability script. The reward service remains outside this overhaul and the ability still uses its existing GameManager dependency. Asset import, acquisition, duplicate/removal behavior and chest rewards have not been verified in Unity; no tests or build were run.

Guaranteed critical stage · 2026-10-29

IGuaranteedCriticalAbility exposes an ordered guaranteed-critical check and a critical-resolved notification; Hooks_GuaranteedCritical uses ordered snapshot dispatch, rejects duplicate orders and removes registrations on owner disposal. Ground Breaker is its first consumer, owns the former Miner assured-critical count and threshold (both initially 20), decrements the count at its existing weapon-fire stage and resets it on every critical after the Sure Fire critical stage and before Ground Breaker's critical count stage. PlayerWeapon and Soul Wager query the contract without naming Ground Breaker. The existing Miner upgrade queues changes to the owned threshold.

The registration is retained after last-entry removal to preserve the old counter's use/reset until owner disposal. Before Ground Breaker exists, the hook is absent: earlier critical hits no longer reset an unowned counter, which may matter if its threshold was upgraded before acquisition. Multi-handler ordering, repeat attacks, removal/reacquisition, early upgrades and Unity serialization remain unverified. No compilation, Unity import, tests or build were run.

Ability revive notification · 2026-10-29

IPlayerAbilityRevive.OnPlayerRevived is called by the player ability runtime after it clears generic cooldown flags during the existing player revive sequence, before the drone is restored. Ground Breaker implements it to clear its separate cooldown flag. The runtime takes a snapshot of its retained behavior modules; this matches the previous direct lookup's retained-module visibility, but multiple participants have no guaranteed relative order. Callback errors propagate. Revival, retained modules and active cooldown work are unverified; no tests, compilation or Unity import were run.

The revive notification now uses the shared runtime lookup, which can see a runtime being prepared before the host publishes it. It clears currently acquired entries and notifies behaviors created so far; reentrant preparation and any later acquisitions remain unverified.

Jet Propulsion early upgrade request · 2026-10-29

The JETPROP upgrade now configures the ability even before it exists. If the runtime is not active when that configuration is applied, Jet Propulsion retains the start request and processes it at tick order 950 after activation. When already active, it begins immediately. In both cases it requests crash before resetting its bonus to zero, preserving the existing upgrade sequence. Multiple early requests coalesce; removal/reacquisition, tick ordering, repeated hits and suspension remain unverified. No tests, compilation or Unity import were run.

Shared authored identities · 2026-10-29

Dash 1 and Dash 2 share type 1 and AB_Dash; Concussive Impact and Deadly Impact share type 33 and AB_ConcussiveImpact; Super Magnet and GKCrown share type 42 and AB_SuperMagnet. The Deadly Impact evolution adds its definition before removing Concussive Impact, leaving their shared type registration in place. These are source observations, not proof that all shared values or evolutions work. Replace AbilityType only with an explicit decision about shared behavior, duplicate and first-match semantics, and serialized asset identity.

Hook removal policy · 2026-10-29

Removing the final entry for a type revokes tick, dash, fire, reload, damage, pickup and companion registrations. Critical and attack-construction contracts select whether their hooks remain through their existing retention properties. Shield, weapon-lifecycle, weapon base-damage, guaranteed-critical and weapon forced-critical registrations remain until owner disposal, as do the behavior objects themselves. This preserves current effect/state lifetimes during the migration; it is not a general rule for new abilities. A replacement lifecycle should make ownership of retained effects explicit, and needs decisions for cancellation, reacquisition and multiple shared identities. No gameplay or lifecycle verification has been performed.

Health modifier notification · 2026-10-29

After ModifHP changes the health bonus and current health, the player ability runtime sends IPlayerHealthModifierAbility.OnHealthModifierApplied the previous projected maximum, before the next stat calculation. Proto Barrier uses that value to adjust its accumulated damage fraction. The notification takes a snapshot of retained behavior modules, including removed ones, matching the earlier retained-module lookup; no ability present means no deferred adjustment. Multiple handlers have no defined relative order. Reentry, timing and gameplay remain unverified; no tests, compilation or Unity import were run.

Weapon forced-critical stage · 2026-10-29

Rebuke implements IWeaponForcedCriticalAbility; Hooks_ForcedCritical checks its active state at the existing weapon critical condition after the Concussive Impact check. Soul Wager retains its separate guaranteed-critical rule, so Rebuke does not automatically qualify for Soul Wager’s supercritical label. Dispatch uses an ordered snapshot and rejects duplicate orders; registrations remain after removal until owner disposal, matching the prior retained behavior lookup. Multiple providers, removal, ordering and gameplay are unverified; no tests, compilation or Unity import were run.

Dash weapon visibility work · 2026-10-29

Both existing-scene and shared-actor dash adapters now run weapon-hide work through the player ability runtime. PlayerWeapon.HideWeapon restores the weapon in finally, including when the owned work is cancelled. If the scene adapter has no runtime, it does not start hide work. Overlapping hides, cancellation, revival and visual timing remain unverified; no tests, compilation or Unity import were run.

Weapon base-damage stage · 2026-10-29

IWeaponBaseDamageAbility participates in Hooks_WeaponBaseDamage before the weapon fixed-damage multiplier and critical-damage calculation. Unsteady Hand supplies its existing rolled multiplier at order 100; the weapon no longer names that ability. The registration is retained after removal to match the prior retained behavior lookup and is disposed with the owner. Multiple modifiers use ordered snapshot dispatch and duplicate orders are rejected. Damage during runtime construction before hook registration, removal, ordering and gameplay remain unverified; no tests, compilation or Unity import were run.

Reload display multiplier · 2026-10-29

IWeaponReloadDisplayAbility supplies the reload bar’s existing denominator multiplier; Frenzy returns two while active and one otherwise. It does not change actual reload timing. The generic lookup returns the first matching retained behavior, like the prior direct Frenzy lookup. A policy for multiple providers is still needed; startup, removal and visual timing remain unverified. No tests, compilation or Unity import were run.