@rpgjs/server 5.0.0-alpha.21 → 5.0.0-alpha.23
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/BattleManager.d.ts +43 -31
- package/dist/Player/ClassManager.d.ts +23 -3
- package/dist/Player/EffectManager.d.ts +49 -3
- package/dist/Player/ElementManager.d.ts +76 -3
- package/dist/Player/ItemManager.d.ts +292 -4
- package/dist/Player/MoveManager.d.ts +145 -4
- package/dist/Player/Player.d.ts +135 -0
- package/dist/Player/SkillManager.d.ts +42 -3
- package/dist/Player/StateManager.d.ts +74 -3
- package/dist/Player/VariableManager.d.ts +47 -3
- package/dist/RpgServer.d.ts +228 -61
- package/dist/decorators/map.d.ts +89 -1
- package/dist/index.js +804 -1703
- package/dist/index.js.map +1 -1
- package/dist/module.d.ts +43 -1
- package/dist/rooms/map.d.ts +676 -12
- package/package.json +8 -8
- package/src/Player/BattleManager.ts +38 -55
- package/src/Player/ClassManager.ts +21 -71
- package/src/Player/EffectManager.ts +50 -96
- package/src/Player/ElementManager.ts +74 -152
- package/src/Player/ItemManager.ts +302 -359
- package/src/Player/MoveManager.ts +141 -438
- package/src/Player/Player.ts +217 -0
- package/src/Player/SkillManager.ts +44 -147
- package/src/Player/StateManager.ts +63 -259
- package/src/Player/VariableManager.ts +53 -150
- package/src/RpgServer.ts +237 -60
- package/src/decorators/map.ts +105 -1
- package/src/module.ts +81 -2
- package/src/rooms/map.ts +757 -23
package/dist/index.js
CHANGED
|
@@ -19913,206 +19913,49 @@ function WithMoveManager(Base) {
|
|
|
19913
19913
|
baseProto.showComponentAnimation.call(this, id, params);
|
|
19914
19914
|
}
|
|
19915
19915
|
}
|
|
19916
|
-
/**
|
|
19917
|
-
* The player passes through the other players (or vice versa). But the player does not go through the events.
|
|
19918
|
-
*
|
|
19919
|
-
* ```ts
|
|
19920
|
-
* player.throughOtherPlayer = true
|
|
19921
|
-
* ```
|
|
19922
|
-
*
|
|
19923
|
-
* @title Go through to other player
|
|
19924
|
-
* @prop {boolean} player.throughOtherPlayer
|
|
19925
|
-
* @default true
|
|
19926
|
-
* @memberof MoveManager
|
|
19927
|
-
* */
|
|
19928
19916
|
set throughOtherPlayer(value) {
|
|
19929
19917
|
this._throughOtherPlayer.set(value);
|
|
19930
19918
|
}
|
|
19931
19919
|
get throughOtherPlayer() {
|
|
19932
19920
|
return this._throughOtherPlayer();
|
|
19933
19921
|
}
|
|
19934
|
-
/**
|
|
19935
|
-
* The player goes through the event or the other players (or vice versa)
|
|
19936
|
-
*
|
|
19937
|
-
* ```ts
|
|
19938
|
-
* player.through = true
|
|
19939
|
-
* ```
|
|
19940
|
-
*
|
|
19941
|
-
* @title Go through the player
|
|
19942
|
-
* @prop {boolean} player.through
|
|
19943
|
-
* @default false
|
|
19944
|
-
* @memberof MoveManager
|
|
19945
|
-
* */
|
|
19946
19922
|
set through(value) {
|
|
19947
19923
|
this._through.set(value);
|
|
19948
19924
|
}
|
|
19949
19925
|
get through() {
|
|
19950
19926
|
return this._through();
|
|
19951
19927
|
}
|
|
19952
|
-
/**
|
|
19953
|
-
* The frequency allows to put a stop time between each movement in the array of the moveRoutes() method.
|
|
19954
|
-
* The value represents a dwell time in milliseconds. The higher the value, the slower the frequency.
|
|
19955
|
-
*
|
|
19956
|
-
* ```ts
|
|
19957
|
-
* player.frequency = 400
|
|
19958
|
-
* ```
|
|
19959
|
-
*
|
|
19960
|
-
* You can use Frequency enum
|
|
19961
|
-
*
|
|
19962
|
-
* ```ts
|
|
19963
|
-
* import { Frequency } from '@rpgjs/server'
|
|
19964
|
-
* player.frequency = Frequency.Low
|
|
19965
|
-
* ```
|
|
19966
|
-
*
|
|
19967
|
-
* @title Change Frequency
|
|
19968
|
-
* @prop {number} player.speed
|
|
19969
|
-
* @enum {number}
|
|
19970
|
-
*
|
|
19971
|
-
* Frequency.Lowest | 600
|
|
19972
|
-
* Frequency.Lower | 400
|
|
19973
|
-
* Frequency.Low | 200
|
|
19974
|
-
* Frequency.High | 100
|
|
19975
|
-
* Frequency.Higher | 50
|
|
19976
|
-
* Frequency.Highest | 25
|
|
19977
|
-
* Frequency.None | 0
|
|
19978
|
-
* @default 0
|
|
19979
|
-
* @memberof MoveManager
|
|
19980
|
-
* */
|
|
19981
19928
|
set frequency(value) {
|
|
19982
19929
|
this._frequency.set(value);
|
|
19983
19930
|
}
|
|
19984
19931
|
get frequency() {
|
|
19985
19932
|
return this._frequency();
|
|
19986
19933
|
}
|
|
19987
|
-
/**
|
|
19988
|
-
* Add a custom movement strategy to this entity
|
|
19989
|
-
*
|
|
19990
|
-
* Allows adding any custom MovementStrategy implementation.
|
|
19991
|
-
* Multiple strategies can be active simultaneously.
|
|
19992
|
-
*
|
|
19993
|
-
* @param strategy - The movement strategy to add
|
|
19994
|
-
*
|
|
19995
|
-
* @example
|
|
19996
|
-
* ```ts
|
|
19997
|
-
* // Add custom movement
|
|
19998
|
-
* const customMove = new LinearMove(5, 0, 1000);
|
|
19999
|
-
* player.addMovement(customMove);
|
|
20000
|
-
*
|
|
20001
|
-
* // Add multiple movements
|
|
20002
|
-
* player.addMovement(new Dash(8, { x: 1, y: 0 }, 200));
|
|
20003
|
-
* player.addMovement(new Oscillate({ x: 0, y: 1 }, 10, 1000));
|
|
20004
|
-
* ```
|
|
20005
|
-
*/
|
|
20006
19934
|
addMovement(strategy) {
|
|
20007
19935
|
const map = this.getCurrentMap();
|
|
20008
19936
|
if (!map) return;
|
|
20009
19937
|
map.moveManager.add(this.id, strategy);
|
|
20010
19938
|
}
|
|
20011
|
-
/**
|
|
20012
|
-
* Remove a specific movement strategy from this entity
|
|
20013
|
-
*
|
|
20014
|
-
* @param strategy - The strategy instance to remove
|
|
20015
|
-
* @returns True if the strategy was found and removed
|
|
20016
|
-
*
|
|
20017
|
-
* @example
|
|
20018
|
-
* ```ts
|
|
20019
|
-
* const dashMove = new Dash(8, { x: 1, y: 0 }, 200);
|
|
20020
|
-
* player.addMovement(dashMove);
|
|
20021
|
-
*
|
|
20022
|
-
* // Later, remove the specific movement
|
|
20023
|
-
* const removed = player.removeMovement(dashMove);
|
|
20024
|
-
* console.log('Movement removed:', removed);
|
|
20025
|
-
* ```
|
|
20026
|
-
*/
|
|
20027
19939
|
removeMovement(strategy) {
|
|
20028
19940
|
const map = this.getCurrentMap();
|
|
20029
19941
|
if (!map) return false;
|
|
20030
19942
|
return map.moveManager.remove(this.id, strategy);
|
|
20031
19943
|
}
|
|
20032
|
-
/**
|
|
20033
|
-
* Remove all active movement strategies from this entity
|
|
20034
|
-
*
|
|
20035
|
-
* Stops all current movements immediately.
|
|
20036
|
-
*
|
|
20037
|
-
* @example
|
|
20038
|
-
* ```ts
|
|
20039
|
-
* // Stop all movements when player dies
|
|
20040
|
-
* player.clearMovements();
|
|
20041
|
-
*
|
|
20042
|
-
* // Clear movements before applying new ones
|
|
20043
|
-
* player.clearMovements();
|
|
20044
|
-
* player.dash({ x: 1, y: 0 });
|
|
20045
|
-
* ```
|
|
20046
|
-
*/
|
|
20047
19944
|
clearMovements() {
|
|
20048
19945
|
const map = this.getCurrentMap();
|
|
20049
19946
|
if (!map) return;
|
|
20050
19947
|
map.moveManager.clear(this.id);
|
|
20051
19948
|
}
|
|
20052
|
-
/**
|
|
20053
|
-
* Check if this entity has any active movement strategies
|
|
20054
|
-
*
|
|
20055
|
-
* @returns True if entity has active movements
|
|
20056
|
-
*
|
|
20057
|
-
* @example
|
|
20058
|
-
* ```ts
|
|
20059
|
-
* // Don't accept input while movements are active
|
|
20060
|
-
* if (!player.hasActiveMovements()) {
|
|
20061
|
-
* player.dash(inputDirection);
|
|
20062
|
-
* }
|
|
20063
|
-
*
|
|
20064
|
-
* // Check before adding new movement
|
|
20065
|
-
* if (player.hasActiveMovements()) {
|
|
20066
|
-
* player.clearMovements();
|
|
20067
|
-
* }
|
|
20068
|
-
* ```
|
|
20069
|
-
*/
|
|
20070
19949
|
hasActiveMovements() {
|
|
20071
19950
|
const map = this.getCurrentMap();
|
|
20072
19951
|
if (!map) return false;
|
|
20073
19952
|
return map.moveManager.hasActiveStrategies(this.id);
|
|
20074
19953
|
}
|
|
20075
|
-
/**
|
|
20076
|
-
* Get all active movement strategies for this entity
|
|
20077
|
-
*
|
|
20078
|
-
* @returns Array of active movement strategies
|
|
20079
|
-
*
|
|
20080
|
-
* @example
|
|
20081
|
-
* ```ts
|
|
20082
|
-
* // Check what movements are currently active
|
|
20083
|
-
* const movements = player.getActiveMovements();
|
|
20084
|
-
* console.log(`Player has ${movements.length} active movements`);
|
|
20085
|
-
*
|
|
20086
|
-
* // Find specific movement type
|
|
20087
|
-
* const hasDash = movements.some(m => m instanceof Dash);
|
|
20088
|
-
* ```
|
|
20089
|
-
*/
|
|
20090
19954
|
getActiveMovements() {
|
|
20091
19955
|
const map = this.getCurrentMap();
|
|
20092
19956
|
if (!map) return [];
|
|
20093
19957
|
return map.moveManager.getStrategies(this.id);
|
|
20094
19958
|
}
|
|
20095
|
-
/**
|
|
20096
|
-
* Move toward a target player or position using AI pathfinding
|
|
20097
|
-
*
|
|
20098
|
-
* Uses SeekAvoid strategy for intelligent pathfinding with obstacle avoidance.
|
|
20099
|
-
* The entity will seek toward the target while avoiding obstacles.
|
|
20100
|
-
*
|
|
20101
|
-
* @param target - Target player or position to move toward
|
|
20102
|
-
*
|
|
20103
|
-
* @example
|
|
20104
|
-
* ```ts
|
|
20105
|
-
* // Move toward another player
|
|
20106
|
-
* const targetPlayer = game.getPlayer('player2');
|
|
20107
|
-
* player.moveTo(targetPlayer);
|
|
20108
|
-
*
|
|
20109
|
-
* // Move toward a specific position
|
|
20110
|
-
* player.moveTo({ x: 300, y: 200 });
|
|
20111
|
-
*
|
|
20112
|
-
* // Stop the movement later
|
|
20113
|
-
* player.stopMoveTo();
|
|
20114
|
-
* ```
|
|
20115
|
-
*/
|
|
20116
19959
|
moveTo(target) {
|
|
20117
19960
|
const map = this.getCurrentMap();
|
|
20118
19961
|
if (!map) return;
|
|
@@ -20135,22 +19978,6 @@ function WithMoveManager(Base) {
|
|
|
20135
19978
|
new SeekAvoid(engine, () => staticTarget, 80, 140, 80, 48)
|
|
20136
19979
|
);
|
|
20137
19980
|
}
|
|
20138
|
-
/**
|
|
20139
|
-
* Stop the current moveTo behavior
|
|
20140
|
-
*
|
|
20141
|
-
* Removes any active SeekAvoid strategies.
|
|
20142
|
-
*
|
|
20143
|
-
* @example
|
|
20144
|
-
* ```ts
|
|
20145
|
-
* // Start following a target
|
|
20146
|
-
* player.moveTo(targetPlayer);
|
|
20147
|
-
*
|
|
20148
|
-
* // Stop following when target is reached
|
|
20149
|
-
* if (distanceToTarget < 10) {
|
|
20150
|
-
* player.stopMoveTo();
|
|
20151
|
-
* }
|
|
20152
|
-
* ```
|
|
20153
|
-
*/
|
|
20154
19981
|
stopMoveTo() {
|
|
20155
19982
|
const map = this.getCurrentMap();
|
|
20156
19983
|
if (!map) return;
|
|
@@ -20161,147 +19988,21 @@ function WithMoveManager(Base) {
|
|
|
20161
19988
|
}
|
|
20162
19989
|
});
|
|
20163
19990
|
}
|
|
20164
|
-
/**
|
|
20165
|
-
* Perform a dash movement in the specified direction
|
|
20166
|
-
*
|
|
20167
|
-
* Applies high-speed movement for a short duration.
|
|
20168
|
-
*
|
|
20169
|
-
* @param direction - Normalized direction vector
|
|
20170
|
-
* @param speed - Movement speed (default: 8)
|
|
20171
|
-
* @param duration - Duration in milliseconds (default: 200)
|
|
20172
|
-
*
|
|
20173
|
-
* @example
|
|
20174
|
-
* ```ts
|
|
20175
|
-
* // Dash right
|
|
20176
|
-
* player.dash({ x: 1, y: 0 });
|
|
20177
|
-
*
|
|
20178
|
-
* // Dash diagonally with custom speed and duration
|
|
20179
|
-
* player.dash({ x: 0.7, y: 0.7 }, 12, 300);
|
|
20180
|
-
*
|
|
20181
|
-
* // Dash in input direction
|
|
20182
|
-
* player.dash(inputDirection, 10, 150);
|
|
20183
|
-
* ```
|
|
20184
|
-
*/
|
|
20185
19991
|
dash(direction, speed = 8, duration = 200) {
|
|
20186
19992
|
this.addMovement(new Dash(speed, direction, duration));
|
|
20187
19993
|
}
|
|
20188
|
-
/**
|
|
20189
|
-
* Apply knockback effect in the specified direction
|
|
20190
|
-
*
|
|
20191
|
-
* Creates a push effect that gradually decreases over time.
|
|
20192
|
-
*
|
|
20193
|
-
* @param direction - Normalized direction vector
|
|
20194
|
-
* @param force - Initial knockback force (default: 5)
|
|
20195
|
-
* @param duration - Duration in milliseconds (default: 300)
|
|
20196
|
-
*
|
|
20197
|
-
* @example
|
|
20198
|
-
* ```ts
|
|
20199
|
-
* // Knockback from explosion
|
|
20200
|
-
* const explosionDir = { x: -1, y: 0 };
|
|
20201
|
-
* player.knockback(explosionDir, 8, 400);
|
|
20202
|
-
*
|
|
20203
|
-
* // Light knockback from attack
|
|
20204
|
-
* player.knockback(attackDirection, 3, 200);
|
|
20205
|
-
* ```
|
|
20206
|
-
*/
|
|
20207
19994
|
knockback(direction, force = 5, duration = 300) {
|
|
20208
19995
|
this.addMovement(new Knockback(direction, force, duration));
|
|
20209
19996
|
}
|
|
20210
|
-
/**
|
|
20211
|
-
* Follow a sequence of waypoints
|
|
20212
|
-
*
|
|
20213
|
-
* Entity will move through each waypoint in order.
|
|
20214
|
-
*
|
|
20215
|
-
* @param waypoints - Array of x,y positions to follow
|
|
20216
|
-
* @param speed - Movement speed (default: 2)
|
|
20217
|
-
* @param loop - Whether to loop back to start (default: false)
|
|
20218
|
-
*
|
|
20219
|
-
* @example
|
|
20220
|
-
* ```ts
|
|
20221
|
-
* // Create a patrol route
|
|
20222
|
-
* const patrolPoints = [
|
|
20223
|
-
* { x: 100, y: 100 },
|
|
20224
|
-
* { x: 300, y: 100 },
|
|
20225
|
-
* { x: 300, y: 300 },
|
|
20226
|
-
* { x: 100, y: 300 }
|
|
20227
|
-
* ];
|
|
20228
|
-
* player.followPath(patrolPoints, 3, true);
|
|
20229
|
-
*
|
|
20230
|
-
* // One-time path to destination
|
|
20231
|
-
* player.followPath([{ x: 500, y: 200 }], 4);
|
|
20232
|
-
* ```
|
|
20233
|
-
*/
|
|
20234
19997
|
followPath(waypoints, speed = 2, loop = false) {
|
|
20235
19998
|
this.addMovement(new PathFollow(waypoints, speed, loop));
|
|
20236
19999
|
}
|
|
20237
|
-
/**
|
|
20238
|
-
* Apply oscillating movement pattern
|
|
20239
|
-
*
|
|
20240
|
-
* Entity moves back and forth along the specified axis.
|
|
20241
|
-
*
|
|
20242
|
-
* @param direction - Primary oscillation axis (normalized)
|
|
20243
|
-
* @param amplitude - Maximum distance from center (default: 50)
|
|
20244
|
-
* @param period - Time for complete cycle in ms (default: 2000)
|
|
20245
|
-
*
|
|
20246
|
-
* @example
|
|
20247
|
-
* ```ts
|
|
20248
|
-
* // Horizontal oscillation
|
|
20249
|
-
* player.oscillate({ x: 1, y: 0 }, 100, 3000);
|
|
20250
|
-
*
|
|
20251
|
-
* // Vertical oscillation
|
|
20252
|
-
* player.oscillate({ x: 0, y: 1 }, 30, 1500);
|
|
20253
|
-
*
|
|
20254
|
-
* // Diagonal oscillation
|
|
20255
|
-
* player.oscillate({ x: 0.7, y: 0.7 }, 75, 2500);
|
|
20256
|
-
* ```
|
|
20257
|
-
*/
|
|
20258
20000
|
oscillate(direction, amplitude = 50, period = 2e3) {
|
|
20259
20001
|
this.addMovement(new Oscillate(direction, amplitude, period));
|
|
20260
20002
|
}
|
|
20261
|
-
/**
|
|
20262
|
-
* Apply ice movement physics
|
|
20263
|
-
*
|
|
20264
|
-
* Creates slippery movement with gradual acceleration and inertia.
|
|
20265
|
-
* Perfect for ice terrains or slippery surfaces.
|
|
20266
|
-
*
|
|
20267
|
-
* @param direction - Target movement direction
|
|
20268
|
-
* @param maxSpeed - Maximum speed when fully accelerated (default: 4)
|
|
20269
|
-
*
|
|
20270
|
-
* @example
|
|
20271
|
-
* ```ts
|
|
20272
|
-
* // Apply ice physics when on ice terrain
|
|
20273
|
-
* if (onIceTerrain) {
|
|
20274
|
-
* player.applyIceMovement(inputDirection, 5);
|
|
20275
|
-
* }
|
|
20276
|
-
*
|
|
20277
|
-
* // Update direction when input changes
|
|
20278
|
-
* iceMovement.setTargetDirection(newDirection);
|
|
20279
|
-
* ```
|
|
20280
|
-
*/
|
|
20281
20003
|
applyIceMovement(direction, maxSpeed = 4) {
|
|
20282
20004
|
this.addMovement(new IceMovement(direction, maxSpeed));
|
|
20283
20005
|
}
|
|
20284
|
-
/**
|
|
20285
|
-
* Shoot a projectile in the specified direction
|
|
20286
|
-
*
|
|
20287
|
-
* Creates projectile movement with various trajectory types.
|
|
20288
|
-
*
|
|
20289
|
-
* @param type - Type of projectile trajectory
|
|
20290
|
-
* @param direction - Normalized direction vector
|
|
20291
|
-
* @param speed - Projectile speed (default: 200)
|
|
20292
|
-
*
|
|
20293
|
-
* @example
|
|
20294
|
-
* ```ts
|
|
20295
|
-
* // Shoot arrow
|
|
20296
|
-
* player.shootProjectile(ProjectileType.Straight, { x: 1, y: 0 }, 300);
|
|
20297
|
-
*
|
|
20298
|
-
* // Throw grenade with arc
|
|
20299
|
-
* player.shootProjectile(ProjectileType.Arc, { x: 0.7, y: 0.7 }, 150);
|
|
20300
|
-
*
|
|
20301
|
-
* // Bouncing projectile
|
|
20302
|
-
* player.shootProjectile(ProjectileType.Bounce, { x: 1, y: 0 }, 100);
|
|
20303
|
-
* ```
|
|
20304
|
-
*/
|
|
20305
20006
|
shootProjectile(type, direction, speed = 200) {
|
|
20306
20007
|
const config = {
|
|
20307
20008
|
speed,
|
|
@@ -20314,49 +20015,6 @@ function WithMoveManager(Base) {
|
|
|
20314
20015
|
};
|
|
20315
20016
|
this.addMovement(new ProjectileMovement(type, config));
|
|
20316
20017
|
}
|
|
20317
|
-
/**
|
|
20318
|
-
* Give an itinerary to follow using movement strategies
|
|
20319
|
-
*
|
|
20320
|
-
* Executes a sequence of movements and actions in order. Each route can be:
|
|
20321
|
-
* - A Direction enum value for basic movement
|
|
20322
|
-
* - A string starting with "turn-" for direction changes
|
|
20323
|
-
* - A function that returns directions or actions
|
|
20324
|
-
* - A Promise for async operations
|
|
20325
|
-
*
|
|
20326
|
-
* The method processes routes sequentially, respecting the entity's frequency
|
|
20327
|
-
* setting for timing between movements.
|
|
20328
|
-
*
|
|
20329
|
-
* @param routes - Array of movement instructions to execute
|
|
20330
|
-
* @returns Promise that resolves when all routes are completed
|
|
20331
|
-
*
|
|
20332
|
-
* @example
|
|
20333
|
-
* ```ts
|
|
20334
|
-
* // Basic directional movements
|
|
20335
|
-
* await player.moveRoutes([
|
|
20336
|
-
* Direction.Right,
|
|
20337
|
-
* Direction.Up,
|
|
20338
|
-
* Direction.Left
|
|
20339
|
-
* ]);
|
|
20340
|
-
*
|
|
20341
|
-
* // Mix of movements and turns
|
|
20342
|
-
* await player.moveRoutes([
|
|
20343
|
-
* Direction.Right,
|
|
20344
|
-
* 'turn-' + Direction.Up,
|
|
20345
|
-
* Direction.Up
|
|
20346
|
-
* ]);
|
|
20347
|
-
*
|
|
20348
|
-
* // Using functions for dynamic behavior
|
|
20349
|
-
* const customMove = (player, map) => [Direction.Right, Direction.Down];
|
|
20350
|
-
* await player.moveRoutes([customMove]);
|
|
20351
|
-
*
|
|
20352
|
-
* // With async operations
|
|
20353
|
-
* await player.moveRoutes([
|
|
20354
|
-
* Direction.Right,
|
|
20355
|
-
* new Promise(resolve => setTimeout(resolve, 1000)), // Wait 1 second
|
|
20356
|
-
* Direction.Left
|
|
20357
|
-
* ]);
|
|
20358
|
-
* ```
|
|
20359
|
-
*/
|
|
20360
20018
|
moveRoutes(routes) {
|
|
20361
20019
|
let count = 0;
|
|
20362
20020
|
let frequence = 0;
|
|
@@ -20468,13 +20126,6 @@ function WithMoveManager(Base) {
|
|
|
20468
20126
|
executeNextRoute();
|
|
20469
20127
|
});
|
|
20470
20128
|
}
|
|
20471
|
-
/**
|
|
20472
|
-
* Utility method to flatten nested route arrays
|
|
20473
|
-
*
|
|
20474
|
-
* @private
|
|
20475
|
-
* @param routes - Routes array that may contain nested arrays
|
|
20476
|
-
* @returns Flattened array of routes
|
|
20477
|
-
*/
|
|
20478
20129
|
flattenRoutes(routes) {
|
|
20479
20130
|
return routes.reduce((acc, item) => {
|
|
20480
20131
|
if (Array.isArray(item)) {
|
|
@@ -20483,43 +20134,6 @@ function WithMoveManager(Base) {
|
|
|
20483
20134
|
return acc.concat(item);
|
|
20484
20135
|
}, []);
|
|
20485
20136
|
}
|
|
20486
|
-
/**
|
|
20487
|
-
* Give a path that repeats itself in a loop to a character
|
|
20488
|
-
*
|
|
20489
|
-
* Creates an infinite movement pattern that continues until manually stopped.
|
|
20490
|
-
* The routes will repeat in a continuous loop, making it perfect for patrol
|
|
20491
|
-
* patterns, ambient movements, or any repetitive behavior.
|
|
20492
|
-
*
|
|
20493
|
-
* You can stop the movement at any time with `breakRoutes()` and replay it
|
|
20494
|
-
* with `replayRoutes()`.
|
|
20495
|
-
*
|
|
20496
|
-
* @param routes - Array of movement instructions to repeat infinitely
|
|
20497
|
-
*
|
|
20498
|
-
* @example
|
|
20499
|
-
* ```ts
|
|
20500
|
-
* // Create an infinite random movement pattern
|
|
20501
|
-
* player.infiniteMoveRoute([Move.random()]);
|
|
20502
|
-
*
|
|
20503
|
-
* // Create a patrol route
|
|
20504
|
-
* player.infiniteMoveRoute([
|
|
20505
|
-
* Direction.Right,
|
|
20506
|
-
* Direction.Right,
|
|
20507
|
-
* Direction.Down,
|
|
20508
|
-
* Direction.Left,
|
|
20509
|
-
* Direction.Left,
|
|
20510
|
-
* Direction.Up
|
|
20511
|
-
* ]);
|
|
20512
|
-
*
|
|
20513
|
-
* // Mix movements and rotations
|
|
20514
|
-
* player.infiniteMoveRoute([
|
|
20515
|
-
* Move.turnRight(),
|
|
20516
|
-
* Direction.Right,
|
|
20517
|
-
* Move.wait(1),
|
|
20518
|
-
* Move.turnLeft(),
|
|
20519
|
-
* Direction.Left
|
|
20520
|
-
* ]);
|
|
20521
|
-
* ```
|
|
20522
|
-
*/
|
|
20523
20137
|
infiniteMoveRoute(routes) {
|
|
20524
20138
|
this._infiniteRoutes = routes;
|
|
20525
20139
|
this._isInfiniteRouteActive = true;
|
|
@@ -20538,29 +20152,6 @@ function WithMoveManager(Base) {
|
|
|
20538
20152
|
};
|
|
20539
20153
|
executeInfiniteRoute();
|
|
20540
20154
|
}
|
|
20541
|
-
/**
|
|
20542
|
-
* Stop an infinite movement
|
|
20543
|
-
*
|
|
20544
|
-
* Works only for infinite movements created with `infiniteMoveRoute()`.
|
|
20545
|
-
* This method stops the current route execution and prevents the next
|
|
20546
|
-
* iteration from starting.
|
|
20547
|
-
*
|
|
20548
|
-
* @param force - Forces the stop of the infinite movement immediately
|
|
20549
|
-
*
|
|
20550
|
-
* @example
|
|
20551
|
-
* ```ts
|
|
20552
|
-
* // Start infinite movement
|
|
20553
|
-
* player.infiniteMoveRoute([Move.random()]);
|
|
20554
|
-
*
|
|
20555
|
-
* // Stop it when player enters combat
|
|
20556
|
-
* if (inCombat) {
|
|
20557
|
-
* player.breakRoutes(true);
|
|
20558
|
-
* }
|
|
20559
|
-
*
|
|
20560
|
-
* // Gentle stop (completes current route first)
|
|
20561
|
-
* player.breakRoutes();
|
|
20562
|
-
* ```
|
|
20563
|
-
*/
|
|
20564
20155
|
breakRoutes(force = false) {
|
|
20565
20156
|
this._isInfiniteRouteActive = false;
|
|
20566
20157
|
if (force) {
|
|
@@ -20571,32 +20162,6 @@ function WithMoveManager(Base) {
|
|
|
20571
20162
|
this._finishRoute = null;
|
|
20572
20163
|
}
|
|
20573
20164
|
}
|
|
20574
|
-
/**
|
|
20575
|
-
* Replay an infinite movement
|
|
20576
|
-
*
|
|
20577
|
-
* Works only for infinite movements that were previously created with
|
|
20578
|
-
* `infiniteMoveRoute()`. If the route was stopped with `breakRoutes()`,
|
|
20579
|
-
* you can restart it with this method using the same route configuration.
|
|
20580
|
-
*
|
|
20581
|
-
* @example
|
|
20582
|
-
* ```ts
|
|
20583
|
-
* // Create infinite movement
|
|
20584
|
-
* player.infiniteMoveRoute([Move.random()]);
|
|
20585
|
-
*
|
|
20586
|
-
* // Stop it temporarily
|
|
20587
|
-
* player.breakRoutes(true);
|
|
20588
|
-
*
|
|
20589
|
-
* // Resume the same movement pattern
|
|
20590
|
-
* player.replayRoutes();
|
|
20591
|
-
*
|
|
20592
|
-
* // Stop and start with different conditions
|
|
20593
|
-
* if (playerNearby) {
|
|
20594
|
-
* player.breakRoutes();
|
|
20595
|
-
* } else {
|
|
20596
|
-
* player.replayRoutes();
|
|
20597
|
-
* }
|
|
20598
|
-
* ```
|
|
20599
|
-
*/
|
|
20600
20165
|
replayRoutes() {
|
|
20601
20166
|
if (this._infiniteRoutes && !this._isInfiniteRouteActive) {
|
|
20602
20167
|
this.infiniteMoveRoute(this._infiniteRoutes);
|
|
@@ -20903,168 +20468,21 @@ function WithVariableManager(Base) {
|
|
|
20903
20468
|
super(...arguments);
|
|
20904
20469
|
this.variables = /* @__PURE__ */ new Map();
|
|
20905
20470
|
}
|
|
20906
|
-
/**
|
|
20907
|
-
* Assign a variable to the player
|
|
20908
|
-
*
|
|
20909
|
-
* Stores a key-value pair in the player's variable map. This is useful for
|
|
20910
|
-
* tracking game state, quest progress, flags, and other player-specific data.
|
|
20911
|
-
* The variable system provides a flexible way to store any type of data
|
|
20912
|
-
* associated with the player that persists throughout the game session.
|
|
20913
|
-
*
|
|
20914
|
-
* @param key - The variable identifier (string key to reference the variable)
|
|
20915
|
-
* @param val - The value to store (can be any type: boolean, number, string, object, array)
|
|
20916
|
-
* @returns void
|
|
20917
|
-
*
|
|
20918
|
-
* @example
|
|
20919
|
-
* ```ts
|
|
20920
|
-
* // Set different types of variables
|
|
20921
|
-
* player.setVariable('CHEST_OPENED', true);
|
|
20922
|
-
* player.setVariable('playerLevel', 5);
|
|
20923
|
-
* player.setVariable('questProgress', { step: 1, completed: false });
|
|
20924
|
-
* player.setVariable('inventory', ['sword', 'potion', 'key']);
|
|
20925
|
-
* player.setVariable('lastSaveTime', new Date().toISOString());
|
|
20926
|
-
* ```
|
|
20927
|
-
*/
|
|
20928
20471
|
setVariable(key, val) {
|
|
20929
20472
|
this.variables.set(key, val);
|
|
20930
20473
|
}
|
|
20931
|
-
/**
|
|
20932
|
-
* Get a variable value
|
|
20933
|
-
*
|
|
20934
|
-
* Retrieves the value associated with the given key from the player's variables.
|
|
20935
|
-
* Returns undefined if the variable doesn't exist. This method is type-safe
|
|
20936
|
-
* and can be used with generic types for better TypeScript support.
|
|
20937
|
-
*
|
|
20938
|
-
* @param key - The variable identifier to retrieve
|
|
20939
|
-
* @returns The stored value or undefined if not found
|
|
20940
|
-
*
|
|
20941
|
-
* @example
|
|
20942
|
-
* ```ts
|
|
20943
|
-
* // Get variables with type inference
|
|
20944
|
-
* const hasKey = player.getVariable('CHEST_OPENED'); // boolean | undefined
|
|
20945
|
-
* const level = player.getVariable('playerLevel'); // number | undefined
|
|
20946
|
-
* const quest = player.getVariable('questProgress'); // object | undefined
|
|
20947
|
-
* const missing = player.getVariable('nonexistent'); // undefined
|
|
20948
|
-
*
|
|
20949
|
-
* // Use with default values
|
|
20950
|
-
* const level = player.getVariable('playerLevel') ?? 1;
|
|
20951
|
-
* const isChestOpened = player.getVariable('CHEST_OPENED') ?? false;
|
|
20952
|
-
* ```
|
|
20953
|
-
*/
|
|
20954
20474
|
getVariable(key) {
|
|
20955
20475
|
return this.variables.get(key);
|
|
20956
20476
|
}
|
|
20957
|
-
/**
|
|
20958
|
-
* Remove a variable
|
|
20959
|
-
*
|
|
20960
|
-
* Deletes a variable from the player's variable map. This is useful for
|
|
20961
|
-
* cleaning up temporary flags, resetting certain game states, or managing
|
|
20962
|
-
* memory by removing unused variables. The method returns a boolean indicating
|
|
20963
|
-
* whether the variable existed and was successfully removed.
|
|
20964
|
-
*
|
|
20965
|
-
* @param key - The variable identifier to remove
|
|
20966
|
-
* @returns true if a variable existed and has been removed, false if the variable does not exist
|
|
20967
|
-
*
|
|
20968
|
-
* @example
|
|
20969
|
-
* ```ts
|
|
20970
|
-
* // Remove variables and check if they existed
|
|
20971
|
-
* const removed = player.removeVariable('CHEST_OPENED'); // true if existed
|
|
20972
|
-
* const notFound = player.removeVariable('nonexistent'); // false
|
|
20973
|
-
*
|
|
20974
|
-
* // Clean up temporary variables
|
|
20975
|
-
* player.removeVariable('tempQuestFlag');
|
|
20976
|
-
* player.removeVariable('battleTempData');
|
|
20977
|
-
*
|
|
20978
|
-
* // Conditional removal
|
|
20979
|
-
* if (player.getVariable('questCompleted')) {
|
|
20980
|
-
* player.removeVariable('questProgress');
|
|
20981
|
-
* }
|
|
20982
|
-
* ```
|
|
20983
|
-
*/
|
|
20984
20477
|
removeVariable(key) {
|
|
20985
20478
|
return this.variables.delete(key);
|
|
20986
20479
|
}
|
|
20987
|
-
/**
|
|
20988
|
-
* Check if a variable exists
|
|
20989
|
-
*
|
|
20990
|
-
* Determines whether a variable with the given key exists in the player's
|
|
20991
|
-
* variable map, regardless of its value (including falsy values like false, 0, '').
|
|
20992
|
-
* This is useful when you need to distinguish between a variable that doesn't
|
|
20993
|
-
* exist and one that has a falsy value.
|
|
20994
|
-
*
|
|
20995
|
-
* @param key - The variable identifier to check
|
|
20996
|
-
* @returns true if the variable exists, false otherwise
|
|
20997
|
-
*
|
|
20998
|
-
* @example
|
|
20999
|
-
* ```ts
|
|
21000
|
-
* // Check variable existence
|
|
21001
|
-
* player.setVariable('flag', false);
|
|
21002
|
-
* player.hasVariable('flag'); // true (even though value is false)
|
|
21003
|
-
* player.hasVariable('missing'); // false
|
|
21004
|
-
*
|
|
21005
|
-
* // Use in conditional logic
|
|
21006
|
-
* if (player.hasVariable('questStarted')) {
|
|
21007
|
-
* // Quest has been started, check progress
|
|
21008
|
-
* const progress = player.getVariable('questProgress');
|
|
21009
|
-
* } else {
|
|
21010
|
-
* // Quest not started yet
|
|
21011
|
-
* player.setVariable('questStarted', true);
|
|
21012
|
-
* }
|
|
21013
|
-
* ```
|
|
21014
|
-
*/
|
|
21015
20480
|
hasVariable(key) {
|
|
21016
20481
|
return this.variables.has(key);
|
|
21017
20482
|
}
|
|
21018
|
-
/**
|
|
21019
|
-
* Get all variable keys
|
|
21020
|
-
*
|
|
21021
|
-
* Returns an array of all variable keys currently stored for this player.
|
|
21022
|
-
* This is useful for debugging, serialization, or iterating over all variables.
|
|
21023
|
-
* The keys are returned in insertion order.
|
|
21024
|
-
*
|
|
21025
|
-
* @returns Array of all variable keys
|
|
21026
|
-
*
|
|
21027
|
-
* @example
|
|
21028
|
-
* ```ts
|
|
21029
|
-
* // Get all variable keys
|
|
21030
|
-
* const keys = player.getVariableKeys();
|
|
21031
|
-
* console.log('Player has variables:', keys);
|
|
21032
|
-
*
|
|
21033
|
-
* // Iterate over all variables
|
|
21034
|
-
* keys.forEach(key => {
|
|
21035
|
-
* const value = player.getVariable(key);
|
|
21036
|
-
* console.log(`${key}: ${value}`);
|
|
21037
|
-
* });
|
|
21038
|
-
*
|
|
21039
|
-
* // Filter specific variable types
|
|
21040
|
-
* const questKeys = keys.filter(key => key.startsWith('quest_'));
|
|
21041
|
-
* ```
|
|
21042
|
-
*/
|
|
21043
20483
|
getVariableKeys() {
|
|
21044
20484
|
return Array.from(this.variables.keys());
|
|
21045
20485
|
}
|
|
21046
|
-
/**
|
|
21047
|
-
* Clear all variables
|
|
21048
|
-
*
|
|
21049
|
-
* Removes all variables from the player's variable map. This is useful for
|
|
21050
|
-
* resetting the player state, cleaning up before saving, or starting fresh.
|
|
21051
|
-
* Use with caution as this operation cannot be undone.
|
|
21052
|
-
*
|
|
21053
|
-
* @returns void
|
|
21054
|
-
*
|
|
21055
|
-
* @example
|
|
21056
|
-
* ```ts
|
|
21057
|
-
* // Clear all variables (use with caution)
|
|
21058
|
-
* player.clearVariables();
|
|
21059
|
-
*
|
|
21060
|
-
* // Clear variables conditionally
|
|
21061
|
-
* if (gameReset) {
|
|
21062
|
-
* player.clearVariables();
|
|
21063
|
-
* // Re-initialize essential variables
|
|
21064
|
-
* player.setVariable('gameStarted', true);
|
|
21065
|
-
* }
|
|
21066
|
-
* ```
|
|
21067
|
-
*/
|
|
21068
20486
|
clearVariables() {
|
|
21069
20487
|
this.variables.clear();
|
|
21070
20488
|
}
|
|
@@ -21673,42 +21091,10 @@ class StateLog {
|
|
|
21673
21091
|
|
|
21674
21092
|
function WithItemManager(Base) {
|
|
21675
21093
|
return class extends Base {
|
|
21676
|
-
/**
|
|
21677
|
-
* Retrieves the information of an object: the number and the instance
|
|
21678
|
-
* @title Get Item
|
|
21679
|
-
* @method player.getItem(itemClass)
|
|
21680
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
21681
|
-
* @returns {{ nb: number, item: instance of ItemClass }}
|
|
21682
|
-
* @memberof ItemManager
|
|
21683
|
-
* @example
|
|
21684
|
-
*
|
|
21685
|
-
* ```ts
|
|
21686
|
-
* import Potion from 'your-database/potion'
|
|
21687
|
-
*
|
|
21688
|
-
* player.addItem(Potion, 5)
|
|
21689
|
-
* const inventory = player.getItem(Potion)
|
|
21690
|
-
* console.log(inventory) // { nb: 5, item: <instance of Potion> }
|
|
21691
|
-
* ```
|
|
21692
|
-
*/
|
|
21693
21094
|
getItem(itemClass) {
|
|
21694
21095
|
const index = this._getItemIndex(itemClass);
|
|
21695
21096
|
return this.items()[index];
|
|
21696
21097
|
}
|
|
21697
|
-
/**
|
|
21698
|
-
* Check if the player has the item in his inventory.
|
|
21699
|
-
* @title Has Item
|
|
21700
|
-
* @method player.hasItem(itemClass)
|
|
21701
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
21702
|
-
* @returns {boolean}
|
|
21703
|
-
* @memberof ItemManager
|
|
21704
|
-
* @example
|
|
21705
|
-
*
|
|
21706
|
-
* ```ts
|
|
21707
|
-
* import Potion from 'your-database/potion'
|
|
21708
|
-
*
|
|
21709
|
-
* player.hasItem(Potion) // false
|
|
21710
|
-
* ```
|
|
21711
|
-
*/
|
|
21712
21098
|
hasItem(itemClass) {
|
|
21713
21099
|
return !!this.getItem(itemClass);
|
|
21714
21100
|
}
|
|
@@ -21720,62 +21106,6 @@ function WithItemManager(Base) {
|
|
|
21720
21106
|
return isInstanceOf(it, itemClass);
|
|
21721
21107
|
});
|
|
21722
21108
|
}
|
|
21723
|
-
/**
|
|
21724
|
-
* Add an item in the player's inventory. You can give more than one by specifying `nb`
|
|
21725
|
-
*
|
|
21726
|
-
* Supports three ways to add items:
|
|
21727
|
-
* 1. **String**: Pass a string ID to retrieve the item from the database (requires item to be registered in `@RpgModule` database).
|
|
21728
|
-
* 2. **Class**: Pass an item class (e.g., `Potion`). The class will be instantiated and automatically added to the map's database if not already present.
|
|
21729
|
-
* 3. **Object**: Pass an item object with properties and hooks directly. The object will be automatically added to the map's database if not already present.
|
|
21730
|
-
*
|
|
21731
|
-
* For classes and objects, if they don't exist in the database, they are automatically added using `map.addInDatabase()`.
|
|
21732
|
-
* This allows dynamic item creation without requiring pre-registration in the module database.
|
|
21733
|
-
*
|
|
21734
|
-
* `onAdd()` method is called on the ItemClass or ItemObject
|
|
21735
|
-
*
|
|
21736
|
-
* @title Add Item
|
|
21737
|
-
* @method player.addItem(item,nb=1)
|
|
21738
|
-
* @param {ItemClass | ItemObject | string} item - Item class, object, or string identifier
|
|
21739
|
-
* @param {number} [nb] Default 1
|
|
21740
|
-
* @returns {Item} The item instance added to inventory
|
|
21741
|
-
* @memberof ItemManager
|
|
21742
|
-
* @example
|
|
21743
|
-
*
|
|
21744
|
-
* ```ts
|
|
21745
|
-
* import Potion from 'your-database/potion'
|
|
21746
|
-
*
|
|
21747
|
-
* // Using string ID (retrieves from database - item must be in @RpgModule database)
|
|
21748
|
-
* player.addItem('Potion', 5)
|
|
21749
|
-
*
|
|
21750
|
-
* // Using class (creates instance, auto-adds to map database if not present)
|
|
21751
|
-
* player.addItem(Potion, 5)
|
|
21752
|
-
*
|
|
21753
|
-
* // Using object directly (auto-adds to map database if not present)
|
|
21754
|
-
* player.addItem({
|
|
21755
|
-
* id: 'custom-potion',
|
|
21756
|
-
* name: 'Custom Potion',
|
|
21757
|
-
* description: 'A custom potion',
|
|
21758
|
-
* price: 150,
|
|
21759
|
-
* hpValue: 50,
|
|
21760
|
-
* consumable: true,
|
|
21761
|
-
* onAdd(player) {
|
|
21762
|
-
* console.log('Custom potion added!');
|
|
21763
|
-
* },
|
|
21764
|
-
* onUse(player) {
|
|
21765
|
-
* player.hp += 50;
|
|
21766
|
-
* }
|
|
21767
|
-
* }, 3)
|
|
21768
|
-
*
|
|
21769
|
-
* // Object without ID (auto-generates ID and adds to database)
|
|
21770
|
-
* player.addItem({
|
|
21771
|
-
* name: 'Dynamic Item',
|
|
21772
|
-
* price: 100,
|
|
21773
|
-
* onUse(player) {
|
|
21774
|
-
* console.log('Dynamic item used!');
|
|
21775
|
-
* }
|
|
21776
|
-
* })
|
|
21777
|
-
* ```
|
|
21778
|
-
*/
|
|
21779
21109
|
addItem(item, nb = 1) {
|
|
21780
21110
|
const map = this.getCurrentMap();
|
|
21781
21111
|
if (!map) {
|
|
@@ -21835,38 +21165,6 @@ function WithItemManager(Base) {
|
|
|
21835
21165
|
this["execMethod"]("onAdd", [this], hookTarget);
|
|
21836
21166
|
return instance;
|
|
21837
21167
|
}
|
|
21838
|
-
/**
|
|
21839
|
-
* Deletes an item. Decreases the value `nb`. If the number falls to 0, then the item is removed from the inventory. The method then returns `undefined`
|
|
21840
|
-
*
|
|
21841
|
-
* `onRemove()` method is called on the ItemClass
|
|
21842
|
-
*
|
|
21843
|
-
* @title Remove Item
|
|
21844
|
-
* @method player.removeItem(item,nb=1)
|
|
21845
|
-
* @param {ItemClass | string} itemClass string is item id
|
|
21846
|
-
* @param {number} [nb] Default 1
|
|
21847
|
-
* @returns {{ nb: number, item: instance of ItemClass } | undefined}
|
|
21848
|
-
* @throws {ItemLog} notInInventory
|
|
21849
|
-
* If the object is not in the inventory, an exception is raised
|
|
21850
|
-
* ```
|
|
21851
|
-
* {
|
|
21852
|
-
* id: ITEM_NOT_INVENTORY,
|
|
21853
|
-
* msg: '...'
|
|
21854
|
-
* }
|
|
21855
|
-
* ```
|
|
21856
|
-
* @memberof ItemManager
|
|
21857
|
-
* @example
|
|
21858
|
-
*
|
|
21859
|
-
* ```ts
|
|
21860
|
-
* import Potion from 'your-database/potion'
|
|
21861
|
-
*
|
|
21862
|
-
* try {
|
|
21863
|
-
* player.removeItem(Potion, 5)
|
|
21864
|
-
* }
|
|
21865
|
-
* catch (err) {
|
|
21866
|
-
* console.log(err)
|
|
21867
|
-
* }
|
|
21868
|
-
* ```
|
|
21869
|
-
*/
|
|
21870
21168
|
removeItem(itemClass, nb = 1) {
|
|
21871
21169
|
const itemIndex = this._getItemIndex(itemClass);
|
|
21872
21170
|
if (itemIndex == -1) {
|
|
@@ -21883,50 +21181,6 @@ function WithItemManager(Base) {
|
|
|
21883
21181
|
this["execMethod"]("onRemove", [this], hookTarget);
|
|
21884
21182
|
return this.items()[itemIndex];
|
|
21885
21183
|
}
|
|
21886
|
-
/**
|
|
21887
|
-
* Purchases an item and reduces the amount of gold
|
|
21888
|
-
*
|
|
21889
|
-
* `onAdd()` method is called on the ItemClass
|
|
21890
|
-
*
|
|
21891
|
-
* @title Buy Item
|
|
21892
|
-
* @method player.buyItem(item,nb=1)
|
|
21893
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
21894
|
-
* @param {number} [nb] Default 1
|
|
21895
|
-
* @returns {{ nb: number, item: instance of ItemClass }}
|
|
21896
|
-
* @throws {ItemLog} haveNotPrice
|
|
21897
|
-
* If you have not set a price on the item
|
|
21898
|
-
* ```
|
|
21899
|
-
* {
|
|
21900
|
-
* id: NOT_PRICE,
|
|
21901
|
-
* msg: '...'
|
|
21902
|
-
* }
|
|
21903
|
-
* ```
|
|
21904
|
-
* @throws {ItemLog} notEnoughGold
|
|
21905
|
-
* If the player does not have enough money
|
|
21906
|
-
* ```
|
|
21907
|
-
* {
|
|
21908
|
-
* id: NOT_ENOUGH_GOLD,
|
|
21909
|
-
* msg: '...'
|
|
21910
|
-
* }
|
|
21911
|
-
* ```
|
|
21912
|
-
* @memberof ItemManager
|
|
21913
|
-
* @example
|
|
21914
|
-
*
|
|
21915
|
-
* ```ts
|
|
21916
|
-
* import Potion from 'your-database/potion'
|
|
21917
|
-
*
|
|
21918
|
-
* try {
|
|
21919
|
-
* // Using class
|
|
21920
|
-
* player.buyItem(Potion)
|
|
21921
|
-
*
|
|
21922
|
-
* // Using string ID
|
|
21923
|
-
* player.buyItem('Potion')
|
|
21924
|
-
* }
|
|
21925
|
-
* catch (err) {
|
|
21926
|
-
* console.log(err)
|
|
21927
|
-
* }
|
|
21928
|
-
* ```
|
|
21929
|
-
*/
|
|
21930
21184
|
buyItem(item, nb = 1) {
|
|
21931
21185
|
let itemId;
|
|
21932
21186
|
let data;
|
|
@@ -21956,58 +21210,6 @@ function WithItemManager(Base) {
|
|
|
21956
21210
|
this._gold.update((gold) => gold - totalPrice);
|
|
21957
21211
|
return this.addItem(item, nb);
|
|
21958
21212
|
}
|
|
21959
|
-
/**
|
|
21960
|
-
* Sell an item and the player wins the amount of the item divided by 2
|
|
21961
|
-
*
|
|
21962
|
-
* `onRemove()` method is called on the ItemClass
|
|
21963
|
-
*
|
|
21964
|
-
* @title Sell Item
|
|
21965
|
-
* @method player.sellItem(item,nb=1)
|
|
21966
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
21967
|
-
* @param {number} [nbToSell] Default 1
|
|
21968
|
-
* @returns {{ nb: number, item: instance of ItemClass }}
|
|
21969
|
-
* @throws {ItemLog} haveNotPrice
|
|
21970
|
-
* If you have not set a price on the item
|
|
21971
|
-
* ```
|
|
21972
|
-
* {
|
|
21973
|
-
* id: NOT_PRICE,
|
|
21974
|
-
* msg: '...'
|
|
21975
|
-
* }
|
|
21976
|
-
* ```
|
|
21977
|
-
* @throws {ItemLog} notInInventory
|
|
21978
|
-
* If the object is not in the inventory, an exception is raised
|
|
21979
|
-
* ```
|
|
21980
|
-
* {
|
|
21981
|
-
* id: ITEM_NOT_INVENTORY,
|
|
21982
|
-
* msg: '...'
|
|
21983
|
-
* }
|
|
21984
|
-
* ```
|
|
21985
|
-
* @throws {ItemLog} tooManyToSell
|
|
21986
|
-
* If the number of items for sale exceeds the number of actual items in the inventory
|
|
21987
|
-
* ```
|
|
21988
|
-
* {
|
|
21989
|
-
* id: TOO_MANY_ITEM_TO_SELL,
|
|
21990
|
-
* msg: '...'
|
|
21991
|
-
* }
|
|
21992
|
-
* ```
|
|
21993
|
-
* @memberof ItemManager
|
|
21994
|
-
* @example
|
|
21995
|
-
*
|
|
21996
|
-
* ```ts
|
|
21997
|
-
* import Potion from 'your-database/potion'
|
|
21998
|
-
*
|
|
21999
|
-
* try {
|
|
22000
|
-
* player.addItem(Potion)
|
|
22001
|
-
* // Using class
|
|
22002
|
-
* player.sellItem(Potion)
|
|
22003
|
-
* // Using string ID
|
|
22004
|
-
* player.sellItem('Potion')
|
|
22005
|
-
* }
|
|
22006
|
-
* catch (err) {
|
|
22007
|
-
* console.log(err)
|
|
22008
|
-
* }
|
|
22009
|
-
* ```
|
|
22010
|
-
*/
|
|
22011
21213
|
sellItem(itemClass, nbToSell = 1) {
|
|
22012
21214
|
const itemId = isString(itemClass) ? itemClass : itemClass.name;
|
|
22013
21215
|
const data = this.databaseById(itemId);
|
|
@@ -22038,100 +21240,15 @@ function WithItemManager(Base) {
|
|
|
22038
21240
|
}
|
|
22039
21241
|
return nb;
|
|
22040
21242
|
}
|
|
22041
|
-
/**
|
|
22042
|
-
* recover the attack sum of items equipped on the player.
|
|
22043
|
-
*
|
|
22044
|
-
* @title Get the player's attack
|
|
22045
|
-
* @prop {number} player.atk
|
|
22046
|
-
* @memberof ItemManager
|
|
22047
|
-
*/
|
|
22048
21243
|
get atk() {
|
|
22049
21244
|
return this.getParamItem(ATK);
|
|
22050
21245
|
}
|
|
22051
|
-
/**
|
|
22052
|
-
* recover the physic defense sum of items equipped on the player.
|
|
22053
|
-
*
|
|
22054
|
-
* @title Get the player's pdef
|
|
22055
|
-
* @prop {number} player.pdef
|
|
22056
|
-
* @memberof ItemManager
|
|
22057
|
-
*/
|
|
22058
21246
|
get pdef() {
|
|
22059
21247
|
return this.getParamItem(PDEF);
|
|
22060
21248
|
}
|
|
22061
|
-
/**
|
|
22062
|
-
* recover the skill defense sum of items equipped on the player.
|
|
22063
|
-
*
|
|
22064
|
-
* @title Get the player's sdef
|
|
22065
|
-
* @prop {number} player.sdef
|
|
22066
|
-
* @memberof ItemManager
|
|
22067
|
-
*/
|
|
22068
21249
|
get sdef() {
|
|
22069
21250
|
return this.getParamItem(SDEF);
|
|
22070
21251
|
}
|
|
22071
|
-
/**
|
|
22072
|
-
* Use an object. Applies effects and states. Removes the object from the inventory then
|
|
22073
|
-
*
|
|
22074
|
-
* `onUse()` method is called on the ItemClass (If the use has worked)
|
|
22075
|
-
* `onRemove()` method is called on the ItemClass
|
|
22076
|
-
*
|
|
22077
|
-
* @title Use an Item
|
|
22078
|
-
* @method player.useItem(item,nb=1)
|
|
22079
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
22080
|
-
* @returns {{ nb: number, item: instance of ItemClass }}
|
|
22081
|
-
* @throws {ItemLog} restriction
|
|
22082
|
-
* If the player has the `Effect.CAN_NOT_ITEM` effect
|
|
22083
|
-
* ```
|
|
22084
|
-
* {
|
|
22085
|
-
* id: RESTRICTION_ITEM,
|
|
22086
|
-
* msg: '...'
|
|
22087
|
-
* }
|
|
22088
|
-
* ```
|
|
22089
|
-
* @throws {ItemLog} notInInventory
|
|
22090
|
-
* If the object is not in the inventory, an exception is raised
|
|
22091
|
-
* ```
|
|
22092
|
-
* {
|
|
22093
|
-
* id: ITEM_NOT_INVENTORY,
|
|
22094
|
-
* msg: '...'
|
|
22095
|
-
* }
|
|
22096
|
-
* ```
|
|
22097
|
-
* @throws {ItemLog} notUseItem
|
|
22098
|
-
* If the `consumable` property is on false
|
|
22099
|
-
* ```
|
|
22100
|
-
* {
|
|
22101
|
-
* id: NOT_USE_ITEM,
|
|
22102
|
-
* msg: '...'
|
|
22103
|
-
* }
|
|
22104
|
-
* ```
|
|
22105
|
-
* @throws {ItemLog} chanceToUseFailed
|
|
22106
|
-
* Chance to use the item has failed. Chances of use is defined with `ItemClass.hitRate`
|
|
22107
|
-
* ```
|
|
22108
|
-
* {
|
|
22109
|
-
* id: USE_CHANCE_ITEM_FAILED,
|
|
22110
|
-
* msg: '...'
|
|
22111
|
-
* }
|
|
22112
|
-
* ```
|
|
22113
|
-
* > the item is still deleted from the inventory
|
|
22114
|
-
*
|
|
22115
|
-
* `onUseFailed()` method is called on the ItemClass
|
|
22116
|
-
*
|
|
22117
|
-
* @memberof ItemManager
|
|
22118
|
-
* @example
|
|
22119
|
-
*
|
|
22120
|
-
* ```ts
|
|
22121
|
-
* import Potion from 'your-database/potion'
|
|
22122
|
-
*
|
|
22123
|
-
* try {
|
|
22124
|
-
* player.addItem(Potion)
|
|
22125
|
-
* // Using class
|
|
22126
|
-
* player.useItem(Potion)
|
|
22127
|
-
* // Using string ID
|
|
22128
|
-
* player.useItem('Potion')
|
|
22129
|
-
* }
|
|
22130
|
-
* catch (err) {
|
|
22131
|
-
* console.log(err)
|
|
22132
|
-
* }
|
|
22133
|
-
* ```
|
|
22134
|
-
*/
|
|
22135
21252
|
useItem(itemClass) {
|
|
22136
21253
|
const itemId = isString(itemClass) ? itemClass : itemClass.name;
|
|
22137
21254
|
const inventory = this.getItem(itemClass);
|
|
@@ -22158,58 +21275,6 @@ function WithItemManager(Base) {
|
|
|
22158
21275
|
this.removeItem(itemClass);
|
|
22159
21276
|
return inventory;
|
|
22160
21277
|
}
|
|
22161
|
-
/**
|
|
22162
|
-
* Equips a weapon or armor on a player. Think first to add the item in the inventory with the `addItem()` method before equipping the item.
|
|
22163
|
-
*
|
|
22164
|
-
* `onEquip()` method is called on the ItemClass
|
|
22165
|
-
*
|
|
22166
|
-
* @title Equip Weapon or Armor
|
|
22167
|
-
* @method player.equip(itemClass,equip=true)
|
|
22168
|
-
* @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
|
|
22169
|
-
* @param {number} [equip] Equip the object if true or un-equipped if false
|
|
22170
|
-
* @returns {void}
|
|
22171
|
-
* @throws {ItemLog} notInInventory
|
|
22172
|
-
* If the item is not in the inventory
|
|
22173
|
-
* ```
|
|
22174
|
-
{
|
|
22175
|
-
id: ITEM_NOT_INVENTORY,
|
|
22176
|
-
msg: '...'
|
|
22177
|
-
}
|
|
22178
|
-
```
|
|
22179
|
-
* @throws {ItemLog} invalidToEquiped
|
|
22180
|
-
If the item is not by a weapon or armor
|
|
22181
|
-
```
|
|
22182
|
-
{
|
|
22183
|
-
id: INVALID_ITEM_TO_EQUIP,
|
|
22184
|
-
msg: '...'
|
|
22185
|
-
}
|
|
22186
|
-
```
|
|
22187
|
-
* @throws {ItemLog} isAlreadyEquiped
|
|
22188
|
-
If the item Is already equipped
|
|
22189
|
-
```
|
|
22190
|
-
{
|
|
22191
|
-
id: ITEM_ALREADY_EQUIPED,
|
|
22192
|
-
msg: '...'
|
|
22193
|
-
}
|
|
22194
|
-
```
|
|
22195
|
-
* @memberof ItemManager
|
|
22196
|
-
* @example
|
|
22197
|
-
*
|
|
22198
|
-
* ```ts
|
|
22199
|
-
* import Sword from 'your-database/sword'
|
|
22200
|
-
*
|
|
22201
|
-
* try {
|
|
22202
|
-
* player.addItem(Sword)
|
|
22203
|
-
* // Using class
|
|
22204
|
-
* player.equip(Sword)
|
|
22205
|
-
* // Using string ID
|
|
22206
|
-
* player.equip('Sword')
|
|
22207
|
-
* }
|
|
22208
|
-
* catch (err) {
|
|
22209
|
-
* console.log(err)
|
|
22210
|
-
* }
|
|
22211
|
-
* ```
|
|
22212
|
-
*/
|
|
22213
21278
|
equip(itemClass, equip = true) {
|
|
22214
21279
|
const itemId = isString(itemClass) ? itemClass : itemClass.name;
|
|
22215
21280
|
const inventory = this.getItem(itemClass);
|
|
@@ -22259,69 +21324,9 @@ var Effect = /* @__PURE__ */ ((Effect2) => {
|
|
|
22259
21324
|
})(Effect || {});
|
|
22260
21325
|
function WithEffectManager(Base) {
|
|
22261
21326
|
return class extends Base {
|
|
22262
|
-
/**
|
|
22263
|
-
* Check if the player has a specific effect
|
|
22264
|
-
*
|
|
22265
|
-
* Determines whether the player currently has the specified effect active.
|
|
22266
|
-
* This includes effects from states, equipment, and temporary conditions.
|
|
22267
|
-
* The effect system provides a flexible way to apply various gameplay
|
|
22268
|
-
* restrictions and enhancements to the player.
|
|
22269
|
-
*
|
|
22270
|
-
* @param effect - The effect identifier to check for
|
|
22271
|
-
* @returns true if the player has the effect, false otherwise
|
|
22272
|
-
*
|
|
22273
|
-
* @example
|
|
22274
|
-
* ```ts
|
|
22275
|
-
* import { Effect } from '@rpgjs/database'
|
|
22276
|
-
*
|
|
22277
|
-
* // Check for skill restriction
|
|
22278
|
-
* const cannotUseSkills = player.hasEffect(Effect.CAN_NOT_SKILL);
|
|
22279
|
-
* if (cannotUseSkills) {
|
|
22280
|
-
* console.log('Player cannot use skills right now');
|
|
22281
|
-
* }
|
|
22282
|
-
*
|
|
22283
|
-
* // Check for guard effect
|
|
22284
|
-
* const isGuarding = player.hasEffect(Effect.GUARD);
|
|
22285
|
-
* if (isGuarding) {
|
|
22286
|
-
* console.log('Player is in guard stance');
|
|
22287
|
-
* }
|
|
22288
|
-
*
|
|
22289
|
-
* // Check for cost reduction
|
|
22290
|
-
* const halfCost = player.hasEffect(Effect.HALF_SP_COST);
|
|
22291
|
-
* const actualCost = skillCost / (halfCost ? 2 : 1);
|
|
22292
|
-
* ```
|
|
22293
|
-
*/
|
|
22294
21327
|
hasEffect(effect) {
|
|
22295
21328
|
return this.effects.includes(effect);
|
|
22296
21329
|
}
|
|
22297
|
-
/**
|
|
22298
|
-
* Retrieves a array of effects assigned to the player, state effects and effects of weapons and armors equipped with the player's own weapons.
|
|
22299
|
-
*
|
|
22300
|
-
* Gets all currently active effects on the player from multiple sources:
|
|
22301
|
-
* - Direct effects assigned to the player
|
|
22302
|
-
* - Effects from active states (buffs/debuffs)
|
|
22303
|
-
* - Effects from equipped weapons and armor
|
|
22304
|
-
* The returned array contains unique effects without duplicates.
|
|
22305
|
-
*
|
|
22306
|
-
* @returns Array of all active effects on the player
|
|
22307
|
-
*
|
|
22308
|
-
* @example
|
|
22309
|
-
* ```ts
|
|
22310
|
-
* // Get all active effects
|
|
22311
|
-
* console.log(player.effects); // ['GUARD', 'HALF_SP_COST', ...]
|
|
22312
|
-
*
|
|
22313
|
-
* // Check multiple effects
|
|
22314
|
-
* const effects = player.effects;
|
|
22315
|
-
* const hasRestrictions = effects.some(effect =>
|
|
22316
|
-
* effect.startsWith('CAN_NOT_')
|
|
22317
|
-
* );
|
|
22318
|
-
*
|
|
22319
|
-
* // Count beneficial effects
|
|
22320
|
-
* const beneficialEffects = effects.filter(effect =>
|
|
22321
|
-
* ['GUARD', 'SUPER_GUARD', 'HALF_SP_COST'].includes(effect)
|
|
22322
|
-
* );
|
|
22323
|
-
* ```
|
|
22324
|
-
*/
|
|
22325
21330
|
get effects() {
|
|
22326
21331
|
const getEffects = (prop) => {
|
|
22327
21332
|
return arrayFlat(this[prop]().map((el) => el.effects || []));
|
|
@@ -22332,39 +21337,6 @@ function WithEffectManager(Base) {
|
|
|
22332
21337
|
...getEffects("equipments")
|
|
22333
21338
|
]);
|
|
22334
21339
|
}
|
|
22335
|
-
/**
|
|
22336
|
-
* Assigns effects to the player. If you give a array, it does not change the effects of the player's states and armor/weapons equipped.
|
|
22337
|
-
*
|
|
22338
|
-
* Sets the direct effects on the player. This only affects the player's own effects
|
|
22339
|
-
* and does not modify effects from states or equipment. The total effects will be
|
|
22340
|
-
* the combination of these direct effects plus any effects from states and equipment.
|
|
22341
|
-
*
|
|
22342
|
-
* @param val - Array of effect identifiers to assign to the player
|
|
22343
|
-
*
|
|
22344
|
-
* @example
|
|
22345
|
-
* ```ts
|
|
22346
|
-
* import { Effect } from '@rpgjs/database'
|
|
22347
|
-
*
|
|
22348
|
-
* // Set direct player effects
|
|
22349
|
-
* player.effects = [Effect.CAN_NOT_SKILL];
|
|
22350
|
-
*
|
|
22351
|
-
* // Add multiple effects
|
|
22352
|
-
* player.effects = [
|
|
22353
|
-
* Effect.GUARD,
|
|
22354
|
-
* Effect.HALF_SP_COST,
|
|
22355
|
-
* Effect.CAN_NOT_ITEM
|
|
22356
|
-
* ];
|
|
22357
|
-
*
|
|
22358
|
-
* // Clear direct effects (equipment/state effects remain)
|
|
22359
|
-
* player.effects = [];
|
|
22360
|
-
*
|
|
22361
|
-
* // Temporary effect application
|
|
22362
|
-
* const originalEffects = player.effects;
|
|
22363
|
-
* player.effects = [...originalEffects, Effect.SUPER_GUARD];
|
|
22364
|
-
* // Later restore
|
|
22365
|
-
* player.effects = originalEffects;
|
|
22366
|
-
* ```
|
|
22367
|
-
*/
|
|
22368
21340
|
set effects(val) {
|
|
22369
21341
|
this._effects.set(val);
|
|
22370
21342
|
}
|
|
@@ -22377,101 +21349,15 @@ function WithElementManager(Base) {
|
|
|
22377
21349
|
super(...arguments);
|
|
22378
21350
|
this._elementsEfficiency = [];
|
|
22379
21351
|
}
|
|
22380
|
-
/**
|
|
22381
|
-
* Recovers the player's elements defense on inventory. This list is generated from the `elementsDefense` property defined on the weapons or armors equipped.
|
|
22382
|
-
* If several items have the same element, only the highest rate will be taken into account.
|
|
22383
|
-
*
|
|
22384
|
-
* Gets the defensive capabilities against various elements from equipped items.
|
|
22385
|
-
* The system automatically consolidates multiple defensive items, keeping only
|
|
22386
|
-
* the highest protection rate for each element type. This provides a comprehensive
|
|
22387
|
-
* view of the player's elemental resistances from all equipped gear.
|
|
22388
|
-
*
|
|
22389
|
-
* @returns Array of element defense objects with rate and element properties
|
|
22390
|
-
*
|
|
22391
|
-
* @example
|
|
22392
|
-
* ```ts
|
|
22393
|
-
* import { Armor } from '@rpgjs/server'
|
|
22394
|
-
*
|
|
22395
|
-
* enum Elements {
|
|
22396
|
-
* Fire = 'fire'
|
|
22397
|
-
* }
|
|
22398
|
-
*
|
|
22399
|
-
* @Armor({
|
|
22400
|
-
* name: 'Shield',
|
|
22401
|
-
* elementsDefense: [{ rate: 1, element: Elements.Fire }]
|
|
22402
|
-
* })
|
|
22403
|
-
* class Shield {}
|
|
22404
|
-
*
|
|
22405
|
-
* @Armor({
|
|
22406
|
-
* name: 'FireShield',
|
|
22407
|
-
* elementsDefense: [{ rate: 0.5, element: Elements.Fire }]
|
|
22408
|
-
* })
|
|
22409
|
-
* class FireShield {}
|
|
22410
|
-
*
|
|
22411
|
-
* player.addItem(Shield)
|
|
22412
|
-
* player.addItem(FireShield)
|
|
22413
|
-
* player.equip(Shield)
|
|
22414
|
-
* player.equip(FireShield)
|
|
22415
|
-
*
|
|
22416
|
-
* console.log(player.elementsDefense) // [{ rate: 1, element: 'fire' }]
|
|
22417
|
-
*
|
|
22418
|
-
* // Check specific element defense
|
|
22419
|
-
* const fireDefense = player.elementsDefense.find(def => def.element === 'fire');
|
|
22420
|
-
* if (fireDefense) {
|
|
22421
|
-
* console.log(`Fire defense rate: ${fireDefense.rate}`);
|
|
22422
|
-
* }
|
|
22423
|
-
* ```
|
|
22424
|
-
*/
|
|
22425
21352
|
get elementsDefense() {
|
|
22426
21353
|
return this.getFeature("elementsDefense", "element");
|
|
22427
21354
|
}
|
|
22428
|
-
/**
|
|
22429
|
-
* Set or retrieves all the elements where the player is vulnerable or not.
|
|
22430
|
-
*
|
|
22431
|
-
* Manages the player's elemental efficiency modifiers, which determine how
|
|
22432
|
-
* effective different elements are against this player. Values greater than 1
|
|
22433
|
-
* indicate vulnerability, while values less than 1 indicate resistance.
|
|
22434
|
-
* This combines both class-based efficiency and player-specific modifiers.
|
|
22435
|
-
*
|
|
22436
|
-
* @returns Array of element efficiency objects with rate and element properties
|
|
22437
|
-
*
|
|
22438
|
-
* @example
|
|
22439
|
-
* ```ts
|
|
22440
|
-
* import { Class } from '@rpgjs/server'
|
|
22441
|
-
*
|
|
22442
|
-
* enum Elements {
|
|
22443
|
-
* Fire = 'fire',
|
|
22444
|
-
* Ice = 'ice'
|
|
22445
|
-
* }
|
|
22446
|
-
*
|
|
22447
|
-
* @Class({
|
|
22448
|
-
* name: 'Fighter',
|
|
22449
|
-
* elementsEfficiency: [{ rate: 1, element: Elements.Fire }]
|
|
22450
|
-
* })
|
|
22451
|
-
* class Hero {}
|
|
22452
|
-
*
|
|
22453
|
-
* player.setClass(Hero)
|
|
22454
|
-
*
|
|
22455
|
-
* console.log(player.elementsEfficiency) // [{ rate: 1, element: 'fire' }]
|
|
22456
|
-
*
|
|
22457
|
-
* player.elementsEfficiency = [{ rate: 2, element: Elements.Ice }]
|
|
22458
|
-
*
|
|
22459
|
-
* console.log(player.elementsEfficiency) // [{ rate: 1, element: 'fire' }, { rate: 2, element: 'ice' }]
|
|
22460
|
-
*
|
|
22461
|
-
* // Check for vulnerabilities
|
|
22462
|
-
* const vulnerabilities = player.elementsEfficiency.filter(eff => eff.rate > 1);
|
|
22463
|
-
* console.log('Vulnerable to:', vulnerabilities.map(v => v.element));
|
|
22464
|
-
*
|
|
22465
|
-
* // Check for resistances
|
|
22466
|
-
* const resistances = player.elementsEfficiency.filter(eff => eff.rate < 1);
|
|
22467
|
-
* console.log('Resistant to:', resistances.map(r => r.element));
|
|
22468
|
-
* ```
|
|
22469
|
-
*/
|
|
22470
21355
|
get elementsEfficiency() {
|
|
22471
21356
|
if (this._class()) {
|
|
21357
|
+
const classData = this._class();
|
|
22472
21358
|
return [
|
|
22473
21359
|
...this._elementsEfficiency,
|
|
22474
|
-
...
|
|
21360
|
+
...classData?.elementsEfficiency || []
|
|
22475
21361
|
];
|
|
22476
21362
|
}
|
|
22477
21363
|
return this._elementsEfficiency;
|
|
@@ -22479,33 +21365,6 @@ function WithElementManager(Base) {
|
|
|
22479
21365
|
set elementsEfficiency(val) {
|
|
22480
21366
|
this._elementsEfficiency = val;
|
|
22481
21367
|
}
|
|
22482
|
-
/**
|
|
22483
|
-
* Retrieves a array of elements assigned to the player and the elements of the weapons / armor equipped
|
|
22484
|
-
*
|
|
22485
|
-
* Gets all offensive elements available to the player from equipped weapons and armor.
|
|
22486
|
-
* This determines what elemental damage types the player can deal in combat.
|
|
22487
|
-
* The system automatically combines elements from all equipped items and removes duplicates.
|
|
22488
|
-
*
|
|
22489
|
-
* @returns Array of element objects with rate and element properties for offensive capabilities
|
|
22490
|
-
*
|
|
22491
|
-
* @example
|
|
22492
|
-
* ```ts
|
|
22493
|
-
* // Get all offensive elements
|
|
22494
|
-
* console.log(player.elements); // [{ rate: 1.5, element: 'fire' }, { rate: 1.2, element: 'ice' }]
|
|
22495
|
-
*
|
|
22496
|
-
* // Check if player can deal fire damage
|
|
22497
|
-
* const hasFireElement = player.elements.some(el => el.element === 'fire');
|
|
22498
|
-
* if (hasFireElement) {
|
|
22499
|
-
* console.log('Player can deal fire damage');
|
|
22500
|
-
* }
|
|
22501
|
-
*
|
|
22502
|
-
* // Get strongest element
|
|
22503
|
-
* const strongestElement = player.elements.reduce((max, current) =>
|
|
22504
|
-
* current.rate > max.rate ? current : max
|
|
22505
|
-
* );
|
|
22506
|
-
* console.log(`Strongest element: ${strongestElement.element} (${strongestElement.rate})`);
|
|
22507
|
-
* ```
|
|
22508
|
-
*/
|
|
22509
21368
|
get elements() {
|
|
22510
21369
|
let elements = [];
|
|
22511
21370
|
for (let item of this.equipments()) {
|
|
@@ -22515,40 +21374,6 @@ function WithElementManager(Base) {
|
|
|
22515
21374
|
}
|
|
22516
21375
|
return arrayUniq(elements);
|
|
22517
21376
|
}
|
|
22518
|
-
/**
|
|
22519
|
-
* Calculate elemental damage coefficient against another player
|
|
22520
|
-
*
|
|
22521
|
-
* Determines the damage multiplier when this player attacks another player,
|
|
22522
|
-
* taking into account the attacker's offensive elements, the defender's
|
|
22523
|
-
* elemental efficiency, and elemental defense from equipment. This is used
|
|
22524
|
-
* in the battle system to calculate elemental damage modifiers.
|
|
22525
|
-
*
|
|
22526
|
-
* @param otherPlayer - The target player to calculate coefficient against
|
|
22527
|
-
* @returns Numerical coefficient to multiply base damage by
|
|
22528
|
-
*
|
|
22529
|
-
* @example
|
|
22530
|
-
* ```ts
|
|
22531
|
-
* // Calculate elemental damage coefficient
|
|
22532
|
-
* const firePlayer = new MyPlayer();
|
|
22533
|
-
* const icePlayer = new MyPlayer();
|
|
22534
|
-
*
|
|
22535
|
-
* // Fire player attacks ice player (assuming ice is weak to fire)
|
|
22536
|
-
* const coefficient = icePlayer.coefficientElements(firePlayer);
|
|
22537
|
-
* console.log(`Damage multiplier: ${coefficient}`); // e.g., 2.0 for double damage
|
|
22538
|
-
*
|
|
22539
|
-
* // Use in damage calculation
|
|
22540
|
-
* const baseDamage = 100;
|
|
22541
|
-
* const finalDamage = baseDamage * coefficient;
|
|
22542
|
-
* console.log(`Final damage: ${finalDamage}`);
|
|
22543
|
-
*
|
|
22544
|
-
* // Check for elemental advantage
|
|
22545
|
-
* if (coefficient > 1) {
|
|
22546
|
-
* console.log('Attacker has elemental advantage!');
|
|
22547
|
-
* } else if (coefficient < 1) {
|
|
22548
|
-
* console.log('Defender resists this element');
|
|
22549
|
-
* }
|
|
22550
|
-
* ```
|
|
22551
|
-
*/
|
|
22552
21377
|
coefficientElements(otherPlayer) {
|
|
22553
21378
|
const atkPlayerElements = otherPlayer.elements;
|
|
22554
21379
|
const playerElements = this.elementsEfficiency;
|
|
@@ -22589,49 +21414,10 @@ function WithSkillManager(Base) {
|
|
|
22589
21414
|
return isInstanceOf(skill, skillClass);
|
|
22590
21415
|
});
|
|
22591
21416
|
}
|
|
22592
|
-
/**
|
|
22593
|
-
* Retrieves a learned skill. Returns null, if not found
|
|
22594
|
-
* ```ts
|
|
22595
|
-
* import Fire from 'your-database/skills/fire'
|
|
22596
|
-
*
|
|
22597
|
-
* player.getSkill(Fire)
|
|
22598
|
-
* ```
|
|
22599
|
-
*
|
|
22600
|
-
* @title Get Skill
|
|
22601
|
-
* @method player.getSkill(skillClass)
|
|
22602
|
-
* @param {SkillClass | string} skillClass or data id
|
|
22603
|
-
* @returns {instance of SkillClass | null}
|
|
22604
|
-
* @memberof SkillManager
|
|
22605
|
-
*/
|
|
22606
21417
|
getSkill(skillClass) {
|
|
22607
21418
|
const index = this._getSkillIndex(skillClass);
|
|
22608
21419
|
return this.skills()[index] ?? null;
|
|
22609
21420
|
}
|
|
22610
|
-
/**
|
|
22611
|
-
* Learn a skill. Attributes the coefficient 1 to the parameter INT (intelligence) if cd is not present on the class.
|
|
22612
|
-
*
|
|
22613
|
-
* `onLearn()` method is called on the SkillClass
|
|
22614
|
-
*
|
|
22615
|
-
* ```ts
|
|
22616
|
-
* import Fire from 'your-database/skills/fire'
|
|
22617
|
-
*
|
|
22618
|
-
* player.learnSkill(Fire)
|
|
22619
|
-
* ```
|
|
22620
|
-
*
|
|
22621
|
-
* @title Learn Skill
|
|
22622
|
-
* @method player.learnSkill(skillClass)
|
|
22623
|
-
* @param {SkillClass | string} skillId or data id
|
|
22624
|
-
* @throws {SkillLog} alreadyLearned
|
|
22625
|
-
* If the player already knows the skill
|
|
22626
|
-
* ```
|
|
22627
|
-
{
|
|
22628
|
-
id: SKILL_ALREADY_LEARNED,
|
|
22629
|
-
msg: '...'
|
|
22630
|
-
}
|
|
22631
|
-
```
|
|
22632
|
-
* @returns {instance of SkillClass}
|
|
22633
|
-
* @memberof SkillManager
|
|
22634
|
-
*/
|
|
22635
21421
|
learnSkill(skillId) {
|
|
22636
21422
|
if (this.getSkill(skillId)) {
|
|
22637
21423
|
throw SkillLog.alreadyLearned(skillId);
|
|
@@ -22640,37 +21426,7 @@ function WithSkillManager(Base) {
|
|
|
22640
21426
|
this.skills().push(instance);
|
|
22641
21427
|
this["execMethod"]("onLearn", [this], instance);
|
|
22642
21428
|
return instance;
|
|
22643
|
-
}
|
|
22644
|
-
/**
|
|
22645
|
-
* Forget a skill
|
|
22646
|
-
*
|
|
22647
|
-
* `onForget()` method is called on the SkillClass
|
|
22648
|
-
*
|
|
22649
|
-
* ```ts
|
|
22650
|
-
* import Fire from 'your-database/skills/fire'
|
|
22651
|
-
*
|
|
22652
|
-
* try {
|
|
22653
|
-
* player.forgetSkill(Fire)
|
|
22654
|
-
* }
|
|
22655
|
-
* catch (err) {
|
|
22656
|
-
* console.log(err)
|
|
22657
|
-
* }
|
|
22658
|
-
* ```
|
|
22659
|
-
*
|
|
22660
|
-
* @title Forget Skill
|
|
22661
|
-
* @method player.learnSkill(skillClass)
|
|
22662
|
-
* @param {SkillClass | string} skillId or data id
|
|
22663
|
-
* @throws {SkillLog} notLearned
|
|
22664
|
-
* If trying to forget a skill not learned
|
|
22665
|
-
* ```
|
|
22666
|
-
* {
|
|
22667
|
-
* id: SKILL_NOT_LEARNED,
|
|
22668
|
-
* msg: '...'
|
|
22669
|
-
* }
|
|
22670
|
-
* ```
|
|
22671
|
-
* @returns {instance of SkillClass}
|
|
22672
|
-
* @memberof SkillManager
|
|
22673
|
-
*/
|
|
21429
|
+
}
|
|
22674
21430
|
forgetSkill(skillId) {
|
|
22675
21431
|
if (isString(skillId)) skillId = this.databaseById(skillId);
|
|
22676
21432
|
const index = this._getSkillIndex(skillId);
|
|
@@ -22682,81 +21438,6 @@ function WithSkillManager(Base) {
|
|
|
22682
21438
|
this["execMethod"]("onForget", [this], instance);
|
|
22683
21439
|
return instance;
|
|
22684
21440
|
}
|
|
22685
|
-
/**
|
|
22686
|
-
* Using a skill
|
|
22687
|
-
*
|
|
22688
|
-
* `onUse()` method is called on the SkillClass
|
|
22689
|
-
*
|
|
22690
|
-
* If other players are indicated then damage will be done to these other players. The method `applyDamage()` will be executed
|
|
22691
|
-
*
|
|
22692
|
-
* ```ts
|
|
22693
|
-
* import Fire from 'your-database/skills/fire'
|
|
22694
|
-
*
|
|
22695
|
-
* try {
|
|
22696
|
-
* player.useSkill(Fire)
|
|
22697
|
-
* }
|
|
22698
|
-
* catch (err) {
|
|
22699
|
-
* console.log(err)
|
|
22700
|
-
* }
|
|
22701
|
-
* ```
|
|
22702
|
-
*
|
|
22703
|
-
* or
|
|
22704
|
-
*
|
|
22705
|
-
*
|
|
22706
|
-
* * ```ts
|
|
22707
|
-
* import Fire from 'your-database/skills/fire'
|
|
22708
|
-
*
|
|
22709
|
-
* try {
|
|
22710
|
-
* player.useSkill(Fire, otherPlayer)
|
|
22711
|
-
* }
|
|
22712
|
-
* catch (err) {
|
|
22713
|
-
* console.log(err)
|
|
22714
|
-
* }
|
|
22715
|
-
* ```
|
|
22716
|
-
*
|
|
22717
|
-
* @title Use Skill
|
|
22718
|
-
* @method player.useSkill(skillClass,otherPlayer)
|
|
22719
|
-
* @param {SkillClass | string} skillId or data id
|
|
22720
|
-
* @param {Array<RpgPlayer> | RpgPlayer} [otherPlayer]
|
|
22721
|
-
* @throws {SkillLog} restriction
|
|
22722
|
-
* If the player has the `Effect.CAN_NOT_SKILL` effect
|
|
22723
|
-
* ```
|
|
22724
|
-
* {
|
|
22725
|
-
* id: RESTRICTION_SKILL,
|
|
22726
|
-
* msg: '...'
|
|
22727
|
-
* }
|
|
22728
|
-
* ```
|
|
22729
|
-
* @throws {SkillLog} notLearned
|
|
22730
|
-
* If the player tries to use an unlearned skill
|
|
22731
|
-
* ```
|
|
22732
|
-
* {
|
|
22733
|
-
* id: SKILL_NOT_LEARNED,
|
|
22734
|
-
* msg: '...'
|
|
22735
|
-
* }
|
|
22736
|
-
* ```
|
|
22737
|
-
* @throws {SkillLog} notEnoughSp
|
|
22738
|
-
* If the player does not have enough SP to use the skill
|
|
22739
|
-
* ```
|
|
22740
|
-
* {
|
|
22741
|
-
* id: NOT_ENOUGH_SP,
|
|
22742
|
-
* msg: '...'
|
|
22743
|
-
* }
|
|
22744
|
-
* ```
|
|
22745
|
-
* @throws {SkillLog} chanceToUseFailed
|
|
22746
|
-
* If the chance to use the skill has failed (defined with the `hitRate` property)
|
|
22747
|
-
* ```
|
|
22748
|
-
* {
|
|
22749
|
-
* id: USE_CHANCE_SKILL_FAILED,
|
|
22750
|
-
* msg: '...'
|
|
22751
|
-
* }
|
|
22752
|
-
* ```
|
|
22753
|
-
*
|
|
22754
|
-
* `onUseFailed()` method is called on the SkillClass
|
|
22755
|
-
*
|
|
22756
|
-
* @returns {instance of SkillClass}
|
|
22757
|
-
* @memberof SkillManager
|
|
22758
|
-
* @todo
|
|
22759
|
-
*/
|
|
22760
21441
|
useSkill(skillId, otherPlayer) {
|
|
22761
21442
|
const skill = this.getSkill(skillId);
|
|
22762
21443
|
if (this.hasEffect(Effect.CAN_NOT_SKILL)) {
|
|
@@ -22792,42 +21473,11 @@ function WithSkillManager(Base) {
|
|
|
22792
21473
|
|
|
22793
21474
|
function WithBattleManager(Base) {
|
|
22794
21475
|
return class extends Base {
|
|
22795
|
-
/**
|
|
22796
|
-
* Apply damage. Player will lose HP. the `attackerPlayer` parameter is the other player, the one who attacks.
|
|
22797
|
-
*
|
|
22798
|
-
* If you don't set the skill parameter, it will be a physical attack.
|
|
22799
|
-
* The attack formula is already defined but you can customize it in the server options.
|
|
22800
|
-
* This method handles all aspects of damage calculation including critical hits,
|
|
22801
|
-
* elemental vulnerabilities, guard effects, and applies the final damage to HP.
|
|
22802
|
-
*
|
|
22803
|
-
* @param attackerPlayer - The attacking player who deals the damage
|
|
22804
|
-
* @param skill - Optional skill object for magical attacks, if not provided uses physical attack
|
|
22805
|
-
* @returns Object containing damage details and special effects that occurred
|
|
22806
|
-
*
|
|
22807
|
-
* @example
|
|
22808
|
-
* ```ts
|
|
22809
|
-
* // Physical attack
|
|
22810
|
-
* const result = player.applyDamage(attackerPlayer);
|
|
22811
|
-
* console.log(`Physical damage: ${result.damage}, Critical: ${result.critical}`);
|
|
22812
|
-
*
|
|
22813
|
-
* // Magical attack with skill
|
|
22814
|
-
* const fireSkill = { id: 'fire', power: 50, element: 'fire' };
|
|
22815
|
-
* const magicResult = player.applyDamage(attackerPlayer, fireSkill);
|
|
22816
|
-
* console.log(`Magic damage: ${magicResult.damage}, Vulnerable: ${magicResult.elementVulnerable}`);
|
|
22817
|
-
*
|
|
22818
|
-
* // Check for guard effects
|
|
22819
|
-
* if (result.guard) {
|
|
22820
|
-
* console.log('Attack was partially blocked!');
|
|
22821
|
-
* }
|
|
22822
|
-
* if (result.superGuard) {
|
|
22823
|
-
* console.log('Attack was heavily reduced by super guard!');
|
|
22824
|
-
* }
|
|
22825
|
-
* ```
|
|
22826
|
-
*/
|
|
22827
21476
|
applyDamage(attackerPlayer, skill) {
|
|
21477
|
+
const self = this;
|
|
22828
21478
|
const getParam = (player) => {
|
|
22829
21479
|
const params = {};
|
|
22830
|
-
|
|
21480
|
+
Object.keys(self.parameters).forEach((key) => {
|
|
22831
21481
|
params[key] = player.param[key];
|
|
22832
21482
|
});
|
|
22833
21483
|
return {
|
|
@@ -22843,26 +21493,25 @@ function WithBattleManager(Base) {
|
|
|
22843
21493
|
let superGuard = false;
|
|
22844
21494
|
let elementVulnerable = false;
|
|
22845
21495
|
const paramA = getParam(attackerPlayer);
|
|
22846
|
-
const paramB = getParam(
|
|
22847
|
-
console.log(paramA, paramB);
|
|
21496
|
+
const paramB = getParam(self);
|
|
22848
21497
|
if (skill) {
|
|
22849
|
-
fn =
|
|
21498
|
+
fn = self.getFormulas("damageSkill");
|
|
22850
21499
|
if (!fn) {
|
|
22851
21500
|
throw new Error("Skill Formulas not exists");
|
|
22852
21501
|
}
|
|
22853
21502
|
damage = fn(paramA, paramB, skill);
|
|
22854
21503
|
} else {
|
|
22855
|
-
fn =
|
|
21504
|
+
fn = self.getFormulas("damagePhysic");
|
|
22856
21505
|
if (!fn) {
|
|
22857
21506
|
throw new Error("Physic Formulas not exists");
|
|
22858
21507
|
}
|
|
22859
21508
|
damage = fn(paramA, paramB);
|
|
22860
|
-
const coef =
|
|
21509
|
+
const coef = self.coefficientElements(attackerPlayer);
|
|
22861
21510
|
if (coef >= 2) {
|
|
22862
21511
|
elementVulnerable = true;
|
|
22863
21512
|
}
|
|
22864
21513
|
damage *= coef;
|
|
22865
|
-
fn =
|
|
21514
|
+
fn = self.getFormulas("damageCritical");
|
|
22866
21515
|
if (fn) {
|
|
22867
21516
|
let newDamage = fn(damage, paramA, paramB);
|
|
22868
21517
|
if (damage != newDamage) {
|
|
@@ -22871,8 +21520,8 @@ function WithBattleManager(Base) {
|
|
|
22871
21520
|
damage = newDamage;
|
|
22872
21521
|
}
|
|
22873
21522
|
}
|
|
22874
|
-
if (
|
|
22875
|
-
fn =
|
|
21523
|
+
if (self.hasEffect(Effect.GUARD)) {
|
|
21524
|
+
fn = self.getFormulas("damageGuard");
|
|
22876
21525
|
if (fn) {
|
|
22877
21526
|
let newDamage = fn(damage, paramA, paramB);
|
|
22878
21527
|
if (damage != newDamage) {
|
|
@@ -22881,11 +21530,11 @@ function WithBattleManager(Base) {
|
|
|
22881
21530
|
damage = newDamage;
|
|
22882
21531
|
}
|
|
22883
21532
|
}
|
|
22884
|
-
if (
|
|
21533
|
+
if (self.hasEffect(Effect.SUPER_GUARD)) {
|
|
22885
21534
|
damage /= 4;
|
|
22886
21535
|
superGuard = true;
|
|
22887
21536
|
}
|
|
22888
|
-
|
|
21537
|
+
self.hp -= damage;
|
|
22889
21538
|
return {
|
|
22890
21539
|
damage,
|
|
22891
21540
|
critical,
|
|
@@ -22921,87 +21570,21 @@ function WithBattleManager(Base) {
|
|
|
22921
21570
|
* ```
|
|
22922
21571
|
*/
|
|
22923
21572
|
getFormulas(name) {
|
|
22924
|
-
const
|
|
22925
|
-
|
|
21573
|
+
const self = this;
|
|
21574
|
+
const map = self.getCurrentMap();
|
|
21575
|
+
return map?.damageFormulas[name];
|
|
22926
21576
|
}
|
|
22927
21577
|
};
|
|
22928
21578
|
}
|
|
22929
21579
|
|
|
22930
21580
|
function WithClassManager(Base) {
|
|
22931
21581
|
return class extends Base {
|
|
22932
|
-
/**
|
|
22933
|
-
* Assign a class to the player
|
|
22934
|
-
*
|
|
22935
|
-
* Sets the player's class, which defines their combat abilities, stat growth,
|
|
22936
|
-
* and available skills. The class system provides the foundation for character
|
|
22937
|
-
* progression and specialization. When a class is set, it automatically triggers
|
|
22938
|
-
* the class's onSet method for any additional initialization.
|
|
22939
|
-
*
|
|
22940
|
-
* @param _class - The class constructor or class ID to assign to the player
|
|
22941
|
-
* @returns The instantiated class object
|
|
22942
|
-
*
|
|
22943
|
-
* @example
|
|
22944
|
-
* ```ts
|
|
22945
|
-
* import { Fighter } from 'my-database/classes/fighter'
|
|
22946
|
-
*
|
|
22947
|
-
* // Set class using constructor
|
|
22948
|
-
* const fighterClass = player.setClass(Fighter);
|
|
22949
|
-
* console.log('Class set:', fighterClass.name);
|
|
22950
|
-
*
|
|
22951
|
-
* // Set class using string ID
|
|
22952
|
-
* player.setClass('fighter');
|
|
22953
|
-
*
|
|
22954
|
-
* // Class affects available skills and stats
|
|
22955
|
-
* console.log('Available skills:', player.skills);
|
|
22956
|
-
* console.log('Class bonuses applied to stats');
|
|
22957
|
-
*
|
|
22958
|
-
* // Class determines level progression
|
|
22959
|
-
* player.level = 5;
|
|
22960
|
-
* // Skills may be automatically learned based on class definition
|
|
22961
|
-
* ```
|
|
22962
|
-
*/
|
|
22963
21582
|
setClass(_class) {
|
|
22964
21583
|
if (isString(_class)) _class = this.databaseById(_class);
|
|
22965
21584
|
const classInstance = new _class();
|
|
22966
21585
|
this["execMethod"]("onSet", [this], classInstance);
|
|
22967
21586
|
return classInstance;
|
|
22968
21587
|
}
|
|
22969
|
-
/**
|
|
22970
|
-
* Allows to give a set of already defined properties to the player (default equipment, or a list of skills to learn according to the level)
|
|
22971
|
-
*
|
|
22972
|
-
* Sets up the player as a specific actor archetype, which includes predefined
|
|
22973
|
-
* characteristics like starting equipment, parameters, level ranges, and associated class.
|
|
22974
|
-
* This is typically used for creating pre-configured character templates or NPCs
|
|
22975
|
-
* with specific roles and equipment loadouts.
|
|
22976
|
-
*
|
|
22977
|
-
* @param actorClass - The actor constructor or actor ID to assign to the player
|
|
22978
|
-
* @returns The instantiated actor object
|
|
22979
|
-
*
|
|
22980
|
-
* @example
|
|
22981
|
-
* ```ts
|
|
22982
|
-
* import { Hero } from 'my-database/classes/hero'
|
|
22983
|
-
*
|
|
22984
|
-
* // Set up player as Hero actor
|
|
22985
|
-
* const heroActor = player.setActor(Hero);
|
|
22986
|
-
* console.log('Actor configured:', heroActor.name);
|
|
22987
|
-
*
|
|
22988
|
-
* // Actor automatically sets up:
|
|
22989
|
-
* // - Starting equipment (sword, armor, etc.)
|
|
22990
|
-
* console.log('Starting equipment:', player.equipments());
|
|
22991
|
-
*
|
|
22992
|
-
* // - Parameter ranges and growth
|
|
22993
|
-
* console.log('Level range:', player.initialLevel, '-', player.finalLevel);
|
|
22994
|
-
*
|
|
22995
|
-
* // - Associated class
|
|
22996
|
-
* console.log('Assigned class:', player.class);
|
|
22997
|
-
*
|
|
22998
|
-
* // - Experience curve
|
|
22999
|
-
* console.log('EXP curve:', player.expCurve);
|
|
23000
|
-
*
|
|
23001
|
-
* // Actor setup is comprehensive
|
|
23002
|
-
* player.setActor('hero'); // Can also use string ID
|
|
23003
|
-
* ```
|
|
23004
|
-
*/
|
|
23005
21588
|
setActor(actorClass) {
|
|
23006
21589
|
if (isString(actorClass)) actorClass = this.databaseById(actorClass);
|
|
23007
21590
|
const actor = new actorClass();
|
|
@@ -23028,137 +21611,15 @@ function WithStateManager(Base) {
|
|
|
23028
21611
|
super(...arguments);
|
|
23029
21612
|
this._statesEfficiency = signal$1([]);
|
|
23030
21613
|
}
|
|
23031
|
-
/**
|
|
23032
|
-
* Recovers the player's states defense on inventory. This list is generated from the `statesDefense` property defined on the weapons or armors equipped.
|
|
23033
|
-
* If several items have the same element, only the highest rate will be taken into account.
|
|
23034
|
-
*
|
|
23035
|
-
* Gets the defensive capabilities against various states from equipped items.
|
|
23036
|
-
* The system automatically consolidates multiple defensive items, keeping only
|
|
23037
|
-
* the highest protection rate for each state type. This provides comprehensive
|
|
23038
|
-
* protection against debuffs and negative status effects.
|
|
23039
|
-
*
|
|
23040
|
-
* @returns Array of state defense objects with rate and state properties
|
|
23041
|
-
*
|
|
23042
|
-
* @example
|
|
23043
|
-
* ```ts
|
|
23044
|
-
* import { Armor, State } from '@rpgjs/server'
|
|
23045
|
-
*
|
|
23046
|
-
* @State({
|
|
23047
|
-
* name: 'Paralyze'
|
|
23048
|
-
* })
|
|
23049
|
-
* class Paralyze {}
|
|
23050
|
-
*
|
|
23051
|
-
* @Armor({
|
|
23052
|
-
* name: 'Shield',
|
|
23053
|
-
* statesDefense: [{ rate: 1, state: Paralyze }]
|
|
23054
|
-
* })
|
|
23055
|
-
* class Shield {}
|
|
23056
|
-
*
|
|
23057
|
-
* @Armor({
|
|
23058
|
-
* name: 'FireShield',
|
|
23059
|
-
* statesDefense: [{ rate: 0.5, state: Paralyze }]
|
|
23060
|
-
* })
|
|
23061
|
-
* class FireShield {}
|
|
23062
|
-
*
|
|
23063
|
-
* player.addItem(Shield)
|
|
23064
|
-
* player.addItem(FireShield)
|
|
23065
|
-
* player.equip(Shield)
|
|
23066
|
-
* player.equip(FireShield)
|
|
23067
|
-
*
|
|
23068
|
-
* console.log(player.statesDefense) // [{ rate: 1, state: instance of Paralyze }]
|
|
23069
|
-
*
|
|
23070
|
-
* // Check specific state defense
|
|
23071
|
-
* const paralyzeDefense = player.statesDefense.find(def => def.state instanceof Paralyze);
|
|
23072
|
-
* if (paralyzeDefense) {
|
|
23073
|
-
* console.log(`Paralyze defense rate: ${paralyzeDefense.rate}`);
|
|
23074
|
-
* }
|
|
23075
|
-
* ```
|
|
23076
|
-
*/
|
|
23077
21614
|
get statesDefense() {
|
|
23078
21615
|
return this.getFeature("statesDefense", "state");
|
|
23079
21616
|
}
|
|
23080
|
-
/**
|
|
23081
|
-
* Set or retrieves all the states where the player is vulnerable or not.
|
|
23082
|
-
*
|
|
23083
|
-
* Manages the player's state efficiency modifiers, which determine how
|
|
23084
|
-
* effective different states are against this player. Values greater than 1
|
|
23085
|
-
* indicate vulnerability, while values less than 1 indicate resistance.
|
|
23086
|
-
* This combines both class-based efficiency and player-specific modifiers.
|
|
23087
|
-
*
|
|
23088
|
-
* @returns Array of state efficiency objects with rate and state properties
|
|
23089
|
-
*
|
|
23090
|
-
* @example
|
|
23091
|
-
* ```ts
|
|
23092
|
-
* import { Class, State } from '@rpgjs/server'
|
|
23093
|
-
*
|
|
23094
|
-
* @State({
|
|
23095
|
-
* name: 'Paralyze'
|
|
23096
|
-
* })
|
|
23097
|
-
* class Paralyze {}
|
|
23098
|
-
*
|
|
23099
|
-
* @State({
|
|
23100
|
-
* name: 'Sleep'
|
|
23101
|
-
* })
|
|
23102
|
-
* class Sleep {}
|
|
23103
|
-
*
|
|
23104
|
-
* @Class({
|
|
23105
|
-
* name: 'Fighter',
|
|
23106
|
-
* statesEfficiency: [{ rate: 1, state: Paralyze }]
|
|
23107
|
-
* })
|
|
23108
|
-
* class Hero {}
|
|
23109
|
-
*
|
|
23110
|
-
* player.setClass(Hero)
|
|
23111
|
-
*
|
|
23112
|
-
* console.log(player.statesEfficiency) // [{ rate: 1, instance of Paralyze }]
|
|
23113
|
-
*
|
|
23114
|
-
* player.statesEfficiency = [{ rate: 2, state: Sleep }]
|
|
23115
|
-
*
|
|
23116
|
-
* console.log(player.statesEfficiency) // [{ rate: 1, state: instance of Paralyze }, { rate: 2, state: instance of Sleep }]
|
|
23117
|
-
*
|
|
23118
|
-
* // Check for vulnerabilities
|
|
23119
|
-
* const vulnerabilities = player.statesEfficiency.filter(eff => eff.rate > 1);
|
|
23120
|
-
* console.log('Vulnerable to states:', vulnerabilities.map(v => v.state.name));
|
|
23121
|
-
*
|
|
23122
|
-
* // Check for resistances
|
|
23123
|
-
* const resistances = player.statesEfficiency.filter(eff => eff.rate < 1);
|
|
23124
|
-
* console.log('Resistant to states:', resistances.map(r => r.state.name));
|
|
23125
|
-
* ```
|
|
23126
|
-
*/
|
|
23127
21617
|
get statesEfficiency() {
|
|
23128
21618
|
return this._statesEfficiency;
|
|
23129
21619
|
}
|
|
23130
21620
|
set statesEfficiency(val) {
|
|
23131
21621
|
this._statesEfficiency = val;
|
|
23132
21622
|
}
|
|
23133
|
-
/**
|
|
23134
|
-
* Apply states to a player from skill or item effects
|
|
23135
|
-
*
|
|
23136
|
-
* Processes state application and removal based on skill or item effects.
|
|
23137
|
-
* This method handles both adding beneficial states and removing negative ones,
|
|
23138
|
-
* with proper chance calculation and resistance checks.
|
|
23139
|
-
*
|
|
23140
|
-
* @param player - The target player to apply states to
|
|
23141
|
-
* @param states - Object containing arrays of states to add or remove
|
|
23142
|
-
*
|
|
23143
|
-
* @example
|
|
23144
|
-
* ```ts
|
|
23145
|
-
* // Apply states from a healing skill
|
|
23146
|
-
* const healingStates = {
|
|
23147
|
-
* addStates: [{ state: Regeneration, rate: 0.8 }],
|
|
23148
|
-
* removeStates: [{ state: Poison, rate: 1.0 }]
|
|
23149
|
-
* };
|
|
23150
|
-
* player.applyStates(targetPlayer, healingStates);
|
|
23151
|
-
*
|
|
23152
|
-
* // Apply debuff from an enemy attack
|
|
23153
|
-
* const debuffStates = {
|
|
23154
|
-
* addStates: [
|
|
23155
|
-
* { state: Paralyze, rate: 0.3 },
|
|
23156
|
-
* { state: Slow, rate: 0.5 }
|
|
23157
|
-
* ]
|
|
23158
|
-
* };
|
|
23159
|
-
* player.applyStates(targetPlayer, debuffStates);
|
|
23160
|
-
* ```
|
|
23161
|
-
*/
|
|
23162
21623
|
applyStates(player, { addStates, removeStates }) {
|
|
23163
21624
|
if (addStates) {
|
|
23164
21625
|
for (let { state, rate } of addStates) {
|
|
@@ -23171,40 +21632,6 @@ function WithStateManager(Base) {
|
|
|
23171
21632
|
}
|
|
23172
21633
|
}
|
|
23173
21634
|
}
|
|
23174
|
-
/**
|
|
23175
|
-
* Get a state to the player. Returns `null` if the state is not present on the player
|
|
23176
|
-
*
|
|
23177
|
-
* Retrieves a specific state instance from the player's active states.
|
|
23178
|
-
* This is useful for checking state properties, duration, or performing
|
|
23179
|
-
* state-specific operations. Returns null if the state is not currently active.
|
|
23180
|
-
*
|
|
23181
|
-
* @param stateClass - The state class constructor or state ID to search for
|
|
23182
|
-
* @returns The state instance if found, null otherwise
|
|
23183
|
-
*
|
|
23184
|
-
* @example
|
|
23185
|
-
* ```ts
|
|
23186
|
-
* import Paralyze from 'your-database/states/paralyze'
|
|
23187
|
-
*
|
|
23188
|
-
* // Check if player has a specific state
|
|
23189
|
-
* const paralyzeState = player.getState(Paralyze);
|
|
23190
|
-
* if (paralyzeState) {
|
|
23191
|
-
* console.log('Player is paralyzed');
|
|
23192
|
-
* console.log('Remaining duration:', paralyzeState.duration);
|
|
23193
|
-
* }
|
|
23194
|
-
*
|
|
23195
|
-
* // Check using string ID
|
|
23196
|
-
* const poisonState = player.getState('poison');
|
|
23197
|
-
* if (poisonState) {
|
|
23198
|
-
* console.log('Player is poisoned');
|
|
23199
|
-
* }
|
|
23200
|
-
*
|
|
23201
|
-
* // Use in conditional logic
|
|
23202
|
-
* if (player.getState(Sleep)) {
|
|
23203
|
-
* console.log('Player cannot act while sleeping');
|
|
23204
|
-
* return; // Skip player turn
|
|
23205
|
-
* }
|
|
23206
|
-
* ```
|
|
23207
|
-
*/
|
|
23208
21635
|
getState(stateClass) {
|
|
23209
21636
|
if (isString(stateClass)) stateClass = this.databaseById(stateClass);
|
|
23210
21637
|
return this.states().find((state) => {
|
|
@@ -23214,54 +21641,6 @@ function WithStateManager(Base) {
|
|
|
23214
21641
|
return isInstanceOf(state, stateClass);
|
|
23215
21642
|
});
|
|
23216
21643
|
}
|
|
23217
|
-
/**
|
|
23218
|
-
* Adds a state to the player. Set the chance between 0 and 1 that the state can apply
|
|
23219
|
-
*
|
|
23220
|
-
* Attempts to apply a state to the player with a specified success chance.
|
|
23221
|
-
* The method considers state resistance, efficiency modifiers, and random chance
|
|
23222
|
-
* to determine if the state is successfully applied. If successful, the state
|
|
23223
|
-
* is added to the player's active states list.
|
|
23224
|
-
*
|
|
23225
|
-
* @param stateClass - The state class constructor or state ID to apply
|
|
23226
|
-
* @param chance - Probability of successful application (0-1, default 1)
|
|
23227
|
-
* @returns The state instance if successfully applied, null if already present
|
|
23228
|
-
* @throws StateLog.addFailed if the chance roll fails
|
|
23229
|
-
*
|
|
23230
|
-
* @example
|
|
23231
|
-
* ```ts
|
|
23232
|
-
* import Paralyze from 'your-database/states/paralyze'
|
|
23233
|
-
*
|
|
23234
|
-
* try {
|
|
23235
|
-
* // Attempt to apply paralyze with 100% chance
|
|
23236
|
-
* const state = player.addState(Paralyze);
|
|
23237
|
-
* if (state) {
|
|
23238
|
-
* console.log('Paralyze applied successfully');
|
|
23239
|
-
* }
|
|
23240
|
-
* } catch (err) {
|
|
23241
|
-
* console.log('Failed to apply paralyze:', err.msg);
|
|
23242
|
-
* }
|
|
23243
|
-
*
|
|
23244
|
-
* // Apply with reduced chance
|
|
23245
|
-
* try {
|
|
23246
|
-
* player.addState(Poison, 0.3); // 30% chance
|
|
23247
|
-
* } catch (err) {
|
|
23248
|
-
* console.log('Poison application failed');
|
|
23249
|
-
* }
|
|
23250
|
-
*
|
|
23251
|
-
* // Apply multiple states with different chances
|
|
23252
|
-
* const debuffs = [
|
|
23253
|
-
* { state: Slow, chance: 0.8 },
|
|
23254
|
-
* { state: Weak, chance: 0.6 }
|
|
23255
|
-
* ];
|
|
23256
|
-
* debuffs.forEach(({ state, chance }) => {
|
|
23257
|
-
* try {
|
|
23258
|
-
* player.addState(state, chance);
|
|
23259
|
-
* } catch (err) {
|
|
23260
|
-
* // Handle failed applications
|
|
23261
|
-
* }
|
|
23262
|
-
* });
|
|
23263
|
-
* ```
|
|
23264
|
-
*/
|
|
23265
21644
|
addState(stateClass, chance = 1) {
|
|
23266
21645
|
const state = this.getState(stateClass);
|
|
23267
21646
|
if (isString(stateClass)) {
|
|
@@ -23278,52 +21657,6 @@ function WithStateManager(Base) {
|
|
|
23278
21657
|
}
|
|
23279
21658
|
return null;
|
|
23280
21659
|
}
|
|
23281
|
-
/**
|
|
23282
|
-
* Remove a state to the player. Set the chance between 0 and 1 that the state can be removed
|
|
23283
|
-
*
|
|
23284
|
-
* Attempts to remove a state from the player with a specified success chance.
|
|
23285
|
-
* This is useful for cure spells, items, or time-based state removal.
|
|
23286
|
-
* The method considers removal resistance and random chance.
|
|
23287
|
-
*
|
|
23288
|
-
* @param stateClass - The state class constructor or state ID to remove
|
|
23289
|
-
* @param chance - Probability of successful removal (0-1, default 1)
|
|
23290
|
-
* @throws StateLog.removeFailed if the chance roll fails
|
|
23291
|
-
* @throws StateLog.notApplied if the state is not currently active
|
|
23292
|
-
*
|
|
23293
|
-
* @example
|
|
23294
|
-
* ```ts
|
|
23295
|
-
* import Paralyze from 'your-database/states/paralyze'
|
|
23296
|
-
*
|
|
23297
|
-
* try {
|
|
23298
|
-
* // Attempt to remove paralyze with 100% chance
|
|
23299
|
-
* player.removeState(Paralyze);
|
|
23300
|
-
* console.log('Paralyze removed successfully');
|
|
23301
|
-
* } catch (err) {
|
|
23302
|
-
* if (err.id === 'STATE_NOT_APPLIED') {
|
|
23303
|
-
* console.log('Player was not paralyzed');
|
|
23304
|
-
* } else {
|
|
23305
|
-
* console.log('Failed to remove paralyze:', err.msg);
|
|
23306
|
-
* }
|
|
23307
|
-
* }
|
|
23308
|
-
*
|
|
23309
|
-
* // Remove with reduced chance (for weak cure spells)
|
|
23310
|
-
* try {
|
|
23311
|
-
* player.removeState(Poison, 0.7); // 70% chance
|
|
23312
|
-
* } catch (err) {
|
|
23313
|
-
* console.log('Cure failed');
|
|
23314
|
-
* }
|
|
23315
|
-
*
|
|
23316
|
-
* // Remove all negative states (cure-all effect)
|
|
23317
|
-
* const negativeStates = [Poison, Paralyze, Sleep, Slow];
|
|
23318
|
-
* negativeStates.forEach(state => {
|
|
23319
|
-
* try {
|
|
23320
|
-
* player.removeState(state);
|
|
23321
|
-
* } catch (err) {
|
|
23322
|
-
* // State wasn't active, continue
|
|
23323
|
-
* }
|
|
23324
|
-
* });
|
|
23325
|
-
* ```
|
|
23326
|
-
*/
|
|
23327
21660
|
removeState(stateClass, chance = 1) {
|
|
23328
21661
|
const index = this.states().findIndex((state) => {
|
|
23329
21662
|
if (isString(stateClass)) {
|
|
@@ -23340,12 +21673,6 @@ function WithStateManager(Base) {
|
|
|
23340
21673
|
throw StateLog.notApplied(stateClass);
|
|
23341
21674
|
}
|
|
23342
21675
|
}
|
|
23343
|
-
/**
|
|
23344
|
-
* Find state efficiency modifier for a specific state class
|
|
23345
|
-
*
|
|
23346
|
-
* @param stateClass - The state class to find efficiency for
|
|
23347
|
-
* @returns The efficiency object if found, undefined otherwise
|
|
23348
|
-
*/
|
|
23349
21676
|
findStateEfficiency(stateClass) {
|
|
23350
21677
|
return this.statesEfficiency().find(
|
|
23351
21678
|
(state) => isInstanceOf(state.state, stateClass)
|
|
@@ -23443,6 +21770,10 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
|
|
|
23443
21770
|
get hooks() {
|
|
23444
21771
|
return inject$1(this.context, ModulesToken);
|
|
23445
21772
|
}
|
|
21773
|
+
// compatibility with v4
|
|
21774
|
+
get server() {
|
|
21775
|
+
return this.map;
|
|
21776
|
+
}
|
|
23446
21777
|
applyFrames() {
|
|
23447
21778
|
this._frames.set(this.frames);
|
|
23448
21779
|
this.frames = [];
|
|
@@ -24034,6 +22365,186 @@ const _RpgPlayer = class _RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
|
|
|
24034
22365
|
};
|
|
24035
22366
|
this.emit("stopSound", data);
|
|
24036
22367
|
}
|
|
22368
|
+
/**
|
|
22369
|
+
* Stop all currently playing sounds for this player
|
|
22370
|
+
*
|
|
22371
|
+
* This method stops all sounds that are currently playing for the player.
|
|
22372
|
+
* Useful when changing maps to prevent sound overlap.
|
|
22373
|
+
*
|
|
22374
|
+
* @example
|
|
22375
|
+
* ```ts
|
|
22376
|
+
* // Stop all sounds before changing map
|
|
22377
|
+
* player.stopAllSounds();
|
|
22378
|
+
* await player.changeMap("new-map");
|
|
22379
|
+
* ```
|
|
22380
|
+
*/
|
|
22381
|
+
stopAllSounds() {
|
|
22382
|
+
const map2 = this.getCurrentMap();
|
|
22383
|
+
if (!map2) return;
|
|
22384
|
+
this.emit("stopAllSounds", {});
|
|
22385
|
+
}
|
|
22386
|
+
/**
|
|
22387
|
+
* Make the camera follow another player or event
|
|
22388
|
+
*
|
|
22389
|
+
* This method sends an instruction to the client to fix the viewport on another sprite.
|
|
22390
|
+
* The camera will follow the specified player or event, with optional smooth animation.
|
|
22391
|
+
*
|
|
22392
|
+
* ## Design
|
|
22393
|
+
*
|
|
22394
|
+
* The camera follow instruction is sent only to this player's client connection.
|
|
22395
|
+
* This allows each player to have their own camera target, useful for cutscenes,
|
|
22396
|
+
* following NPCs, or focusing on specific events.
|
|
22397
|
+
*
|
|
22398
|
+
* @param otherPlayer - The player or event that the camera should follow
|
|
22399
|
+
* @param options - Camera follow options
|
|
22400
|
+
* @param options.smoothMove - Enable smooth animation. Can be a boolean (default: true) or an object with animation parameters
|
|
22401
|
+
* @param options.smoothMove.time - Time duration for the animation in milliseconds (optional)
|
|
22402
|
+
* @param options.smoothMove.ease - Easing function name. Visit https://easings.net for available functions (optional)
|
|
22403
|
+
*
|
|
22404
|
+
* @example
|
|
22405
|
+
* ```ts
|
|
22406
|
+
* // Follow another player with default smooth animation
|
|
22407
|
+
* player.cameraFollow(otherPlayer, { smoothMove: true });
|
|
22408
|
+
*
|
|
22409
|
+
* // Follow an event with custom smooth animation
|
|
22410
|
+
* player.cameraFollow(npcEvent, {
|
|
22411
|
+
* smoothMove: {
|
|
22412
|
+
* time: 1000,
|
|
22413
|
+
* ease: "easeInOutQuad"
|
|
22414
|
+
* }
|
|
22415
|
+
* });
|
|
22416
|
+
*
|
|
22417
|
+
* // Follow without animation (instant)
|
|
22418
|
+
* player.cameraFollow(targetPlayer, { smoothMove: false });
|
|
22419
|
+
* ```
|
|
22420
|
+
*/
|
|
22421
|
+
cameraFollow(otherPlayer, options) {
|
|
22422
|
+
const map2 = this.getCurrentMap();
|
|
22423
|
+
if (!map2) return;
|
|
22424
|
+
const data = {
|
|
22425
|
+
targetId: otherPlayer.id
|
|
22426
|
+
};
|
|
22427
|
+
if (options?.smoothMove !== void 0) {
|
|
22428
|
+
if (typeof options.smoothMove === "boolean") {
|
|
22429
|
+
data.smoothMove = options.smoothMove;
|
|
22430
|
+
} else {
|
|
22431
|
+
data.smoothMove = {
|
|
22432
|
+
enabled: true,
|
|
22433
|
+
...options.smoothMove
|
|
22434
|
+
};
|
|
22435
|
+
}
|
|
22436
|
+
} else {
|
|
22437
|
+
data.smoothMove = true;
|
|
22438
|
+
}
|
|
22439
|
+
this.emit("cameraFollow", data);
|
|
22440
|
+
}
|
|
22441
|
+
/**
|
|
22442
|
+
* Trigger a flash animation on this player
|
|
22443
|
+
*
|
|
22444
|
+
* This method sends a flash animation event to the client, creating a visual
|
|
22445
|
+
* feedback effect on the player's sprite. The flash can be configured with
|
|
22446
|
+
* various options including type (alpha, tint, or both), duration, cycles, and color.
|
|
22447
|
+
*
|
|
22448
|
+
* ## Design
|
|
22449
|
+
*
|
|
22450
|
+
* The flash is sent as a broadcast event to all clients viewing this player.
|
|
22451
|
+
* This is useful for visual feedback when the player takes damage, receives
|
|
22452
|
+
* a buff, or when an important event occurs.
|
|
22453
|
+
*
|
|
22454
|
+
* @param options - Flash configuration options
|
|
22455
|
+
* @param options.type - Type of flash effect: 'alpha' (opacity), 'tint' (color), or 'both' (default: 'alpha')
|
|
22456
|
+
* @param options.duration - Duration of the flash animation in milliseconds (default: 300)
|
|
22457
|
+
* @param options.cycles - Number of flash cycles (flash on/off) (default: 1)
|
|
22458
|
+
* @param options.alpha - Alpha value when flashing, from 0 to 1 (default: 0.3)
|
|
22459
|
+
* @param options.tint - Tint color when flashing as hex value or color name (default: 0xffffff - white)
|
|
22460
|
+
*
|
|
22461
|
+
* @example
|
|
22462
|
+
* ```ts
|
|
22463
|
+
* // Simple flash with default settings (alpha flash)
|
|
22464
|
+
* player.flash();
|
|
22465
|
+
*
|
|
22466
|
+
* // Flash with red tint when taking damage
|
|
22467
|
+
* player.flash({ type: 'tint', tint: 0xff0000 });
|
|
22468
|
+
*
|
|
22469
|
+
* // Flash with both alpha and tint for dramatic effect
|
|
22470
|
+
* player.flash({
|
|
22471
|
+
* type: 'both',
|
|
22472
|
+
* alpha: 0.5,
|
|
22473
|
+
* tint: 0xff0000,
|
|
22474
|
+
* duration: 200,
|
|
22475
|
+
* cycles: 2
|
|
22476
|
+
* });
|
|
22477
|
+
*
|
|
22478
|
+
* // Quick damage flash
|
|
22479
|
+
* player.flash({
|
|
22480
|
+
* type: 'tint',
|
|
22481
|
+
* tint: 'red',
|
|
22482
|
+
* duration: 150,
|
|
22483
|
+
* cycles: 1
|
|
22484
|
+
* });
|
|
22485
|
+
* ```
|
|
22486
|
+
*/
|
|
22487
|
+
flash(options) {
|
|
22488
|
+
const map2 = this.getCurrentMap();
|
|
22489
|
+
if (!map2) return;
|
|
22490
|
+
const flashOptions = {
|
|
22491
|
+
type: options?.type || "alpha",
|
|
22492
|
+
duration: options?.duration ?? 300,
|
|
22493
|
+
cycles: options?.cycles ?? 1,
|
|
22494
|
+
alpha: options?.alpha ?? 0.3,
|
|
22495
|
+
tint: options?.tint ?? 16777215
|
|
22496
|
+
};
|
|
22497
|
+
map2.$broadcast({
|
|
22498
|
+
type: "flash",
|
|
22499
|
+
value: {
|
|
22500
|
+
object: this.id,
|
|
22501
|
+
...flashOptions
|
|
22502
|
+
}
|
|
22503
|
+
});
|
|
22504
|
+
}
|
|
22505
|
+
/**
|
|
22506
|
+
* Set the hitbox of the player for collision detection
|
|
22507
|
+
*
|
|
22508
|
+
* This method defines the hitbox used for collision detection in the physics engine.
|
|
22509
|
+
* The hitbox can be smaller or larger than the visual representation of the player,
|
|
22510
|
+
* allowing for precise collision detection.
|
|
22511
|
+
*
|
|
22512
|
+
* ## Design
|
|
22513
|
+
*
|
|
22514
|
+
* The hitbox is used by the physics engine to detect collisions with other entities,
|
|
22515
|
+
* static obstacles, and shapes. Changing the hitbox will immediately update the
|
|
22516
|
+
* collision detection without affecting the visual appearance of the player.
|
|
22517
|
+
*
|
|
22518
|
+
* @param width - Width of the hitbox in pixels
|
|
22519
|
+
* @param height - Height of the hitbox in pixels
|
|
22520
|
+
*
|
|
22521
|
+
* @example
|
|
22522
|
+
* ```ts
|
|
22523
|
+
* // Set a 20x20 hitbox for precise collision detection
|
|
22524
|
+
* player.setHitbox(20, 20);
|
|
22525
|
+
*
|
|
22526
|
+
* // Set a larger hitbox for easier collision detection
|
|
22527
|
+
* player.setHitbox(40, 40);
|
|
22528
|
+
* ```
|
|
22529
|
+
*/
|
|
22530
|
+
setHitbox(width, height) {
|
|
22531
|
+
if (typeof width !== "number" || width <= 0) {
|
|
22532
|
+
throw new Error("setHitbox: width must be a positive number");
|
|
22533
|
+
}
|
|
22534
|
+
if (typeof height !== "number" || height <= 0) {
|
|
22535
|
+
throw new Error("setHitbox: height must be a positive number");
|
|
22536
|
+
}
|
|
22537
|
+
this.hitbox.set({
|
|
22538
|
+
w: width,
|
|
22539
|
+
h: height
|
|
22540
|
+
});
|
|
22541
|
+
const map2 = this.getCurrentMap();
|
|
22542
|
+
if (map2 && map2.physic) {
|
|
22543
|
+
const topLeftX = this.x();
|
|
22544
|
+
const topLeftY = this.y();
|
|
22545
|
+
map2.updateHitbox(this.id, topLeftX, topLeftY, width, height);
|
|
22546
|
+
}
|
|
22547
|
+
}
|
|
24037
22548
|
/**
|
|
24038
22549
|
* Set the sync schema for the map
|
|
24039
22550
|
* @param schema - The schema to set
|
|
@@ -27587,10 +26098,72 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27587
26098
|
super();
|
|
27588
26099
|
this.players = signal$1({});
|
|
27589
26100
|
this.events = signal$1({});
|
|
26101
|
+
/**
|
|
26102
|
+
* Signal containing the map's database of items, classes, and other game data
|
|
26103
|
+
*
|
|
26104
|
+
* This database can be dynamically populated using `addInDatabase()` and
|
|
26105
|
+
* `removeInDatabase()` methods. It's used to store game entities like items,
|
|
26106
|
+
* classes, skills, etc. that are specific to this map.
|
|
26107
|
+
*
|
|
26108
|
+
* @example
|
|
26109
|
+
* ```ts
|
|
26110
|
+
* // Add data to database
|
|
26111
|
+
* map.addInDatabase('Potion', PotionClass);
|
|
26112
|
+
*
|
|
26113
|
+
* // Access database
|
|
26114
|
+
* const potion = map.database()['Potion'];
|
|
26115
|
+
* ```
|
|
26116
|
+
*/
|
|
27590
26117
|
this.database = signal$1({});
|
|
26118
|
+
/**
|
|
26119
|
+
* Array of map configurations - can contain MapOptions objects or instances of map classes
|
|
26120
|
+
*
|
|
26121
|
+
* This array stores the configuration for this map and any related maps.
|
|
26122
|
+
* It's populated when the map is loaded via `updateMap()`.
|
|
26123
|
+
*/
|
|
27591
26124
|
this.maps = [];
|
|
26125
|
+
/**
|
|
26126
|
+
* Array of sound IDs to play when players join the map
|
|
26127
|
+
*
|
|
26128
|
+
* These sounds are automatically played for each player when they join the map.
|
|
26129
|
+
* Sounds must be defined on the client side.
|
|
26130
|
+
*
|
|
26131
|
+
* @example
|
|
26132
|
+
* ```ts
|
|
26133
|
+
* // Set sounds for the map
|
|
26134
|
+
* map.sounds = ['background-music', 'ambient-forest'];
|
|
26135
|
+
* ```
|
|
26136
|
+
*/
|
|
26137
|
+
this.sounds = [];
|
|
26138
|
+
/**
|
|
26139
|
+
* BehaviorSubject that completes when the map data is ready
|
|
26140
|
+
*
|
|
26141
|
+
* This subject is used to signal when the map has finished loading all its data.
|
|
26142
|
+
* Players wait for this to complete before the map is fully initialized.
|
|
26143
|
+
*
|
|
26144
|
+
* @example
|
|
26145
|
+
* ```ts
|
|
26146
|
+
* // Wait for map data to be ready
|
|
26147
|
+
* map.dataIsReady$.subscribe(() => {
|
|
26148
|
+
* console.log('Map is ready!');
|
|
26149
|
+
* });
|
|
26150
|
+
* ```
|
|
26151
|
+
*/
|
|
27592
26152
|
this.dataIsReady$ = new BehaviorSubject$1(void 0);
|
|
26153
|
+
/**
|
|
26154
|
+
* Global configuration object for the map
|
|
26155
|
+
*
|
|
26156
|
+
* This object contains configuration settings that apply to the entire map.
|
|
26157
|
+
* It's populated from the map data when `updateMap()` is called.
|
|
26158
|
+
*/
|
|
27593
26159
|
this.globalConfig = {};
|
|
26160
|
+
/**
|
|
26161
|
+
* Damage formulas configuration for the map
|
|
26162
|
+
*
|
|
26163
|
+
* Contains formulas for calculating damage from skills, physical attacks,
|
|
26164
|
+
* critical hits, and element coefficients. Default formulas are merged
|
|
26165
|
+
* with custom formulas when the map is loaded.
|
|
26166
|
+
*/
|
|
27594
26167
|
this.damageFormulas = {};
|
|
27595
26168
|
/** Internal: Map of shapes by name */
|
|
27596
26169
|
this._shapes = /* @__PURE__ */ new Map();
|
|
@@ -27712,7 +26285,31 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27712
26285
|
activeCollisions.delete(collisionKey);
|
|
27713
26286
|
});
|
|
27714
26287
|
}
|
|
27715
|
-
|
|
26288
|
+
/**
|
|
26289
|
+
* Intercepts and modifies packets before they are sent to clients
|
|
26290
|
+
*
|
|
26291
|
+
* This method is automatically called by @signe/room for each packet sent to clients.
|
|
26292
|
+
* It adds timestamp and acknowledgment information to sync packets for client-side
|
|
26293
|
+
* prediction reconciliation. This helps with network synchronization and reduces
|
|
26294
|
+
* perceived latency.
|
|
26295
|
+
*
|
|
26296
|
+
* ## Architecture
|
|
26297
|
+
*
|
|
26298
|
+
* Adds metadata to packets:
|
|
26299
|
+
* - `timestamp`: Current server time for client-side prediction
|
|
26300
|
+
* - `ack`: Acknowledgment info with last processed frame and authoritative position
|
|
26301
|
+
*
|
|
26302
|
+
* @param player - The player receiving the packet
|
|
26303
|
+
* @param packet - The packet data to intercept
|
|
26304
|
+
* @param conn - The connection object
|
|
26305
|
+
* @returns Modified packet with timestamp and ack info, or null if player is invalid
|
|
26306
|
+
*
|
|
26307
|
+
* @example
|
|
26308
|
+
* ```ts
|
|
26309
|
+
* // This method is called automatically by the framework
|
|
26310
|
+
* // You typically don't call it directly
|
|
26311
|
+
* ```
|
|
26312
|
+
*/
|
|
27716
26313
|
interceptorPacket(player, packet, conn) {
|
|
27717
26314
|
let obj = {};
|
|
27718
26315
|
if (!player) {
|
|
@@ -27741,37 +26338,174 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27741
26338
|
}
|
|
27742
26339
|
};
|
|
27743
26340
|
}
|
|
26341
|
+
/**
|
|
26342
|
+
* Called when a player joins the map
|
|
26343
|
+
*
|
|
26344
|
+
* This method is automatically called by @signe/room when a player connects to the map.
|
|
26345
|
+
* It initializes the player's connection, sets up the map context, and waits for
|
|
26346
|
+
* the map data to be ready before playing sounds and triggering hooks.
|
|
26347
|
+
*
|
|
26348
|
+
* ## Architecture
|
|
26349
|
+
*
|
|
26350
|
+
* 1. Sets player's map reference and context
|
|
26351
|
+
* 2. Initializes the player
|
|
26352
|
+
* 3. Waits for map data to be ready
|
|
26353
|
+
* 4. Plays map sounds for the player
|
|
26354
|
+
* 5. Triggers `server-player-onJoinMap` hook
|
|
26355
|
+
*
|
|
26356
|
+
* @param player - The player joining the map
|
|
26357
|
+
* @param conn - The connection object for the player
|
|
26358
|
+
*
|
|
26359
|
+
* @example
|
|
26360
|
+
* ```ts
|
|
26361
|
+
* // This method is called automatically by the framework
|
|
26362
|
+
* // You can listen to the hook to perform custom logic
|
|
26363
|
+
* server.addHook('server-player-onJoinMap', (player, map) => {
|
|
26364
|
+
* console.log(`Player ${player.id} joined map ${map.id}`);
|
|
26365
|
+
* });
|
|
26366
|
+
* ```
|
|
26367
|
+
*/
|
|
27744
26368
|
onJoin(player, conn) {
|
|
27745
26369
|
player.map = this;
|
|
27746
26370
|
player.context = context$1;
|
|
27747
26371
|
player.conn = conn;
|
|
27748
26372
|
player._onInit();
|
|
27749
26373
|
this.dataIsReady$.pipe(
|
|
27750
|
-
finalize$1(() => {
|
|
27751
|
-
|
|
26374
|
+
finalize$1(async () => {
|
|
26375
|
+
if (this.stopAllSoundsBeforeJoin) {
|
|
26376
|
+
player.stopAllSounds();
|
|
26377
|
+
}
|
|
26378
|
+
this.sounds.forEach((sound) => player.playSound(sound, { loop: true }));
|
|
26379
|
+
await lastValueFrom(this.hooks.callHooks("server-map-onJoin", player, this));
|
|
26380
|
+
if (typeof this._onJoin === "function") {
|
|
26381
|
+
await this._onJoin(player);
|
|
26382
|
+
}
|
|
26383
|
+
await lastValueFrom(this.hooks.callHooks("server-player-onJoinMap", player, this));
|
|
27752
26384
|
})
|
|
27753
26385
|
).subscribe();
|
|
27754
26386
|
}
|
|
27755
|
-
|
|
27756
|
-
|
|
26387
|
+
/**
|
|
26388
|
+
* Called when a player leaves the map
|
|
26389
|
+
*
|
|
26390
|
+
* This method is automatically called by @signe/room when a player disconnects from the map.
|
|
26391
|
+
* It cleans up the player's pending inputs and triggers the appropriate hooks.
|
|
26392
|
+
*
|
|
26393
|
+
* ## Architecture
|
|
26394
|
+
*
|
|
26395
|
+
* 1. Triggers `server-player-onLeaveMap` hook
|
|
26396
|
+
* 2. Clears pending inputs to prevent processing after disconnection
|
|
26397
|
+
*
|
|
26398
|
+
* @param player - The player leaving the map
|
|
26399
|
+
* @param conn - The connection object for the player
|
|
26400
|
+
*
|
|
26401
|
+
* @example
|
|
26402
|
+
* ```ts
|
|
26403
|
+
* // This method is called automatically by the framework
|
|
26404
|
+
* // You can listen to the hook to perform custom cleanup
|
|
26405
|
+
* server.addHook('server-player-onLeaveMap', (player, map) => {
|
|
26406
|
+
* console.log(`Player ${player.id} left map ${map.id}`);
|
|
26407
|
+
* });
|
|
26408
|
+
* ```
|
|
26409
|
+
*/
|
|
26410
|
+
async onLeave(player, conn) {
|
|
26411
|
+
await lastValueFrom(this.hooks.callHooks("server-map-onLeave", player, this));
|
|
26412
|
+
if (typeof this._onLeave === "function") {
|
|
26413
|
+
await this._onLeave(player);
|
|
26414
|
+
}
|
|
26415
|
+
await lastValueFrom(this.hooks.callHooks("server-player-onLeaveMap", player, this));
|
|
27757
26416
|
player.pendingInputs = [];
|
|
27758
26417
|
}
|
|
26418
|
+
/**
|
|
26419
|
+
* Get the hooks system for this map
|
|
26420
|
+
*
|
|
26421
|
+
* Returns the dependency-injected Hooks instance that allows you to trigger
|
|
26422
|
+
* and listen to various game events.
|
|
26423
|
+
*
|
|
26424
|
+
* @returns The Hooks instance for this map
|
|
26425
|
+
*
|
|
26426
|
+
* @example
|
|
26427
|
+
* ```ts
|
|
26428
|
+
* // Trigger a custom hook
|
|
26429
|
+
* map.hooks.callHooks('custom-event', data).subscribe();
|
|
26430
|
+
* ```
|
|
26431
|
+
*/
|
|
27759
26432
|
get hooks() {
|
|
27760
26433
|
return inject$1(context$1, ModulesToken);
|
|
27761
26434
|
}
|
|
26435
|
+
/**
|
|
26436
|
+
* Get the width of the map in pixels
|
|
26437
|
+
*
|
|
26438
|
+
* @returns The width of the map in pixels, or 0 if not loaded
|
|
26439
|
+
*
|
|
26440
|
+
* @example
|
|
26441
|
+
* ```ts
|
|
26442
|
+
* const width = map.widthPx;
|
|
26443
|
+
* console.log(`Map width: ${width}px`);
|
|
26444
|
+
* ```
|
|
26445
|
+
*/
|
|
27762
26446
|
get widthPx() {
|
|
27763
26447
|
return this.data()?.width ?? 0;
|
|
27764
26448
|
}
|
|
26449
|
+
/**
|
|
26450
|
+
* Get the height of the map in pixels
|
|
26451
|
+
*
|
|
26452
|
+
* @returns The height of the map in pixels, or 0 if not loaded
|
|
26453
|
+
*
|
|
26454
|
+
* @example
|
|
26455
|
+
* ```ts
|
|
26456
|
+
* const height = map.heightPx;
|
|
26457
|
+
* console.log(`Map height: ${height}px`);
|
|
26458
|
+
* ```
|
|
26459
|
+
*/
|
|
27765
26460
|
get heightPx() {
|
|
27766
26461
|
return this.data()?.height ?? 0;
|
|
27767
26462
|
}
|
|
26463
|
+
/**
|
|
26464
|
+
* Get the unique identifier of the map
|
|
26465
|
+
*
|
|
26466
|
+
* @returns The map ID, or empty string if not loaded
|
|
26467
|
+
*
|
|
26468
|
+
* @example
|
|
26469
|
+
* ```ts
|
|
26470
|
+
* const mapId = map.id;
|
|
26471
|
+
* console.log(`Current map: ${mapId}`);
|
|
26472
|
+
* ```
|
|
26473
|
+
*/
|
|
27768
26474
|
get id() {
|
|
27769
26475
|
return this.data()?.id ?? "";
|
|
27770
26476
|
}
|
|
26477
|
+
/**
|
|
26478
|
+
* Get the X position of this map in the world coordinate system
|
|
26479
|
+
*
|
|
26480
|
+
* This is used when maps are part of a larger world map. The world position
|
|
26481
|
+
* indicates where this map is located relative to other maps.
|
|
26482
|
+
*
|
|
26483
|
+
* @returns The X position in world coordinates, or 0 if not in a world
|
|
26484
|
+
*
|
|
26485
|
+
* @example
|
|
26486
|
+
* ```ts
|
|
26487
|
+
* const worldX = map.worldX;
|
|
26488
|
+
* console.log(`Map is at world position (${worldX}, ${map.worldY})`);
|
|
26489
|
+
* ```
|
|
26490
|
+
*/
|
|
27771
26491
|
get worldX() {
|
|
27772
26492
|
const worldMaps = this.getWorldMapsManager?.();
|
|
27773
26493
|
return worldMaps?.getMapInfo(this.id)?.worldX ?? 0;
|
|
27774
26494
|
}
|
|
26495
|
+
/**
|
|
26496
|
+
* Get the Y position of this map in the world coordinate system
|
|
26497
|
+
*
|
|
26498
|
+
* This is used when maps are part of a larger world map. The world position
|
|
26499
|
+
* indicates where this map is located relative to other maps.
|
|
26500
|
+
*
|
|
26501
|
+
* @returns The Y position in world coordinates, or 0 if not in a world
|
|
26502
|
+
*
|
|
26503
|
+
* @example
|
|
26504
|
+
* ```ts
|
|
26505
|
+
* const worldY = map.worldY;
|
|
26506
|
+
* console.log(`Map is at world position (${map.worldX}, ${worldY})`);
|
|
26507
|
+
* ```
|
|
26508
|
+
*/
|
|
27775
26509
|
get worldY() {
|
|
27776
26510
|
const worldMaps = this.getWorldMapsManager?.();
|
|
27777
26511
|
return worldMaps?.getMapInfo(this.id)?.worldY ?? 0;
|
|
@@ -27828,6 +26562,26 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27828
26562
|
...map.events
|
|
27829
26563
|
];
|
|
27830
26564
|
}
|
|
26565
|
+
if (mapFound?.sounds) {
|
|
26566
|
+
this.sounds = [
|
|
26567
|
+
...map.sounds ?? [],
|
|
26568
|
+
...mapFound.sounds
|
|
26569
|
+
];
|
|
26570
|
+
} else {
|
|
26571
|
+
this.sounds = map.sounds ?? [];
|
|
26572
|
+
}
|
|
26573
|
+
if (mapFound?.onLoad) {
|
|
26574
|
+
this._onLoad = mapFound.onLoad;
|
|
26575
|
+
}
|
|
26576
|
+
if (mapFound?.onJoin) {
|
|
26577
|
+
this._onJoin = mapFound.onJoin;
|
|
26578
|
+
}
|
|
26579
|
+
if (mapFound?.onLeave) {
|
|
26580
|
+
this._onLeave = mapFound.onLeave;
|
|
26581
|
+
}
|
|
26582
|
+
if (mapFound?.stopAllSoundsBeforeJoin !== void 0) {
|
|
26583
|
+
this.stopAllSoundsBeforeJoin = mapFound.stopAllSoundsBeforeJoin;
|
|
26584
|
+
}
|
|
27831
26585
|
}
|
|
27832
26586
|
await lastValueFrom(this.hooks.callHooks("server-map-onBeforeUpdate", map, this));
|
|
27833
26587
|
this.loadPhysic();
|
|
@@ -27835,6 +26589,10 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27835
26589
|
await this.createDynamicEvent(event);
|
|
27836
26590
|
}
|
|
27837
26591
|
this.dataIsReady$.complete();
|
|
26592
|
+
await lastValueFrom(this.hooks.callHooks("server-map-onLoad", this));
|
|
26593
|
+
if (typeof this._onLoad === "function") {
|
|
26594
|
+
await this._onLoad();
|
|
26595
|
+
}
|
|
27838
26596
|
}
|
|
27839
26597
|
async updateWorld(request) {
|
|
27840
26598
|
let worldId = "";
|
|
@@ -27972,6 +26730,26 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27972
26730
|
inputs: processedInputs
|
|
27973
26731
|
};
|
|
27974
26732
|
}
|
|
26733
|
+
/**
|
|
26734
|
+
* Main game loop that processes player inputs
|
|
26735
|
+
*
|
|
26736
|
+
* This private method runs continuously every 50ms to process pending inputs
|
|
26737
|
+
* for all players on the map. It ensures inputs are processed in order and
|
|
26738
|
+
* prevents concurrent processing for the same player.
|
|
26739
|
+
*
|
|
26740
|
+
* ## Architecture
|
|
26741
|
+
*
|
|
26742
|
+
* - Runs every 50ms for responsive input processing
|
|
26743
|
+
* - Processes inputs for each player with pending inputs
|
|
26744
|
+
* - Uses a flag to prevent concurrent processing for the same player
|
|
26745
|
+
* - Calls `processInput()` to handle anti-cheat validation and movement
|
|
26746
|
+
*
|
|
26747
|
+
* @example
|
|
26748
|
+
* ```ts
|
|
26749
|
+
* // This method is called automatically in the constructor
|
|
26750
|
+
* // You typically don't call it directly
|
|
26751
|
+
* ```
|
|
26752
|
+
*/
|
|
27975
26753
|
loop() {
|
|
27976
26754
|
setInterval(async () => {
|
|
27977
26755
|
for (const player of this.getPlayers()) {
|
|
@@ -27988,7 +26766,21 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27988
26766
|
}, 50);
|
|
27989
26767
|
}
|
|
27990
26768
|
/**
|
|
27991
|
-
* Get a world manager by id
|
|
26769
|
+
* Get a world manager by id
|
|
26770
|
+
*
|
|
26771
|
+
* Returns the world maps manager for the given world ID. Currently, only
|
|
26772
|
+
* one world manager is supported per map instance.
|
|
26773
|
+
*
|
|
26774
|
+
* @param id - The world ID (currently unused, returns the single manager)
|
|
26775
|
+
* @returns The WorldMapsManager instance, or null if not initialized
|
|
26776
|
+
*
|
|
26777
|
+
* @example
|
|
26778
|
+
* ```ts
|
|
26779
|
+
* const worldManager = map.getWorldMaps('my-world');
|
|
26780
|
+
* if (worldManager) {
|
|
26781
|
+
* const mapInfo = worldManager.getMapInfo('map1');
|
|
26782
|
+
* }
|
|
26783
|
+
* ```
|
|
27992
26784
|
*/
|
|
27993
26785
|
getWorldMaps(id) {
|
|
27994
26786
|
if (!this.worldMapsManager) return null;
|
|
@@ -27996,6 +26788,20 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
27996
26788
|
}
|
|
27997
26789
|
/**
|
|
27998
26790
|
* Delete a world manager by id
|
|
26791
|
+
*
|
|
26792
|
+
* Removes the world maps manager from this map instance. Currently, only
|
|
26793
|
+
* one world manager is supported, so this clears the single manager.
|
|
26794
|
+
*
|
|
26795
|
+
* @param id - The world ID (currently unused)
|
|
26796
|
+
* @returns true if the manager was deleted, false if it didn't exist
|
|
26797
|
+
*
|
|
26798
|
+
* @example
|
|
26799
|
+
* ```ts
|
|
26800
|
+
* const deleted = map.deleteWorldMaps('my-world');
|
|
26801
|
+
* if (deleted) {
|
|
26802
|
+
* console.log('World manager removed');
|
|
26803
|
+
* }
|
|
26804
|
+
* ```
|
|
27999
26805
|
*/
|
|
28000
26806
|
deleteWorldMaps(id) {
|
|
28001
26807
|
if (!this.worldMapsManager) return false;
|
|
@@ -28004,6 +26810,26 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
28004
26810
|
}
|
|
28005
26811
|
/**
|
|
28006
26812
|
* Create a world manager dynamically
|
|
26813
|
+
*
|
|
26814
|
+
* Creates a new WorldMapsManager instance and configures it with the provided
|
|
26815
|
+
* map configurations. This is used when loading world data from Tiled or
|
|
26816
|
+
* other map editors.
|
|
26817
|
+
*
|
|
26818
|
+
* @param world - World configuration object
|
|
26819
|
+
* @param world.id - Optional world identifier
|
|
26820
|
+
* @param world.maps - Array of map configurations for the world
|
|
26821
|
+
* @returns The newly created WorldMapsManager instance
|
|
26822
|
+
*
|
|
26823
|
+
* @example
|
|
26824
|
+
* ```ts
|
|
26825
|
+
* const manager = map.createDynamicWorldMaps({
|
|
26826
|
+
* id: 'my-world',
|
|
26827
|
+
* maps: [
|
|
26828
|
+
* { id: 'map1', worldX: 0, worldY: 0, width: 800, height: 600 },
|
|
26829
|
+
* { id: 'map2', worldX: 800, worldY: 0, width: 800, height: 600 }
|
|
26830
|
+
* ]
|
|
26831
|
+
* });
|
|
26832
|
+
* ```
|
|
28007
26833
|
*/
|
|
28008
26834
|
createDynamicWorldMaps(world) {
|
|
28009
26835
|
const manager = new WorldMapsManager();
|
|
@@ -28013,6 +26839,22 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
28013
26839
|
}
|
|
28014
26840
|
/**
|
|
28015
26841
|
* Update world maps by id. Auto-create when missing.
|
|
26842
|
+
*
|
|
26843
|
+
* Updates the world maps configuration. If the world manager doesn't exist,
|
|
26844
|
+
* it is automatically created. This is useful for dynamically loading world
|
|
26845
|
+
* data or updating map positions.
|
|
26846
|
+
*
|
|
26847
|
+
* @param id - The world ID
|
|
26848
|
+
* @param maps - Array of map configurations to update
|
|
26849
|
+
* @returns Promise that resolves when the update is complete
|
|
26850
|
+
*
|
|
26851
|
+
* @example
|
|
26852
|
+
* ```ts
|
|
26853
|
+
* await map.updateWorldMaps('my-world', [
|
|
26854
|
+
* { id: 'map1', worldX: 0, worldY: 0, width: 800, height: 600 },
|
|
26855
|
+
* { id: 'map2', worldX: 800, worldY: 0, width: 800, height: 600 }
|
|
26856
|
+
* ]);
|
|
26857
|
+
* ```
|
|
28016
26858
|
*/
|
|
28017
26859
|
async updateWorldMaps(id, maps) {
|
|
28018
26860
|
let world = this.getWorldMaps(id);
|
|
@@ -28168,24 +27010,159 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
28168
27010
|
this.events()[id] = eventInstance;
|
|
28169
27011
|
await eventInstance.execMethod("onInit");
|
|
28170
27012
|
}
|
|
27013
|
+
/**
|
|
27014
|
+
* Get an event by its ID
|
|
27015
|
+
*
|
|
27016
|
+
* Returns the event with the specified ID, or undefined if not found.
|
|
27017
|
+
* The return type can be narrowed using TypeScript generics.
|
|
27018
|
+
*
|
|
27019
|
+
* @param eventId - The unique identifier of the event
|
|
27020
|
+
* @returns The event instance, or undefined if not found
|
|
27021
|
+
*
|
|
27022
|
+
* @example
|
|
27023
|
+
* ```ts
|
|
27024
|
+
* // Get any event
|
|
27025
|
+
* const event = map.getEvent('npc-1');
|
|
27026
|
+
*
|
|
27027
|
+
* // Get event with type narrowing
|
|
27028
|
+
* const npc = map.getEvent<MyNPC>('npc-1');
|
|
27029
|
+
* if (npc) {
|
|
27030
|
+
* npc.speak('Hello!');
|
|
27031
|
+
* }
|
|
27032
|
+
* ```
|
|
27033
|
+
*/
|
|
28171
27034
|
getEvent(eventId) {
|
|
28172
27035
|
return this.events()[eventId];
|
|
28173
27036
|
}
|
|
27037
|
+
/**
|
|
27038
|
+
* Get a player by their ID
|
|
27039
|
+
*
|
|
27040
|
+
* Returns the player with the specified ID, or undefined if not found.
|
|
27041
|
+
*
|
|
27042
|
+
* @param playerId - The unique identifier of the player
|
|
27043
|
+
* @returns The player instance, or undefined if not found
|
|
27044
|
+
*
|
|
27045
|
+
* @example
|
|
27046
|
+
* ```ts
|
|
27047
|
+
* const player = map.getPlayer('player-123');
|
|
27048
|
+
* if (player) {
|
|
27049
|
+
* console.log(`Player ${player.name} is on the map`);
|
|
27050
|
+
* }
|
|
27051
|
+
* ```
|
|
27052
|
+
*/
|
|
28174
27053
|
getPlayer(playerId) {
|
|
28175
27054
|
return this.players()[playerId];
|
|
28176
27055
|
}
|
|
27056
|
+
/**
|
|
27057
|
+
* Get all players currently on the map
|
|
27058
|
+
*
|
|
27059
|
+
* Returns an array of all players that are currently connected to this map.
|
|
27060
|
+
*
|
|
27061
|
+
* @returns Array of all RpgPlayer instances on the map
|
|
27062
|
+
*
|
|
27063
|
+
* @example
|
|
27064
|
+
* ```ts
|
|
27065
|
+
* const players = map.getPlayers();
|
|
27066
|
+
* console.log(`There are ${players.length} players on the map`);
|
|
27067
|
+
*
|
|
27068
|
+
* players.forEach(player => {
|
|
27069
|
+
* console.log(`- ${player.name}`);
|
|
27070
|
+
* });
|
|
27071
|
+
* ```
|
|
27072
|
+
*/
|
|
28177
27073
|
getPlayers() {
|
|
28178
27074
|
return Object.values(this.players());
|
|
28179
27075
|
}
|
|
27076
|
+
/**
|
|
27077
|
+
* Get all events on the map
|
|
27078
|
+
*
|
|
27079
|
+
* Returns an array of all events (NPCs, objects, etc.) that are currently
|
|
27080
|
+
* on this map.
|
|
27081
|
+
*
|
|
27082
|
+
* @returns Array of all RpgEvent instances on the map
|
|
27083
|
+
*
|
|
27084
|
+
* @example
|
|
27085
|
+
* ```ts
|
|
27086
|
+
* const events = map.getEvents();
|
|
27087
|
+
* console.log(`There are ${events.length} events on the map`);
|
|
27088
|
+
*
|
|
27089
|
+
* events.forEach(event => {
|
|
27090
|
+
* console.log(`- ${event.name} at (${event.x}, ${event.y})`);
|
|
27091
|
+
* });
|
|
27092
|
+
* ```
|
|
27093
|
+
*/
|
|
28180
27094
|
getEvents() {
|
|
28181
27095
|
return Object.values(this.events());
|
|
28182
27096
|
}
|
|
27097
|
+
/**
|
|
27098
|
+
* Get the first event that matches a condition
|
|
27099
|
+
*
|
|
27100
|
+
* Searches through all events on the map and returns the first one that
|
|
27101
|
+
* matches the provided callback function.
|
|
27102
|
+
*
|
|
27103
|
+
* @param cb - Callback function that returns true for the desired event
|
|
27104
|
+
* @returns The first matching event, or undefined if none found
|
|
27105
|
+
*
|
|
27106
|
+
* @example
|
|
27107
|
+
* ```ts
|
|
27108
|
+
* // Find an event by name
|
|
27109
|
+
* const npc = map.getEventBy(event => event.name === 'Merchant');
|
|
27110
|
+
*
|
|
27111
|
+
* // Find an event at a specific position
|
|
27112
|
+
* const chest = map.getEventBy(event =>
|
|
27113
|
+
* event.x === 100 && event.y === 200
|
|
27114
|
+
* );
|
|
27115
|
+
* ```
|
|
27116
|
+
*/
|
|
28183
27117
|
getEventBy(cb) {
|
|
28184
27118
|
return this.getEventsBy(cb)[0];
|
|
28185
27119
|
}
|
|
27120
|
+
/**
|
|
27121
|
+
* Get all events that match a condition
|
|
27122
|
+
*
|
|
27123
|
+
* Searches through all events on the map and returns all events that
|
|
27124
|
+
* match the provided callback function.
|
|
27125
|
+
*
|
|
27126
|
+
* @param cb - Callback function that returns true for desired events
|
|
27127
|
+
* @returns Array of all matching events
|
|
27128
|
+
*
|
|
27129
|
+
* @example
|
|
27130
|
+
* ```ts
|
|
27131
|
+
* // Find all NPCs
|
|
27132
|
+
* const npcs = map.getEventsBy(event => event.name.startsWith('NPC-'));
|
|
27133
|
+
*
|
|
27134
|
+
* // Find all events in a specific area
|
|
27135
|
+
* const nearbyEvents = map.getEventsBy(event =>
|
|
27136
|
+
* event.x >= 0 && event.x <= 100 &&
|
|
27137
|
+
* event.y >= 0 && event.y <= 100
|
|
27138
|
+
* );
|
|
27139
|
+
* ```
|
|
27140
|
+
*/
|
|
28186
27141
|
getEventsBy(cb) {
|
|
28187
27142
|
return this.getEvents().filter(cb);
|
|
28188
27143
|
}
|
|
27144
|
+
/**
|
|
27145
|
+
* Remove an event from the map
|
|
27146
|
+
*
|
|
27147
|
+
* Removes the event with the specified ID from the map. The event will
|
|
27148
|
+
* be removed from the synchronized events signal, causing it to disappear
|
|
27149
|
+
* on all clients.
|
|
27150
|
+
*
|
|
27151
|
+
* @param eventId - The unique identifier of the event to remove
|
|
27152
|
+
*
|
|
27153
|
+
* @example
|
|
27154
|
+
* ```ts
|
|
27155
|
+
* // Remove an event
|
|
27156
|
+
* map.removeEvent('npc-1');
|
|
27157
|
+
*
|
|
27158
|
+
* // Remove event after interaction
|
|
27159
|
+
* const chest = map.getEvent('chest-1');
|
|
27160
|
+
* if (chest) {
|
|
27161
|
+
* // ... do something with chest ...
|
|
27162
|
+
* map.removeEvent('chest-1');
|
|
27163
|
+
* }
|
|
27164
|
+
* ```
|
|
27165
|
+
*/
|
|
28189
27166
|
removeEvent(eventId) {
|
|
28190
27167
|
delete this.events()[eventId];
|
|
28191
27168
|
}
|
|
@@ -28267,16 +27244,44 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
28267
27244
|
animationName
|
|
28268
27245
|
});
|
|
28269
27246
|
}
|
|
28270
|
-
/**
|
|
28271
|
-
* Set the sync schema for the map
|
|
28272
|
-
* @param schema - The schema to set
|
|
28273
|
-
*/
|
|
28274
27247
|
/**
|
|
28275
27248
|
* Configure runtime synchronized properties on the map
|
|
28276
|
-
*
|
|
28277
|
-
*
|
|
27249
|
+
*
|
|
27250
|
+
* This method allows you to dynamically add synchronized properties to the map
|
|
27251
|
+
* that will be automatically synced with clients. The schema follows the same
|
|
27252
|
+
* structure as module properties with `$initial`, `$syncWithClient`, and `$permanent` options.
|
|
27253
|
+
*
|
|
27254
|
+
* ## Architecture
|
|
27255
|
+
*
|
|
28278
27256
|
* - Reads a schema object shaped like module props
|
|
28279
27257
|
* - Creates typed sync signals with @signe/sync
|
|
27258
|
+
* - Properties are accessible as `map.propertyName`
|
|
27259
|
+
*
|
|
27260
|
+
* @param schema - Schema object defining the properties to sync
|
|
27261
|
+
* @param schema[key].$initial - Initial value for the property
|
|
27262
|
+
* @param schema[key].$syncWithClient - Whether to sync this property to clients
|
|
27263
|
+
* @param schema[key].$permanent - Whether to persist this property
|
|
27264
|
+
*
|
|
27265
|
+
* @example
|
|
27266
|
+
* ```ts
|
|
27267
|
+
* // Add synchronized properties to the map
|
|
27268
|
+
* map.setSync({
|
|
27269
|
+
* weather: {
|
|
27270
|
+
* $initial: 'sunny',
|
|
27271
|
+
* $syncWithClient: true,
|
|
27272
|
+
* $permanent: false
|
|
27273
|
+
* },
|
|
27274
|
+
* timeOfDay: {
|
|
27275
|
+
* $initial: 12,
|
|
27276
|
+
* $syncWithClient: true,
|
|
27277
|
+
* $permanent: false
|
|
27278
|
+
* }
|
|
27279
|
+
* });
|
|
27280
|
+
*
|
|
27281
|
+
* // Use the properties
|
|
27282
|
+
* map.weather.set('rainy');
|
|
27283
|
+
* const currentWeather = map.weather();
|
|
27284
|
+
* ```
|
|
28280
27285
|
*/
|
|
28281
27286
|
setSync(schema) {
|
|
28282
27287
|
for (let key in schema) {
|
|
@@ -28559,6 +27564,64 @@ let RpgMap = class extends RpgCommonMap {
|
|
|
28559
27564
|
player.stopSound(soundId);
|
|
28560
27565
|
});
|
|
28561
27566
|
}
|
|
27567
|
+
/**
|
|
27568
|
+
* Shake the map for all players
|
|
27569
|
+
*
|
|
27570
|
+
* This method triggers a shake animation on the map for all players currently on the map.
|
|
27571
|
+
* The shake effect creates a visual feedback that can be used for earthquakes, explosions,
|
|
27572
|
+
* impacts, or any dramatic event that should affect the entire map visually.
|
|
27573
|
+
*
|
|
27574
|
+
* ## Architecture
|
|
27575
|
+
*
|
|
27576
|
+
* Broadcasts a shake event to all clients connected to the map. Each client receives
|
|
27577
|
+
* the shake configuration and triggers the shake animation on the map container using
|
|
27578
|
+
* Canvas Engine's shake directive.
|
|
27579
|
+
*
|
|
27580
|
+
* @param options - Optional shake configuration
|
|
27581
|
+
* @param options.intensity - Shake intensity in pixels (default: 10)
|
|
27582
|
+
* @param options.duration - Duration of the shake animation in milliseconds (default: 500)
|
|
27583
|
+
* @param options.frequency - Number of shake oscillations during the animation (default: 10)
|
|
27584
|
+
* @param options.direction - Direction of the shake - 'x', 'y', or 'both' (default: 'both')
|
|
27585
|
+
*
|
|
27586
|
+
* @example
|
|
27587
|
+
* ```ts
|
|
27588
|
+
* // Basic shake with default settings
|
|
27589
|
+
* map.shakeMap();
|
|
27590
|
+
*
|
|
27591
|
+
* // Intense earthquake effect
|
|
27592
|
+
* map.shakeMap({
|
|
27593
|
+
* intensity: 25,
|
|
27594
|
+
* duration: 1000,
|
|
27595
|
+
* frequency: 15,
|
|
27596
|
+
* direction: 'both'
|
|
27597
|
+
* });
|
|
27598
|
+
*
|
|
27599
|
+
* // Horizontal shake for side impact
|
|
27600
|
+
* map.shakeMap({
|
|
27601
|
+
* intensity: 15,
|
|
27602
|
+
* duration: 400,
|
|
27603
|
+
* direction: 'x'
|
|
27604
|
+
* });
|
|
27605
|
+
*
|
|
27606
|
+
* // Vertical shake for ground impact
|
|
27607
|
+
* map.shakeMap({
|
|
27608
|
+
* intensity: 20,
|
|
27609
|
+
* duration: 600,
|
|
27610
|
+
* direction: 'y'
|
|
27611
|
+
* });
|
|
27612
|
+
* ```
|
|
27613
|
+
*/
|
|
27614
|
+
shakeMap(options) {
|
|
27615
|
+
this.$broadcast({
|
|
27616
|
+
type: "shakeMap",
|
|
27617
|
+
value: {
|
|
27618
|
+
intensity: options?.intensity ?? 10,
|
|
27619
|
+
duration: options?.duration ?? 500,
|
|
27620
|
+
frequency: options?.frequency ?? 10,
|
|
27621
|
+
direction: options?.direction ?? "both"
|
|
27622
|
+
}
|
|
27623
|
+
});
|
|
27624
|
+
}
|
|
28562
27625
|
};
|
|
28563
27626
|
__decorateClass$1([
|
|
28564
27627
|
users$1(RpgPlayer)
|
|
@@ -28894,6 +27957,14 @@ function provideServerModules(modules) {
|
|
|
28894
27957
|
const mainModuleServer = findModules(context, "Server");
|
|
28895
27958
|
modules2 = [...mainModuleServer, ...modules2];
|
|
28896
27959
|
modules2 = modules2.map((module) => {
|
|
27960
|
+
if (typeof module === "function") {
|
|
27961
|
+
const instance = new module();
|
|
27962
|
+
const moduleObj = {};
|
|
27963
|
+
for (const key in instance) {
|
|
27964
|
+
moduleObj[key] = instance[key];
|
|
27965
|
+
}
|
|
27966
|
+
module = moduleObj;
|
|
27967
|
+
}
|
|
28897
27968
|
if ("server" in module) {
|
|
28898
27969
|
module = module.server;
|
|
28899
27970
|
}
|
|
@@ -28914,7 +27985,27 @@ function provideServerModules(modules) {
|
|
|
28914
27985
|
maps: {
|
|
28915
27986
|
load: (engine) => {
|
|
28916
27987
|
maps.forEach((map) => {
|
|
28917
|
-
|
|
27988
|
+
let mapInstance;
|
|
27989
|
+
if (typeof map === "function") {
|
|
27990
|
+
const MapClass = map;
|
|
27991
|
+
mapInstance = {
|
|
27992
|
+
id: MapClass.prototype?.id ?? MapClass.id,
|
|
27993
|
+
file: MapClass.prototype?.file ?? MapClass.file,
|
|
27994
|
+
type: MapClass.type,
|
|
27995
|
+
name: MapClass.prototype?.name,
|
|
27996
|
+
sounds: MapClass.prototype?.sounds,
|
|
27997
|
+
lowMemory: MapClass.prototype?.lowMemory,
|
|
27998
|
+
stopAllSoundsBeforeJoin: MapClass.prototype?.stopAllSoundsBeforeJoin,
|
|
27999
|
+
events: MapClass.prototype?._events,
|
|
28000
|
+
syncSchema: MapClass.prototype?.$schema,
|
|
28001
|
+
onLoad: MapClass.prototype?.onLoad,
|
|
28002
|
+
onJoin: MapClass.prototype?.onJoin,
|
|
28003
|
+
onLeave: MapClass.prototype?.onLeave
|
|
28004
|
+
};
|
|
28005
|
+
} else {
|
|
28006
|
+
mapInstance = map;
|
|
28007
|
+
}
|
|
28008
|
+
engine.maps.push(mapInstance);
|
|
28918
28009
|
});
|
|
28919
28010
|
}
|
|
28920
28011
|
}
|
|
@@ -28966,11 +28057,21 @@ function MapData(options) {
|
|
|
28966
28057
|
target.prototype.id = options.id;
|
|
28967
28058
|
target.prototype.sounds = options.sounds;
|
|
28968
28059
|
target.prototype.lowMemory = options.lowMemory;
|
|
28060
|
+
target.prototype.stopAllSoundsBeforeJoin = options.stopAllSoundsBeforeJoin;
|
|
28969
28061
|
target.prototype.$schema = {};
|
|
28970
28062
|
if (options.syncSchema) {
|
|
28971
28063
|
target.prototype.$schema = options.syncSchema;
|
|
28972
28064
|
}
|
|
28973
28065
|
target.prototype._events = options.events;
|
|
28066
|
+
if (options.onLoad) {
|
|
28067
|
+
target.prototype.onLoad = options.onLoad;
|
|
28068
|
+
}
|
|
28069
|
+
if (options.onJoin) {
|
|
28070
|
+
target.prototype.onJoin = options.onJoin;
|
|
28071
|
+
}
|
|
28072
|
+
if (options.onLeave) {
|
|
28073
|
+
target.prototype.onLeave = options.onLeave;
|
|
28074
|
+
}
|
|
28974
28075
|
};
|
|
28975
28076
|
}
|
|
28976
28077
|
|