5.6 KiB
5.6 KiB
| description | globs | alwaysApply |
|---|---|---|
| Effect Processor architecture - the central system for executing all game state changes | src/systems/EffectProcessor.js, src/systems/EffectProcessor.ts, src/types/Effects.ts | false |
Effect Processor Rule
The EffectProcessor is the central system responsible for executing all changes to the game state (Damage, Healing, Movement, Spawning). It is a stateless logic engine that takes a Definition (What to do) and a Context (Who is doing it to whom), and applies the necessary mutations to the UnitManager or VoxelGrid.
1. System Overview
Architectural Role
- Input: EffectDefinition (JSON), Source (Unit), Target (Unit/Tile)
- Output: State Mutation (HP changed, Unit moved) + EffectResult (Log data)
- Pattern: Strategy Pattern. Each effect_type maps to a specific Handler Function
2. Integration Points
A. Calling the Processor
The Processor is never called directly by the UI. It is invoked by:
- SkillManager: When an Active Skill is executed
- EventSystem: When a Passive Item triggers (e.g., "On Hit -> Apply Burn")
- Environmental Hazard: When a unit starts their turn on Fire/Acid
B. Dependencies
The Processor requires injection of:
- VoxelGrid: To check collision, modify terrain, or move units
- UnitManager: To find neighbors (Chain Lightning) or spawn tokens (Turrets)
- RNG: A seeded random number generator for damage variance and status chances
3. Data Structure (JSON Schema)
Every effect in the game must adhere to this structure. See src/types/Effects.ts for full TypeScript definitions.
Effect Types
export type EffectType =
// Combat
| "DAMAGE"
| "HEAL"
| "CHAIN_DAMAGE"
| "REDIRECT_DAMAGE"
| "PREVENT_DEATH"
// Status & Stats
| "APPLY_STATUS"
| "REMOVE_STATUS"
| "REMOVE_ALL_DEBUFFS"
| "APPLY_BUFF"
| "GIVE_AP"
| "ADD_CHARGE"
| "ADD_SHIELD"
| "CONVERT_DAMAGE_TO_HEAL"
| "DYNAMIC_BUFF"
// Movement & Physics
| "TELEPORT"
| "MOVE_TO_TARGET"
| "SWAP_POSITIONS"
| "PHYSICS_PULL"
| "PUSH"
// World & Spawning
| "SPAWN_OBJECT"
| "SPAWN_HAZARD"
| "SPAWN_LOOT"
| "MODIFY_TERRAIN"
| "DESTROY_VOXEL"
| "DESTROY_OBJECTS"
| "REVEAL_OBJECTS"
| "COLLECT_LOOT"
// Meta / Logic
| "REPEAT_SKILL"
| "CANCEL_EVENT"
| "REDUCE_COST"
| "BUFF_SPAWN"
| "MODIFY_AOE";
Effect Parameters
export interface EffectParams {
// Combat Magnitude
power?: number; // Base amount (Damage/Heal)
attribute?: string; // Stat to scale off (e.g., "strength", "magic")
scaling?: number; // Multiplier for attribute (Default: 1.0)
element?: "PHYSICAL" | "FIRE" | "ICE" | "SHOCK" | "VOID" | "TECH";
// Chaining
bounces?: number;
decay?: number;
synergy_trigger?: string; // Status ID that triggers bonus effect
// Status/Buffs
status_id?: string;
duration?: number;
stat?: string; // For Buffs
value?: number; // For Buffs/Mods
chance?: number; // 0.0 to 1.0 (Proc chance)
// Physics
force?: number; // Distance
destination?: "TARGET" | "BEHIND_TARGET" | "ADJACENT_TO_TARGET";
// World
object_id?: string; // Unit ID to spawn
hazard_id?: string;
tag?: string; // Filter for objects (e.g. "COVER")
range?: number; // AoE radius
// Logic
percentage?: number; // 0.0 - 1.0
amount?: number; // Flat amount (AP/Charge)
amount_range?: [number, number]; // [min, max]
set_hp?: number; // Hard set HP value
shape?: "CIRCLE" | "LINE" | "CONE" | "SINGLE";
size?: number;
multiplier?: number;
}
4. Handler Specifications
Handler: DAMAGE
- Logic:
FinalDamage = (BasePower + (Source[Attribute] * Scaling)) - Target.Defense - Element Check: If Target has Resistance/Weakness to
element, modify FinalDamage - Result:
Target.currentHP -= FinalDamage
Handler: CHAIN_DAMAGE
- Logic: Apply
DAMAGEto primary target. Then, scan for N nearest enemies within Range R. ApplyDAMAGE * Decayto them - Synergy: If
condition.target_statusis present on a target, the chain may branch or deal double damage
Handler: TELEPORT
- Logic: Validate destination tile (must be Air and Unoccupied). Update
Unit.positionandVoxelGrid.unitMap - Visuals: Trigger "Vanish" VFX at old pos, "Appear" VFX at new pos
Handler: MODIFY_TERRAIN
- Logic: Update
VoxelGridID at Target coordinates - Use Case: Sapper's "Breach Charge" turns
ID_WALLintoID_AIR - Safety: Check
VoxelGrid.isDestructible(). Do not destroy bedrock
5. Conditions of Acceptance (CoA)
CoA 1: Attribute Scaling
- Given a Damage Effect with
power: 10andattribute: "magic", if Source hasmagic: 5, the output damage must be 15
CoA 2: Conditional Logic
- Given an Effect with
condition: { target_status: "WET" }, if the target does not have the "WET" status, the effect must not execute (return early)
CoA 3: State Mutation
- When
APPLY_STATUSis executed, the Target unit'sstatusEffectsarray must contain the new ID with the correct duration
CoA 4: Physics Safety
- When
PUSHis executed, the system must checkVoxelGrid.isSolid()behind the target. If a wall exists, the unit must not move into the wall (optionally take "Smash" damage instead)
6. Implementation Requirements
- Statelessness: The processor should not hold state. It acts on the Unit and Grid passed to it
- Schema: Effects must adhere to the EffectDefinition interface (Type + Params)
- All game state mutations (Damage, Move, Spawn) MUST go through
EffectProcessor.process()