@rpgjs/server 5.0.0-alpha.14 → 5.0.0-alpha.16
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.
- package/dist/Player/MoveManager.d.ts +2 -2
- package/dist/Player/Player.d.ts +20 -2
- package/dist/index.js +6172 -13472
- package/dist/index.js.map +1 -1
- package/dist/rooms/map.d.ts +50 -1
- package/package.json +3 -2
- package/src/Player/MoveManager.ts +289 -283
- package/src/Player/Player.ts +40 -3
- package/src/rooms/map.ts +249 -35
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { PlayerCtor,
|
|
2
|
-
import { RpgCommonPlayer,
|
|
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
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
153
|
+
return this.repeatMove(Direction.Right, repeat)
|
|
158
154
|
}
|
|
159
155
|
|
|
160
156
|
left(repeat: number = 1): Direction[] {
|
|
161
|
-
|
|
157
|
+
return this.repeatMove(Direction.Left, repeat)
|
|
162
158
|
}
|
|
163
159
|
|
|
164
160
|
up(repeat: number = 1): Direction[] {
|
|
165
|
-
|
|
161
|
+
return this.repeatMove(Direction.Up, repeat)
|
|
166
162
|
}
|
|
167
163
|
|
|
168
164
|
down(repeat: number = 1): Direction[] {
|
|
169
|
-
|
|
165
|
+
return this.repeatMove(Direction.Down, repeat)
|
|
170
166
|
}
|
|
171
167
|
|
|
172
168
|
wait(sec: number): Promise<unknown> {
|
|
173
|
-
|
|
169
|
+
return wait(sec)
|
|
174
170
|
}
|
|
175
171
|
|
|
176
172
|
random(repeat: number = 1): Direction[] {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
202
|
+
return this.repeatTileMove('right', repeat, 'tileWidth')
|
|
207
203
|
}
|
|
208
204
|
|
|
209
205
|
tileLeft(repeat: number = 1): CallbackTileMove {
|
|
210
|
-
|
|
206
|
+
return this.repeatTileMove('left', repeat, 'tileWidth')
|
|
211
207
|
}
|
|
212
208
|
|
|
213
209
|
tileUp(repeat: number = 1): CallbackTileMove {
|
|
214
|
-
|
|
210
|
+
return this.repeatTileMove('up', repeat, 'tileHeight')
|
|
215
211
|
}
|
|
216
212
|
|
|
217
213
|
tileDown(repeat: number = 1): CallbackTileMove {
|
|
218
|
-
|
|
214
|
+
return this.repeatTileMove('down', repeat, 'tileHeight')
|
|
219
215
|
}
|
|
220
216
|
|
|
221
217
|
tileRandom(repeat: number = 1): CallbackTileMove {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
335
|
+
return this._awayFromPlayer({ isTile: false, typeMov: 'toward' }, player, repeat)
|
|
340
336
|
}
|
|
341
337
|
|
|
342
338
|
tileTowardPlayer(player: RpgPlayer, repeat: number = 1) {
|
|
343
|
-
|
|
339
|
+
return this._awayFromPlayer({ isTile: true, typeMov: 'toward' }, player, repeat)
|
|
344
340
|
}
|
|
345
341
|
|
|
346
342
|
awayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
|
|
347
|
-
|
|
343
|
+
return this._awayFromPlayer({ isTile: false, typeMov: 'away' }, player, repeat)
|
|
348
344
|
}
|
|
349
345
|
|
|
350
346
|
tileAwayFromPlayer(player: RpgPlayer, repeat: number = 1): CallbackTileMove {
|
|
351
|
-
|
|
347
|
+
return this._awayFromPlayer({ isTile: true, typeMov: 'away' }, player, repeat)
|
|
352
348
|
}
|
|
353
349
|
|
|
354
350
|
turnLeft(): string {
|
|
355
|
-
|
|
351
|
+
return 'turn-' + Direction.Left
|
|
356
352
|
}
|
|
357
353
|
|
|
358
354
|
turnRight(): string {
|
|
359
|
-
|
|
355
|
+
return 'turn-' + Direction.Right
|
|
360
356
|
}
|
|
361
357
|
|
|
362
358
|
turnUp(): string {
|
|
363
|
-
|
|
359
|
+
return 'turn-' + Direction.Up
|
|
364
360
|
}
|
|
365
361
|
|
|
366
362
|
turnDown(): string {
|
|
367
|
-
|
|
363
|
+
return 'turn-' + Direction.Down
|
|
368
364
|
}
|
|
369
365
|
|
|
370
366
|
turnRandom(): string {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
712
|
-
|
|
718
|
+
|
|
719
|
+
const engine = map.physic;
|
|
720
|
+
|
|
713
721
|
if ('id' in target) {
|
|
714
|
-
|
|
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(
|
|
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
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
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:
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
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
|
-
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
return WithMoveManagerClass as unknown as PlayerCtor;
|
|
1248
1254
|
}
|
|
1249
1255
|
|
|
1250
1256
|
/**
|