133 lines
4.7 KiB
Markdown
133 lines
4.7 KiB
Markdown
|
|
# **Effect Processor Specification: The Game Logic Engine**
|
||
|
|
|
||
|
|
This document defines the architecture for the **Effect Processor**, the central system responsible for executing all changes to the game state (Damage, Healing, Movement, Spawning).
|
||
|
|
|
||
|
|
## **1. System Overview**
|
||
|
|
|
||
|
|
The EffectProcessor is a stateless logic engine. It 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.
|
||
|
|
|
||
|
|
### **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.
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface EffectDefinition {
|
||
|
|
type: EffectType;
|
||
|
|
|
||
|
|
// -- 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)
|
||
|
|
|
||
|
|
// -- Flavour --
|
||
|
|
element?: "PHYSICAL" | "FIRE" | "ICE" | "SHOCK" | "VOID" | "TECH";
|
||
|
|
|
||
|
|
// -- Status/Buffs --
|
||
|
|
status_id?: string; // For APPLY_STATUS
|
||
|
|
duration?: number; // Turns
|
||
|
|
chance?: number; // 0.0 to 1.0
|
||
|
|
|
||
|
|
// -- Movement/Physics --
|
||
|
|
force?: number; // Distance for Push/Pull
|
||
|
|
destination?: "TARGET" | "BEHIND_TARGET"; // For Teleport
|
||
|
|
|
||
|
|
// -- Conditionals --
|
||
|
|
condition?: {
|
||
|
|
target_tag?: string; // e.g. "MECHANICAL"
|
||
|
|
target_status?: string; // e.g. "WET"
|
||
|
|
hp_threshold?: number; // e.g. 0.3 (30%)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
type EffectType =
|
||
|
|
| "DAMAGE"
|
||
|
|
| "HEAL"
|
||
|
|
| "APPLY_STATUS"
|
||
|
|
| "REMOVE_STATUS"
|
||
|
|
| "TELEPORT"
|
||
|
|
| "PUSH"
|
||
|
|
| "PULL"
|
||
|
|
| "SPAWN_UNIT"
|
||
|
|
| "MODIFY_TERRAIN" // Destroy walls, create hazards
|
||
|
|
| "CHAIN_DAMAGE"; // Bouncing projectiles
|
||
|
|
```
|
||
|
|
|
||
|
|
## 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. Prompt for Coding Agent
|
||
|
|
|
||
|
|
> "Create `src/systems/EffectProcessor.js`.
|
||
|
|
>
|
||
|
|
> 1. **Constructor:** Accept `VoxelGrid` and `UnitManager`. Initialize a map of `handlers`.
|
||
|
|
> 2. **Process Method:** `process(effectDef, source, target)`. Look up handler by `effectDef.type`. Verify `checkConditions()`. Execute handler. Return `ResultObject`.
|
||
|
|
> 3. **Handlers:** Implement `handleDamage`, `handleHeal`, `handleStatus`, `handleMove`.
|
||
|
|
> 4. **Helper:** Implement `calculatePower(def, source)` to handle attribute scaling logic centrally."
|