Rift Bolt detonation: weapons mark, the Rift Bolt cashes in
Rift Bolt detonation — design
Section titled “Rift Bolt detonation — design”Status: approved in brainstorming 2026-10-12 (Chris). Next: implementation plan.
Problem
Section titled “Problem”Every weapon hit calls ElementalSystem.apply_element() (sim/elemental_system.gd), which tints the
enemy with the weapon’s element, sets stacks = 1 and a 4 s aura_remaining. Only two of the 14
elements do anything with it: Fire (burn, 2 HP/s DoT) and Lightning (shock, +15 % damage taken),
live since 2026-09-23. The other weapon elements in play (kinetic, void, poison, light, blood, time,
cold, aether) are pure tint, and stacks never exceed 1. To the player the element colours read as
decoration with no mechanic.
Every weapon hit leaves an elemental mark (stacks). The Rift Bolt (WeaponAim, the always-on
right-stick weapon) detonates marks on the enemies it physically hits, for damage that scales
with stacks. The aimed weapon becomes the skill-shot payoff for the auto weapons’ setup.
Lesson carried from the archived reactions mode (2026-07-09): every-hit reactions were wildly lethal (~350 kills/min, player untouched). Here only the aimed Rift Bolt can trigger, which is the brake.
Decisions (Chris, 2026-10-12)
Section titled “Decisions (Chris, 2026-10-12)”| Question | Choice | Deferred alternatives |
|---|---|---|
| Payoff shape | ONE generic detonation; element only changes colour | per-element payoffs; generic + bespoke headline elements (test later) |
| Power budget | Shift, don’t add: lower Rift Bolt base damage so a typical marked hit ≈ today’s damage | pure bonus; Rift Bolt as pure trigger |
| Stack building | ANY weapon hit adds a stack (cap stacks_max = 6), colour = last element |
same-element-only stacks; binary mark |
| What detonates | Direct hit + pierce victims only; the impact splash does NOT detonate | splash detonates; chain detonations (kept for a Rift Bolt upgrade / Railspike evolution) |
Mechanics (sim)
Section titled “Mechanics (sim)”- In code these are “element stacks”, NOT “marks”:
mark_*is already the Railgun’s marked debuff (mark_timer/mark_mult). “Mark” below is design shorthand only. - An enemy is stacked when it carries an applied (non-innate) aura:
aura_element != -1 and aura_remaining < EnemyPool.BASE_AURA_PERSIST * 0.5 and stacks > 0— the same testfx/enemy_aura_look.gdalready uses. (An exact!= BASE_AURA_PERSISTtest is wrong:Elemental.decaycounts innate auras down too.) An innate base aura is never stacked. apply_element(sim, ei, el)withel >= 0on a live enemy:- if already stacked:
stacks = min(stacks + 1, ElementalSystem.STACKS_MAX), elsestacks = 1; aura_element = el(last element wins the colour);aura_remaining = aura_decay_sofel(refresh).- A hit whose element equals the enemy’s innate element still stacks (stacked is decided by the
aura_remainingtest, not by element difference).
- if already stacked:
ElementalSystem.STACKS_MAXis a tunable defaulting to 6 (= biblestacks_max).- Expiry is unchanged (
Elemental.decay): when the window runs out the whole stack drops at once and the enemy reverts to its innate aura (or none). No per-stack decay. ModState.stack_bonus/aura_duration_multstay unoffered (CRYSTALS_DEAD_EFFECTS).
Status effects stay at single-stack magnitude
Section titled “Status effects stay at single-stack magnitude”burn DoT (apply_status_and_decay) and shock vulnerability (vuln_mult) currently multiply by
stacks. With accumulation that would silently 6x both. They are pinned to 1-stack magnitude
regardless of stack count. Stacks feed detonation only. The existing foreign-aura gate on status
(el != base_element) is unchanged.
Detonation
Section titled “Detonation”- Trigger: a Rift Bolt projectile (
ProjPool.KIND_AIM, including the evolved Railspike) collides with an enemy inresolve_collisions— the first hit and every pierce hit. The impact burst (burst_radiussplash) deals its normal damage and does NOT detonate. - A Rift Bolt hit does NOT add a stack (no
apply_elementforKIND_AIM); otherwise a fresh enemy is stacked by the shot meant to cash in. - If the hit enemy is stacked with
nstacks:- detonation damage
D = bolt_hit_damage * WeaponAim.DETONATE_MULT_PER_STACK * n, wherebolt_hit_damageis the projectile’s own damage (already includesdamage_mult, Rift Bolt power picks and the shot’s crit roll — so detonation scales with Rift Bolt upgrades and no second crit is rolled); - the target takes
D; every other enemy withinWeaponAim.DETONATE_RADIUStakesD * DETONATE_SPLASH_FRAC; any boss (target or splash) takesDETONATE_BOSS_FRACof its share; - the target’s stacks are consumed: revert exactly as decay does (innate aura or none);
- the whole detonation is ONE
begin_aoe_group()/end_aoe_group()hit (Wyrm shared pool rule).
- detonation damage
- All damage goes through
damage_enemy(deferred death sweep; no removal mid-tick), so the existingdmgnumfloating number shows it automatically. - Emits a
rift_detonatefx event{pos, radius, element, stacks}(render-only, excluded from checksums like allfx_events).
Power budget (shift, not add)
Section titled “Power budget (shift, not add)”WeaponAim.DEF_DAMAGE drops below today’s 6.0 and DETONATE_MULT_PER_STACK is set so a hit on a
typical stacked enemy (≈2-3 stacks, measured in soak, not assumed) lands about today’s damage.
Starting values (4.0 base, 0.25/stack → 2 stacks = 6.0) are placeholders; calibrated from soak
stack-count data + a paired-seed economy-sim comparison (skill bh-economy-sim): target is run power
≈ level vs. main, with stacked hits above and unstacked hits below today’s output.
Tunables (live console, per the console-tunable-by-default rule)
Section titled “Tunables (live console, per the console-tunable-by-default rule)”WeaponAim.DEF_DAMAGE (already one), ElementalSystem.STACKS_MAX, WeaponAim.DETONATE_MULT_PER_STACK,
WeaponAim.DETONATE_RADIUS, WeaponAim.DETONATE_SPLASH_FRAC, WeaponAim.DETONATE_BOSS_FRAC,
EnemyAuraLook.RINGS_MAX, AudioManager.RIFT_DETONATE_SFX_DB/_PITCH — registered static vars with
labels in tools/tunable_docs/docs.d/*.json (skill bh-tunable-batch).
Determinism
Section titled “Determinism”stacks is in state_checksum/snapshot_string, and stack accumulation plus the damage shift change
the seed-1234 baselines. Expected: re-pin via skill bh-determinism-repin after confirming the shift
comes only from this change. No new RNG draws.
Render / UX
Section titled “Render / UX”- Stack read:
fx/enemy_aura_look.gdalready draws one extra ring per stack but caps at the constMAX_RINGS = 3. It becomes a live tunableRINGS_MAX(default 6, range 1-6), so 3 vs. 6 rings can be compared live on iPhone + ATV from the console (the switchable comparison) before settling the default. - Detonation VFX: new
rift_detonateFxManager kind — element-coloured ring atDETONATE_RADIUSplus a hot flash, brighter with stacks consumed; ESSENTIAL (damage lands) with its own per-frame cap. New entry + score + preview intools/vfx_library/(pinned bytests/test_vfx_library_manifest.gd). - Damage number: the existing
dmgnumpath (see Detonation). - Audio:
rift_detonatereuses thescatter_explosionasset viacue_shapewith its ownRIFT_DETONATE_SFX_DB/_PITCHtunables (low-risk mix change, flagged for a listen). Pitch-by-stacks is deferred. - Teaching: the existing
tut_riftboltdialogue (data/story.json; the name “Rift Bolt” is already live there) gains a line on detonating stacked enemies.
Autopilot
Section titled “Autopilot”SkilledAutoPlayer.compute_aim_for (ai/skilled_auto_player.gd): when no enemy is inside a danger
radius of the pilot, aim at the in-range enemy with the most stacks (≥ a minimum); otherwise keep
today’s threat-cluster aim. Without this the soak / economy-sim numbers under-rate the mechanic (the
shift lowers unstacked damage).
Testing (TDD, GUT)
Section titled “Testing (TDD, GUT)”Unit:
- any weapon hit adds a stack up to
STACKS_MAX; colour follows the last element; - refresh on hit; whole mark drops at expiry; innate aura restored;
- innate aura alone is not stacked (no detonation on an untouched elemental enemy);
- burn DoT and shock vuln are identical at 1 and 6 stacks;
- Rift Bolt direct hit and pierce hit detonate; splash victims do not; Rift Bolt hit adds no stack;
- detonation damage = bolt hit × per-stack mult × stacks (target), splash fraction, boss fraction; stacks consumed.
End-to-end: real spawn → weapons stack an enemy → Rift Bolt kills it via _sweep_dead → XP awarded
(the biomass trap rule: assert awarded XP through the real path).
Then: determinism re-pin, economy-sim paired comparison, scripts/gate.sh, tests/test_vfx_library_manifest.gd, and a Dev install for on-device feel with the tunables live.
Out of scope
Section titled “Out of scope”Per-element payoffs (options 2/3), chain detonations (future Rift Bolt upgrade / Railspike path),
re-enabling stack/duration crystals, the dead Elemental.apply reactions code.