@rpgjs/server 5.0.0-alpha.5 → 5.0.0-alpha.7

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,17 +1,47 @@
1
- import { arrayUniq, RpgCommonPlayer } from "@rpgjs/common";
1
+ import { arrayUniq, PlayerCtor, RpgCommonPlayer } from "@rpgjs/common";
2
2
  import { Constructor } from "@rpgjs/common";
3
3
  import { RpgPlayer } from "./Player";
4
4
 
5
- export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
6
- Base: TBase
7
- ) {
8
- return class extends Base implements IWithElementManager {
5
+ /**
6
+ * Element Manager Mixin
7
+ *
8
+ * Provides elemental management capabilities to any class. This mixin handles
9
+ * elemental resistances, vulnerabilities, and attack elements. It manages both
10
+ * defensive capabilities (elementsDefense) and offensive elements from equipment,
11
+ * as well as player-specific elemental efficiency modifiers.
12
+ *
13
+ * @param Base - The base class to extend with element management
14
+ * @returns Extended class with element management methods
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * class MyPlayer extends WithElementManager(BasePlayer) {
19
+ * constructor() {
20
+ * super();
21
+ * this.elementsEfficiency = [{ rate: 0.5, element: 'fire' }];
22
+ * }
23
+ * }
24
+ *
25
+ * const player = new MyPlayer();
26
+ * const fireResistance = player.elementsDefense.find(e => e.element === 'fire');
27
+ * ```
28
+ */
29
+ export function WithElementManager<TBase extends PlayerCtor>(Base: TBase) {
30
+ return class extends Base {
9
31
  _elementsEfficiency: { rate: number; element: any }[] = [];
10
32
 
11
33
  /**
12
34
  * Recovers the player's elements defense on inventory. This list is generated from the `elementsDefense` property defined on the weapons or armors equipped.
13
35
  * If several items have the same element, only the highest rate will be taken into account.
14
36
  *
37
+ * Gets the defensive capabilities against various elements from equipped items.
38
+ * The system automatically consolidates multiple defensive items, keeping only
39
+ * the highest protection rate for each element type. This provides a comprehensive
40
+ * view of the player's elemental resistances from all equipped gear.
41
+ *
42
+ * @returns Array of element defense objects with rate and element properties
43
+ *
44
+ * @example
15
45
  * ```ts
16
46
  * import { Armor } from '@rpgjs/server'
17
47
  *
@@ -37,19 +67,29 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
37
67
  * player.equip(FireShield)
38
68
  *
39
69
  * console.log(player.elementsDefense) // [{ rate: 1, element: 'fire' }]
70
+ *
71
+ * // Check specific element defense
72
+ * const fireDefense = player.elementsDefense.find(def => def.element === 'fire');
73
+ * if (fireDefense) {
74
+ * console.log(`Fire defense rate: ${fireDefense.rate}`);
75
+ * }
40
76
  * ```
41
- * @title Get Elements Defense
42
- * @prop {Array<{ rate: number, element: Element}>} player.elementsDefense
43
- * @readonly
44
- * @memberof ElementManager
45
- * */
77
+ */
46
78
  get elementsDefense(): { rate: number; element: any }[] {
47
- return this.getFeature("elementsDefense", "element");
79
+ return (this as any).getFeature("elementsDefense", "element");
48
80
  }
49
81
 
50
82
  /**
51
83
  * Set or retrieves all the elements where the player is vulnerable or not.
52
84
  *
85
+ * Manages the player's elemental efficiency modifiers, which determine how
86
+ * effective different elements are against this player. Values greater than 1
87
+ * indicate vulnerability, while values less than 1 indicate resistance.
88
+ * This combines both class-based efficiency and player-specific modifiers.
89
+ *
90
+ * @returns Array of element efficiency objects with rate and element properties
91
+ *
92
+ * @example
53
93
  * ```ts
54
94
  * import { Class } from '@rpgjs/server'
55
95
  *
@@ -71,13 +111,18 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
71
111
  * player.elementsEfficiency = [{ rate: 2, element: Elements.Ice }]
72
112
  *
73
113
  * console.log(player.elementsEfficiency) // [{ rate: 1, element: 'fire' }, { rate: 2, element: 'ice' }]
114
+ *
115
+ * // Check for vulnerabilities
116
+ * const vulnerabilities = player.elementsEfficiency.filter(eff => eff.rate > 1);
117
+ * console.log('Vulnerable to:', vulnerabilities.map(v => v.element));
118
+ *
119
+ * // Check for resistances
120
+ * const resistances = player.elementsEfficiency.filter(eff => eff.rate < 1);
121
+ * console.log('Resistant to:', resistances.map(r => r.element));
74
122
  * ```
75
- * @title Set/Get Elements Efficiency
76
- * @prop {Array<{ rate: number, element: Element}>} player.elementsEfficiency
77
- * @memberof ElementManager
78
- * */
123
+ */
79
124
  get elementsEfficiency(): { rate: number; element: any }[] {
80
- if (this._class) {
125
+ if (this._class()) {
81
126
  return <any>[
82
127
  ...this._elementsEfficiency,
83
128
  ...(this._class()?.elementsEfficiency || []),
@@ -93,14 +138,30 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
93
138
  /**
94
139
  * Retrieves a array of elements assigned to the player and the elements of the weapons / armor equipped
95
140
  *
141
+ * Gets all offensive elements available to the player from equipped weapons and armor.
142
+ * This determines what elemental damage types the player can deal in combat.
143
+ * The system automatically combines elements from all equipped items and removes duplicates.
144
+ *
145
+ * @returns Array of element objects with rate and element properties for offensive capabilities
146
+ *
147
+ * @example
96
148
  * ```ts
97
- * console.log(player.elements)
149
+ * // Get all offensive elements
150
+ * console.log(player.elements); // [{ rate: 1.5, element: 'fire' }, { rate: 1.2, element: 'ice' }]
151
+ *
152
+ * // Check if player can deal fire damage
153
+ * const hasFireElement = player.elements.some(el => el.element === 'fire');
154
+ * if (hasFireElement) {
155
+ * console.log('Player can deal fire damage');
156
+ * }
157
+ *
158
+ * // Get strongest element
159
+ * const strongestElement = player.elements.reduce((max, current) =>
160
+ * current.rate > max.rate ? current : max
161
+ * );
162
+ * console.log(`Strongest element: ${strongestElement.element} (${strongestElement.rate})`);
98
163
  * ```
99
- * @title Get Elements
100
- * @prop {Array<Element>} player.elements
101
- * @readonly
102
- * @memberof ElementManager
103
- * */
164
+ */
104
165
  get elements(): {
105
166
  rate: number;
106
167
  element: string;
@@ -114,8 +175,42 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
114
175
  return arrayUniq(elements);
115
176
  }
116
177
 
178
+ /**
179
+ * Calculate elemental damage coefficient against another player
180
+ *
181
+ * Determines the damage multiplier when this player attacks another player,
182
+ * taking into account the attacker's offensive elements, the defender's
183
+ * elemental efficiency, and elemental defense from equipment. This is used
184
+ * in the battle system to calculate elemental damage modifiers.
185
+ *
186
+ * @param otherPlayer - The target player to calculate coefficient against
187
+ * @returns Numerical coefficient to multiply base damage by
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * // Calculate elemental damage coefficient
192
+ * const firePlayer = new MyPlayer();
193
+ * const icePlayer = new MyPlayer();
194
+ *
195
+ * // Fire player attacks ice player (assuming ice is weak to fire)
196
+ * const coefficient = icePlayer.coefficientElements(firePlayer);
197
+ * console.log(`Damage multiplier: ${coefficient}`); // e.g., 2.0 for double damage
198
+ *
199
+ * // Use in damage calculation
200
+ * const baseDamage = 100;
201
+ * const finalDamage = baseDamage * coefficient;
202
+ * console.log(`Final damage: ${finalDamage}`);
203
+ *
204
+ * // Check for elemental advantage
205
+ * if (coefficient > 1) {
206
+ * console.log('Attacker has elemental advantage!');
207
+ * } else if (coefficient < 1) {
208
+ * console.log('Defender resists this element');
209
+ * }
210
+ * ```
211
+ */
117
212
  coefficientElements(otherPlayer: RpgPlayer): number {
118
- const atkPlayerElements: any = otherPlayer.elements;
213
+ const atkPlayerElements: any = (otherPlayer as any).elements;
119
214
  const playerElements: any = this.elementsEfficiency;
120
215
  let coefficient = 1;
121
216
 
@@ -127,7 +222,7 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
127
222
  (el) => el.element == atkElement.element
128
223
  );
129
224
  if (!elementPlayer) continue;
130
- const fn = this.getFormulas("coefficientElements");
225
+ const fn = (this as any).getFormulas("coefficientElements");
131
226
  if (!fn) {
132
227
  return coefficient;
133
228
  }
@@ -139,5 +234,11 @@ export function WithElementManager<TBase extends Constructor<RpgCommonPlayer>>(
139
234
  }
140
235
  return coefficient;
141
236
  }
142
- };
237
+ } as unknown as TBase;
143
238
  }
239
+
240
+ /**
241
+ * Type helper to extract the interface from the WithElementManager mixin
242
+ * This provides the type without duplicating method signatures
243
+ */
244
+ export type IElementManager = InstanceType<ReturnType<typeof WithElementManager>>;
@@ -1,44 +1,41 @@
1
- import { type Constructor } from "@rpgjs/common";
2
- import { RpgCommonPlayer } from "@rpgjs/common";
1
+ import { PlayerCtor } from "@rpgjs/common";
3
2
 
4
- /**
5
- * Interface defining what MoveManager adds to a class
6
- */
7
- export interface IGoldManager {
8
-
3
+ export interface GoldManager {
4
+ /**
5
+ * You can change the game money
6
+ *
7
+ * ```ts
8
+ * player.gold += 100
9
+ * ```
10
+ *
11
+ * @title Change Gold
12
+ * @prop {number} player.gold
13
+ * @default 0
14
+ * @memberof GoldManager
15
+ * */
16
+ gold: number;
9
17
  }
10
18
 
11
- /**
12
- * Move Manager mixin
13
- *
14
- * Adds methods to manage player gold
15
- *
16
- * @param Base - The base class to extend
17
- * @returns A new class with gold management capabilities
18
- */
19
- export function WithGoldManager<TBase extends Constructor<RpgCommonPlayer>>(Base: TBase) {
20
- return class extends Base implements IGoldManager {
21
- /**
22
- * You can change the game money
23
- *
24
- * ```ts
25
- * player.gold += 100
26
- * ```
27
- *
28
- * @title Change Gold
29
- * @prop {number} player.gold
30
- * @default 0
31
- * @memberof GoldManager
32
- * */
19
+ export function WithGoldManager<TBase extends PlayerCtor>(
20
+ Base: TBase
21
+ ): new (...args: ConstructorParameters<TBase>) => InstanceType<TBase> &
22
+ GoldManager {
23
+ return class extends Base {
33
24
  set gold(val: number) {
34
- if (val < 0) {
35
- val = 0
36
- }
37
- this._gold.set(val)
25
+ if (val < 0) {
26
+ val = 0;
27
+ }
28
+ this._gold.set(val);
38
29
  }
39
30
 
40
31
  get gold(): number {
41
- return this._gold()
32
+ return this._gold();
42
33
  }
43
- };
34
+ } as unknown as any;
44
35
  }
36
+
37
+ /**
38
+ * Type helper to extract the interface from the WithGoldManager mixin
39
+ * This provides the type without duplicating method signatures
40
+ */
41
+ export type IGoldManager = InstanceType<ReturnType<typeof WithGoldManager>>;
@@ -1,17 +1,34 @@
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 { 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>>(
12
- Base: TBase
13
- ) {
14
- return class extends Base implements IGuiManager {
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>(Base: TBase) {
31
+ return class extends Base {
15
32
  _gui: { [id: string]: Gui } = {};
16
33
 
17
34
  /**
@@ -253,11 +270,11 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
253
270
  }
254
271
  }
255
272
 
256
- private _attachedGui(players: RpgPlayer[] | RpgPlayer, display: boolean) {
273
+ _attachedGui(players: RpgPlayer[] | RpgPlayer, display: boolean) {
257
274
  if (!Array.isArray(players)) {
258
275
  players = [players] as RpgPlayer[];
259
276
  }
260
- this.emit("gui.tooltip", {
277
+ (this as any).emit("gui.tooltip", {
261
278
  players: (players as RpgPlayer[]).map((player) => player.id),
262
279
  display,
263
280
  });
@@ -313,5 +330,11 @@ export function WithGuiManager<TBase extends Constructor<RpgCommonPlayer>>(
313
330
  const _players = players || this;
314
331
  this._attachedGui(_players as RpgPlayer[], false);
315
332
  }
316
- };
333
+ } as unknown as TBase;
317
334
  }
335
+
336
+ /**
337
+ * Type helper to extract the interface from the WithGuiManager mixin
338
+ * This provides the type without duplicating method signatures
339
+ */
340
+ export type IGuiManager = InstanceType<ReturnType<typeof WithGuiManager>>;
@@ -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>>;