Skill System
Relevant source files
The following files were used as context for generating this wiki page:- src/models/skill_refactoring/SkillSystem.js
- src/models/skill_refactoring/SkillCore/Skill.js
- src/config/characterData.js
- src/entities/enemies/systems/EnemySkillSystem.js
- src/models/skill_refactoring/SkillCore/SkillValidator.js
- src/models/skill_refactoring/SkillHandlers/ChannelingSkillHandler.js
- src/utils/SaveManager.js
- src/entities/characters/playable/Monk.js
The Skill System is a comprehensive module responsible for managing all character and enemy abilities within the game. It handles the entire lifecycle of a skill, from initialization based on configuration files to execution, validation, state management, and cooldown tracking. The system is designed to be data-driven, with skill properties and behaviors defined externally in characterData.js, allowing for flexible and scalable character and enemy design. It supports various skill types, including melee, instant, movement, and channeling skills, for both playable characters and AI-controlled enemies.
This system is central to the game's combat mechanics, interacting with character state machines, animation controllers, and persistence layers to provide a cohesive and responsive combat experience.
Architecture Overview
The Skill System is composed of several key classes that work together to manage and execute skills. The SkillSystem (or EnemySkillSystem) acts as the central orchestrator for an entity, managing a collection of Skill objects. When a skill is used, a SkillHandler specific to the skill's type is retrieved from a SkillHandlerFactory to execute the skill's logic.
The following diagram illustrates the high-level architecture of the Skill System.
Core Components
SkillSystem Class
This is the main class that orchestrates skill management for a character. An analogous EnemySkillSystem exists for enemies with specialized logic.
- Initialization: The
SkillSystemis instantiated with a scene, a character entity, and the character's skill data. It creates and manages aMapofSkillobjects and their correspondingSkillHitboxinstances. - Managers: It initializes and coordinates several manager classes:
StateLockManager: Prevents other actions while a skill is active.ChannelingManager: Handles the logic for skills that are held down.AnimationController: Manages playing skill animations.HitstopManager: Triggers screen freeze effects on hit.
- Skill Execution: The primary method is
useSkill(skillName), which validates and triggers the execution of a specific skill.
Sources: src/models/skill_refactoring/SkillSystem.js:12-54, src/entities/enemies/systems/EnemySkillSystem.js:10-20
Skill Class
This class represents a single skill instance, holding its state and configuration.
- State Properties:
cooldownRemaining: Time left until the skill can be used again.isActive: A boolean flag indicating if the skill animation/effect is currently in progress.isChanneling: A boolean for channeling skills.pendingCooldown: A flag to indicate that the cooldown should start once the skill's animation completes.
- Lifecycle Methods:
canUse(character): Checks for cooldown, mana, and other basic requirements.use(character): Consumes resources (like mana) and activates the skill.activate(): Sets the skill to active and flags the cooldown as pending.complete(): Called when the skill's action is finished (typically by an animation event). It deactivates the skill and starts the cooldown if it was pending.update(delta): Updates thecooldownRemainingtime each frame.
Sources: src/models/skill_refactoring/SkillCore/Skill.js
Skill Configuration (characterData.js)
All skill properties are defined declaratively in characterData.js. This allows for easy modification of skills without changing game logic. Each character has a skills object containing configurations for each ability.
Below is an example configuration for the Monk's r_skill.
// src/config/characterData.js:131-171
r_skill: {
type: 'instant',
icon: 'assets/skills/monk/r_skill.png',
hitboxSequence: [
{
delay: 0,
hitbox: { width: 175, height: 40, offsetX: 80, offsetY: 100, duration: 900 },
damage: 10,
},
{
delay: 700,
hitbox: { width: 55, height: 120, offsetX: 80, offsetY: 60, duration: 600 },
damage: 10,
},
// ... more steps
],
animation: 'r_skill',
knockback: { x: 250, y: -150 },
effects: ['burn'],
cooldown: 0,
cost: { mana: 0 },
targetType: 'multi',
hitstop: 'FIREKNIGHT_ULTIMATE',
impactEffect: [],
},
Key Configuration Properties
| Property | Type | Description |
|---|---|---|
type | string | The skill type (e.g., instant, melee, movement, channeling). Determines which SkillHandler is used. |
icon | string | Path to the skill's UI icon. |
animation | string | The animation key to play when the skill is used. |
cooldown | number | The cooldown duration in milliseconds. |
cost | object | Resource cost, e.g., { mana: 20 }. |
hitboxSequence | Array<object> | An array defining a sequence of hitboxes for multi-part attacks. Each object can have its own delay, hitbox properties, and damage. |
hitbox | object or Array<object> | Defines the skill's damage area(s). Used if hitboxSequence is not present. |
knockback | object | The force to apply to a target on hit, e.g., { x: 250, y: -150 }. |
effects | Array<string> | Status effects to apply on hit (e.g., burn, stun). |
hitstop | string | A preset key for a hit-stop effect (screen freeze) on impact. |
channeling | object | Configuration for channeling skills, including maxDuration and manaPerTick. |
Sources: src/config/characterData.js
Skill Execution Flow
The process of using a skill involves multiple components, from initial validation to final execution and cooldown.
The sequence diagram below shows the typical flow when a player presses a skill key.
Skill Types and Handlers
The system uses a factory pattern (SkillHandlerFactory) to delegate execution logic to specialized handler classes based on the skill's type from its configuration.
ChannelingSkillHandler
This handler manages skills that are active while a key is held down, such as the Monk's e_skill.
- It locks the character's state machine upon execution.
- It plays a looping "channeling" animation.
- It uses a throttled function (
applyEffectByConfig) to apply effects like healing or mana regeneration periodically. - When the skill is stopped (either by releasing the key, running out of mana, or reaching max duration), it unlocks the state machine and returns the character to a neutral state (e.g., 'idle').
Sources: src/models/skill_refactoring/SkillHandlers/ChannelingSkillHandler.js, src/config/characterData.js:120-130
hitboxSequence and Melee/Instant Skills
Most offensive skills (melee, instant) rely on the hitboxSequence property. This powerful feature allows a single skill to have multiple, distinct attack phases.
- Sequencing: The
hitboxSequenceis an array where each element is a step in the attack. - Timing: Each step has a
delay(in ms) from the start of the skill, allowing for precisely timed combos. - Custom Properties: Each step can define its own
hitboxshape,damage,duration, and even charactermovement.
The EnemySkillSystem and SkillSystem process this sequence, creating temporary hitboxes for each step using time.delayedCall. This enables complex attack patterns like the Assassin's r_skill, which involves multiple movements and strikes.
Sources: src/entities/enemies/systems/EnemySkillSystem.js:314-350, src/config/characterData.js:229-270
State, Animation, and Cooldown Lifecycle
The skill lifecycle is tightly coupled with the animation system. This ensures that cooldowns and state locks are respected for the full duration of a skill's visual representation.
- Activation:
skill.use()is called. The skill becomesisActive, but the cooldown does not start yet. ApendingCooldownflag is set. The character's state is locked byStateLockManager. - Animation:
AnimationControllerplays the skill's animation. - Completion: The character's sprite emits an
animationcompleteevent when the animation finishes. - Cooldown Trigger:
SkillSystemlistens for this event. Upon firing, it callsskill.complete(). - Finalization:
skill.complete()checks thependingCooldownflag and, if true, starts the actual cooldown timer. TheStateLockManagercan then unlock the character's state.
This event-driven approach decouples the skill's active duration from a fixed timer, tying it directly to the animation's length.
Sources: src/models/skill_refactoring/SkillSystem.js:122-142, src/models/skill_refactoring/SkillCore/Skill.js:62-72
Skill Unlocking and Persistence
Skill Unlocking
Skills are not always available. Their availability is tied to the character's level via a skillUnlockSystem present in the game scene.
- The
SkillSystemcontains askillKeyMappingto map internal skill names (e.g.,q_skill) to UI keys (Q). - Before using a skill,
SkillSystem.canUseSkillcallsisSkillLocked, which queries theskillUnlockSystem. - The
TutorialSystemindicates that skills unlock at levels 10 (Q), 20 (W), 30 (E), and 40 (R). If a skill is locked, a message is displayed to the player.
Sources: src/models/skill_refactoring/SkillSystem.js:174-190, src/systems/Tutorial.js:109-115
Cooldown Persistence
To ensure a consistent experience across play sessions, skill cooldowns are saved.
- The
SaveManagerandSaveSlotManagerprovide methods to persist game data. saveAllSkillCooldowns(characterType, cooldowns)saves a map of skill keys and their cooldown end timestamps to the current save slot.getSkillCooldowns(characterType)retrieves this data upon loading a game.- The system calculates the remaining cooldown by subtracting the current time from the saved end time.
Sources: src/utils/SaveManager.js:201-218, src/utils/SaveSlotManager.js:415-432