@rpgjs/server 5.0.0-alpha.14 → 5.0.0-alpha.15

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,7 +1,6 @@
1
- import { PlayerCtor, 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
@@ -35,11 +33,9 @@ interface PlayerWithMixins extends RpgCommonPlayer {
35
33
  }
36
34
 
37
35
 
38
-
39
-
40
36
  function wait(sec: number) {
41
37
  return new Promise((resolve) => {
42
- setTimeout(resolve, sec * 1000)
38
+ setTimeout(resolve, sec * 1000)
43
39
  })
44
40
  }
45
41
 
@@ -97,297 +93,297 @@ export enum Speed {
97
93
  class MoveList {
98
94
 
99
95
  repeatMove(direction: Direction, repeat: number): Direction[] {
100
- // Safety check for valid repeat value
101
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
102
- console.warn('Invalid repeat value:', repeat, 'using default value 1');
103
- 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);
104
127
  }
105
-
106
- // Ensure repeat is an integer
107
- repeat = Math.floor(repeat);
108
-
109
- // Additional safety check - ensure repeat is a safe integer
110
- if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
111
- console.warn('Unsafe repeat value:', repeat, 'using default value 1');
112
- 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);
113
135
  }
114
-
115
- try {
116
- return new Array(repeat).fill(direction);
117
- } catch (error) {
118
- console.error('Error creating array with repeat:', repeat, error);
119
- 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);
120
141
  }
121
- }
122
142
 
123
- private repeatTileMove(direction: string, repeat: number, propMap: string): CallbackTileMove {
124
- return (player: RpgPlayer, map): Direction[] => {
125
- const playerSpeed = typeof player.speed === 'function' ? player.speed() : player.speed;
126
-
127
- // Safety checks
128
- if (!playerSpeed || playerSpeed <= 0) {
129
- console.warn('Invalid player speed:', playerSpeed, 'using default speed 3');
130
- return this[direction](repeat);
131
- }
132
-
133
- const repeatTile = Math.floor((map[propMap] || 32) / playerSpeed) * repeat;
134
-
135
- // Additional safety check for the calculated repeat value
136
- if (!Number.isFinite(repeatTile) || repeatTile < 0 || repeatTile > 10000) {
137
- console.warn('Calculated repeatTile is invalid:', repeatTile, 'using original repeat:', repeat);
138
- return this[direction](repeat);
139
- }
140
-
141
- // Final safety check before calling the method
142
- if (!Number.isSafeInteger(repeatTile)) {
143
- console.warn('repeatTile is not a safe integer:', repeatTile, 'using original repeat:', repeat);
144
- return this[direction](repeat);
145
- }
146
-
147
- try {
148
- return this[direction](repeatTile);
149
- } catch (error) {
150
- console.error('Error calling direction method with repeatTile:', repeatTile, error);
151
- return this[direction](repeat); // Fallback to original repeat
152
- }
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
153
148
  }
149
+ }
154
150
  }
155
151
 
156
152
  right(repeat: number = 1): Direction[] {
157
- return this.repeatMove(Direction.Right, repeat)
153
+ return this.repeatMove(Direction.Right, repeat)
158
154
  }
159
155
 
160
156
  left(repeat: number = 1): Direction[] {
161
- return this.repeatMove(Direction.Left, repeat)
157
+ return this.repeatMove(Direction.Left, repeat)
162
158
  }
163
159
 
164
160
  up(repeat: number = 1): Direction[] {
165
- return this.repeatMove(Direction.Up, repeat)
161
+ return this.repeatMove(Direction.Up, repeat)
166
162
  }
167
163
 
168
164
  down(repeat: number = 1): Direction[] {
169
- return this.repeatMove(Direction.Down, repeat)
165
+ return this.repeatMove(Direction.Down, repeat)
170
166
  }
171
167
 
172
168
  wait(sec: number): Promise<unknown> {
173
- return wait(sec)
169
+ return wait(sec)
174
170
  }
175
171
 
176
172
  random(repeat: number = 1): Direction[] {
177
- // Safety check for valid repeat value
178
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 10000) {
179
- console.warn('Invalid repeat value in random:', repeat, 'using default value 1');
180
- repeat = 1;
181
- }
182
-
183
- // Ensure repeat is an integer
184
- repeat = Math.floor(repeat);
185
-
186
- // Additional safety check - ensure repeat is a safe integer
187
- if (repeat < 0 || repeat > Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(repeat)) {
188
- console.warn('Unsafe repeat value in random:', repeat, 'using default value 1');
189
- repeat = 1;
190
- }
191
-
192
- try {
193
- return new Array(repeat).fill(null).map(() => [
194
- Direction.Right,
195
- Direction.Left,
196
- Direction.Up,
197
- Direction.Down
198
- ][random(0, 3)]);
199
- } catch (error) {
200
- console.error('Error creating random array with repeat:', repeat, error);
201
- return [Direction.Down]; // Return single direction as fallback
202
- }
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
+ }
203
199
  }
204
200
 
205
201
  tileRight(repeat: number = 1): CallbackTileMove {
206
- return this.repeatTileMove('right', repeat, 'tileWidth')
202
+ return this.repeatTileMove('right', repeat, 'tileWidth')
207
203
  }
208
204
 
209
205
  tileLeft(repeat: number = 1): CallbackTileMove {
210
- return this.repeatTileMove('left', repeat, 'tileWidth')
206
+ return this.repeatTileMove('left', repeat, 'tileWidth')
211
207
  }
212
208
 
213
209
  tileUp(repeat: number = 1): CallbackTileMove {
214
- return this.repeatTileMove('up', repeat, 'tileHeight')
210
+ return this.repeatTileMove('up', repeat, 'tileHeight')
215
211
  }
216
212
 
217
213
  tileDown(repeat: number = 1): CallbackTileMove {
218
- return this.repeatTileMove('down', repeat, 'tileHeight')
214
+ return this.repeatTileMove('down', repeat, 'tileHeight')
219
215
  }
220
216
 
221
217
  tileRandom(repeat: number = 1): CallbackTileMove {
222
- return (player: RpgPlayer, map): Direction[] => {
223
- // Safety check for valid repeat value
224
- if (!Number.isFinite(repeat) || repeat < 0 || repeat > 1000) {
225
- console.warn('Invalid repeat value in tileRandom:', repeat, 'using default value 1');
226
- repeat = 1;
227
- }
228
-
229
- // Ensure repeat is an integer
230
- repeat = Math.floor(repeat);
231
-
232
- let directions: Direction[] = []
233
- for (let i = 0; i < repeat; i++) {
234
- const randFn: CallbackTileMove = [
235
- this.tileRight(),
236
- this.tileLeft(),
237
- this.tileUp(),
238
- this.tileDown()
239
- ][random(0, 3)]
240
-
241
- try {
242
- const newDirections = randFn(player, map);
243
- if (Array.isArray(newDirections)) {
244
- directions = [...directions, ...newDirections];
245
- }
246
- } catch (error) {
247
- console.warn('Error in tileRandom iteration:', error);
248
- // Continue with next iteration instead of breaking
249
- }
250
-
251
- // Safety check to prevent excessive array growth
252
- if (directions.length > 10000) {
253
- console.warn('tileRandom generated too many directions, truncating');
254
- break;
255
- }
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];
256
241
  }
257
- 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
+ }
258
252
  }
253
+ return directions
254
+ }
259
255
  }
260
256
 
261
257
  private _awayFromPlayerDirection(player: RpgPlayer, otherPlayer: RpgPlayer): Direction {
262
- const directionOtherPlayer = otherPlayer.getDirection()
263
- let newDirection: Direction = Direction.Down
264
-
265
- switch (directionOtherPlayer) {
266
- case Direction.Left:
267
- case Direction.Right:
268
- if (otherPlayer.x() > player.x()) {
269
- newDirection = Direction.Left
270
- }
271
- else {
272
- newDirection = Direction.Right
273
- }
274
- break
275
- case Direction.Up:
276
- case Direction.Down:
277
- if (otherPlayer.y() > player.y()) {
278
- newDirection = Direction.Up
279
- }
280
- else {
281
- newDirection = Direction.Down
282
- }
283
- break
284
- }
285
- return newDirection
258
+ const directionOtherPlayer = otherPlayer.getDirection()
259
+ let newDirection: Direction = Direction.Down
260
+
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
286
282
  }
287
283
 
288
284
  private _towardPlayerDirection(player: RpgPlayer, otherPlayer: RpgPlayer): Direction {
289
- const directionOtherPlayer = otherPlayer.getDirection()
290
- let newDirection: Direction = Direction.Down
291
-
292
- switch (directionOtherPlayer) {
293
- case Direction.Left:
294
- case Direction.Right:
295
- if (otherPlayer.x() > player.x()) {
296
- newDirection = Direction.Right
297
- }
298
- else {
299
- newDirection = Direction.Left
300
- }
301
- break
302
- case Direction.Up:
303
- case Direction.Down:
304
- if (otherPlayer.y() > player.y()) {
305
- newDirection = Direction.Down
306
- }
307
- else {
308
- newDirection = Direction.Up
309
- }
310
- break
311
- }
312
- 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
313
309
  }
314
310
 
315
311
  private _awayFromPlayer({ isTile, typeMov }: { isTile: boolean, typeMov: string }, otherPlayer: RpgPlayer, repeat: number = 1) {
316
- const method = (dir: Direction) => {
317
- const direction: string = DirectionNames[dir as any] || 'down'
318
- 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
319
325
  }
320
- return (player: RpgPlayer, map) => {
321
- let newDirection: Direction = Direction.Down
322
- switch (typeMov) {
323
- case 'away':
324
- newDirection = this._awayFromPlayerDirection(player, otherPlayer)
325
- break;
326
- case 'toward':
327
- newDirection = this._towardPlayerDirection(player, otherPlayer)
328
- break
329
- }
330
- let direction: any = method(newDirection)
331
- if (isFunction(direction)) {
332
- direction = direction(player, map)
333
- }
334
- return direction
326
+ let direction: any = method(newDirection)
327
+ if (isFunction(direction)) {
328
+ direction = direction(player, map)
335
329
  }
330
+ return direction
331
+ }
336
332
  }
337
333
 
338
334
  towardPlayer(player: RpgPlayer, repeat: number = 1) {
339
- return this._awayFromPlayer({ isTile: false, typeMov: 'toward' }, player, repeat)
335
+ return this._awayFromPlayer({ isTile: false, typeMov: 'toward' }, player, repeat)
340
336
  }
341
337
 
342
338
  tileTowardPlayer(player: RpgPlayer, repeat: number = 1) {
343
- return this._awayFromPlayer({ isTile: true, typeMov: 'toward' }, player, repeat)
339
+ return this._awayFromPlayer({ isTile: true, typeMov: 'toward' }, player, repeat)
344
340
  }
345
341
 
346
342
  awayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
347
- return this._awayFromPlayer({ isTile: false, typeMov: 'away' }, player, repeat)
343
+ return this._awayFromPlayer({ isTile: false, typeMov: 'away' }, player, repeat)
348
344
  }
349
345
 
350
346
  tileAwayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
351
- return this._awayFromPlayer({ isTile: true, typeMov: 'away' }, player, repeat)
347
+ return this._awayFromPlayer({ isTile: true, typeMov: 'away' }, player, repeat)
352
348
  }
353
349
 
354
350
  turnLeft(): string {
355
- return 'turn-' + Direction.Left
351
+ return 'turn-' + Direction.Left
356
352
  }
357
353
 
358
354
  turnRight(): string {
359
- return 'turn-' + Direction.Right
355
+ return 'turn-' + Direction.Right
360
356
  }
361
357
 
362
358
  turnUp(): string {
363
- return 'turn-' + Direction.Up
359
+ return 'turn-' + Direction.Up
364
360
  }
365
361
 
366
362
  turnDown(): string {
367
- return 'turn-' + Direction.Down
363
+ return 'turn-' + Direction.Down
368
364
  }
369
365
 
370
366
  turnRandom(): string {
371
- return [
372
- this.turnRight(),
373
- this.turnLeft(),
374
- this.turnUp(),
375
- this.turnDown()
376
- ][random(0, 3)]
367
+ return [
368
+ this.turnRight(),
369
+ this.turnLeft(),
370
+ this.turnUp(),
371
+ this.turnDown()
372
+ ][random(0, 3)]
377
373
  }
378
374
 
379
375
  turnAwayFromPlayer(otherPlayer: RpgPlayer): CallbackTurnMove {
380
- return (player: RpgPlayer) => {
381
- const direction = this._awayFromPlayerDirection(player, otherPlayer)
382
- return 'turn-' + direction
383
- }
376
+ return (player: RpgPlayer) => {
377
+ const direction = this._awayFromPlayerDirection(player, otherPlayer)
378
+ return 'turn-' + direction
379
+ }
384
380
  }
385
381
 
386
382
  turnTowardPlayer(otherPlayer: RpgPlayer): CallbackTurnMove {
387
- return (player: RpgPlayer) => {
388
- const direction = this._towardPlayerDirection(player, otherPlayer)
389
- return 'turn-' + direction
390
- }
383
+ return (player: RpgPlayer) => {
384
+ const direction = this._towardPlayerDirection(player, otherPlayer)
385
+ return 'turn-' + direction
386
+ }
391
387
  }
392
388
  }
393
389
 
@@ -412,7 +408,7 @@ export const Move = new MoveList();
412
408
  * - **Strategy Management**: Add, remove, and query movement strategies
413
409
  * - **Predefined Movements**: Quick access to common movement patterns
414
410
  * - **Composite Movements**: Combine multiple strategies
415
- * - **Physics Integration**: Seamless integration with Matter.js physics
411
+ * - **Physics Integration**: Seamless integration with the deterministic @rpgjs/physic engine
416
412
  *
417
413
  * ## Available Movement Strategies
418
414
  * - `LinearMove`: Constant velocity movement
@@ -481,8 +477,20 @@ export const Move = new MoveList();
481
477
  * ```
482
478
  */
483
479
  export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
484
- return class extends Base {
485
-
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
+
486
494
  // Properties for infinite route management
487
495
  _infiniteRoutes: Routes | null = null;
488
496
  _finishRoute: ((value: boolean) => void) | null = null;
@@ -523,7 +531,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
523
531
  set through(value: boolean) {
524
532
  this._through.set(value);
525
533
  }
526
-
534
+
527
535
  get through(): boolean {
528
536
  return this._through();
529
537
  }
@@ -564,7 +572,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
564
572
  get frequency(): number {
565
573
  return this._frequency();
566
574
  }
567
-
575
+
568
576
  /**
569
577
  * Add a custom movement strategy to this entity
570
578
  *
@@ -585,9 +593,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
585
593
  * ```
586
594
  */
587
595
  addMovement(strategy: MovementStrategy): void {
588
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
596
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
589
597
  if (!map) return;
590
-
598
+
591
599
  map.moveManager.add((this as unknown as PlayerWithMixins).id, strategy);
592
600
  }
593
601
 
@@ -608,9 +616,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
608
616
  * ```
609
617
  */
610
618
  removeMovement(strategy: MovementStrategy): boolean {
611
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
619
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
612
620
  if (!map) return false;
613
-
621
+
614
622
  return map.moveManager.remove((this as unknown as PlayerWithMixins).id, strategy);
615
623
  }
616
624
 
@@ -630,9 +638,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
630
638
  * ```
631
639
  */
632
640
  clearMovements(): void {
633
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
641
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
634
642
  if (!map) return;
635
-
643
+
636
644
  map.moveManager.clear((this as unknown as PlayerWithMixins).id);
637
645
  }
638
646
 
@@ -655,9 +663,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
655
663
  * ```
656
664
  */
657
665
  hasActiveMovements(): boolean {
658
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
666
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
659
667
  if (!map) return false;
660
-
668
+
661
669
  return map.moveManager.hasActiveStrategies((this as unknown as PlayerWithMixins).id);
662
670
  }
663
671
 
@@ -677,9 +685,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
677
685
  * ```
678
686
  */
679
687
  getActiveMovements(): MovementStrategy[] {
680
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
688
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
681
689
  if (!map) return [];
682
-
690
+
683
691
  return map.moveManager.getStrategies((this as unknown as PlayerWithMixins).id);
684
692
  }
685
693
 
@@ -705,30 +713,30 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
705
713
  * ```
706
714
  */
707
715
  moveTo(target: RpgCommonPlayer | { x: number, y: number }): void {
708
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
716
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
709
717
  if (!map) return;
710
-
711
- let targetBody: Matter.Body | null = null;
712
-
718
+
719
+ const engine = map.physic;
720
+
713
721
  if ('id' in target) {
714
- // Target is a player
715
- targetBody = map.physic.getBody(target.id);
716
- } else {
717
- // Target is a position - create a temporary target function
718
- const getTargetPos = () => Matter.Vector.create(target.x, target.y);
722
+ const targetProvider = () => (map as any).getBody(target.id) ?? null;
719
723
  map.moveManager.add(
720
- (this as unknown as PlayerWithMixins).id,
721
- new SeekAvoid(map.physic, getTargetPos, 3, 50, 5)
724
+ (this as unknown as PlayerWithMixins).id,
725
+ new SeekAvoid(engine, targetProvider, 180, 140, 80, 48)
722
726
  );
723
727
  return;
724
728
  }
725
-
726
- if (targetBody) {
727
- map.moveManager.add(
728
- (this as unknown as PlayerWithMixins).id,
729
- new SeekAvoid(map.physic, targetBody, 3, 50, 5)
730
- );
731
- }
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, 3, 50, 5)
739
+ );
732
740
  }
733
741
 
734
742
  /**
@@ -748,9 +756,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
748
756
  * ```
749
757
  */
750
758
  stopMoveTo(): void {
751
- const map = (this as unknown as PlayerWithMixins).getCurrentMap();
759
+ const map = (this as unknown as PlayerWithMixins).getCurrentMap() as any;
752
760
  if (!map) return;
753
-
761
+
754
762
  const strategies = this.getActiveMovements();
755
763
  strategies.forEach(strategy => {
756
764
  if (strategy instanceof SeekAvoid || strategy instanceof LinearRepulsion) {
@@ -915,7 +923,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
915
923
  maxBounces: type === ProjectileType.Bounce ? 3 : undefined,
916
924
  bounciness: type === ProjectileType.Bounce ? 0.6 : undefined
917
925
  };
918
-
926
+
919
927
  this.addMovement(new ProjectileMovement(type, config));
920
928
  }
921
929
 
@@ -966,18 +974,18 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
966
974
  let count = 0;
967
975
  let frequence = 0;
968
976
  const player = this as unknown as PlayerWithMixins;
969
-
977
+
970
978
  // Break any existing route movement
971
979
  this.clearMovements();
972
-
980
+
973
981
  return new Promise(async (resolve) => {
974
982
  // Store the resolve function for potential breaking
975
983
  this._finishRoute = resolve;
976
-
984
+
977
985
  // Process function routes first
978
986
  const processedRoutes = routes.map((route: any) => {
979
987
  if (typeof route === 'function') {
980
- const map = player.getCurrentMap();
988
+ const map = player.getCurrentMap() as any;
981
989
  if (!map) {
982
990
  return undefined;
983
991
  }
@@ -985,11 +993,11 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
985
993
  }
986
994
  return route;
987
995
  });
988
-
996
+
989
997
  // Flatten nested arrays
990
998
  const flatRoutes = this.flattenRoutes(processedRoutes);
991
999
  let routeIndex = 0;
992
-
1000
+
993
1001
  const executeNextRoute = async (): Promise<void> => {
994
1002
  // Check if player still exists and is on a map
995
1003
  if (!player || !player.getCurrentMap()) {
@@ -997,7 +1005,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
997
1005
  resolve(false);
998
1006
  return;
999
1007
  }
1000
-
1008
+
1001
1009
  // Handle frequency timing
1002
1010
  if (count >= (player.nbPixelInTile || 32)) {
1003
1011
  if (frequence < (player.frequency || 0)) {
@@ -1006,25 +1014,25 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1006
1014
  return;
1007
1015
  }
1008
1016
  }
1009
-
1017
+
1010
1018
  frequence = 0;
1011
1019
  count++;
1012
-
1020
+
1013
1021
  // Check if we've completed all routes
1014
1022
  if (routeIndex >= flatRoutes.length) {
1015
1023
  this._finishRoute = null;
1016
1024
  resolve(true);
1017
1025
  return;
1018
1026
  }
1019
-
1027
+
1020
1028
  const currentRoute = flatRoutes[routeIndex];
1021
1029
  routeIndex++;
1022
-
1030
+
1023
1031
  if (currentRoute === undefined) {
1024
1032
  executeNextRoute();
1025
1033
  return;
1026
1034
  }
1027
-
1035
+
1028
1036
  try {
1029
1037
  // Handle different route types
1030
1038
  if (typeof currentRoute === 'object' && 'then' in currentRoute) {
@@ -1035,7 +1043,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1035
1043
  // Handle turn commands
1036
1044
  const directionStr = currentRoute.replace('turn-', '');
1037
1045
  let direction: Direction = Direction.Down;
1038
-
1046
+
1039
1047
  // Convert string direction to Direction enum
1040
1048
  switch (directionStr) {
1041
1049
  case 'up':
@@ -1055,7 +1063,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1055
1063
  direction = Direction.Right;
1056
1064
  break;
1057
1065
  }
1058
-
1066
+
1059
1067
  if (player.changeDirection) {
1060
1068
  player.changeDirection(direction);
1061
1069
  }
@@ -1074,7 +1082,8 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1074
1082
  case Direction.Down: vy = 1; break;
1075
1083
  case Direction.Up: vy = -1; break;
1076
1084
  }
1077
- 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));
1078
1087
  setTimeout(executeNextRoute, 100);
1079
1088
  return;
1080
1089
  }
@@ -1088,11 +1097,11 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1088
1097
  executeNextRoute();
1089
1098
  }
1090
1099
  };
1091
-
1100
+
1092
1101
  executeNextRoute();
1093
1102
  });
1094
1103
  }
1095
-
1104
+
1096
1105
  /**
1097
1106
  * Utility method to flatten nested route arrays
1098
1107
  *
@@ -1100,18 +1109,13 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1100
1109
  * @param routes - Routes array that may contain nested arrays
1101
1110
  * @returns Flattened array of routes
1102
1111
  */
1103
- flattenRoutes(routes: any[]): any[] {
1104
- const result: any[] = [];
1105
-
1106
- for (const route of routes) {
1107
- if (Array.isArray(route)) {
1108
- result.push(...this.flattenRoutes(route));
1109
- } else {
1110
- 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));
1111
1116
  }
1112
- }
1113
-
1114
- return result;
1117
+ return acc.concat(item);
1118
+ }, []);
1115
1119
  }
1116
1120
 
1117
1121
  /**
@@ -1157,7 +1161,7 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1157
1161
 
1158
1162
  const executeInfiniteRoute = (isBreaking: boolean = false) => {
1159
1163
  if (isBreaking || !this._isInfiniteRouteActive) return;
1160
-
1164
+
1161
1165
  this.moveRoutes(routes).then((completed) => {
1162
1166
  // Only continue if the route completed successfully and we're still active
1163
1167
  if (completed && this._isInfiniteRouteActive) {
@@ -1200,12 +1204,12 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1200
1204
  */
1201
1205
  breakRoutes(force: boolean = false): void {
1202
1206
  this._isInfiniteRouteActive = false;
1203
-
1207
+
1204
1208
  if (force) {
1205
1209
  // Force stop by clearing all movements immediately
1206
1210
  this.clearMovements();
1207
1211
  }
1208
-
1212
+
1209
1213
  // If there's an active route promise, resolve it
1210
1214
  if (this._finishRoute) {
1211
1215
  this._finishRoute(force);
@@ -1244,7 +1248,9 @@ export function WithMoveManager<TBase extends PlayerCtor>(Base: TBase) {
1244
1248
  this.infiniteMoveRoute(this._infiniteRoutes);
1245
1249
  }
1246
1250
  }
1247
- } as unknown as TBase;
1251
+ }
1252
+
1253
+ return WithMoveManagerClass as unknown as PlayerCtor;
1248
1254
  }
1249
1255
 
1250
1256
  /**