@rpgjs/server 5.0.0-alpha.26 → 5.0.0-alpha.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,54 @@
1
- import { PlayerCtor, ProjectileType, RpgCommonPlayer, Direction, MovementStrategy } from '../../../common/src';
1
+ import { PlayerCtor, ProjectileType, RpgCommonPlayer, Direction, MovementStrategy, MovementOptions } from '../../../common/src';
2
2
  import { RpgPlayer } from './Player';
3
3
  type CallbackTileMove = (player: RpgPlayer, map: any) => Direction[];
4
4
  type CallbackTurnMove = (player: RpgPlayer, map: any) => string;
5
5
  type Routes = (string | Promise<any> | Direction | Direction[] | Function)[];
6
+ export type { MovementOptions };
7
+ /**
8
+ * Options for moveRoutes method
9
+ */
10
+ export interface MoveRoutesOptions {
11
+ /**
12
+ * Callback function called when the player gets stuck (cannot move towards target)
13
+ *
14
+ * This callback is triggered when the player is trying to move but cannot make progress
15
+ * towards the target position, typically due to obstacles or collisions.
16
+ *
17
+ * @param player - The player instance that is stuck
18
+ * @param target - The target position the player was trying to reach
19
+ * @param currentPosition - The current position of the player
20
+ * @returns If true, the route will continue; if false, the route will be cancelled
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * await player.moveRoutes([Move.right()], {
25
+ * onStuck: (player, target, currentPos) => {
26
+ * console.log('Player is stuck!');
27
+ * return false; // Cancel the route
28
+ * }
29
+ * });
30
+ * ```
31
+ */
32
+ onStuck?: (player: RpgPlayer, target: {
33
+ x: number;
34
+ y: number;
35
+ }, currentPosition: {
36
+ x: number;
37
+ y: number;
38
+ }) => boolean | void;
39
+ /**
40
+ * Time in milliseconds to wait before considering the player stuck (default: 500ms)
41
+ *
42
+ * The player must be unable to make progress for this duration before onStuck is called.
43
+ */
44
+ stuckTimeout?: number;
45
+ /**
46
+ * Minimum distance change in pixels to consider movement progress (default: 1 pixel)
47
+ *
48
+ * If the player moves less than this distance over the stuckTimeout period, they are considered stuck.
49
+ */
50
+ stuckThreshold?: number;
51
+ }
6
52
  export declare enum Frequency {
7
53
  Lowest = 600,
8
54
  Lower = 400,
@@ -21,34 +67,39 @@ export declare enum Speed {
21
67
  Faster = 7,
22
68
  Fastest = 10
23
69
  }
24
- /**
25
- * @title Move
26
- * @enum {Object}
27
- *
28
- * Move.right(repeat=1) | Movement of a number of pixels on the right
29
- * Move.left(repeat=1) | Movement of a number of pixels on the left
30
- * Move.up(repeat=1) | Movement of a number of pixels on the up
31
- * Move.down(repeat=1) | Movement of a number of pixels on the down
32
- * Move.random(repeat=1) | Movement of a number of pixels in a random direction
33
- * Move.towardPlayer(player, repeat=1) | Moves a number of pixels in the direction of the designated player
34
- * Move.awayFromPlayer(player, repeat=1) | Moves a number of pixels in the opposite direction of the designated player
35
- * Move.tileRight(repeat=1) | Movement of a number of tiles on the right
36
- * Move.tileLeft(repeat=1) | Movement of a number of tiles on the left
37
- * Move.tileUp(repeat=1) | Movement of a number of tiles on the up
38
- * Move.tileDown(repeat=1) | Movement of a number of tiles on the down
39
- * Move.tileRandom(repeat=1) | Movement of a number of tiles in a random direction
40
- * Move.tileTowardPlayer(player, repeat=1) | Moves a number of tiles in the direction of the designated player
41
- * Move.tileAwayFromPlayer(player, repeat=1) | Moves a number of tiles in the opposite direction of the designated player
42
- * Move.turnRight() | Turn to the right
43
- * Move.turnLeft() | Turn to the left
44
- * Move.turnUp() | Turn to the up
45
- * Move.turnDown() | Turn to the down
46
- * Move.turnRandom() | Turn to random direction
47
- * Move.turnAwayFromPlayer(player) | Turns in the opposite direction of the designated player
48
- * Move.turnTowardPlayer(player) | Turns in the direction of the designated player
49
- * @memberof Move
50
- * */
51
70
  declare class MoveList {
71
+ private static perlinNoise;
72
+ private static randomCounter;
73
+ private static callCounter;
74
+ private static playerMoveStates;
75
+ private static readonly STUCK_THRESHOLD;
76
+ /**
77
+ * Clears the movement state for a specific player
78
+ *
79
+ * Should be called when a player changes map or is destroyed to prevent
80
+ * memory leaks and stale stuck detection data.
81
+ *
82
+ * @param playerId - The ID of the player to clear state for
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // Clear state when player leaves map
87
+ * Move.clearPlayerState(player.id);
88
+ * ```
89
+ */
90
+ static clearPlayerState(playerId: string): void;
91
+ /**
92
+ * Clears all player movement states
93
+ *
94
+ * Useful for cleanup during server shutdown or when resetting game state.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * // Clear all states on server shutdown
99
+ * Move.clearAllPlayerStates();
100
+ * ```
101
+ */
102
+ static clearAllPlayerStates(): void;
52
103
  repeatMove(direction: Direction, repeat: number): Direction[];
53
104
  private repeatTileMove;
54
105
  right(repeat?: number): Direction[];
@@ -166,18 +217,77 @@ export declare function WithMoveManager<TBase extends PlayerCtor>(Base: TBase):
166
217
  * This interface defines the public API of the MoveManager mixin.
167
218
  */
168
219
  export interface IMoveManager {
169
- /** Whether the player passes through other players */
220
+ /**
221
+ * Whether the player passes through other players
222
+ *
223
+ * When `true`, the player can walk through other player entities without collision.
224
+ * This is useful for busy areas where players shouldn't block each other.
225
+ *
226
+ * @default true
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * // Disable player-to-player collision
231
+ * player.throughOtherPlayer = true;
232
+ *
233
+ * // Enable player-to-player collision
234
+ * player.throughOtherPlayer = false;
235
+ * ```
236
+ */
170
237
  throughOtherPlayer: boolean;
171
- /** Whether the player goes through events or other players */
238
+ /**
239
+ * Whether the player goes through all characters (players and events)
240
+ *
241
+ * When `true`, the player can walk through all character entities (both players and events)
242
+ * without collision. Walls and obstacles still block movement.
243
+ * This takes precedence over `throughOtherPlayer` and `throughEvent`.
244
+ *
245
+ * @default false
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * // Enable ghost mode - pass through all characters
250
+ * player.through = true;
251
+ *
252
+ * // Disable ghost mode
253
+ * player.through = false;
254
+ * ```
255
+ */
172
256
  through: boolean;
257
+ /**
258
+ * Whether the player passes through events (NPCs, objects)
259
+ *
260
+ * When `true`, the player can walk through event entities without collision.
261
+ * This is useful for NPCs that shouldn't block player movement.
262
+ *
263
+ * @default false
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * // Allow passing through events
268
+ * player.throughEvent = true;
269
+ *
270
+ * // Block passage through events
271
+ * player.throughEvent = false;
272
+ * ```
273
+ */
274
+ throughEvent: boolean;
173
275
  /** Frequency for movement timing (milliseconds between movements) */
174
276
  frequency: number;
277
+ /** Whether direction changes are locked (prevents automatic direction changes) */
278
+ directionFixed: boolean;
279
+ /** Whether animation changes are locked (prevents automatic animation changes) */
280
+ animationFixed: boolean;
175
281
  /**
176
282
  * Add a custom movement strategy to this entity
177
283
  *
284
+ * Returns a Promise that resolves when the movement completes.
285
+ *
178
286
  * @param strategy - The movement strategy to add
287
+ * @param options - Optional callbacks for movement lifecycle events
288
+ * @returns Promise that resolves when the movement completes
179
289
  */
180
- addMovement(strategy: MovementStrategy): void;
290
+ addMovement(strategy: MovementStrategy, options?: MovementOptions): Promise<void>;
181
291
  /**
182
292
  * Remove a specific movement strategy from this entity
183
293
  *
@@ -217,36 +327,48 @@ export interface IMoveManager {
217
327
  /**
218
328
  * Perform a dash movement in the specified direction
219
329
  *
330
+ * The total speed is calculated by adding the player's base speed to the additional speed.
331
+ * Returns a Promise that resolves when the dash completes.
332
+ *
220
333
  * @param direction - Normalized direction vector
221
- * @param speed - Movement speed (default: 8)
334
+ * @param additionalSpeed - Extra speed added on top of base speed (default: 4)
222
335
  * @param duration - Duration in milliseconds (default: 200)
336
+ * @param options - Optional callbacks for movement lifecycle events
337
+ * @returns Promise that resolves when the dash completes
223
338
  */
224
339
  dash(direction: {
225
340
  x: number;
226
341
  y: number;
227
- }, speed?: number, duration?: number): void;
342
+ }, additionalSpeed?: number, duration?: number, options?: MovementOptions): Promise<void>;
228
343
  /**
229
344
  * Apply knockback effect in the specified direction
230
345
  *
346
+ * The force is scaled by the player's base speed for consistent behavior.
347
+ * Returns a Promise that resolves when the knockback completes.
348
+ *
231
349
  * @param direction - Normalized direction vector
232
- * @param force - Initial knockback force (default: 5)
350
+ * @param force - Force multiplier applied to base speed (default: 5)
233
351
  * @param duration - Duration in milliseconds (default: 300)
352
+ * @param options - Optional callbacks for movement lifecycle events
353
+ * @returns Promise that resolves when the knockback completes
234
354
  */
235
355
  knockback(direction: {
236
356
  x: number;
237
357
  y: number;
238
- }, force?: number, duration?: number): void;
358
+ }, force?: number, duration?: number, options?: MovementOptions): Promise<void>;
239
359
  /**
240
360
  * Follow a sequence of waypoints
241
361
  *
362
+ * Speed is calculated from the player's base speed multiplied by the speedMultiplier.
363
+ *
242
364
  * @param waypoints - Array of x,y positions to follow
243
- * @param speed - Movement speed (default: 2)
365
+ * @param speedMultiplier - Multiplier applied to base speed (default: 0.5)
244
366
  * @param loop - Whether to loop back to start (default: false)
245
367
  */
246
368
  followPath(waypoints: Array<{
247
369
  x: number;
248
370
  y: number;
249
- }>, speed?: number, loop?: boolean): void;
371
+ }>, speedMultiplier?: number, loop?: boolean): void;
250
372
  /**
251
373
  * Apply oscillating movement pattern
252
374
  *
@@ -261,31 +383,36 @@ export interface IMoveManager {
261
383
  /**
262
384
  * Apply ice movement physics
263
385
  *
386
+ * Max speed is calculated from the player's base speed multiplied by the speedFactor.
387
+ *
264
388
  * @param direction - Target movement direction
265
- * @param maxSpeed - Maximum speed when fully accelerated (default: 4)
389
+ * @param speedFactor - Factor multiplied with base speed for max speed (default: 1.0)
266
390
  */
267
391
  applyIceMovement(direction: {
268
392
  x: number;
269
393
  y: number;
270
- }, maxSpeed?: number): void;
394
+ }, speedFactor?: number): void;
271
395
  /**
272
396
  * Shoot a projectile in the specified direction
273
397
  *
398
+ * Speed is calculated from the player's base speed multiplied by the speedFactor.
399
+ *
274
400
  * @param type - Type of projectile trajectory
275
401
  * @param direction - Normalized direction vector
276
- * @param speed - Projectile speed (default: 200)
402
+ * @param speedFactor - Factor multiplied with base speed (default: 50)
277
403
  */
278
404
  shootProjectile(type: ProjectileType, direction: {
279
405
  x: number;
280
406
  y: number;
281
- }, speed?: number): void;
407
+ }, speedFactor?: number): void;
282
408
  /**
283
409
  * Give an itinerary to follow using movement strategies
284
410
  *
285
411
  * @param routes - Array of movement instructions to execute
412
+ * @param options - Optional configuration including onStuck callback
286
413
  * @returns Promise that resolves when all routes are completed
287
414
  */
288
- moveRoutes(routes: Routes): Promise<boolean>;
415
+ moveRoutes(routes: Routes, options?: MoveRoutesOptions): Promise<boolean>;
289
416
  /**
290
417
  * Give a path that repeats itself in a loop to a character
291
418
  *
@@ -303,4 +430,3 @@ export interface IMoveManager {
303
430
  */
304
431
  replayRoutes(): void;
305
432
  }
306
- export {};
@@ -136,6 +136,8 @@ export declare class RpgPlayer extends RpgPlayer_base {
136
136
  * When `nbTimes` is set to a finite number, the animation will play that many times
137
137
  * before returning to the previous animation state.
138
138
  *
139
+ * If `animationFixed` is true, this method will not change the animation.
140
+ *
139
141
  * @param animationName - The name of the animation to play (e.g., 'attack', 'skill', 'walk')
140
142
  * @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
141
143
  *
@@ -147,8 +149,9 @@ export declare class RpgPlayer extends RpgPlayer_base {
147
149
  * // Play attack animation 3 times then return to previous state
148
150
  * player.setAnimation('attack', 3);
149
151
  *
150
- * // Play skill animation once
151
- * player.setAnimation('skill', 1);
152
+ * // Lock animation to prevent automatic changes
153
+ * player.animationFixed = true;
154
+ * player.setAnimation('skill'); // This will be ignored
152
155
  *
153
156
  * // Set idle/stand animation
154
157
  * player.setAnimation('stand');
@@ -459,10 +462,18 @@ export declare class RpgPlayer extends RpgPlayer_base {
459
462
  * @param schema - The schema to set
460
463
  */
461
464
  setSync(schema: any): void;
465
+ isEvent(): boolean;
462
466
  }
463
467
  export declare class RpgEvent extends RpgPlayer {
464
468
  execMethod(methodName: string, methodData?: any[], instance?: this): Promise<any>;
469
+ /**
470
+ * Remove this event from the map
471
+ *
472
+ * Stops all movements before removing to prevent "unable to resolve entity" errors
473
+ * from the MovementManager when the entity is destroyed while moving.
474
+ */
465
475
  remove(): void;
476
+ isEvent(): boolean;
466
477
  }
467
478
  /**
468
479
  * Interface extension for RpgPlayer
@@ -1,5 +1,124 @@
1
1
  import { PlayerCtor } from '../../../common/src';
2
2
  import { RpgPlayer } from './Player';
3
+ /**
4
+ * Type for skill class constructor
5
+ */
6
+ type SkillClass = {
7
+ new (...args: any[]): any;
8
+ };
9
+ /**
10
+ * Interface defining the hooks that can be implemented on skill classes or objects
11
+ *
12
+ * These hooks are called at specific moments during the skill lifecycle:
13
+ * - `onLearn`: When the skill is learned by the player
14
+ * - `onUse`: When the skill is successfully used
15
+ * - `onUseFailed`: When the skill usage fails (e.g., chance roll failed)
16
+ * - `onForget`: When the skill is forgotten
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const skillHooks: SkillHooks = {
21
+ * onLearn(player) {
22
+ * console.log('Skill learned!');
23
+ * },
24
+ * onUse(player, target) {
25
+ * console.log('Skill used on target');
26
+ * }
27
+ * };
28
+ * ```
29
+ */
30
+ export interface SkillHooks {
31
+ /**
32
+ * Called when the skill is learned by the player
33
+ *
34
+ * @param player - The player learning the skill
35
+ */
36
+ onLearn?: (player: RpgPlayer) => void | Promise<void>;
37
+ /**
38
+ * Called when the skill is successfully used
39
+ *
40
+ * @param player - The player using the skill
41
+ * @param target - The target player(s) if any
42
+ */
43
+ onUse?: (player: RpgPlayer, target?: RpgPlayer | RpgPlayer[]) => void | Promise<void>;
44
+ /**
45
+ * Called when the skill usage fails (e.g., chance roll failed)
46
+ *
47
+ * @param player - The player attempting to use the skill
48
+ * @param target - The intended target player(s) if any
49
+ */
50
+ onUseFailed?: (player: RpgPlayer, target?: RpgPlayer | RpgPlayer[]) => void | Promise<void>;
51
+ /**
52
+ * Called when the skill is forgotten
53
+ *
54
+ * @param player - The player forgetting the skill
55
+ */
56
+ onForget?: (player: RpgPlayer) => void | Promise<void>;
57
+ }
58
+ /**
59
+ * Interface for skill object definition
60
+ *
61
+ * Defines the properties that a skill can have when defined as an object.
62
+ * Skills can be defined as objects, classes, or string IDs referencing the database.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const fireSkill: SkillObject = {
67
+ * id: 'fire',
68
+ * name: 'Fire',
69
+ * description: 'A basic fire spell',
70
+ * spCost: 10,
71
+ * hitRate: 0.9,
72
+ * power: 50,
73
+ * onUse(player) {
74
+ * console.log('Fire spell cast!');
75
+ * }
76
+ * };
77
+ *
78
+ * player.learnSkill(fireSkill);
79
+ * ```
80
+ */
81
+ export interface SkillObject extends SkillHooks {
82
+ /**
83
+ * Unique identifier for the skill
84
+ * If not provided, one will be auto-generated
85
+ */
86
+ id?: string;
87
+ /**
88
+ * Display name of the skill
89
+ */
90
+ name?: string;
91
+ /**
92
+ * Description of the skill
93
+ */
94
+ description?: string;
95
+ /**
96
+ * SP (Skill Points) cost to use the skill
97
+ * @default 0
98
+ */
99
+ spCost?: number;
100
+ /**
101
+ * Hit rate (0-1) - probability of successful skill usage
102
+ * @default 1
103
+ */
104
+ hitRate?: number;
105
+ /**
106
+ * Base power of the skill for damage calculation
107
+ */
108
+ power?: number;
109
+ /**
110
+ * Coefficient multipliers for damage calculation
111
+ */
112
+ coefficient?: Record<string, number>;
113
+ /**
114
+ * Type marker for database
115
+ */
116
+ _type?: 'skill';
117
+ /**
118
+ * Allow additional properties
119
+ */
120
+ [key: string]: any;
121
+ }
3
122
  /**
4
123
  * Skill Manager Mixin
5
124
  *
@@ -7,21 +126,31 @@ import { RpgPlayer } from './Player';
7
126
  * learning, forgetting, and using skills, including SP cost management,
8
127
  * hit rate calculations, and skill effects application.
9
128
  *
129
+ * Supports three input formats for skills:
130
+ * - **String ID**: References a skill in the database
131
+ * - **Class**: A skill class that will be instantiated
132
+ * - **Object**: A skill object with properties and hooks
133
+ *
10
134
  * @param Base - The base class to extend with skill management
11
135
  * @returns Extended class with skill management methods
12
136
  *
13
137
  * @example
14
138
  * ```ts
15
- * class MyPlayer extends WithSkillManager(BasePlayer) {
16
- * constructor() {
17
- * super();
18
- * // Skill system is automatically initialized
19
- * }
20
- * }
139
+ * // Using string ID (from database)
140
+ * player.learnSkill('fire');
21
141
  *
22
- * const player = new MyPlayer();
23
- * player.learnSkill(Fire);
24
- * player.useSkill(Fire, targetPlayer);
142
+ * // Using skill class
143
+ * player.learnSkill(FireSkill);
144
+ *
145
+ * // Using skill object
146
+ * player.learnSkill({
147
+ * id: 'ice',
148
+ * name: 'Ice',
149
+ * spCost: 15,
150
+ * onUse(player) {
151
+ * console.log('Ice spell cast!');
152
+ * }
153
+ * });
25
154
  * ```
26
155
  */
27
156
  export declare function WithSkillManager<TBase extends PlayerCtor>(Base: TBase): TBase;
@@ -35,36 +164,42 @@ export interface ISkillManager {
35
164
  /**
36
165
  * Retrieves a learned skill. Returns null if not found
37
166
  *
38
- * @param skillClass - Skill class or data id
39
- * @returns Instance of SkillClass or null
167
+ * @param skillInput - Skill class, object, or data id
168
+ * @returns The skill data or null
40
169
  */
41
- getSkill(skillClass: any | string): any | null;
170
+ getSkill(skillInput: SkillClass | SkillObject | string): any | null;
42
171
  /**
43
172
  * Learn a skill
44
173
  *
45
- * @param skillId - Skill class or data id
46
- * @returns Instance of SkillClass
174
+ * Supports three input formats:
175
+ * - String ID: Retrieves from database
176
+ * - Class: Creates instance and adds to database
177
+ * - Object: Uses directly and adds to database
178
+ *
179
+ * @param skillInput - Skill class, object, or data id
180
+ * @returns The learned skill data
47
181
  * @throws SkillLog.alreadyLearned if the player already knows the skill
48
182
  */
49
- learnSkill(skillId: any | string): any;
183
+ learnSkill(skillInput: SkillClass | SkillObject | string): any;
50
184
  /**
51
185
  * Forget a skill
52
186
  *
53
- * @param skillId - Skill class or data id
54
- * @returns Instance of SkillClass
187
+ * @param skillInput - Skill class, object, or data id
188
+ * @returns The forgotten skill data
55
189
  * @throws SkillLog.notLearned if trying to forget a skill not learned
56
190
  */
57
- forgetSkill(skillId: any | string): any;
191
+ forgetSkill(skillInput: SkillClass | SkillObject | string): any;
58
192
  /**
59
- * Using a skill
193
+ * Use a skill
60
194
  *
61
- * @param skillId - Skill class or data id
195
+ * @param skillInput - Skill class, object, or data id
62
196
  * @param otherPlayer - Optional target player(s) to apply skill to
63
- * @returns Instance of SkillClass
197
+ * @returns The used skill data
64
198
  * @throws SkillLog.restriction if player has Effect.CAN_NOT_SKILL
65
199
  * @throws SkillLog.notLearned if player tries to use an unlearned skill
66
200
  * @throws SkillLog.notEnoughSp if player does not have enough SP
67
201
  * @throws SkillLog.chanceToUseFailed if the chance to use the skill has failed
68
202
  */
69
- useSkill(skillId: any | string, otherPlayer?: RpgPlayer | RpgPlayer[]): any;
203
+ useSkill(skillInput: SkillClass | SkillObject | string, otherPlayer?: RpgPlayer | RpgPlayer[]): any;
70
204
  }
205
+ export {};
package/dist/index.d.ts CHANGED
@@ -13,3 +13,4 @@ export * from './Gui';
13
13
  export { RpgShape, RpgModule } from '../../common/src';
14
14
  export * from './decorators/event';
15
15
  export * from './decorators/map';
16
+ export * from './Player/MoveManager';