@rpgjs/server 5.0.0-alpha.0 → 5.0.0-alpha.10

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.
Files changed (40) hide show
  1. package/dist/Player/BattleManager.d.ts +32 -22
  2. package/dist/Player/ClassManager.d.ts +31 -18
  3. package/dist/Player/ComponentManager.d.ts +60 -0
  4. package/dist/Player/EffectManager.d.ts +40 -0
  5. package/dist/Player/ElementManager.d.ts +31 -0
  6. package/dist/Player/GoldManager.d.ts +22 -0
  7. package/dist/Player/GuiManager.d.ts +176 -0
  8. package/dist/Player/ItemFixture.d.ts +6 -0
  9. package/dist/Player/ItemManager.d.ts +27 -13
  10. package/dist/Player/MoveManager.d.ts +31 -43
  11. package/dist/Player/ParameterManager.d.ts +27 -19
  12. package/dist/Player/Player.d.ts +123 -8
  13. package/dist/Player/SkillManager.d.ts +27 -19
  14. package/dist/Player/StateManager.d.ts +28 -35
  15. package/dist/Player/VariableManager.d.ts +30 -0
  16. package/dist/RpgServer.d.ts +224 -1
  17. package/dist/index.js +1097 -636
  18. package/dist/index.js.map +1 -1
  19. package/dist/rooms/map.d.ts +70 -1
  20. package/package.json +8 -8
  21. package/src/Player/BattleManager.ts +97 -38
  22. package/src/Player/ClassManager.ts +95 -35
  23. package/src/Player/ComponentManager.ts +64 -20
  24. package/src/Player/EffectManager.ts +110 -27
  25. package/src/Player/ElementManager.ts +126 -25
  26. package/src/Player/GoldManager.ts +32 -35
  27. package/src/Player/GuiManager.ts +187 -140
  28. package/src/Player/ItemFixture.ts +4 -5
  29. package/src/Player/ItemManager.ts +39 -26
  30. package/src/Player/MoveManager.ts +40 -31
  31. package/src/Player/ParameterManager.ts +35 -25
  32. package/src/Player/Player.ts +184 -39
  33. package/src/Player/SkillManager.ts +44 -23
  34. package/src/Player/StateManager.ts +210 -95
  35. package/src/Player/VariableManager.ts +180 -48
  36. package/src/RpgServer.ts +232 -1
  37. package/src/core/context.ts +1 -0
  38. package/src/rooms/map.ts +76 -8
  39. package/dist/Player/Event.d.ts +0 -0
  40. package/src/Player/Event.ts +0 -0
@@ -1,132 +1,45 @@
1
1
  import { RpgPlayer } from "./Player";
2
2
  import { Gui, DialogGui, MenuGui, ShopGui, NotificationGui } from "../Gui";
3
3
  import { DialogOptions, Choice } from "../Gui/DialogGui";
4
- import { Constructor, RpgCommonPlayer } from "@rpgjs/common";
4
+ import { Constructor, PlayerCtor } from "@rpgjs/common";
5
5
 
6
- export interface IGuiManager {
7
- emit: any;
8
- removeGui: (guiId: string, data?: any) => void;
9
- }
10
-
11
- export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
6
+ /**
7
+ * GUI Manager Mixin
8
+ *
9
+ * Provides graphical user interface management capabilities to any class. This mixin handles
10
+ * dialog boxes, menus, notifications, shops, and custom GUI components. It manages the
11
+ * complete GUI system including opening, closing, and data passing between client and server.
12
+ *
13
+ * @param Base - The base class to extend with GUI management
14
+ * @returns Extended class with GUI management methods
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * class MyPlayer extends WithGuiManager(BasePlayer) {
19
+ * constructor() {
20
+ * super();
21
+ * // GUI system is automatically initialized
22
+ * }
23
+ * }
24
+ *
25
+ * const player = new MyPlayer();
26
+ * await player.showText('Hello World!');
27
+ * player.callMainMenu();
28
+ * ```
29
+ */
30
+ export function WithGuiManager<TBase extends PlayerCtor>(
12
31
  Base: TBase
13
- ) {
14
- return class extends Base implements IGuiManager {
32
+ ): new (...args: ConstructorParameters<TBase>) => InstanceType<TBase> &
33
+ IGuiManager {
34
+ class GuiManagerMixin extends Base {
15
35
  _gui: { [id: string]: Gui } = {};
16
36
 
17
- /**
18
- * Show a text. This is a graphical interface already built. Opens the GUI named `rpg-dialog`
19
- *
20
- * ```ts
21
- * player.showText('Hello World')
22
- * ```
23
- *
24
- * The method returns a promise. It is resolved when the dialog box is closed.
25
- *
26
- * ```ts
27
- * await player.showText('Hello World')
28
- * // dialog box is closed, then ...
29
- * ```
30
- *
31
- * **Option: position**
32
- *
33
- * You can define how the dialog box is displayed:
34
- * - top
35
- * - middle
36
- * - bottom
37
- *
38
- * (bottom by default)
39
- *
40
- * ```ts
41
- * player.showText('Hello World', {
42
- * position: 'top'
43
- * })
44
- * ```
45
- *
46
- * **Option: fullWidth**
47
- *
48
- * `boolean` (true by default)
49
- *
50
- * Indicate that the dialog box will take the full width of the screen.
51
- *
52
- * ```ts
53
- * player.showText('Hello World', {
54
- * fullWidth: true
55
- * })
56
- * ```
57
- *
58
- * **Option: autoClose**
59
- *
60
- * `boolean` (false by default)
61
- *
62
- * If false, the user will have to press Enter to close the dialog box.
63
- *
64
- * ```ts
65
- * player.showText('Hello World', {
66
- * autoClose: true
67
- * })
68
- * ```
69
- *
70
- * **Option: typewriterEffect**
71
- *
72
- * `boolean` (true by default)
73
- *
74
- * Performs a typewriter effect
75
- *
76
- * ```ts
77
- * player.showText('Hello World', {
78
- * typewriterEffect: false
79
- * })
80
- * ```
81
- *
82
- * **Option: talkWith**
83
- *
84
- * `RpgPlayer` (nothing by default)
85
- *
86
- * If you specify the event or another player, the other player will stop his or her movement and look in the player's direction.
87
- *
88
- * ```ts
89
- * // Code in an event
90
- * player.showText('Hello World', {
91
- * talkWith: this
92
- * })
93
- * ```
94
- *
95
- * @title Show Text
96
- * @method player.showText(text,options)
97
- * @param {string} text
98
- * @param {object} [options] the different options, see usage below
99
- * @returns {Promise}
100
- * @memberof GuiManager
101
- */
102
37
  showText(msg: string, options: DialogOptions = {}): Promise<any> {
103
38
  const gui = new DialogGui(<any>this);
104
39
  this._gui[gui.id] = gui;
105
40
  return gui.openDialog(msg, options);
106
41
  }
107
42
 
108
- /**
109
- * Shows a dialog box with a choice. Opens the GUI named `rpg-dialog`
110
- *
111
- * ```ts
112
- * const choice = await player.showChoices('What color do you prefer?', [
113
- * { text: 'Black', value: 'black' },
114
- * { text: 'Rather the blue', value: 'blue' },
115
- * { text: 'I don\'t have a preference!', value: 'none' }
116
- * ])
117
- *
118
- * // If the player selects the first
119
- * console.log(choice) // { text: 'Black', value: 'black' }
120
- * ```
121
- *
122
- * @title Show Choices
123
- * @method player.showChoices(text,choices)
124
- * @param {string} text
125
- * @param {Array<{ text: string, value: any }>} choices
126
- * @param {object} [options] Same options as the openDialog method
127
- * @returns {Promise<Choice | null>}
128
- * @memberof GuiManager
129
- */
130
43
  showChoices(
131
44
  msg: string,
132
45
  choices: Choice[],
@@ -141,19 +54,6 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
141
54
  });
142
55
  }
143
56
 
144
- /**
145
- * Displays a notification . Opens the GUI named `rpg-notification`
146
- *
147
- * @title Displays a notification
148
- * @method player.showNotification()
149
- * @param {string} message - The message to display in the notification
150
- * @param {object} options - An object containing options for the notification
151
- * @param {number} options.time - The time to display the notification for (in ms). Default: 2000ms
152
- * @param {string} options.icon - The icon to display in the notification. Put the identifier of the spritesheet (defined on the client side)
153
- * @param {string} options.sound - The sound to play when the notification is shown. Set the sound ID (defined on the client side)
154
- * @returns {void}
155
- * @memberof GuiManager
156
- */
157
57
  showNotification(
158
58
  message: string,
159
59
  options: { time?: number; icon?: string; sound?: string } = {}
@@ -167,14 +67,6 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
167
67
  return gui.open(data);
168
68
  }
169
69
 
170
- /**
171
- * Calls main menu. Opens the GUI named `rpg-main-menu`
172
- *
173
- * @title Call Main Menu
174
- * @method player.callMainMenu()
175
- * @returns {void}
176
- * @memberof GuiManager
177
- */
178
70
  callMainMenu() {
179
71
  const gui = new MenuGui(<any>this);
180
72
  this._gui[gui.id] = gui;
@@ -253,11 +145,11 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
253
145
  }
254
146
  }
255
147
 
256
- private _attachedGui(players: RpgPlayer[] | RpgPlayer, display: boolean) {
148
+ _attachedGui(players: RpgPlayer[] | RpgPlayer, display: boolean) {
257
149
  if (!Array.isArray(players)) {
258
150
  players = [players] as RpgPlayer[];
259
151
  }
260
- this.emit("gui.tooltip", {
152
+ (this as any).emit("gui.tooltip", {
261
153
  players: (players as RpgPlayer[]).map((player) => player.id),
262
154
  display,
263
155
  });
@@ -313,5 +205,160 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
313
205
  const _players = players || this;
314
206
  this._attachedGui(_players as RpgPlayer[], false);
315
207
  }
316
- };
208
+ }
209
+
210
+ return GuiManagerMixin as unknown as any;
211
+ }
212
+
213
+ /**
214
+ * Interface for GUI management capabilities
215
+ * Defines the methods that will be available on the player
216
+ */
217
+ export interface IGuiManager {
218
+ /**
219
+ * Show a text. This is a graphical interface already built. Opens the GUI named `rpg-dialog`
220
+ *
221
+ * ```ts
222
+ * player.showText('Hello World')
223
+ * ```
224
+ *
225
+ * The method returns a promise. It is resolved when the dialog box is closed.
226
+ *
227
+ * ```ts
228
+ * await player.showText('Hello World')
229
+ * // dialog box is closed, then ...
230
+ * ```
231
+ *
232
+ * **Option: position**
233
+ *
234
+ * You can define how the dialog box is displayed:
235
+ * - top
236
+ * - middle
237
+ * - bottom
238
+ *
239
+ * (bottom by default)
240
+ *
241
+ * ```ts
242
+ * player.showText('Hello World', {
243
+ * position: 'top'
244
+ * })
245
+ * ```
246
+ *
247
+ * **Option: fullWidth**
248
+ *
249
+ * `boolean` (true by default)
250
+ *
251
+ * Indicate that the dialog box will take the full width of the screen.
252
+ *
253
+ * ```ts
254
+ * player.showText('Hello World', {
255
+ * fullWidth: true
256
+ * })
257
+ * ```
258
+ *
259
+ * **Option: autoClose**
260
+ *
261
+ * `boolean` (false by default)
262
+ *
263
+ * If false, the user will have to press Enter to close the dialog box.
264
+ *
265
+ * ```ts
266
+ * player.showText('Hello World', {
267
+ * autoClose: true
268
+ * })
269
+ * ```
270
+ *
271
+ * **Option: typewriterEffect**
272
+ *
273
+ * `boolean` (true by default)
274
+ *
275
+ * Performs a typewriter effect
276
+ *
277
+ * ```ts
278
+ * player.showText('Hello World', {
279
+ * typewriterEffect: false
280
+ * })
281
+ * ```
282
+ *
283
+ * **Option: talkWith**
284
+ *
285
+ * `RpgPlayer` (nothing by default)
286
+ *
287
+ * If you specify the event or another player, the other player will stop his or her movement and look in the player's direction.
288
+ *
289
+ * ```ts
290
+ * // Code in an event
291
+ * player.showText('Hello World', {
292
+ * talkWith: this
293
+ * })
294
+ * ```
295
+ *
296
+ * @title Show Text
297
+ * @method player.showText(text,options)
298
+ * @param {string} text
299
+ * @param {object} [options] the different options, see usage below
300
+ * @returns {Promise}
301
+ * @memberof GuiManager
302
+ */
303
+ showText(msg: string, options?: DialogOptions): Promise<any>;
304
+
305
+ /**
306
+ * Shows a dialog box with a choice. Opens the GUI named `rpg-dialog`
307
+ *
308
+ * ```ts
309
+ * const choice = await player.showChoices('What color do you prefer?', [
310
+ * { text: 'Black', value: 'black' },
311
+ * { text: 'Rather the blue', value: 'blue' },
312
+ * { text: 'I don\'t have a preference!', value: 'none' }
313
+ * ])
314
+ *
315
+ * // If the player selects the first
316
+ * console.log(choice) // { text: 'Black', value: 'black' }
317
+ * ```
318
+ *
319
+ * @title Show Choices
320
+ * @method player.showChoices(text,choices)
321
+ * @param {string} text
322
+ * @param {Array<{ text: string, value: any }>} choices
323
+ * @param {object} [options] Same options as the openDialog method
324
+ * @returns {Promise<Choice | null>}
325
+ * @memberof GuiManager
326
+ */
327
+ showChoices(
328
+ msg: string,
329
+ choices: Choice[],
330
+ options?: DialogOptions
331
+ ): Promise<Choice | null>;
332
+
333
+ /**
334
+ * Displays a notification . Opens the GUI named `rpg-notification`
335
+ *
336
+ * @title Displays a notification
337
+ * @method player.showNotification()
338
+ * @param {string} message - The message to display in the notification
339
+ * @param {object} options - An object containing options for the notification
340
+ * @param {number} options.time - The time to display the notification for (in ms). Default: 2000ms
341
+ * @param {string} options.icon - The icon to display in the notification. Put the identifier of the spritesheet (defined on the client side)
342
+ * @param {string} options.sound - The sound to play when the notification is shown. Set the sound ID (defined on the client side)
343
+ * @returns {void}
344
+ * @memberof GuiManager
345
+ */
346
+ showNotification(
347
+ message: string,
348
+ options?: { time?: number; icon?: string; sound?: string }
349
+ ): Promise<any>;
350
+ /**
351
+ * Calls main menu. Opens the GUI named `rpg-main-menu`
352
+ *
353
+ * @title Call Main Menu
354
+ * @method player.callMainMenu()
355
+ * @returns {void}
356
+ * @memberof GuiManager
357
+ */
358
+ callMainMenu(): void;
359
+ callShop(items: any[]): void;
360
+ gui(guiId: string): Gui;
361
+ removeGui(guiId: string, data?: any): void;
362
+ showAttachedGui(players?: RpgPlayer[] | RpgPlayer): void;
363
+ hideAttachedGui(players?: RpgPlayer[] | RpgPlayer): void;
317
364
  }
@@ -1,11 +1,10 @@
1
1
  import { ItemInstance } from "@rpgjs/database";
2
- import { RpgCommonPlayer, type Constructor } from "@rpgjs/common";
3
- export class ItemFixture {}
2
+ import { PlayerCtor } from "@rpgjs/common";
4
3
 
5
- export function WithItemFixture<TBase extends Constructor<RpgCommonPlayer>>(
4
+ export function WithItemFixture<TBase extends PlayerCtor>(
6
5
  Base: TBase
7
6
  ) {
8
- return class extends Base implements IItemFixture {
7
+ return class extends Base {
9
8
  protected getFeature(name, prop): any {
10
9
  const array = {};
11
10
  for (let item of this.equipments()) {
@@ -21,7 +20,7 @@ export function WithItemFixture<TBase extends Constructor<RpgCommonPlayer>>(
21
20
  }
22
21
  return Object.values(array);
23
22
  }
24
- };
23
+ } as unknown as TBase;
25
24
  }
26
25
 
27
26
  export interface ItemFixture {
@@ -1,4 +1,4 @@
1
- import { isInstanceOf, isString, Item, type Constructor } from "@rpgjs/common";
1
+ import { isInstanceOf, isString, Item, PlayerCtor, type Constructor } from "@rpgjs/common";
2
2
  import { RpgCommonPlayer, Matter } from "@rpgjs/common";
3
3
  import { ATK, PDEF, SDEF } from "../presets";
4
4
  import { ItemLog } from "../logs";
@@ -13,27 +13,34 @@ enum ClassHooks {
13
13
  canEquip = 'canEquip'
14
14
  }
15
15
 
16
- /**
17
- * Interface defining what MoveManager adds to a class
18
- */
19
- export interface IItemManager {
20
- databaseById(id: string): ItemClass;
21
- }
22
-
23
16
  type Inventory = { nb: number; item: ItemInstance };
24
17
 
25
18
  /**
26
- * Move Manager mixin
19
+ * Item Manager Mixin
27
20
  *
28
- * Adds methods to manage player movement
21
+ * Provides comprehensive item management capabilities to any class. This mixin handles
22
+ * inventory management, item usage, equipment, buying/selling, and item effects.
23
+ * It manages the complete item system including restrictions, transactions, and equipment.
29
24
  *
30
- * @param Base - The base class to extend
31
- * @returns A new class with move management capabilities
25
+ * @param Base - The base class to extend with item management
26
+ * @returns Extended class with item management methods
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * class MyPlayer extends WithItemManager(BasePlayer) {
31
+ * constructor() {
32
+ * super();
33
+ * // Item system is automatically initialized
34
+ * }
35
+ * }
36
+ *
37
+ * const player = new MyPlayer();
38
+ * player.addItem('potion', 5);
39
+ * player.useItem('potion');
40
+ * ```
32
41
  */
33
- export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
34
- Base: TBase
35
- ): Constructor<IItemManager> & TBase {
36
- return class extends Base implements IItemManager {
42
+ export function WithItemManager<TBase extends PlayerCtor>(Base: TBase) {
43
+ return class extends Base {
37
44
 
38
45
  /**
39
46
  * Retrieves the information of an object: the number and the instance
@@ -54,7 +61,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
54
61
  */
55
62
  getItem(itemClass: ItemClass | string): Item {
56
63
  const index: number = this._getItemIndex(itemClass);
57
- return this.items()[index];
64
+ return (this as any).items()[index];
58
65
  }
59
66
 
60
67
  /**
@@ -77,7 +84,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
77
84
  }
78
85
 
79
86
  _getItemIndex(itemClass: ItemClass | string): number {
80
- return this.items().findIndex((it: Item): boolean => {
87
+ return (this as any).items().findIndex((it: Item): boolean => {
81
88
  if (isString(itemClass)) {
82
89
  return it.id() == itemClass;
83
90
  }
@@ -103,8 +110,8 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
103
110
  * ```
104
111
  */
105
112
  addItem(itemId: string, nb: number = 1): Item {
106
- const data = this.databaseById(itemId);
107
- const item = this.items().find((it) => it.id() == itemId);
113
+ const data = (this as any).databaseById(itemId);
114
+ const item = (this as any).items().find((it) => it.id() == itemId);
108
115
  let instance: Item;
109
116
  if (item) {
110
117
  instance = item;
@@ -112,9 +119,9 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
112
119
  } else {
113
120
  instance = new Item(data);
114
121
  instance.id.set(itemId);
115
- this.items().push(instance);
122
+ (this as any).items().push(instance);
116
123
  }
117
- this["execMethod"]("onAdd", [this], instance);
124
+ (this as any)["execMethod"]("onAdd", [this], instance);
118
125
  return instance;
119
126
  }
120
127
 
@@ -210,7 +217,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
210
217
  * ```
211
218
  */
212
219
  buyItem(itemId: string, nb = 1): Item {
213
- const data = this.databaseById(itemId);
220
+ const data = (this as any).databaseById(itemId);
214
221
  if (!data.price) {
215
222
  throw ItemLog.haveNotPrice(itemId);
216
223
  }
@@ -272,7 +279,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
272
279
  * ```
273
280
  */
274
281
  sellItem(itemId: string, nbToSell = 1): Item {
275
- const data = this.databaseById(itemId);
282
+ const data = (this as any).databaseById(itemId);
276
283
  const inventory = this.getItem(itemId);
277
284
  if (!inventory) {
278
285
  throw ItemLog.notInInventory(itemId);
@@ -478,7 +485,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
478
485
  if (!inventory) {
479
486
  throw ItemLog.notInInventory(itemId);
480
487
  }
481
- const data = this.databaseById(itemId);
488
+ const data = (this as any).databaseById(itemId);
482
489
  if (data._type == "item") {
483
490
  throw ItemLog.invalidToEquiped(itemId);
484
491
  }
@@ -508,5 +515,11 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
508
515
  }
509
516
  this["execMethod"]("onEquip", [this, equip], item);
510
517
  }
511
- };
518
+ } as unknown as TBase;
512
519
  }
520
+
521
+ /**
522
+ * Type helper to extract the interface from the WithItemManager mixin
523
+ * This provides the type without duplicating method signatures
524
+ */
525
+ export type IItemManager = InstanceType<ReturnType<typeof WithItemManager>>;
@@ -1,4 +1,4 @@
1
- import { type Constructor } from "@rpgjs/common";
1
+ import { PlayerCtor, type Constructor } from "@rpgjs/common";
2
2
  import { RpgCommonPlayer, Matter, Direction } from "@rpgjs/common";
3
3
  import {
4
4
  MovementManager,
@@ -34,26 +34,7 @@ interface PlayerWithMixins extends RpgCommonPlayer {
34
34
  changeDirection: (direction: Direction) => boolean;
35
35
  }
36
36
 
37
- export interface IMoveManager {
38
- addMovement(strategy: MovementStrategy): void;
39
- removeMovement(strategy: MovementStrategy): boolean;
40
- clearMovements(): void;
41
- hasActiveMovements(): boolean;
42
- getActiveMovements(): MovementStrategy[];
43
-
44
- moveTo(target: RpgCommonPlayer | { x: number, y: number }): void;
45
- stopMoveTo(): void;
46
- dash(direction: { x: number, y: number }, speed?: number, duration?: number): void;
47
- knockback(direction: { x: number, y: number }, force?: number, duration?: number): void;
48
- followPath(waypoints: Array<{ x: number, y: number }>, speed?: number, loop?: boolean): void;
49
- oscillate(direction: { x: number, y: number }, amplitude?: number, period?: number): void;
50
- applyIceMovement(direction: { x: number, y: number }, maxSpeed?: number): void;
51
- shootProjectile(type: ProjectileType, direction: { x: number, y: number }, speed?: number): void;
52
- moveRoutes(routes: Routes): Promise<boolean>;
53
- infiniteMoveRoute(routes: Routes): void;
54
- breakRoutes(force?: boolean): void;
55
- replayRoutes(): void;
56
- }
37
+
57
38
 
58
39
 
59
40
  function wait(sec: number) {
@@ -475,15 +456,37 @@ export const Move = new MoveList();
475
456
  * }
476
457
  * ```
477
458
  */
478
- export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
479
- Base: TBase
480
- ): Constructor<IMoveManager> & TBase {
481
- return class extends Base implements IMoveManager {
459
+ /**
460
+ * Move Manager Mixin
461
+ *
462
+ * Provides comprehensive movement management capabilities to any class. This mixin handles
463
+ * various types of movement including pathfinding, physics-based movement, route following,
464
+ * and advanced movement strategies like dashing, knockback, and projectile movement.
465
+ *
466
+ * @param Base - The base class to extend with movement management
467
+ * @returns Extended class with movement management methods
468
+ *
469
+ * @example
470
+ * ```ts
471
+ * class MyPlayer extends WithMoveManager(BasePlayer) {
472
+ * constructor() {
473
+ * super();
474
+ * this.frequency = Frequency.High;
475
+ * }
476
+ * }
477
+ *
478
+ * const player = new MyPlayer();
479
+ * player.moveTo({ x: 100, y: 100 });
480
+ * player.dash({ x: 1, y: 0 }, 8, 200);
481
+ * ```
482
+ */
483
+ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
484
+ return class extends Base {
482
485
 
483
- // Private properties for infinite route management
484
- private _infiniteRoutes: Routes | null = null;
485
- private _finishRoute: ((value: boolean) => void) | null = null;
486
- private _isInfiniteRouteActive: boolean = false;
486
+ // Properties for infinite route management
487
+ _infiniteRoutes: Routes | null = null;
488
+ _finishRoute: ((value: boolean) => void) | null = null;
489
+ _isInfiniteRouteActive: boolean = false;
487
490
 
488
491
  /**
489
492
  * The player passes through the other players (or vice versa). But the player does not go through the events.
@@ -1097,7 +1100,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1097
1100
  * @param routes - Routes array that may contain nested arrays
1098
1101
  * @returns Flattened array of routes
1099
1102
  */
1100
- private flattenRoutes(routes: any[]): any[] {
1103
+ flattenRoutes(routes: any[]): any[] {
1101
1104
  const result: any[] = [];
1102
1105
 
1103
1106
  for (const route of routes) {
@@ -1241,5 +1244,11 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1241
1244
  this.infiniteMoveRoute(this._infiniteRoutes);
1242
1245
  }
1243
1246
  }
1244
- };
1247
+ } as unknown as TBase;
1245
1248
  }
1249
+
1250
+ /**
1251
+ * Type helper to extract the interface from the WithMoveManager mixin
1252
+ * This provides the type without duplicating method signatures
1253
+ */
1254
+ export type IMoveManager = InstanceType<ReturnType<typeof WithMoveManager>>;