@rpgjs/server 5.0.0-alpha.2 → 5.0.0-alpha.21

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 (53) hide show
  1. package/dist/Gui/DialogGui.d.ts +4 -0
  2. package/dist/Gui/index.d.ts +1 -0
  3. package/dist/Player/BattleManager.d.ts +32 -22
  4. package/dist/Player/ClassManager.d.ts +31 -18
  5. package/dist/Player/ComponentManager.d.ts +123 -0
  6. package/dist/Player/Components.d.ts +345 -0
  7. package/dist/Player/EffectManager.d.ts +40 -0
  8. package/dist/Player/ElementManager.d.ts +31 -0
  9. package/dist/Player/GoldManager.d.ts +22 -0
  10. package/dist/Player/GuiManager.d.ts +176 -0
  11. package/dist/Player/ItemFixture.d.ts +6 -0
  12. package/dist/Player/ItemManager.d.ts +164 -10
  13. package/dist/Player/MoveManager.d.ts +32 -44
  14. package/dist/Player/ParameterManager.d.ts +343 -14
  15. package/dist/Player/Player.d.ts +266 -8
  16. package/dist/Player/SkillManager.d.ts +27 -19
  17. package/dist/Player/StateManager.d.ts +28 -35
  18. package/dist/Player/VariableManager.d.ts +30 -0
  19. package/dist/RpgServer.d.ts +227 -1
  20. package/dist/decorators/event.d.ts +46 -0
  21. package/dist/decorators/map.d.ts +177 -0
  22. package/dist/index.d.ts +6 -0
  23. package/dist/index.js +17472 -18167
  24. package/dist/index.js.map +1 -1
  25. package/dist/rooms/map.d.ts +486 -8
  26. package/package.json +17 -15
  27. package/src/Gui/DialogGui.ts +7 -2
  28. package/src/Gui/index.ts +3 -1
  29. package/src/Player/BattleManager.ts +97 -38
  30. package/src/Player/ClassManager.ts +95 -35
  31. package/src/Player/ComponentManager.ts +425 -19
  32. package/src/Player/Components.ts +380 -0
  33. package/src/Player/EffectManager.ts +110 -27
  34. package/src/Player/ElementManager.ts +126 -25
  35. package/src/Player/GoldManager.ts +32 -35
  36. package/src/Player/GuiManager.ts +187 -140
  37. package/src/Player/ItemFixture.ts +4 -5
  38. package/src/Player/ItemManager.ts +363 -48
  39. package/src/Player/MoveManager.ts +323 -308
  40. package/src/Player/ParameterManager.ts +499 -99
  41. package/src/Player/Player.ts +719 -80
  42. package/src/Player/SkillManager.ts +44 -23
  43. package/src/Player/StateManager.ts +210 -95
  44. package/src/Player/VariableManager.ts +180 -48
  45. package/src/RpgServer.ts +236 -1
  46. package/src/core/context.ts +1 -0
  47. package/src/decorators/event.ts +61 -0
  48. package/src/decorators/map.ts +198 -0
  49. package/src/index.ts +7 -1
  50. package/src/module.ts +24 -0
  51. package/src/rooms/map.ts +1054 -54
  52. package/dist/Player/Event.d.ts +0 -0
  53. package/src/Player/Event.ts +0 -0
@@ -1,7 +1,6 @@
1
- import { type Constructor } from "@rpgjs/common";
2
- import { RpgCommonPlayer, Matter, Direction } from "@rpgjs/common";
3
- import {
4
- MovementManager,
1
+ import { PlayerCtor, ProjectileType } from "@rpgjs/common";
2
+ import { RpgCommonPlayer, Direction, Entity } from "@rpgjs/common";
3
+ import {
5
4
  MovementStrategy,
6
5
  LinearMove,
7
6
  Dash,
@@ -13,7 +12,6 @@ import {
13
12
  LinearRepulsion,
14
13
  IceMovement,
15
14
  ProjectileMovement,
16
- ProjectileType,
17
15
  random,
18
16
  isFunction,
19
17
  capitalize
@@ -34,31 +32,10 @@ interface PlayerWithMixins extends RpgCommonPlayer {
34
32
  changeDirection: (direction: Direction) => boolean;
35
33
  }
36
34
 
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
- }
57
-
58
35
 
59
36
  function wait(sec: number) {
60
37
  return new Promise((resolve) => {
61
- setTimeout(resolve, sec * 1000)
38
+ setTimeout(resolve, sec * 1000)
62
39
  })
63
40
  }
64
41
 
@@ -116,297 +93,297 @@ export enum Speed {
116
93
  class MoveList {
117
94
 
118
95
  repeatMove(direction: Direction, repeat: number): Direction[] {
119
- // Safety check for valid repeat value
120
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
121
- console.warn('Invalid repeat value:', repeat, 'using default value 1');
122
- repeat = 1;
96
+ // Safety check for valid repeat value
97
+ if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
98
+ console.warn('Invalid repeat value:', repeat, 'using default value 1');
99
+ repeat = 1;
100
+ }
101
+
102
+ // Ensure repeat is an integer
103
+ repeat = Math.floor(repeat);
104
+
105
+ // Additional safety check - ensure repeat is a safe integer
106
+ if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
107
+ console.warn('Unsafe repeat value:', repeat, 'using default value 1');
108
+ repeat = 1;
109
+ }
110
+
111
+ try {
112
+ return new Array(repeat).fill(direction);
113
+ } catch (error) {
114
+ console.error('Error creating array with repeat:', repeat, error);
115
+ return [direction]; // Return single direction as fallback
116
+ }
117
+ }
118
+
119
+ private repeatTileMove(direction: string, repeat: number, propMap: string): CallbackTileMove {
120
+ return (player: RpgPlayer, map): Direction[] => {
121
+ const playerSpeed = typeof player.speed === 'function' ? player.speed() : player.speed;
122
+
123
+ // Safety checks
124
+ if (!playerSpeed || playerSpeed <= 0) {
125
+ console.warn('Invalid player speed:', playerSpeed, 'using default speed 3');
126
+ return this[direction](repeat);
123
127
  }
124
-
125
- // Ensure repeat is an integer
126
- repeat = Math.floor(repeat);
127
-
128
- // Additional safety check - ensure repeat is a safe integer
129
- if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
130
- console.warn('Unsafe repeat value:', repeat, 'using default value 1');
131
- repeat = 1;
128
+
129
+ const repeatTile = Math.floor((map[propMap] || 32) / playerSpeed) * repeat;
130
+
131
+ // Additional safety check for the calculated repeat value
132
+ if (!Number.isFinite(repeatTile) || repeatTile < 0 || repeatTile > 10000) {
133
+ console.warn('Calculated repeatTile is invalid:', repeatTile, 'using original repeat:', repeat);
134
+ return this[direction](repeat);
132
135
  }
133
-
134
- try {
135
- return new Array(repeat).fill(direction);
136
- } catch (error) {
137
- console.error('Error creating array with repeat:', repeat, error);
138
- return [direction]; // Return single direction as fallback
136
+
137
+ // Final safety check before calling the method
138
+ if (!Number.isSafeInteger(repeatTile)) {
139
+ console.warn('repeatTile is not a safe integer:', repeatTile, 'using original repeat:', repeat);
140
+ return this[direction](repeat);
139
141
  }
140
- }
141
142
 
142
- private repeatTileMove(direction: string, repeat: number, propMap: string): CallbackTileMove {
143
- return (player: RpgPlayer, map): Direction[] => {
144
- const playerSpeed = typeof player.speed === 'function' ? player.speed() : player.speed;
145
-
146
- // Safety checks
147
- if (!playerSpeed || playerSpeed <= 0) {
148
- console.warn('Invalid player speed:', playerSpeed, 'using default speed 3');
149
- return this[direction](repeat);
150
- }
151
-
152
- const repeatTile = Math.floor((map[propMap] || 32) / playerSpeed) * repeat;
153
-
154
- // Additional safety check for the calculated repeat value
155
- if (!Number.isFinite(repeatTile) || repeatTile < 0 || repeatTile > 10000) {
156
- console.warn('Calculated repeatTile is invalid:', repeatTile, 'using original repeat:', repeat);
157
- return this[direction](repeat);
158
- }
159
-
160
- // Final safety check before calling the method
161
- if (!Number.isSafeInteger(repeatTile)) {
162
- console.warn('repeatTile is not a safe integer:', repeatTile, 'using original repeat:', repeat);
163
- return this[direction](repeat);
164
- }
165
-
166
- try {
167
- return this[direction](repeatTile);
168
- } catch (error) {
169
- console.error('Error calling direction method with repeatTile:', repeatTile, error);
170
- return this[direction](repeat); // Fallback to original repeat
171
- }
143
+ try {
144
+ return this[direction](repeatTile);
145
+ } catch (error) {
146
+ console.error('Error calling direction method with repeatTile:', repeatTile, error);
147
+ return this[direction](repeat); // Fallback to original repeat
172
148
  }
149
+ }
173
150
  }
174
151
 
175
152
  right(repeat: number = 1): Direction[] {
176
- return this.repeatMove(Direction.Right, repeat)
153
+ return this.repeatMove(Direction.Right, repeat)
177
154
  }
178
155
 
179
156
  left(repeat: number = 1): Direction[] {
180
- return this.repeatMove(Direction.Left, repeat)
157
+ return this.repeatMove(Direction.Left, repeat)
181
158
  }
182
159
 
183
160
  up(repeat: number = 1): Direction[] {
184
- return this.repeatMove(Direction.Up, repeat)
161
+ return this.repeatMove(Direction.Up, repeat)
185
162
  }
186
163
 
187
164
  down(repeat: number = 1): Direction[] {
188
- return this.repeatMove(Direction.Down, repeat)
165
+ return this.repeatMove(Direction.Down, repeat)
189
166
  }
190
167
 
191
168
  wait(sec: number): Promise<unknown> {
192
- return wait(sec)
169
+ return wait(sec)
193
170
  }
194
171
 
195
172
  random(repeat: number = 1): Direction[] {
196
- // Safety check for valid repeat value
197
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
198
- console.warn('Invalid repeat value in random:', repeat, 'using default value 1');
199
- repeat = 1;
200
- }
201
-
202
- // Ensure repeat is an integer
203
- repeat = Math.floor(repeat);
204
-
205
- // Additional safety check - ensure repeat is a safe integer
206
- if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
207
- console.warn('Unsafe repeat value in random:', repeat, 'using default value 1');
208
- repeat = 1;
209
- }
210
-
211
- try {
212
- return new Array(repeat).fill(null).map(() => [
213
- Direction.Right,
214
- Direction.Left,
215
- Direction.Up,
216
- Direction.Down
217
- ][random(0, 3)]);
218
- } catch (error) {
219
- console.error('Error creating random array with repeat:', repeat, error);
220
- return [Direction.Down]; // Return single direction as fallback
221
- }
173
+ // Safety check for valid repeat value
174
+ if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
175
+ console.warn('Invalid repeat value in random:', repeat, 'using default value 1');
176
+ repeat = 1;
177
+ }
178
+
179
+ // Ensure repeat is an integer
180
+ repeat = Math.floor(repeat);
181
+
182
+ // Additional safety check - ensure repeat is a safe integer
183
+ if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
184
+ console.warn('Unsafe repeat value in random:', repeat, 'using default value 1');
185
+ repeat = 1;
186
+ }
187
+
188
+ try {
189
+ return new Array(repeat).fill(null).map(() => [
190
+ Direction.Right,
191
+ Direction.Left,
192
+ Direction.Up,
193
+ Direction.Down
194
+ ][random(0, 3)]);
195
+ } catch (error) {
196
+ console.error('Error creating random array with repeat:', repeat, error);
197
+ return [Direction.Down]; // Return single direction as fallback
198
+ }
222
199
  }
223
200
 
224
201
  tileRight(repeat: number = 1): CallbackTileMove {
225
- return this.repeatTileMove('right', repeat, 'tileWidth')
202
+ return this.repeatTileMove('right', repeat, 'tileWidth')
226
203
  }
227
204
 
228
205
  tileLeft(repeat: number = 1): CallbackTileMove {
229
- return this.repeatTileMove('left', repeat, 'tileWidth')
206
+ return this.repeatTileMove('left', repeat, 'tileWidth')
230
207
  }
231
208
 
232
209
  tileUp(repeat: number = 1): CallbackTileMove {
233
- return this.repeatTileMove('up', repeat, 'tileHeight')
210
+ return this.repeatTileMove('up', repeat, 'tileHeight')
234
211
  }
235
212
 
236
213
  tileDown(repeat: number = 1): CallbackTileMove {
237
- return this.repeatTileMove('down', repeat, 'tileHeight')
214
+ return this.repeatTileMove('down', repeat, 'tileHeight')
238
215
  }
239
216
 
240
217
  tileRandom(repeat: number = 1): CallbackTileMove {
241
- return (player: RpgPlayer, map): Direction[] => {
242
- // Safety check for valid repeat value
243
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 1000) {
244
- console.warn('Invalid repeat value in tileRandom:', repeat, 'using default value 1');
245
- repeat = 1;
246
- }
247
-
248
- // Ensure repeat is an integer
249
- repeat = Math.floor(repeat);
250
-
251
- let directions: Direction[] = []
252
- for (let i = 0; i < repeat; i++) {
253
- const randFn: CallbackTileMove = [
254
- this.tileRight(),
255
- this.tileLeft(),
256
- this.tileUp(),
257
- this.tileDown()
258
- ][random(0, 3)]
259
-
260
- try {
261
- const newDirections = randFn(player, map);
262
- if (Array.isArray(newDirections)) {
263
- directions = [...directions, ...newDirections];
264
- }
265
- } catch (error) {
266
- console.warn('Error in tileRandom iteration:', error);
267
- // Continue with next iteration instead of breaking
268
- }
269
-
270
- // Safety check to prevent excessive array growth
271
- if (directions.length > 10000) {
272
- console.warn('tileRandom generated too many directions, truncating');
273
- break;
274
- }
218
+ return (player: RpgPlayer, map): Direction[] => {
219
+ // Safety check for valid repeat value
220
+ if (!Number.isFinite(repeat) || repeat < 0 || repeat > 1000) {
221
+ console.warn('Invalid repeat value in tileRandom:', repeat, 'using default value 1');
222
+ repeat = 1;
223
+ }
224
+
225
+ // Ensure repeat is an integer
226
+ repeat = Math.floor(repeat);
227
+
228
+ let directions: Direction[] = []
229
+ for (let i = 0; i < repeat; i++) {
230
+ const randFn: CallbackTileMove = [
231
+ this.tileRight(),
232
+ this.tileLeft(),
233
+ this.tileUp(),
234
+ this.tileDown()
235
+ ][random(0, 3)]
236
+
237
+ try {
238
+ const newDirections = randFn(player, map);
239
+ if (Array.isArray(newDirections)) {
240
+ directions = [...directions, ...newDirections];
275
241
  }
276
- return directions
242
+ } catch (error) {
243
+ console.warn('Error in tileRandom iteration:', error);
244
+ // Continue with next iteration instead of breaking
245
+ }
246
+
247
+ // Safety check to prevent excessive array growth
248
+ if (directions.length > 10000) {
249
+ console.warn('tileRandom generated too many directions, truncating');
250
+ break;
251
+ }
277
252
  }
253
+ return directions
254
+ }
278
255
  }
279
256
 
280
257
  private _awayFromPlayerDirection(player: RpgPlayer, otherPlayer: RpgPlayer): Direction {
281
- const directionOtherPlayer = otherPlayer.getDirection()
282
- let newDirection: Direction = Direction.Down
258
+ const directionOtherPlayer = otherPlayer.getDirection()
259
+ let newDirection: Direction = Direction.Down
283
260
 
284
- switch (directionOtherPlayer) {
285
- case Direction.Left:
286
- case Direction.Right:
287
- if (otherPlayer.x() > player.x()) {
288
- newDirection = Direction.Left
289
- }
290
- else {
291
- newDirection = Direction.Right
292
- }
293
- break
294
- case Direction.Up:
295
- case Direction.Down:
296
- if (otherPlayer.y() > player.y()) {
297
- newDirection = Direction.Up
298
- }
299
- else {
300
- newDirection = Direction.Down
301
- }
302
- break
303
- }
304
- return newDirection
261
+ switch (directionOtherPlayer) {
262
+ case Direction.Left:
263
+ case Direction.Right:
264
+ if (otherPlayer.x() > player.x()) {
265
+ newDirection = Direction.Left
266
+ }
267
+ else {
268
+ newDirection = Direction.Right
269
+ }
270
+ break
271
+ case Direction.Up:
272
+ case Direction.Down:
273
+ if (otherPlayer.y() > player.y()) {
274
+ newDirection = Direction.Up
275
+ }
276
+ else {
277
+ newDirection = Direction.Down
278
+ }
279
+ break
280
+ }
281
+ return newDirection
305
282
  }
306
283
 
307
284
  private _towardPlayerDirection(player: RpgPlayer, otherPlayer: RpgPlayer): Direction {
308
- const directionOtherPlayer = otherPlayer.getDirection()
309
- let newDirection: Direction = Direction.Down
310
-
311
- switch (directionOtherPlayer) {
312
- case Direction.Left:
313
- case Direction.Right:
314
- if (otherPlayer.x() > player.x()) {
315
- newDirection = Direction.Right
316
- }
317
- else {
318
- newDirection = Direction.Left
319
- }
320
- break
321
- case Direction.Up:
322
- case Direction.Down:
323
- if (otherPlayer.y() > player.y()) {
324
- newDirection = Direction.Down
325
- }
326
- else {
327
- newDirection = Direction.Up
328
- }
329
- break
330
- }
331
- return newDirection
285
+ const directionOtherPlayer = otherPlayer.getDirection()
286
+ let newDirection: Direction = Direction.Down
287
+
288
+ switch (directionOtherPlayer) {
289
+ case Direction.Left:
290
+ case Direction.Right:
291
+ if (otherPlayer.x() > player.x()) {
292
+ newDirection = Direction.Right
293
+ }
294
+ else {
295
+ newDirection = Direction.Left
296
+ }
297
+ break
298
+ case Direction.Up:
299
+ case Direction.Down:
300
+ if (otherPlayer.y() > player.y()) {
301
+ newDirection = Direction.Down
302
+ }
303
+ else {
304
+ newDirection = Direction.Up
305
+ }
306
+ break
307
+ }
308
+ return newDirection
332
309
  }
333
310
 
334
311
  private _awayFromPlayer({ isTile, typeMov }: { isTile: boolean, typeMov: string }, otherPlayer: RpgPlayer, repeat: number = 1) {
335
- const method = (dir: Direction) => {
336
- const direction: string = DirectionNames[dir as any] || 'down'
337
- return this[isTile ? 'tile' + capitalize(direction) : direction](repeat)
312
+ const method = (dir: Direction) => {
313
+ const direction: string = DirectionNames[dir as any] || 'down'
314
+ return this[isTile ? 'tile' + capitalize(direction) : direction](repeat)
315
+ }
316
+ return (player: RpgPlayer, map) => {
317
+ let newDirection: Direction = Direction.Down
318
+ switch (typeMov) {
319
+ case 'away':
320
+ newDirection = this._awayFromPlayerDirection(player, otherPlayer)
321
+ break;
322
+ case 'toward':
323
+ newDirection = this._towardPlayerDirection(player, otherPlayer)
324
+ break
338
325
  }
339
- return (player: RpgPlayer, map) => {
340
- let newDirection: Direction = Direction.Down
341
- switch (typeMov) {
342
- case 'away':
343
- newDirection = this._awayFromPlayerDirection(player, otherPlayer)
344
- break;
345
- case 'toward':
346
- newDirection = this._towardPlayerDirection(player, otherPlayer)
347
- break
348
- }
349
- let direction: any = method(newDirection)
350
- if (isFunction(direction)) {
351
- direction = direction(player, map)
352
- }
353
- return direction
326
+ let direction: any = method(newDirection)
327
+ if (isFunction(direction)) {
328
+ direction = direction(player, map)
354
329
  }
330
+ return direction
331
+ }
355
332
  }
356
333
 
357
334
  towardPlayer(player: RpgPlayer, repeat: number = 1) {
358
- return this._awayFromPlayer({ isTile: false, typeMov: 'toward' }, player, repeat)
335
+ return this._awayFromPlayer({ isTile: false, typeMov: 'toward' }, player, repeat)
359
336
  }
360
337
 
361
338
  tileTowardPlayer(player: RpgPlayer, repeat: number = 1) {
362
- return this._awayFromPlayer({ isTile: true, typeMov: 'toward' }, player, repeat)
339
+ return this._awayFromPlayer({ isTile: true, typeMov: 'toward' }, player, repeat)
363
340
  }
364
341
 
365
342
  awayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
366
- return this._awayFromPlayer({ isTile: false, typeMov: 'away' }, player, repeat)
343
+ return this._awayFromPlayer({ isTile: false, typeMov: 'away' }, player, repeat)
367
344
  }
368
345
 
369
346
  tileAwayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
370
- return this._awayFromPlayer({ isTile: true, typeMov: 'away' }, player, repeat)
347
+ return this._awayFromPlayer({ isTile: true, typeMov: 'away' }, player, repeat)
371
348
  }
372
349
 
373
350
  turnLeft(): string {
374
- return 'turn-' + Direction.Left
351
+ return 'turn-' + Direction.Left
375
352
  }
376
353
 
377
354
  turnRight(): string {
378
- return 'turn-' + Direction.Right
355
+ return 'turn-' + Direction.Right
379
356
  }
380
357
 
381
358
  turnUp(): string {
382
- return 'turn-' + Direction.Up
359
+ return 'turn-' + Direction.Up
383
360
  }
384
361
 
385
362
  turnDown(): string {
386
- return 'turn-' + Direction.Down
363
+ return 'turn-' + Direction.Down
387
364
  }
388
365
 
389
366
  turnRandom(): string {
390
- return [
391
- this.turnRight(),
392
- this.turnLeft(),
393
- this.turnUp(),
394
- this.turnDown()
395
- ][random(0, 3)]
367
+ return [
368
+ this.turnRight(),
369
+ this.turnLeft(),
370
+ this.turnUp(),
371
+ this.turnDown()
372
+ ][random(0, 3)]
396
373
  }
397
374
 
398
375
  turnAwayFromPlayer(otherPlayer: RpgPlayer): CallbackTurnMove {
399
- return (player: RpgPlayer) => {
400
- const direction = this._awayFromPlayerDirection(player, otherPlayer)
401
- return 'turn-' + direction
402
- }
376
+ return (player: RpgPlayer) => {
377
+ const direction = this._awayFromPlayerDirection(player, otherPlayer)
378
+ return 'turn-' + direction
379
+ }
403
380
  }
404
381
 
405
382
  turnTowardPlayer(otherPlayer: RpgPlayer): CallbackTurnMove {
406
- return (player: RpgPlayer) => {
407
- const direction = this._towardPlayerDirection(player, otherPlayer)
408
- return 'turn-' + direction
409
- }
383
+ return (player: RpgPlayer) => {
384
+ const direction = this._towardPlayerDirection(player, otherPlayer)
385
+ return 'turn-' + direction
386
+ }
410
387
  }
411
388
  }
412
389
 
@@ -431,7 +408,7 @@ export const Move = new MoveList();
431
408
  * - **Strategy Management**: Add, remove, and query movement strategies
432
409
  * - **Predefined Movements**: Quick access to common movement patterns
433
410
  * - **Composite Movements**: Combine multiple strategies
434
- * - **Physics Integration**: Seamless integration with Matter.js physics
411
+ * - **Physics Integration**: Seamless integration with the deterministic @rpgjs/physic engine
435
412
  *
436
413
  * ## Available Movement Strategies
437
414
  * - `LinearMove`: Constant velocity movement
@@ -475,15 +452,49 @@ export const Move = new MoveList();
475
452
  * }
476
453
  * ```
477
454
  */
478
- export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
479
- Base: TBase
480
- ): Constructor<IMoveManager> & TBase {
481
- return class extends Base implements IMoveManager {
482
-
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;
455
+ /**
456
+ * Move Manager Mixin
457
+ *
458
+ * Provides comprehensive movement management capabilities to any class. This mixin handles
459
+ * various types of movement including pathfinding, physics-based movement, route following,
460
+ * and advanced movement strategies like dashing, knockback, and projectile movement.
461
+ *
462
+ * @param Base - The base class to extend with movement management
463
+ * @returns Extended class with movement management methods
464
+ *
465
+ * @example
466
+ * ```ts
467
+ * class MyPlayer extends WithMoveManager(BasePlayer) {
468
+ * constructor() {
469
+ * super();
470
+ * this.frequency = Frequency.High;
471
+ * }
472
+ * }
473
+ *
474
+ * const player = new MyPlayer();
475
+ * player.moveTo({ x: 100, y: 100 });
476
+ * player.dash({ x: 1, y: 0 }, 8, 200);
477
+ * ```
478
+ */
479
+ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
480
+ const baseProto = Base.prototype as any;
481
+ class WithMoveManagerClass extends Base {
482
+ setAnimation(animationName: string, nbTimes: number): void {
483
+ if (typeof baseProto.setAnimation === 'function') {
484
+ baseProto.setAnimation.call(this, animationName, nbTimes);
485
+ }
486
+ }
487
+
488
+ showComponentAnimation(id: string, params: any): void {
489
+ if (typeof baseProto.showComponentAnimation === 'function') {
490
+ baseProto.showComponentAnimation.call(this, id, params);
491
+ }
492
+ }
493
+
494
+ // Properties for infinite route management
495
+ _infiniteRoutes: Routes | null = null;
496
+ _finishRoute: ((value: boolean) => void) | null = null;
497
+ _isInfiniteRouteActive: boolean = false;
487
498
 
488
499
  /**
489
500
  * The player passes through the other players (or vice versa). But the player does not go through the events.
@@ -520,7 +531,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
520
531
  set through(value: boolean) {
521
532
  this._through.set(value);
522
533
  }
523
-
534
+
524
535
  get through(): boolean {
525
536
  return this._through();
526
537
  }
@@ -561,7 +572,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
561
572
  get frequency(): number {
562
573
  return this._frequency();
563
574
  }
564
-
575
+
565
576
  /**
566
577
  * Add a custom movement strategy to this entity
567
578
  *
@@ -582,9 +593,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
582
593
  * ```
583
594
  */
584
595
  addMovement(strategy: MovementStrategy): void {
585
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
596
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
586
597
  if (!map) return;
587
-
598
+
588
599
  map.moveManager.add((this as unknown as PlayerWithMixins).id, strategy);
589
600
  }
590
601
 
@@ -605,9 +616,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
605
616
  * ```
606
617
  */
607
618
  removeMovement(strategy: MovementStrategy): boolean {
608
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
619
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
609
620
  if (!map) return false;
610
-
621
+
611
622
  return map.moveManager.remove((this as unknown as PlayerWithMixins).id, strategy);
612
623
  }
613
624
 
@@ -627,9 +638,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
627
638
  * ```
628
639
  */
629
640
  clearMovements(): void {
630
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
641
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
631
642
  if (!map) return;
632
-
643
+
633
644
  map.moveManager.clear((this as unknown as PlayerWithMixins).id);
634
645
  }
635
646
 
@@ -652,9 +663,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
652
663
  * ```
653
664
  */
654
665
  hasActiveMovements(): boolean {
655
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
666
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
656
667
  if (!map) return false;
657
-
668
+
658
669
  return map.moveManager.hasActiveStrategies((this as unknown as PlayerWithMixins).id);
659
670
  }
660
671
 
@@ -674,9 +685,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
674
685
  * ```
675
686
  */
676
687
  getActiveMovements(): MovementStrategy[] {
677
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
688
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
678
689
  if (!map) return [];
679
-
690
+
680
691
  return map.moveManager.getStrategies((this as unknown as PlayerWithMixins).id);
681
692
  }
682
693
 
@@ -702,30 +713,30 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
702
713
  * ```
703
714
  */
704
715
  moveTo(target: RpgCommonPlayer | { x: number, y: number }): void {
705
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
716
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
706
717
  if (!map) return;
707
-
708
- let targetBody: Matter.Body | null = null;
709
-
718
+
719
+ const engine = map.physic;
720
+
710
721
  if ('id' in target) {
711
- // Target is a player
712
- targetBody = map.physic.getBody(target.id);
713
- } else {
714
- // Target is a position - create a temporary target function
715
- const getTargetPos = () => Matter.Vector.create(target.x, target.y);
722
+ const targetProvider = () => (map as any).getBody(target.id) ?? null;
716
723
  map.moveManager.add(
717
- (this as unknown as PlayerWithMixins).id,
718
- new SeekAvoid(map.physic, getTargetPos, 3, 50, 5)
724
+ (this as unknown as PlayerWithMixins).id,
725
+ new SeekAvoid(engine, targetProvider, 180, 140, 80, 48)
719
726
  );
720
727
  return;
721
728
  }
722
-
723
- if (targetBody) {
724
- map.moveManager.add(
725
- (this as unknown as PlayerWithMixins).id,
726
- new SeekAvoid(map.physic, targetBody, 3, 50, 5)
727
- );
728
- }
729
+
730
+ const staticTarget = new Entity({
731
+ position: { x: target.x, y: target.y },
732
+ mass: Infinity,
733
+ });
734
+ staticTarget.freeze();
735
+
736
+ map.moveManager.add(
737
+ (this as unknown as PlayerWithMixins).id,
738
+ new SeekAvoid(engine, () => staticTarget, 80, 140, 80, 48)
739
+ );
729
740
  }
730
741
 
731
742
  /**
@@ -745,9 +756,9 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
745
756
  * ```
746
757
  */
747
758
  stopMoveTo(): void {
748
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
759
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
749
760
  if (!map) return;
750
-
761
+
751
762
  const strategies = this.getActiveMovements();
752
763
  strategies.forEach(strategy => {
753
764
  if (strategy instanceof SeekAvoid || strategy instanceof LinearRepulsion) {
@@ -912,7 +923,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
912
923
  maxBounces: type === ProjectileType.Bounce ? 3 : undefined,
913
924
  bounciness: type === ProjectileType.Bounce ? 0.6 : undefined
914
925
  };
915
-
926
+
916
927
  this.addMovement(new ProjectileMovement(type, config));
917
928
  }
918
929
 
@@ -963,18 +974,18 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
963
974
  let count = 0;
964
975
  let frequence = 0;
965
976
  const player = this as unknown as PlayerWithMixins;
966
-
977
+
967
978
  // Break any existing route movement
968
979
  this.clearMovements();
969
-
980
+
970
981
  return new Promise(async (resolve) => {
971
982
  // Store the resolve function for potential breaking
972
983
  this._finishRoute = resolve;
973
-
984
+
974
985
  // Process function routes first
975
986
  const processedRoutes = routes.map((route: any) => {
976
987
  if (typeof route === 'function') {
977
- const map = player.getCurrentMap();
988
+ const map = player.getCurrentMap() as any;
978
989
  if (!map) {
979
990
  return undefined;
980
991
  }
@@ -982,11 +993,11 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
982
993
  }
983
994
  return route;
984
995
  });
985
-
996
+
986
997
  // Flatten nested arrays
987
998
  const flatRoutes = this.flattenRoutes(processedRoutes);
988
999
  let routeIndex = 0;
989
-
1000
+
990
1001
  const executeNextRoute = async (): Promise<void> => {
991
1002
  // Check if player still exists and is on a map
992
1003
  if (!player || !player.getCurrentMap()) {
@@ -994,7 +1005,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
994
1005
  resolve(false);
995
1006
  return;
996
1007
  }
997
-
1008
+
998
1009
  // Handle frequency timing
999
1010
  if (count >= (player.nbPixelInTile || 32)) {
1000
1011
  if (frequence < (player.frequency || 0)) {
@@ -1003,25 +1014,25 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1003
1014
  return;
1004
1015
  }
1005
1016
  }
1006
-
1017
+
1007
1018
  frequence = 0;
1008
1019
  count++;
1009
-
1020
+
1010
1021
  // Check if we've completed all routes
1011
1022
  if (routeIndex >= flatRoutes.length) {
1012
1023
  this._finishRoute = null;
1013
1024
  resolve(true);
1014
1025
  return;
1015
1026
  }
1016
-
1027
+
1017
1028
  const currentRoute = flatRoutes[routeIndex];
1018
1029
  routeIndex++;
1019
-
1030
+
1020
1031
  if (currentRoute === undefined) {
1021
1032
  executeNextRoute();
1022
1033
  return;
1023
1034
  }
1024
-
1035
+
1025
1036
  try {
1026
1037
  // Handle different route types
1027
1038
  if (typeof currentRoute === 'object' && 'then' in currentRoute) {
@@ -1032,7 +1043,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1032
1043
  // Handle turn commands
1033
1044
  const directionStr = currentRoute.replace('turn-', '');
1034
1045
  let direction: Direction = Direction.Down;
1035
-
1046
+
1036
1047
  // Convert string direction to Direction enum
1037
1048
  switch (directionStr) {
1038
1049
  case 'up':
@@ -1052,7 +1063,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1052
1063
  direction = Direction.Right;
1053
1064
  break;
1054
1065
  }
1055
-
1066
+
1056
1067
  if (player.changeDirection) {
1057
1068
  player.changeDirection(direction);
1058
1069
  }
@@ -1071,7 +1082,8 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1071
1082
  case Direction.Down: vy = 1; break;
1072
1083
  case Direction.Up: vy = -1; break;
1073
1084
  }
1074
- this.addMovement(new LinearMove(vx * (player.speed?.() || 3), vy * (player.speed?.() || 3), 100));
1085
+ const speed = player.speed?.() ?? 3;
1086
+ this.addMovement(new LinearMove({ x: vx * speed, y: vy * speed }, 0.1));
1075
1087
  setTimeout(executeNextRoute, 100);
1076
1088
  return;
1077
1089
  }
@@ -1085,11 +1097,11 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1085
1097
  executeNextRoute();
1086
1098
  }
1087
1099
  };
1088
-
1100
+
1089
1101
  executeNextRoute();
1090
1102
  });
1091
1103
  }
1092
-
1104
+
1093
1105
  /**
1094
1106
  * Utility method to flatten nested route arrays
1095
1107
  *
@@ -1097,18 +1109,13 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1097
1109
  * @param routes - Routes array that may contain nested arrays
1098
1110
  * @returns Flattened array of routes
1099
1111
  */
1100
- private flattenRoutes(routes: any[]): any[] {
1101
- const result: any[] = [];
1102
-
1103
- for (const route of routes) {
1104
- if (Array.isArray(route)) {
1105
- result.push(...this.flattenRoutes(route));
1106
- } else {
1107
- result.push(route);
1112
+ private flattenRoutes(routes: Routes): Routes {
1113
+ return routes.reduce((acc: Routes, item) => {
1114
+ if (Array.isArray(item)) {
1115
+ return acc.concat(this.flattenRoutes(item));
1108
1116
  }
1109
- }
1110
-
1111
- return result;
1117
+ return acc.concat(item);
1118
+ }, []);
1112
1119
  }
1113
1120
 
1114
1121
  /**
@@ -1154,7 +1161,7 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1154
1161
 
1155
1162
  const executeInfiniteRoute = (isBreaking: boolean = false) => {
1156
1163
  if (isBreaking || !this._isInfiniteRouteActive) return;
1157
-
1164
+
1158
1165
  this.moveRoutes(routes).then((completed) => {
1159
1166
  // Only continue if the route completed successfully and we're still active
1160
1167
  if (completed && this._isInfiniteRouteActive) {
@@ -1197,12 +1204,12 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1197
1204
  */
1198
1205
  breakRoutes(force: boolean = false): void {
1199
1206
  this._isInfiniteRouteActive = false;
1200
-
1207
+
1201
1208
  if (force) {
1202
1209
  // Force stop by clearing all movements immediately
1203
1210
  this.clearMovements();
1204
1211
  }
1205
-
1212
+
1206
1213
  // If there's an active route promise, resolve it
1207
1214
  if (this._finishRoute) {
1208
1215
  this._finishRoute(force);
@@ -1241,5 +1248,13 @@ export function WithMoveManager<TBase extends Constructor<RpgCommonPlayer>>(
1241
1248
  this.infiniteMoveRoute(this._infiniteRoutes);
1242
1249
  }
1243
1250
  }
1244
- };
1251
+ }
1252
+
1253
+ return WithMoveManagerClass as unknown as PlayerCtor;
1245
1254
  }
1255
+
1256
+ /**
1257
+ * Type helper to extract the interface from the WithMoveManager mixin
1258
+ * This provides the type without duplicating method signatures
1259
+ */
1260
+ export type IMoveManager = InstanceType<ReturnType<typeof WithMoveManager>>;