Combat Modules
Shared combat code is split by responsibility:
spellEffects.tsowns spell target plans and the shared spell-effect applier.combatEngine.tsowns repeated per-member tick math: damage reduction, shields, HoTs, poison, debuff timers, and bounce-heal jumps.combatPresentation.tsowns UI-facing caps and grouping for combat logs and floating combat text.- Screen files provide
SpellEffectProfileobjects for mode-specific numbers. spellCasting.tsowns cast readiness and cooldown writes.pvpSpellCasting.tsowns the shared PvP cast pipeline: readiness validation, live target validation, effect application, floating-heal emission, and side-state writes.combatTick.tsowns small tick helpers such as resource regeneration and cooldown decay.cpuAi.tsowns CPU healer timing, mistake rolls, spell choice, and turn execution.stackCounts.tsowns stacked buff/upgrade count maps and summaries.spellModifiers.tsowns stack-based spell modifiers such as cost, cooldown, extra targets, free casts, and power multipliers.combatStateTransitions.tsowns shared combat state writes such as applying a completed cast to party, resource, cooldown, and free-cast fields.stadiumLifecycle.tsowns pure Stadium round/shop decisions: round outcome resolution, shop point awards, and CPU purchase selection.pvpRoguelikeLifecycle.tsowns pure PvP roguelike lifecycle decisions: live snapshot outcomes, combat tick outcomes, upgrade-complete checks, and next-stage progression.pvpRoguelikeUpgrades.tsowns PvP roguelike upgrade application, revive cleanup, party recovery, resource restore, cooldown reset, and next enemy health setup.pvpRoguelikeMatchSetup.tsowns PvP roguelike match-start side creation, first segment setup, live opponent naming, and shared reset defaults.stadiumMatchSetup.tsowns Stadium starter side creation, local/live match setup, live opponent naming, and shared reset defaults.pveRoguelikeRunSetup.tsowns PvE combat-state creation and roguelike run reset defaults.rewardSummaries.tsowns reward summary initialization, unlocked ability merging, XP/level/talent accumulation, and PvP roguelike boss loot accumulation.dualScreenPayloads.tsowns dual-screen combat payload construction and mode-specific status normalization.pvpLiveLifecycle.tsowns live PvP polling, local progress publication, and rematch request state.
SpellEffectProfile
Use a profile when spell behavior is the same shape but different by mode.
Examples:
- PvE stores Renew-style effects in
hotEffects; PvP modes mostly usehotTicks. - Stadium applies dampening through profile power callbacks.
- PvE cleanse intentionally does not emit floating heal text; PvP modes do.
- Shield ratios such as Radiance
0.3, Mend0.5, and Stadium group shield0.5belong in profiles.
When adding a spell rule, prefer adding a named profile field or callback instead of branching in screen components.
StackCounts
Use createStackCounts once per party state, upgrade list, or cast snapshot when repeated math needs stack totals. Then pass the map to spell cost, cooldown, target, and effect helpers. This keeps stacked upgrade behavior consistent and avoids repeated filter/scan work in combat render and cast paths.
Spell Modifiers
Use spellModifiers.ts for stacked upgrade math instead of open-coded exponent formulas in screen components. Screens still own mode-specific IDs, but shared helpers own the math:
- slot cost/cooldown reducers default to
0.75 ** stacks. - opponent slot penalties default to
1.25 ** stacks. - power boosts default to
1.25 ** stacks. - free-cast checks use a named stack modifier and the mode's existing
freeCastReadyrules.
State Transitions
Use applyCastStateUpdate after a spell effect profile returns the next party. Screens can still prepare mode-specific cooldown adjustments before the spell cooldown lands, but the final resource spend, cooldown write, party replacement, and free-cast progress should go through the transition helper.
PvP Spell Casting
Use applyPvpSpellCast after a PvP screen builds its mode-specific target plan and SpellEffectProfile. Keep balance inputs such as roguelike effects, Stadium dampening, shop buffs, cooldown tweaks, and free-cast flags in the screen; let the helper own the repeated validate/apply/emit/write pipeline.
CPU AI
Use runCpuHealTurn for PvP CPU turns. Screens still own mode-specific behavior tables and apply-spell adapters, while cpuAi.ts owns timing checks, mistake rolls, action selection, and invoking the selected spell.
Stadium Lifecycle
Use resolveStadiumRound for win/loss/tie decisions instead of open-coding score checks in PvpStadiumScreen. Use stadiumShopPointsForOutcome and chooseStadiumCpuPurchases for shop setup so player and CPU point rules stay in one place.
PvP Roguelike Lifecycle
Use resolvePvpRoguelikeCombatOutcome after each tick advances both sides. Use resolvePvpRoguelikeLiveSnapshot when a live match snapshot arrives. Use nextPvpRoguelikeStage after upgrade choices to decide whether to continue, advance stage, or complete the match. Components should execute the returned intent with React setters instead of duplicating the decision tree.
PvP Roguelike Upgrades
Use applyPvpRoguelikeUpgradeChoice to apply selected buffs, incoming debuffs, and revive-buff debuff cleanup. Use preparePvpRoguelikeNextEncounter after progression chooses the next encounter so recovery, 25% resource restore, cooldown reset, and enemy health setup stay consistent between live and CPU matches.
PvP Roguelike Match Setup
Use createPvpRoguelikeMatchStart for local/CPU starts and createPvpRoguelikeLiveMatchStart for live matches. These helpers build starter sides, set first encounter health, name live opponents, and provide reset defaults so rematch, checkpoint start, and queue fallback do not duplicate initial state construction.
Stadium Match Setup
Use createStadiumMatchStart for queue/CPU starts, createStadiumLiveMatchStart for live matches, and createStadiumStarterSide for advancing to the next round. These helpers reset party state, carry purchased buffs and round wins where needed, and provide shared reset defaults for queue, rematch, and live match starts.
PvE Run Setup
Use createPveCombatState for initial single-player combat state and createPveRoguelikeRunStart when resetting a run. This keeps party cloning, resource setup, enemy health, cooldown/free-cast reset, and UI reset defaults in one place.
Reward Summaries
Use createEmptyRewardSummary, createEmptyPvpRunSummary, mergeDungeonRewardSummary, and mergePvpRunRewardSummary instead of open-coding reward accumulation in screens. This keeps XP, level, talent points, unlocked abilities, and boss loot merge behavior consistent.
Presentation components for these summaries live in components/RewardPanels.tsx: use RewardXpSummary, BonusItemReward, LootRollList, and PvpRunLootList instead of duplicating reward JSX in result screens.
Dual-Screen Payloads
Use the builders in dualScreenPayloads.ts when publishing combat state to the secondary display. Keep render-derived arrays such as stripped floating text and opponent summaries memoized before calling the builder, then let the builder normalize mode status values like queueing, countdown, and Stadium shop into the bottom-screen status model.
Live PvP Sync
Use usePvpLiveMatchSync for live match polling and rematch controls. Screens should provide only mode-specific progress payloads and opponent snapshot rules; the hook owns publish/poll intervals, rematch pending state, expiry, and error messages.
Timers
Use useRoundCountdown for PvP round starts and useDeadlineTimer for mode deadlines such as PvP roguelike upgrade choice and Stadium shop. Keep countdown expiry behavior mode-specific, but avoid open-coded interval refs and Date.now() loops in screens.
Floating Combat Text
Use useFloatingCombatText for single-sided combat screens and useSidedFloatingCombatText for PvP screens. The hooks own IDs, expiry cleanup, member grouping, side filtering, and dual-screen text stripping so screens only emit heal events.
Party Targeting
Use usePartyTargeting for combat-screen navigation wrappers. Keep raw grid/direct selection rules in combat/targeting.ts; the hook owns relative, directional, and direct target callbacks around the current party ref, selected-id ref, grid columns, living-target flags, and target group.
Render Allocation
Keep repeated combat-render derivations memoized near their source state: active input bindings, stack summaries, visible shop choices, enemy health segments, and stripped floating text payloads. Avoid calling summary helpers or bindings[lastDevice] repeatedly inside JSX loops.