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.
155 lines
5.6 KiB
Markdown
155 lines
5.6 KiB
Markdown
---
|
|
description: Combat skill usage workflow - selection, targeting, and execution of active skills
|
|
globs: src/systems/SkillTargetingSystem.js, src/systems/SkillTargetingSystem.ts, src/core/GameLoop.js
|
|
alwaysApply: false
|
|
---
|
|
|
|
# **Combat Skill Usage Rule**
|
|
|
|
This rule defines the workflow for selecting, targeting, and executing Active Skills during the Combat Phase.
|
|
|
|
## **1. The Interaction Flow**
|
|
|
|
The process follows a strict 3-step sequence:
|
|
|
|
1. **Selection (UI):** Player clicks a skill button in the HUD
|
|
2. **Targeting (Grid):** Game enters `TARGETING_MODE`. Player moves cursor to select a target. Valid targets are highlighted
|
|
3. **Execution (Engine):** Player confirms selection. Costs are paid, and effects are applied
|
|
|
|
## **2. State Machine Updates**
|
|
|
|
We need to expand the CombatState in GameLoop to handle targeting.
|
|
|
|
| State | Description | Input Behavior |
|
|
| :------------------------ | :---------------------------------------------------------- | :------------------------------------------------------------------------------------------- |
|
|
| **IDLE / SELECTING_MOVE** | Standard state. Cursor highlights movement range. | Click Unit = Select. Click Empty = Move. |
|
|
| **TARGETING_SKILL** | Player has selected a skill. Cursor highlights Skill Range. | **Hover:** Update AoE Reticle. **Click:** Execute Skill. **Cancel (B/Esc):** Return to IDLE. |
|
|
| **EXECUTING_SKILL** | Animation playing. Input locked. | None. |
|
|
|
|
## **3. The Skill Targeting System**
|
|
|
|
We need a helper system (`src/systems/SkillTargetingSystem.js`) to handle the complex math of "Can I hit this?" without cluttering the GameLoop.
|
|
|
|
### **Core Logic: isValidTarget(source, targetTile, skillDef)**
|
|
|
|
1. **Range Check:** Manhattan distance between Source and Target <= `skill.range`
|
|
2. **Line of Sight (LOS):** Raycast from Source head height to Target center. Must not hit `isSolid` voxels (unless skill has `ignore_cover`)
|
|
3. **Content Check:**
|
|
- If `target_type` is **ENEMY**: Tile must contain a unit AND `unit.team != source.team`
|
|
- If `target_type` is **ALLY**: Tile must contain a unit AND `unit.team == source.team`
|
|
- If `target_type` is **EMPTY**: Tile must be empty
|
|
|
|
### **Visual Logic: getAffectedTiles(targetTile, skillDef)**
|
|
|
|
Calculates the Area of Effect (AoE) to highlight in **Red**.
|
|
|
|
- **SINGLE:** Just the target tile
|
|
- **CIRCLE (Radius R):** All tiles within distance R of target
|
|
- **LINE (Length L):** Raycast L tiles in the cardinal direction from Source to Target
|
|
- **CONE:** A triangle pattern originating from Source
|
|
|
|
## **4. Integration Steps**
|
|
|
|
### **Step 1: Create SkillTargetingSystem**
|
|
|
|
This class encapsulates the math.
|
|
|
|
```js
|
|
class SkillTargetingSystem {
|
|
constructor(grid, unitManager) { ... }
|
|
|
|
/** Returns { valid: boolean, reason: string } */
|
|
validateTarget(sourceUnit, targetPos, skillId) { ... }
|
|
|
|
/** Returns array of {x,y,z} for highlighting */
|
|
getAoETiles(sourcePos, cursorPos, skillId) { ... }
|
|
}
|
|
```
|
|
|
|
### **Step 2: Update GameLoop State**
|
|
|
|
Add `activeSkillId` to track which skill is pending.
|
|
|
|
```js
|
|
// In GameLoop.js
|
|
|
|
// 1. Handle UI Event
|
|
onSkillClicked(skillId) {
|
|
// Validate unit has AP
|
|
if (this.unit.currentAP < getSkillCost(skillId)) return;
|
|
|
|
this.combatState = 'TARGETING_SKILL';
|
|
this.activeSkillId = skillId;
|
|
|
|
// VISUALS: Clear Movement Blue Grid -> Show Attack Red Grid (Range)
|
|
const skill = this.unit.skills.get(skillId);
|
|
this.voxelManager.highlightRange(this.unit.pos, skill.range, 'RED_OUTLINE');
|
|
}
|
|
|
|
// 2. Handle Cursor Hover (InputManager event)
|
|
onCursorHover(pos) {
|
|
if (this.combatState === 'TARGETING_SKILL') {
|
|
const aoeTiles = this.targetingSystem.getAoETiles(this.unit.pos, pos, this.activeSkillId);
|
|
this.voxelManager.showReticle(aoeTiles); // Solid Red Highlight
|
|
}
|
|
}
|
|
```
|
|
|
|
### **Step 3: Execution Logic**
|
|
|
|
When the player confirms the click.
|
|
|
|
```js
|
|
// In GameLoop.js -> triggerSelection()
|
|
|
|
if (this.combatState === 'TARGETING_SKILL') {
|
|
const valid = this.targetingSystem.validateTarget(this.unit, cursor, this.activeSkillId);
|
|
|
|
if (valid) {
|
|
this.executeSkill(this.activeSkillId, cursor);
|
|
} else {
|
|
// Audio: Error Buzz
|
|
console.log("Invalid Target");
|
|
}
|
|
}
|
|
|
|
executeSkill(skillId, targetPos) {
|
|
this.combatState = 'EXECUTING_SKILL';
|
|
|
|
// 1. Deduct Costs (AP, Cooldown) via SkillManager
|
|
this.unit.skillManager.payCosts(skillId);
|
|
|
|
// 2. Get Targets (Units in AoE)
|
|
const targets = this.targetingSystem.getUnitsInAoE(targetPos, skillId);
|
|
|
|
// 3. Process Effects (Damage, Status) via EffectProcessor
|
|
const skillDef = this.registry.get(skillId);
|
|
skillDef.effects.forEach(eff => {
|
|
targets.forEach(t => this.effectProcessor.process(eff, this.unit, t));
|
|
});
|
|
|
|
// 4. Cleanup
|
|
this.combatState = 'IDLE';
|
|
this.activeSkillId = null;
|
|
this.voxelManager.clearHighlights();
|
|
}
|
|
```
|
|
|
|
## **5. Conditions of Acceptance (CoA)**
|
|
|
|
**CoA 1: Range Validation**
|
|
|
|
- A skill with `range: 3` must reject targets beyond 3 tiles (Manhattan distance)
|
|
|
|
**CoA 2: Line of Sight**
|
|
|
|
- A skill targeting an enemy behind a wall must fail the LOS check
|
|
|
|
**CoA 3: Cost Payment**
|
|
|
|
- Executing a skill must deduct AP and increment cooldown before effects are applied
|
|
|
|
**CoA 4: State Cleanup**
|
|
|
|
- After skill execution, the game must return to `IDLE` state and clear all targeting highlights
|
|
|