@reldens/skills Class Hierarchy
Reference of every class in the @reldens/skills package: inheritance, composition, properties, methods, owner requirements and integration patterns.
Inheritance
- Skill
- Attack extends Skill
- PhysicalAttack extends Attack
- Effect extends Skill
- PhysicalEffect extends Effect
- Attack extends Skill
- LevelsSet
- ClassPath extends LevelsSet
- Level - standalone data class.
- SkillsServer - standalone wrapper (composition, not inheritance).
- Sender (server) and Receiver (client) - standalone communication classes.
No class extends the EventsManager: Skill, LevelsSet and ClassPath hold a reference to it in their events property (EventsManagerSingleton by default).
Class Details
Level
Data container for a single level.
- key (required) - level number; must be numeric and is converted with parseInt().
- modifiers - array of @reldens/modifiers Modifier instances (a warning is logged when empty).
- label - display name (defaults to the key).
- requiredExperience - total experience needed (also read from required_experience, default 0).
Used by LevelsSet and ClassPath.
LevelsSet
Manages the level progression, the experience and the level modifiers.
Constructor props: owner and events (EventsManager, default EventsManagerSingleton).
init(props) props:
- levels (required) - object of Level instances indexed by level key.
- currentLevel (default 0), currentExp (default 0).
- autoFillRanges (default false), autoFillExperienceMultiplier (default 1.5).
- increaseLevelsWithExperience (default true).
- levelsByExperience - ordered array of level keys (default: keys sorted by level key).
- setRequiredExperienceLimit (default false).
- ownerIdProperty (default id).
Methods:
- setOwner(props) - validates and sets the owner and the owner ID property.
- async init(props), async setLevels(levels), async createLevels(levels) (auto-fill).
- async levelUp(), async levelDown(), async applyLevelModifiers(revert).
- async addExperience(number), getNextLevelExperience(), getLevelInstance(levelKey).
- getOwnerId(), getOwnerEventKey(), getOwnerUniqueEventKey(suffix).
- async fireEvent(eventName, ...args), listenEvent(eventName, callback, removeKey, masterKey), eventFullName(eventName).
ClassPath
Extends LevelsSet with the skill tree and labels by level.
Additional init(props) props:
- key (required) - class path identifier.
- label - base display name (defaults to the key).
- labelsByLevel - {levelKey: 'label'}.
- currentLabel - defaults to the label of the highest level reached in labelsByLevel.
- skillsByLevel - {levelKey: [Skill instances]}.
- currentSkills - optional preset of the current skills.
- affectedProperty - property affected by the class skills.
Additional properties: skillsByLevelKeys ({levelKey: [skill keys]}) and currentSkills ({skillKey: Skill}).
Methods:
- async levelUp() - overridden: adds the skills and the label of the next level, then calls the parent level up.
- async levelDown() - overridden: removes the skills of the current level, sets the previous level label, then calls the parent level down.
- async addSkills(skills), async removeSkills(skills) (skill instances or keys), async setOwnerSkills(skills).
- getCurrentLabel(), getSkillsByLevelKeys().
SkillsServer
Server-side wrapper that creates (or receives) a ClassPath and, with a client, a Sender.
- owner (required) - must implement getPosition().
- classPath (optional) - an existing ClassPath instance; otherwise new ClassPath(props) is created.
- client (optional) - must implement send() and broadcast(); a Sender is created and its listeners registered.
- All ClassPath init props (key, label, levels, skills by level, etc.).
Properties: classPath and client (the Sender). The constructor starts classPath.init(props) without awaiting it; validation problems are logged as critical errors instead of thrown.
Skill
Base class for every skill type.
Constructor props:
- key (required), owner (required, with getPosition()), ownerIdProperty (default id).
- target - fixed target, or pass it to execute().
- range (default 0 = infinite), rangeAutomaticValidation (default false), rangePropertyX, rangePropertyY, rangeTargetPropertyX, rangeTargetPropertyY.
- allowSelfTarget (default false) - stored for your own validations.
- skillDelay (cooldown in ms, default 0), castTime (ms, default 0), canActivate (default true).
- usesLimit (default 0 = unlimited), autoValidation (default false).
- ownerConditions - Condition instances; ownerEffects - Modifier instances applied to the owner.
- criticalChance (percentage 0-100, default 0), criticalMultiplier (default 1), criticalFixedValue (default 0).
- customData, groups, events.
Runtime properties: isReady (false when required props are missing), isValid, uses, lastState, lastAppliedModifiers, skillActivationTimer, type. The constructor also resets owner.isCasting and owner.castingTimer.
Methods:
- validate(), validateConditions().
- validateRange(target), isInRange(ownerPosition, targetPosition), async isValidRange(target).
- async execute(target), async applySkillLogicOnTarget(target), async finishExecution(target).
- Hooks: onExecuteConditions(), async runSkillLogic(), async onExecuteRewards().
- Critical: isCritical(), applyCriticalValue(value), getCriticalDiff(value).
- applyModifiers(modifiersObjectList, target, avoidCritical).
- Events and owner: getOwnerId(), getOwnerEventKey(), getOwnerUniqueEventKey(suffix), fireEvent(), listenEvent(), eventFullName().
Attack
Extends Skill with damage calculation. Type SKILL.TYPE.ATTACK (2).
- affectedProperty (required) - target property that receives the damage.
- hitDamage (default 0), applyDirectDamage (default false).
- attackProperties, defenseProperties, aimProperties, dodgeProperties - arrays of property paths (owner for attack and aim, target for defense and dodge).
- dodgeFullEnabled (default true), dodgeOverAimSuccess (default 1).
- damageAffected, criticalAffected (default false).
- propertiesTotalOperators - {propertyPath: ModifierConst.OPS value} to combine a property with an operation other than addition.
- allowEffectBelowZero (default false).
Methods: runSkillLogic(), applyDamageTo(target), calculateProportionDamage(), calculateCriticalDamage(), getPropertiesTotal(object, properties), getDiffProportion(total, value), getAffectedPropertyValue(target), setAffectedPropertyValue(target, value).
Effect
Extends Skill to apply modifiers to the target (buffs and debuffs). Type SKILL.TYPE.EFFECT (3).
- targetEffects (required) - Modifier instances applied to the target, with critical.
PhysicalAttack and PhysicalEffect
Extend Attack (type 4) and Effect (type 5) for skills resolved by a physics system: the skill creates a projectile or area through the owner, and the damage or effects are applied on collision.
- magnitude, objectWidth, objectHeight (required).
- validateTargetOnHit (default false) - only apply when the collided object is the skill target.
- The owner must implement executePhysicalSkill(target, skill); otherwise isReady is false.
- parentType - the type of the parent class (ATTACK or EFFECT).
- async executeOnHit(target) - call it from your physics system when the collision happens.
Helpers: PhysicalPropertiesValidator (required props) and PhysicalSkillRunner (shared logic for both types).
Sender
Server-side broadcaster created by SkillsServer.
- constructor(classPath, client).
- registerListeners() - listens to the class path init end, level up, experience added, skill before cast and attack apply damage events.
- sendInitClassPathData(), sendLevelUpData(), sendLevelExperienceAdded(), sendSkillBeforeCastData(), sendSkillAttackApplyDamage().
- runBehaviors(messageData, actionName, behavior, ownerId) - sends, broadcasts or both, and ignores events from other owners.
Receiver
Client-side message processor.
- Constructor props: owner, actions (extra action to method mapping), avoidDefaults.
- processMessage(message) - ignores messages without the rski. prefix and calls the mapped handler.
- setDefaultMethods(), isValidMessage(message).
Composition
- LevelsSet
- contains Level instances, each one with Modifier instances.
- uses the EventsManager.
- ClassPath
- inherits the LevelsSet composition.
- contains Skill instances by level (Attack, Effect, PhysicalAttack, PhysicalEffect), each one with Condition and Modifier instances.
- SkillsServer
- contains a ClassPath.
- contains a Sender, which listens to the ClassPath events and uses the client send() / broadcast().
Server and Client Architecture
- Server side
- SkillsServer creates the ClassPath (progression) and the Sender (broadcaster).
- The ClassPath and its skills fire events through the EventsManager.
- The Sender listens to those events and sends messages through the client connection.
- Network - the messages travel through your transport (for example, a Colyseus room).
- Client side
- The Receiver processes each message and calls the handler that updates the UI or the game client.
Message flow example:
- Server: skillsServer.classPath.addExperience(500) fires the experience added event.
- Server: the Sender handles it in sendLevelExperienceAdded(classPath) and calls client.send() with the action rski.Ea, the owner ID and data.exp set to the current experience.
- Network: the message is transmitted.
- Client: receiver.processMessage(message) calls onLevelExperienceAdded(message), which updates the experience bar.
External Dependencies
- @reldens/utils - used by all classes:
- sc (Shortcuts) - property getters and helpers.
- EventsManagerSingleton - emit() and onWithKey().
- InteractionArea - range validation in Skill.
- Logger.
- @reldens/modifiers - used by Level, Skill, Attack and Effect:
- Modifier - level modifiers, owner effects and target effects.
- Condition - owner conditions.
- PropertyManager and Calculator - property access and property totals.
Owner Requirements
Minimal owner
class GameEntity
{
constructor(id)
{
this.id = id;
// recommended, used as the events namespace:
this.eventsPrefix = 'player.'+id;
this.position = {x: 0, y: 0};
this.stats = {hp: 100, maxHp: 100, mp: 50, atk: 10, def: 5, aim: 10, dodge: 5};
}
getPosition()
{
return this.position;
}
}
Skills manage owner.isCasting and owner.castingTimer themselves for the cast time.
Physical skills owner
class PhysicalEntity extends GameEntity
{
async executePhysicalSkill(target, skill)
{
// create a body using skill.objectWidth, skill.objectHeight and skill.magnitude,
// then, when your physics engine detects the collision:
// await skill.executeOnHit(collidedEntity);
}
}
Client for SkillsServer
let client = {
send: (message) => {
// send the message to this owner client only
},
broadcast: (message) => {
// send the message to every client in the room
}
};
Integration Patterns
1. Basic single class setup
const { ClassPath, Level, Skill } = require('@reldens/skills');
let levels = {
1: new Level({key: 1, modifiers: [], requiredExperience: 0}),
5: new Level({key: 5, modifiers: [], requiredExperience: 1000})
};
let basicSkill = new Skill({key: 'basic', owner: player});
let advancedSkill = new Skill({key: 'advanced', owner: player});
let classPath = new ClassPath({owner: player});
await classPath.init({
key: 'warrior',
levels: levels,
currentLevel: 1,
skillsByLevel: {
1: [basicSkill],
5: [advancedSkill]
}
});
2. Server-side class manager
const SkillsServer = require('@reldens/skills/lib/server');
class PlayerClassManager
{
constructor(player, client)
{
this.player = player;
this.client = client;
this.classes = {};
}
createClass(key, config)
{
this.classes[key] = new SkillsServer({
owner: this.player,
client: this.client,
key: key,
label: config.label,
levels: config.levels,
currentLevel: 1,
skillsByLevel: config.skillsByLevel
});
return this.classes[key];
}
async addExperience(classKey, amount)
{
if(!this.classes[classKey]){
return false;
}
await this.classes[classKey].classPath.addExperience(amount);
return true;
}
}
3. Client-side integration
const { Receiver } = require('@reldens/skills');
class SkillsUi extends Receiver
{
onInitClassPathEnd(message)
{
this.updateLevel(message.data.lvl, message.data.lab);
this.updateSkills(message.data.skl);
}
onLevelUp(message)
{
this.updateLevel(message.data.lvl, message.data.lab);
}
onLevelExperienceAdded(message)
{
this.updateExperience(message.data.exp);
}
}
let skillsUi = new SkillsUi({owner: player});
// call skillsUi.processMessage(message) for every message received from the server
4. Custom skill type
const { Skill } = require('@reldens/skills');
class HealSkill extends Skill
{
constructor(props)
{
super(props);
this.healAmount = props.healAmount || 50;
this.affectedProperty = props.affectedProperty || 'stats/hp';
this.maxProperty = props.maxProperty || 'stats/maxHp';
}
async runSkillLogic()
{
if(!this.target){
return false;
}
let healAmount = this.healAmount + this.getCriticalDiff(this.healAmount);
let currentValue = this.propertyManager.getPropertyValue(this.target, this.affectedProperty);
let maxValue = this.propertyManager.getPropertyValue(this.target, this.maxProperty);
let newValue = Math.min(currentValue + healAmount, maxValue);
this.propertyManager.setOwnerProperty(this.target, this.affectedProperty, newValue);
await this.fireEvent('custom.skills.healApplied', this, this.target, healAmount, newValue);
return true;
}
}
5. Persistent class path
const { ClassPath, SkillsEvents } = require('@reldens/skills');
class PersistentClassPath extends ClassPath
{
async init(props)
{
let savedData = await database.loadClassPath(this.owner.id, props.key);
if(savedData){
props.currentLevel = savedData.currentLevel;
props.currentExp = savedData.currentExp;
}
await super.init(props);
this.listenEvent(
SkillsEvents.LEVEL_UP,
async () => await this.save(),
this.getOwnerUniqueEventKey('persistLevelUp'),
this.getOwnerEventKey()
);
this.listenEvent(
SkillsEvents.LEVEL_EXPERIENCE_ADDED,
async () => await this.save(),
this.getOwnerUniqueEventKey('persistExperience'),
this.getOwnerEventKey()
);
}
async save()
{
await database.saveClassPath(this.owner.id, this.key, {
currentLevel: this.currentLevel,
currentExp: this.currentExp
});
}
}
Class Responsibility Summary
- Level - stores the level data. No events.
- LevelsSet - level progression and experience (init, levelUp, addExperience). Events: level up / down, experience added, level set init.
- ClassPath - skill trees on top of the progression (setOwnerSkills, addSkills, removeSkills). Events: add / remove skills, set skills, init end.
- SkillsServer - server to client synchronization setup (constructor only).
- Skill - base execution (validate, execute, applyModifiers). Events: validate, execute, cast, run logic.
- Attack - damage calculation. Event: attack apply damage.
- Effect - target modifiers. Event: effect target modifiers.
- PhysicalAttack / PhysicalEffect - physics-based execution. Events: physical attack / effect hit.
- Sender - broadcasts server events to clients.
- Receiver - processes client messages through on* handlers.
Related Documentation
- @reldens/skills Architecture - Package overview and data flows.
- Skills Execution Flow - Step by step skill execution.
- Skills Event System - Events and listeners.
- Skills Level Progression - Levels, experience and class paths.
- Skills Testing Guide - Mocks and test patterns.
- Class Path Entity, Levels Set Entity and Level Entity - Configuration reference.
reldens