aether-shards/.cursor/rules/logic/EffectProcessor/RULE.md
Matthew Mone 5c335b4b3c Add HubScreen and MissionBoard components for campaign management
Introduce the HubScreen as the main interface for managing resources, units, and mission selection, integrating with the GameStateManager for dynamic data binding. Implement the MissionBoard component to display and select available missions, enhancing user interaction with mission details and selection logic. Update the GameStateManager to handle transitions between game states, ensuring a seamless experience for players. Add tests for HubScreen and MissionBoard to validate functionality and integration with the overall game architecture.
2025-12-31 10:49:26 -08:00

174 lines
5.6 KiB
Markdown

---
description: Effect Processor architecture - the central system for executing all game state changes
globs: src/systems/EffectProcessor.js, src/systems/EffectProcessor.ts, src/types/Effects.ts
alwaysApply: 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:
1. **SkillManager:** When an Active Skill is executed
2. **EventSystem:** When a Passive Item triggers (e.g., "On Hit -> Apply Burn")
3. **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**
```typescript
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**
```typescript
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 `DAMAGE` to primary target. Then, scan for N nearest enemies within Range R. Apply `DAMAGE * Decay` to them
- **Synergy:** If `condition.target_status` is 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.position` and `VoxelGrid.unitMap`
- **Visuals:** Trigger "Vanish" VFX at old pos, "Appear" VFX at new pos
### **Handler: MODIFY_TERRAIN**
- **Logic:** Update `VoxelGrid` ID at Target coordinates
- **Use Case:** Sapper's "Breach Charge" turns `ID_WALL` into `ID_AIR`
- **Safety:** Check `VoxelGrid.isDestructible()`. Do not destroy bedrock
## **5. Conditions of Acceptance (CoA)**
**CoA 1: Attribute Scaling**
- Given a Damage Effect with `power: 10` and `attribute: "magic"`, if Source has `magic: 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_STATUS` is executed, the Target unit's `statusEffects` array must contain the new ID with the correct duration
**CoA 4: Physics Safety**
- When `PUSH` is executed, the system must check `VoxelGrid.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()`