@rpgjs/server 5.0.0-alpha.8 → 5.0.0-beta.1
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/Gui/DialogGui.d.ts +5 -0
- package/dist/Gui/GameoverGui.d.ts +23 -0
- package/dist/Gui/Gui.d.ts +6 -0
- package/dist/Gui/MenuGui.d.ts +22 -3
- package/dist/Gui/NotificationGui.d.ts +1 -2
- package/dist/Gui/SaveLoadGui.d.ts +13 -0
- package/dist/Gui/ShopGui.d.ts +28 -3
- package/dist/Gui/TitleGui.d.ts +23 -0
- package/dist/Gui/index.d.ts +10 -1
- package/dist/Player/BattleManager.d.ts +44 -32
- package/dist/Player/ClassManager.d.ts +24 -4
- package/dist/Player/ComponentManager.d.ts +100 -7
- package/dist/Player/Components.d.ts +345 -0
- package/dist/Player/EffectManager.d.ts +50 -4
- package/dist/Player/ElementManager.d.ts +77 -4
- package/dist/Player/GoldManager.d.ts +1 -1
- package/dist/Player/GuiManager.d.ts +233 -5
- package/dist/Player/ItemFixture.d.ts +1 -1
- package/dist/Player/ItemManager.d.ts +431 -4
- package/dist/Player/MoveManager.d.ts +301 -34
- package/dist/Player/ParameterManager.d.ts +364 -28
- package/dist/Player/Player.d.ts +558 -14
- package/dist/Player/SkillManager.d.ts +187 -13
- package/dist/Player/StateManager.d.ts +75 -4
- package/dist/Player/VariableManager.d.ts +62 -4
- package/dist/RpgServer.d.ts +278 -63
- package/dist/RpgServerEngine.d.ts +2 -1
- package/dist/decorators/event.d.ts +46 -0
- package/dist/decorators/map.d.ts +299 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +17920 -29866
- package/dist/index.js.map +1 -1
- package/dist/logs/log.d.ts +2 -3
- package/dist/module-CaCW1SDh.js +11018 -0
- package/dist/module-CaCW1SDh.js.map +1 -0
- package/dist/module.d.ts +43 -1
- package/dist/node/connection.d.ts +51 -0
- package/dist/node/index.d.ts +5 -0
- package/dist/node/index.js +551 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/map.d.ts +16 -0
- package/dist/node/room.d.ts +21 -0
- package/dist/node/transport.d.ts +28 -0
- package/dist/node/types.d.ts +47 -0
- package/dist/presets/index.d.ts +0 -9
- package/dist/rooms/BaseRoom.d.ts +132 -0
- package/dist/rooms/lobby.d.ts +10 -2
- package/dist/rooms/map.d.ts +1359 -32
- package/dist/services/save.d.ts +43 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/localStorage.d.ts +23 -0
- package/package.json +25 -10
- package/src/Gui/DialogGui.ts +19 -4
- package/src/Gui/GameoverGui.ts +39 -0
- package/src/Gui/Gui.ts +23 -1
- package/src/Gui/MenuGui.ts +155 -6
- package/src/Gui/NotificationGui.ts +1 -2
- package/src/Gui/SaveLoadGui.ts +60 -0
- package/src/Gui/ShopGui.ts +146 -16
- package/src/Gui/TitleGui.ts +39 -0
- package/src/Gui/index.ts +15 -2
- package/src/Player/BattleManager.ts +39 -56
- package/src/Player/ClassManager.ts +82 -74
- package/src/Player/ComponentManager.ts +401 -37
- package/src/Player/Components.ts +380 -0
- package/src/Player/EffectManager.ts +50 -96
- package/src/Player/ElementManager.ts +74 -152
- package/src/Player/GuiManager.ts +284 -149
- package/src/Player/ItemManager.ts +747 -341
- package/src/Player/MoveManager.ts +1532 -750
- package/src/Player/ParameterManager.ts +636 -106
- package/src/Player/Player.ts +1273 -79
- package/src/Player/SkillManager.ts +558 -197
- package/src/Player/StateManager.ts +131 -258
- package/src/Player/VariableManager.ts +85 -157
- package/src/RpgServer.ts +293 -62
- package/src/decorators/event.ts +61 -0
- package/src/decorators/map.ts +343 -0
- package/src/index.ts +11 -1
- package/src/logs/log.ts +10 -3
- package/src/module.ts +126 -3
- package/src/node/connection.ts +254 -0
- package/src/node/index.ts +22 -0
- package/src/node/map.ts +328 -0
- package/src/node/room.ts +63 -0
- package/src/node/transport.ts +532 -0
- package/src/node/types.ts +61 -0
- package/src/presets/index.ts +1 -10
- package/src/rooms/BaseRoom.ts +232 -0
- package/src/rooms/lobby.ts +25 -7
- package/src/rooms/map.ts +2682 -206
- package/src/services/save.ts +147 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/localStorage.ts +76 -0
- package/tests/battle.spec.ts +375 -0
- package/tests/change-map.spec.ts +72 -0
- package/tests/class.spec.ts +274 -0
- package/tests/custom-websocket.spec.ts +127 -0
- package/tests/effect.spec.ts +219 -0
- package/tests/element.spec.ts +221 -0
- package/tests/event.spec.ts +80 -0
- package/tests/gold.spec.ts +99 -0
- package/tests/item.spec.ts +609 -0
- package/tests/module.spec.ts +38 -0
- package/tests/move.spec.ts +601 -0
- package/tests/node-transport.spec.ts +223 -0
- package/tests/player-param.spec.ts +45 -0
- package/tests/prediction-reconciliation.spec.ts +182 -0
- package/tests/random-move.spec.ts +65 -0
- package/tests/skill.spec.ts +658 -0
- package/tests/state.spec.ts +467 -0
- package/tests/variable.spec.ts +185 -0
- package/tests/world-maps.spec.ts +896 -0
- package/vite.config.ts +36 -3
- package/dist/Player/Event.d.ts +0 -0
- package/src/Player/Event.ts +0 -0
|
@@ -1,67 +1,580 @@
|
|
|
1
1
|
import { isString, PlayerCtor } from "@rpgjs/common";
|
|
2
|
-
import {
|
|
2
|
+
import { signal, computed, WritableSignal, ComputedSignal } from "@signe/reactive";
|
|
3
|
+
import { MAXHP, MAXSP } from "@rpgjs/common";
|
|
4
|
+
import { type } from "@signe/sync";
|
|
3
5
|
|
|
6
|
+
export type ExpCurve = {
|
|
7
|
+
basis: number;
|
|
8
|
+
extra: number;
|
|
9
|
+
accelerationA: number;
|
|
10
|
+
accelerationB: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type ParameterCurve = {
|
|
14
|
+
start: number;
|
|
15
|
+
end: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ParameterValue = number | ParameterCurve;
|
|
19
|
+
|
|
20
|
+
const DEFAULT_EXP_CURVE: ExpCurve = {
|
|
21
|
+
basis: 30,
|
|
22
|
+
extra: 20,
|
|
23
|
+
accelerationA: 30,
|
|
24
|
+
accelerationB: 30
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
28
|
+
return typeof value === "object" && value !== null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function toValidNumber(value: unknown, fallback: number): number {
|
|
32
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeExpCurve(value: unknown): ExpCurve {
|
|
36
|
+
if (!isObject(value)) return DEFAULT_EXP_CURVE;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
basis: toValidNumber(value.basis, DEFAULT_EXP_CURVE.basis),
|
|
40
|
+
extra: toValidNumber(value.extra, DEFAULT_EXP_CURVE.extra),
|
|
41
|
+
accelerationA: toValidNumber(value.accelerationA, DEFAULT_EXP_CURVE.accelerationA),
|
|
42
|
+
accelerationB: toValidNumber(value.accelerationB, DEFAULT_EXP_CURVE.accelerationB)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function normalizeParameterCurve(value: unknown): ParameterCurve {
|
|
47
|
+
if (typeof value === "number") {
|
|
48
|
+
const normalized = toValidNumber(value, 0);
|
|
49
|
+
return {
|
|
50
|
+
start: normalized,
|
|
51
|
+
end: normalized
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!isObject(value)) {
|
|
56
|
+
return {
|
|
57
|
+
start: 0,
|
|
58
|
+
end: 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const start = toValidNumber(value.start, 0);
|
|
63
|
+
const end = toValidNumber(value.end, start);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
start,
|
|
67
|
+
end
|
|
68
|
+
};
|
|
69
|
+
}
|
|
4
70
|
|
|
5
71
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* This mixin provides comprehensive parameter management including:
|
|
9
|
-
* - Health Points (HP) and Skill Points (SP) management
|
|
10
|
-
* - Experience and level progression system
|
|
11
|
-
* - Custom parameter creation and modification
|
|
12
|
-
* - Parameter modifiers for temporary stat changes
|
|
72
|
+
* Interface for Parameter Manager functionality
|
|
13
73
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* @returns A new class that extends the base with parameter management capabilities
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* class MyPlayer extends WithParameterManager(BasePlayer) {
|
|
21
|
-
* constructor() {
|
|
22
|
-
* super();
|
|
23
|
-
* this.addParameter('strength', { start: 10, end: 100 });
|
|
24
|
-
* }
|
|
25
|
-
* }
|
|
26
|
-
* ```
|
|
74
|
+
* Provides comprehensive parameter management including health points (HP), skill points (SP),
|
|
75
|
+
* experience and level progression, custom parameters, and parameter modifiers.
|
|
27
76
|
*/
|
|
77
|
+
export interface IParameterManager {
|
|
78
|
+
/**
|
|
79
|
+
* ```ts
|
|
80
|
+
* player.initialLevel = 5
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @title Set initial level
|
|
84
|
+
* @prop {number} player.initialLevel
|
|
85
|
+
* @default 1
|
|
86
|
+
* @memberof ParameterManager
|
|
87
|
+
* */
|
|
88
|
+
initialLevel: number;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* ```ts
|
|
92
|
+
* player.finalLevel = 50
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @title Set final level
|
|
96
|
+
* @prop {number} player.finalLevel
|
|
97
|
+
* @default 99
|
|
98
|
+
* @memberof ParameterManager
|
|
99
|
+
* */
|
|
100
|
+
finalLevel: number;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* With Object-based syntax, you can use following options:
|
|
104
|
+
* - `basis: number`
|
|
105
|
+
* - `extra: number`
|
|
106
|
+
* - `accelerationA: number`
|
|
107
|
+
* - `accelerationB: number`
|
|
108
|
+
* @title Change Experience Curve
|
|
109
|
+
* @prop {object} player.expCurve
|
|
110
|
+
* @default
|
|
111
|
+
* ```ts
|
|
112
|
+
* {
|
|
113
|
+
* basis: 30,
|
|
114
|
+
* extra: 20,
|
|
115
|
+
* accelerationA: 30,
|
|
116
|
+
* accelerationB: 30
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
* @memberof ParameterManager
|
|
120
|
+
* */
|
|
121
|
+
expCurve: ExpCurve;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Changes the health points
|
|
125
|
+
* - Cannot exceed the MaxHP parameter
|
|
126
|
+
* - Cannot have a negative value
|
|
127
|
+
* - If the value is 0, a hook named `onDead()` is called in the RpgPlayer class.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* player.hp = 100
|
|
131
|
+
* ```
|
|
132
|
+
* @title Change HP
|
|
133
|
+
* @prop {number} player.hp
|
|
134
|
+
* @default MaxHPValue
|
|
135
|
+
* @memberof ParameterManager
|
|
136
|
+
* */
|
|
137
|
+
hp: number;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Changes the skill points
|
|
141
|
+
* - Cannot exceed the MaxSP parameter
|
|
142
|
+
* - Cannot have a negative value
|
|
143
|
+
*
|
|
144
|
+
* ```ts
|
|
145
|
+
* player.sp = 200
|
|
146
|
+
* ```
|
|
147
|
+
* @title Change SP
|
|
148
|
+
* @prop {number} player.sp
|
|
149
|
+
* @default MaxSPValue
|
|
150
|
+
* @memberof ParameterManager
|
|
151
|
+
* */
|
|
152
|
+
sp: number;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Changing the player's experience.
|
|
156
|
+
* ```ts
|
|
157
|
+
* player.exp += 100
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* Levels are based on the experience curve.
|
|
161
|
+
*
|
|
162
|
+
* ```ts
|
|
163
|
+
* console.log(player.level) // 1
|
|
164
|
+
* console.log(player.expForNextlevel) // 150
|
|
165
|
+
* player.exp += 160
|
|
166
|
+
* console.log(player.level) // 2
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @title Change Experience
|
|
170
|
+
* @prop {number} player.exp
|
|
171
|
+
* @default 0
|
|
172
|
+
* @memberof ParameterManager
|
|
173
|
+
* */
|
|
174
|
+
exp: number;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Changing the player's level.
|
|
178
|
+
*
|
|
179
|
+
* ```ts
|
|
180
|
+
* player.level += 1
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* The level will be between the initial level given by the `initialLevel` and final level given by `finalLevel`
|
|
184
|
+
*
|
|
185
|
+
* ```ts
|
|
186
|
+
* player.finalLevel = 50
|
|
187
|
+
* player.level = 60
|
|
188
|
+
* console.log(player.level) // 50
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* @title Change Level
|
|
192
|
+
* @prop {number} player.level
|
|
193
|
+
* @default 1
|
|
194
|
+
* @memberof ParameterManager
|
|
195
|
+
* */
|
|
196
|
+
level: number;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* ```ts
|
|
200
|
+
* console.log(player.expForNextlevel) // 150
|
|
201
|
+
* ```
|
|
202
|
+
* @title Experience for next level ?
|
|
203
|
+
* @prop {number} player.expForNextlevel
|
|
204
|
+
* @readonly
|
|
205
|
+
* @memberof ParameterManager
|
|
206
|
+
* */
|
|
207
|
+
readonly expForNextlevel: number;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Read the value of a parameter. Put the name of the parameter.
|
|
211
|
+
*
|
|
212
|
+
* ```ts
|
|
213
|
+
* import { Presets } from '@rpgjs/server'
|
|
214
|
+
*
|
|
215
|
+
* const { MAXHP } = Presets
|
|
216
|
+
*
|
|
217
|
+
* console.log(player.param[MAXHP])
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* > Possible to use the `player.getParamValue(name)` method instead
|
|
221
|
+
* @title Get Param Value
|
|
222
|
+
* @prop {object} player.param
|
|
223
|
+
* @readonly
|
|
224
|
+
* @memberof ParameterManager
|
|
225
|
+
* */
|
|
226
|
+
readonly param: { [key: string]: number };
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Direct parameter modifiers (reactive signal)
|
|
230
|
+
*
|
|
231
|
+
* > It is important that these parameters have been created beforehand with the `addParameter()` method.
|
|
232
|
+
* > By default, the following settings have been created:
|
|
233
|
+
* - maxhp
|
|
234
|
+
* - maxsp
|
|
235
|
+
* - str
|
|
236
|
+
* - int
|
|
237
|
+
* - dex
|
|
238
|
+
* - agi
|
|
239
|
+
*
|
|
240
|
+
* **Object Key**
|
|
241
|
+
*
|
|
242
|
+
* The key of the object is the name of the parameter
|
|
243
|
+
*
|
|
244
|
+
* > The good practice is to retrieve the name coming from a constant
|
|
245
|
+
*
|
|
246
|
+
* **Object Value**
|
|
247
|
+
*
|
|
248
|
+
* The value of the key is an object containing:
|
|
249
|
+
* ```
|
|
250
|
+
* {
|
|
251
|
+
* value: number,
|
|
252
|
+
* rate: number
|
|
253
|
+
* }
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* - value: Adds a number to the parameter
|
|
257
|
+
* - rate: Adds a rate to the parameter
|
|
258
|
+
*
|
|
259
|
+
* > Note that you can put both (value and rate)
|
|
260
|
+
*
|
|
261
|
+
* This property uses reactive signals - changes automatically trigger parameter recalculation.
|
|
262
|
+
* The final parameter values in `param` include aggregated modifiers from equipment, states, etc.
|
|
263
|
+
*
|
|
264
|
+
* @prop {Object} [paramsModifier]
|
|
265
|
+
* @example
|
|
266
|
+
*
|
|
267
|
+
* ```ts
|
|
268
|
+
* import { Presets } from '@rpgjs/server'
|
|
269
|
+
*
|
|
270
|
+
* const { MAXHP } = Presets
|
|
271
|
+
*
|
|
272
|
+
* // Set direct modifiers (reactive)
|
|
273
|
+
* player.paramsModifier = {
|
|
274
|
+
* [MAXHP]: {
|
|
275
|
+
* value: 100
|
|
276
|
+
* }
|
|
277
|
+
* }
|
|
278
|
+
*
|
|
279
|
+
* // Parameters automatically recalculate
|
|
280
|
+
* console.log(player.param[MAXHP]); // Updated value
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* @title Set Parameters Modifier
|
|
284
|
+
* @prop {object} paramsModifier
|
|
285
|
+
* @memberof ParameterManager
|
|
286
|
+
* */
|
|
287
|
+
paramsModifier: {
|
|
288
|
+
[key: string]: {
|
|
289
|
+
value?: number,
|
|
290
|
+
rate?: number
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get or set the parameters object
|
|
296
|
+
*
|
|
297
|
+
* @prop {object} parameters
|
|
298
|
+
* @memberof ParameterManager
|
|
299
|
+
*/
|
|
300
|
+
parameters: { [key: string]: { start: number, end: number } };
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Set a parameter with either a fixed value or a level curve
|
|
304
|
+
*
|
|
305
|
+
* A numeric value is stored as a fixed parameter where `start === end`.
|
|
306
|
+
*
|
|
307
|
+
* @param name - Parameter name
|
|
308
|
+
* @param value - Fixed value or parameter curve
|
|
309
|
+
*/
|
|
310
|
+
setParameter(name: string, value: ParameterValue): void;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get the value of a specific parameter by name
|
|
314
|
+
*
|
|
315
|
+
* @deprecated Use `player.param[name]` instead for better reactivity
|
|
316
|
+
* @param name - The name of the parameter to get
|
|
317
|
+
* @returns The calculated parameter value
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* import { Presets } from '@rpgjs/server'
|
|
322
|
+
*
|
|
323
|
+
* const { MAXHP } = Presets
|
|
324
|
+
*
|
|
325
|
+
* // Preferred way (reactive)
|
|
326
|
+
* const maxHp = player.param[MAXHP];
|
|
327
|
+
*
|
|
328
|
+
* // Legacy way (still works)
|
|
329
|
+
* const maxHp = player.getParamValue(MAXHP);
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
getParamValue(name: string): number;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Give a new parameter. Give a start value and an end value.
|
|
336
|
+
* The start value will be set to the level set at `player.initialLevel` and the end value will be linked to the level set at `player.finalLevel`.
|
|
337
|
+
*
|
|
338
|
+
* ```ts
|
|
339
|
+
* const SPEED = 'speed'
|
|
340
|
+
*
|
|
341
|
+
* player.addParameter(SPEED, {
|
|
342
|
+
* start: 10,
|
|
343
|
+
* end: 100
|
|
344
|
+
* })
|
|
345
|
+
*
|
|
346
|
+
* player.param[SPEED] // 10
|
|
347
|
+
* player.level += 5
|
|
348
|
+
* player.param[SPEED] // 14
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @title Add custom parameters
|
|
352
|
+
* @method player.addParameter(name,curve)
|
|
353
|
+
* @param {string} name - The name of the parameter
|
|
354
|
+
* @param {object} curve - Scheme of the object: { start: number, end: number }
|
|
355
|
+
* @returns {void}
|
|
356
|
+
* @memberof ParameterManager
|
|
357
|
+
* */
|
|
358
|
+
addParameter(name: string, curve: { start: number, end: number }): void;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Gives back in percentage of health points to skill points
|
|
362
|
+
*
|
|
363
|
+
* ```ts
|
|
364
|
+
* import { Presets } from '@rpgjs/server'
|
|
365
|
+
*
|
|
366
|
+
* const { MAXHP } = Presets
|
|
367
|
+
*
|
|
368
|
+
* console.log(player.param[MAXHP]) // 800
|
|
369
|
+
* player.hp = 100
|
|
370
|
+
* player.recovery({ hp: 0.5 }) // = 800 * 0.5
|
|
371
|
+
* console.log(player.hp) // 400
|
|
372
|
+
* ```
|
|
373
|
+
*
|
|
374
|
+
* @title Recovery HP and/or SP
|
|
375
|
+
* @method player.recovery(params)
|
|
376
|
+
* @param {object} params - Scheme of the object: { hp: number, sp: number }. The values of the numbers must be in 0 and 1
|
|
377
|
+
* @returns {void}
|
|
378
|
+
* @memberof ParameterManager
|
|
379
|
+
* */
|
|
380
|
+
recovery(params: { hp?: number, sp?: number }): void;
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* restores all HP and SP
|
|
384
|
+
*
|
|
385
|
+
* ```ts
|
|
386
|
+
* import { Presets } from '@rpgjs/server'
|
|
387
|
+
*
|
|
388
|
+
* const { MAXHP, MAXSP } = Presets
|
|
389
|
+
*
|
|
390
|
+
* console.log(player.param[MAXHP], player.param[MAXSP]) // 800, 230
|
|
391
|
+
* player.hp = 100
|
|
392
|
+
* player.sp = 0
|
|
393
|
+
* player.allRecovery()
|
|
394
|
+
* console.log(player.hp, player.sp) // 800, 230
|
|
395
|
+
* ```
|
|
396
|
+
*
|
|
397
|
+
* @title All Recovery
|
|
398
|
+
* @method player.allRecovery()
|
|
399
|
+
* @returns {void}
|
|
400
|
+
* @memberof ParameterManager
|
|
401
|
+
* */
|
|
402
|
+
allRecovery(): void;
|
|
403
|
+
}
|
|
404
|
+
|
|
28
405
|
/**
|
|
29
|
-
* Parameter Manager Mixin
|
|
406
|
+
* Parameter Manager Mixin with Reactive Signals
|
|
30
407
|
*
|
|
31
|
-
* Provides comprehensive parameter management functionality
|
|
32
|
-
* health points (HP), skill points (SP), experience and level progression,
|
|
33
|
-
* and parameter modifiers
|
|
408
|
+
* Provides comprehensive parameter management functionality using reactive signals from `@signe/reactive`.
|
|
409
|
+
* This mixin handles health points (HP), skill points (SP), experience and level progression,
|
|
410
|
+
* custom parameters, and parameter modifiers with automatic reactivity.
|
|
34
411
|
*
|
|
412
|
+
* **Key Features:**
|
|
413
|
+
* - ✨ **Reactive Parameters**: All parameters automatically recalculate when level or modifiers change
|
|
414
|
+
* - 🚀 **Performance Optimized**: Uses computed signals to avoid unnecessary recalculations
|
|
415
|
+
* - 🔄 **Real-time Updates**: Changes propagate automatically throughout the system
|
|
416
|
+
* - 🎯 **Type Safe**: Full TypeScript support with proper type inference
|
|
417
|
+
*
|
|
418
|
+
* @template TBase - The base class constructor type
|
|
35
419
|
* @param Base - The base class to extend with parameter management
|
|
36
|
-
* @returns Extended class with parameter management methods
|
|
420
|
+
* @returns Extended class with reactive parameter management methods
|
|
37
421
|
*
|
|
38
422
|
* @example
|
|
39
423
|
* ```ts
|
|
40
424
|
* class MyPlayer extends WithParameterManager(BasePlayer) {
|
|
41
425
|
* constructor() {
|
|
42
426
|
* super();
|
|
427
|
+
*
|
|
428
|
+
* // Add custom parameters
|
|
43
429
|
* this.addParameter('strength', { start: 10, end: 100 });
|
|
430
|
+
* this.addParameter('magic', { start: 5, end: 80 });
|
|
44
431
|
* }
|
|
45
432
|
* }
|
|
46
433
|
*
|
|
47
434
|
* const player = new MyPlayer();
|
|
48
|
-
*
|
|
435
|
+
*
|
|
436
|
+
* // Reactive parameter updates
|
|
49
437
|
* player.level = 5;
|
|
438
|
+
* console.log(player.param.strength); // Automatically calculated for level 5
|
|
439
|
+
*
|
|
440
|
+
* // Reactive modifiers
|
|
441
|
+
* player.paramsModifier = {
|
|
442
|
+
* [MAXHP]: { value: 100, rate: 1.2 }
|
|
443
|
+
* };
|
|
444
|
+
* console.log(player.param[MAXHP]); // Automatically includes modifiers
|
|
50
445
|
* ```
|
|
51
446
|
*/
|
|
52
447
|
export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
53
448
|
return class extends Base {
|
|
54
|
-
|
|
449
|
+
/**
|
|
450
|
+
* Signal for parameter modifiers - allows reactive updates when modifiers change
|
|
451
|
+
*
|
|
452
|
+
* This signal tracks temporary parameter modifications from equipment, states, etc.
|
|
453
|
+
* When updated, it automatically triggers recalculation of all computed parameters.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* // Set modifier that adds 100 to MaxHP
|
|
458
|
+
* player.paramsModifier = {
|
|
459
|
+
* [MAXHP]: { value: 100 }
|
|
460
|
+
* };
|
|
461
|
+
*
|
|
462
|
+
* // Parameters automatically recalculate
|
|
463
|
+
* console.log(player.param[MAXHP]); // Updated value
|
|
464
|
+
* ```
|
|
465
|
+
*/
|
|
466
|
+
private _paramsModifierSignal = type(signal<{
|
|
55
467
|
[key: string]: {
|
|
56
468
|
value?: number,
|
|
57
469
|
rate?: number
|
|
58
470
|
}
|
|
59
|
-
}
|
|
471
|
+
}>({}) as any, '_paramsModifierSignal', { persist: true }, this as any)
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Signal for base parameters configuration
|
|
475
|
+
*
|
|
476
|
+
* Stores the start and end values for each parameter's level curve.
|
|
477
|
+
* Changes to this signal trigger recalculation of all parameter values.
|
|
478
|
+
*/
|
|
479
|
+
private _parametersSignal = type(signal<{
|
|
480
|
+
[key: string]: {
|
|
481
|
+
start: number,
|
|
482
|
+
end: number
|
|
483
|
+
}
|
|
484
|
+
}>({}) as any, '_parametersSignal', { persist: true }, this as any)
|
|
485
|
+
|
|
486
|
+
private _paramProxy: { [key: string]: number } | null = null
|
|
60
487
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
488
|
+
/**
|
|
489
|
+
* Computed signal for all parameter values
|
|
490
|
+
*
|
|
491
|
+
* Automatically recalculates all parameter values when level or modifiers change.
|
|
492
|
+
* This provides reactive parameter updates throughout the system.
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* ```ts
|
|
496
|
+
* // Access reactive parameters
|
|
497
|
+
* const maxHp = player.param[MAXHP]; // Always current value
|
|
498
|
+
*
|
|
499
|
+
* // Parameters update automatically when level changes
|
|
500
|
+
* player.level = 10;
|
|
501
|
+
* console.log(player.param[MAXHP]); // New calculated value
|
|
502
|
+
* ```
|
|
503
|
+
*/
|
|
504
|
+
_param = type(computed(() => {
|
|
505
|
+
const obj = {}
|
|
506
|
+
const parameters = this._parametersSignal()
|
|
507
|
+
const allModifiers = this._getAggregatedModifiers()
|
|
508
|
+
const level = this._level()
|
|
509
|
+
|
|
510
|
+
for (const [name, paramConfig] of Object.entries(parameters)) {
|
|
511
|
+
let curveVal = Math.floor((paramConfig.end - paramConfig.start) * ((level - 1) / (this.finalLevel - this.initialLevel))) + paramConfig.start
|
|
512
|
+
|
|
513
|
+
const modifier = allModifiers[name]
|
|
514
|
+
if (modifier) {
|
|
515
|
+
if (modifier.rate) curveVal *= modifier.rate
|
|
516
|
+
if (modifier.value) curveVal += modifier.value
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
obj[name] = curveVal
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return obj
|
|
523
|
+
}) as any, '_param', {}, this as any)
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Aggregates parameter modifiers from all sources (direct modifiers, states, equipment)
|
|
527
|
+
*
|
|
528
|
+
* This method combines modifiers from multiple sources and calculates the final
|
|
529
|
+
* modifier values for each parameter. It handles both value and rate modifiers.
|
|
530
|
+
*
|
|
531
|
+
* @returns Aggregated parameter modifiers
|
|
532
|
+
*
|
|
533
|
+
* @example
|
|
534
|
+
* ```ts
|
|
535
|
+
* // Internal usage - gets modifiers from all sources
|
|
536
|
+
* const modifiers = this._getAggregatedModifiers();
|
|
537
|
+
* console.log(modifiers[MAXHP]); // { value: 100, rate: 1.2 }
|
|
538
|
+
* ```
|
|
539
|
+
*/
|
|
540
|
+
private _getAggregatedModifiers(): { [key: string]: { value?: number, rate?: number } } {
|
|
541
|
+
const params = {}
|
|
542
|
+
const paramsAvg = {}
|
|
543
|
+
|
|
544
|
+
const changeParam = (paramsModifier) => {
|
|
545
|
+
for (let key in paramsModifier) {
|
|
546
|
+
const { rate, value } = paramsModifier[key]
|
|
547
|
+
if (!params[key]) params[key] = { rate: 0, value: 0 }
|
|
548
|
+
if (!paramsAvg[key]) paramsAvg[key] = 0
|
|
549
|
+
if (value) params[key].value += value
|
|
550
|
+
if (rate !== undefined) params[key].rate += rate
|
|
551
|
+
paramsAvg[key]++
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const getModifier = (prop) => {
|
|
556
|
+
if (!isString(prop)) {
|
|
557
|
+
changeParam(prop)
|
|
558
|
+
return
|
|
559
|
+
}
|
|
560
|
+
for (let el of this[prop]()) {
|
|
561
|
+
if (!el.paramsModifier) continue
|
|
562
|
+
changeParam(el.paramsModifier)
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Aggregate modifiers from all sources
|
|
567
|
+
getModifier(this._paramsModifierSignal())
|
|
568
|
+
getModifier('states')
|
|
569
|
+
getModifier('equipments')
|
|
570
|
+
|
|
571
|
+
// Average the rates
|
|
572
|
+
for (let key in params) {
|
|
573
|
+
params[key].rate /= paramsAvg[key]
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return params
|
|
577
|
+
}
|
|
65
578
|
|
|
66
579
|
/**
|
|
67
580
|
* ```ts
|
|
@@ -106,11 +619,22 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
106
619
|
* ```
|
|
107
620
|
* @memberof ParameterManager
|
|
108
621
|
* */
|
|
109
|
-
public
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
622
|
+
public _expCurveSignal = type(signal<string>(JSON.stringify(DEFAULT_EXP_CURVE)) as any, '_expCurveSignal', { persist: true }, this as any)
|
|
623
|
+
|
|
624
|
+
get expCurve(): ExpCurve {
|
|
625
|
+
const raw = this._expCurveSignal()
|
|
626
|
+
if (!raw) return DEFAULT_EXP_CURVE
|
|
627
|
+
|
|
628
|
+
try {
|
|
629
|
+
return normalizeExpCurve(JSON.parse(raw))
|
|
630
|
+
}
|
|
631
|
+
catch {
|
|
632
|
+
return DEFAULT_EXP_CURVE
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
set expCurve(val: ExpCurve) {
|
|
637
|
+
this._expCurveSignal.set(JSON.stringify(val))
|
|
114
638
|
}
|
|
115
639
|
|
|
116
640
|
/**
|
|
@@ -135,11 +659,11 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
135
659
|
this['execMethod']('onDead')
|
|
136
660
|
val = 0
|
|
137
661
|
}
|
|
138
|
-
|
|
662
|
+
this.hpSignal.set(val)
|
|
139
663
|
}
|
|
140
664
|
|
|
141
665
|
get hp(): number {
|
|
142
|
-
return
|
|
666
|
+
return this.hpSignal()
|
|
143
667
|
}
|
|
144
668
|
|
|
145
669
|
/**
|
|
@@ -159,12 +683,12 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
159
683
|
if (val > this.param[MAXSP]) {
|
|
160
684
|
val = this.param[MAXSP]
|
|
161
685
|
}
|
|
162
|
-
this.
|
|
686
|
+
this.spSignal.set(val)
|
|
163
687
|
}
|
|
164
688
|
|
|
165
689
|
get sp(): number {
|
|
166
|
-
return this.
|
|
167
|
-
}
|
|
690
|
+
return this.spSignal()
|
|
691
|
+
}
|
|
168
692
|
|
|
169
693
|
/**
|
|
170
694
|
* Changing the player's experience.
|
|
@@ -244,7 +768,6 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
244
768
|
get level(): number {
|
|
245
769
|
return this._level()
|
|
246
770
|
}
|
|
247
|
-
|
|
248
771
|
/**
|
|
249
772
|
* ```ts
|
|
250
773
|
* console.log(player.expForNextlevel) // 150
|
|
@@ -276,43 +799,50 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
276
799
|
* @memberof ParameterManager
|
|
277
800
|
* */
|
|
278
801
|
get param() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
802
|
+
if (!this._paramProxy) {
|
|
803
|
+
this._paramProxy = new Proxy({}, {
|
|
804
|
+
get: (_target, property) => {
|
|
805
|
+
if (typeof property !== 'string') {
|
|
806
|
+
return undefined
|
|
807
|
+
}
|
|
808
|
+
return this._param()[property]
|
|
809
|
+
},
|
|
810
|
+
set: (_target, property, value) => {
|
|
811
|
+
if (typeof property !== 'string') {
|
|
812
|
+
return false
|
|
813
|
+
}
|
|
814
|
+
this.setParameter(property, value as ParameterValue)
|
|
815
|
+
return true
|
|
816
|
+
},
|
|
817
|
+
has: (_target, property) => {
|
|
818
|
+
if (typeof property !== 'string') {
|
|
819
|
+
return false
|
|
820
|
+
}
|
|
821
|
+
return property in this._param()
|
|
822
|
+
},
|
|
823
|
+
ownKeys: () => Reflect.ownKeys(this._param()),
|
|
824
|
+
getOwnPropertyDescriptor: (_target, property) => {
|
|
825
|
+
if (typeof property !== 'string') {
|
|
826
|
+
return undefined
|
|
827
|
+
}
|
|
828
|
+
const parameters = this._param()
|
|
829
|
+
if (!(property in parameters)) {
|
|
830
|
+
return undefined
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
configurable: true,
|
|
834
|
+
enumerable: true,
|
|
835
|
+
writable: true,
|
|
836
|
+
value: parameters[property]
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}) as { [key: string]: number }
|
|
840
|
+
}
|
|
841
|
+
return this._paramProxy
|
|
284
842
|
}
|
|
285
843
|
|
|
286
844
|
get paramsModifier() {
|
|
287
|
-
|
|
288
|
-
const paramsAvg = {}
|
|
289
|
-
const changeParam = (paramsModifier) => {
|
|
290
|
-
for (let key in paramsModifier) {
|
|
291
|
-
const { rate, value } = paramsModifier[key]
|
|
292
|
-
if (!params[key]) params[key] = { rate: 0, value: 0 }
|
|
293
|
-
if (!paramsAvg[key]) paramsAvg[key] = 0
|
|
294
|
-
if (value) params[key].value += value
|
|
295
|
-
if (rate !== undefined) params[key].rate += rate
|
|
296
|
-
paramsAvg[key]++
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const getModifier = (prop) => {
|
|
300
|
-
if (!isString(prop)) {
|
|
301
|
-
changeParam(prop)
|
|
302
|
-
return
|
|
303
|
-
}
|
|
304
|
-
for (let el of this[prop]()) {
|
|
305
|
-
if (!el.paramsModifier) continue
|
|
306
|
-
changeParam(el.paramsModifier)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
getModifier(this._paramsModifier)
|
|
310
|
-
getModifier('states')
|
|
311
|
-
getModifier('equipments')
|
|
312
|
-
for (let key in params) {
|
|
313
|
-
params[key].rate /= paramsAvg[key]
|
|
314
|
-
}
|
|
315
|
-
return params
|
|
845
|
+
return this._paramsModifierSignal()
|
|
316
846
|
}
|
|
317
847
|
|
|
318
848
|
/**
|
|
@@ -378,15 +908,25 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
378
908
|
rate?: number
|
|
379
909
|
}
|
|
380
910
|
}) {
|
|
381
|
-
this.
|
|
911
|
+
this._paramsModifierSignal.set(val)
|
|
382
912
|
}
|
|
383
913
|
|
|
384
914
|
get parameters() {
|
|
385
|
-
return this.
|
|
915
|
+
return this._parametersSignal()
|
|
386
916
|
}
|
|
387
917
|
|
|
388
918
|
set parameters(val) {
|
|
389
|
-
|
|
919
|
+
const normalizedParameters = {}
|
|
920
|
+
for (const [name, parameterValue] of Object.entries(val || {})) {
|
|
921
|
+
normalizedParameters[name] = normalizeParameterCurve(parameterValue)
|
|
922
|
+
}
|
|
923
|
+
this._parametersSignal.set(normalizedParameters)
|
|
924
|
+
if (MAXHP in normalizedParameters && this.hp > this.param[MAXHP]) {
|
|
925
|
+
this.hp = this.param[MAXHP]
|
|
926
|
+
}
|
|
927
|
+
if (MAXSP in normalizedParameters && this.sp > this.param[MAXSP]) {
|
|
928
|
+
this.sp = this.param[MAXSP]
|
|
929
|
+
}
|
|
390
930
|
}
|
|
391
931
|
|
|
392
932
|
private _expForLevel(level: number): number {
|
|
@@ -399,23 +939,8 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
399
939
|
return Math.round(basis * (Math.pow(level - 1, 0.9 + accelerationA / 250)) * level * (level + 1) / (6 + Math.pow(level, 2) / 50 / accelerationB) + (level - 1) * extra)
|
|
400
940
|
}
|
|
401
941
|
|
|
402
|
-
private getParam(name: string) {
|
|
403
|
-
const features = this._parameters.get(name)
|
|
404
|
-
if (!features) {
|
|
405
|
-
throw `Parameter ${name} not exists. Please use addParameter() before`
|
|
406
|
-
}
|
|
407
|
-
return features
|
|
408
|
-
}
|
|
409
|
-
|
|
410
942
|
getParamValue(name: string): number | never {
|
|
411
|
-
|
|
412
|
-
let curveVal = Math.floor((features.end - features.start) * ((this.level-1) / (this.finalLevel - this.initialLevel))) + features.start
|
|
413
|
-
const modifier = this.paramsModifier[name]
|
|
414
|
-
if (modifier) {
|
|
415
|
-
if (modifier.rate) curveVal *= modifier.rate
|
|
416
|
-
if (modifier.value) curveVal += modifier.value
|
|
417
|
-
}
|
|
418
|
-
return curveVal
|
|
943
|
+
return this.param[name]
|
|
419
944
|
}
|
|
420
945
|
|
|
421
946
|
/**
|
|
@@ -437,15 +962,18 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
437
962
|
*
|
|
438
963
|
* @title Add custom parameters
|
|
439
964
|
* @method player.addParameter(name,curve)
|
|
440
|
-
* @param {
|
|
441
|
-
* @param {object} curve Scheme of the object: { start: number, end: number }
|
|
965
|
+
* @param {string} name - The name of the parameter
|
|
966
|
+
* @param {object} curve - Scheme of the object: { start: number, end: number }
|
|
442
967
|
* @returns {void}
|
|
443
968
|
* @memberof ParameterManager
|
|
444
969
|
* */
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
970
|
+
setParameter(name: string, value: ParameterValue): void {
|
|
971
|
+
const normalizedValue = normalizeParameterCurve(value)
|
|
972
|
+
this._parametersSignal.mutate(parameters => {
|
|
973
|
+
parameters[name] = {
|
|
974
|
+
start: normalizedValue.start,
|
|
975
|
+
end: normalizedValue.end
|
|
976
|
+
}
|
|
449
977
|
})
|
|
450
978
|
const maxHp = this.param[MAXHP]
|
|
451
979
|
const maxSp = this.param[MAXSP]
|
|
@@ -457,6 +985,10 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
457
985
|
}
|
|
458
986
|
}
|
|
459
987
|
|
|
988
|
+
addParameter(name: string, { start, end }: { start: number, end: number }): void {
|
|
989
|
+
this.setParameter(name, { start, end })
|
|
990
|
+
}
|
|
991
|
+
|
|
460
992
|
/**
|
|
461
993
|
* Gives back in percentage of health points to skill points
|
|
462
994
|
*
|
|
@@ -473,7 +1005,7 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
473
1005
|
*
|
|
474
1006
|
* @title Recovery HP and/or SP
|
|
475
1007
|
* @method player.recovery(params)
|
|
476
|
-
* @param {object} params Scheme of the object: { hp: number, sp: number }. The values of the numbers must be in 0 and 1
|
|
1008
|
+
* @param {object} params - Scheme of the object: { hp: number, sp: number }. The values of the numbers must be in 0 and 1
|
|
477
1009
|
* @returns {void}
|
|
478
1010
|
* @memberof ParameterManager
|
|
479
1011
|
* */
|
|
@@ -507,5 +1039,3 @@ export function WithParameterManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
|
507
1039
|
}
|
|
508
1040
|
} as unknown as TBase;
|
|
509
1041
|
}
|
|
510
|
-
|
|
511
|
-
export type IParameterManager = InstanceType<ReturnType<typeof WithParameterManager>>;
|