@rpgjs/server 5.0.0-alpha.5 → 5.0.0-alpha.7
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 +32 -22
- package/dist/Player/ClassManager.d.ts +31 -18
- package/dist/Player/ComponentManager.d.ts +30 -0
- package/dist/Player/EffectManager.d.ts +40 -0
- package/dist/Player/ElementManager.d.ts +31 -0
- package/dist/Player/GoldManager.d.ts +22 -0
- package/dist/Player/GuiManager.d.ts +31 -0
- package/dist/Player/ItemFixture.d.ts +6 -0
- package/dist/Player/ItemManager.d.ts +27 -13
- package/dist/Player/MoveManager.d.ts +31 -43
- package/dist/Player/ParameterManager.d.ts +27 -19
- package/dist/Player/Player.d.ts +43 -6
- package/dist/Player/SkillManager.d.ts +27 -19
- package/dist/Player/StateManager.d.ts +28 -35
- package/dist/Player/VariableManager.d.ts +30 -0
- package/dist/index.js +984 -536
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/Player/BattleManager.ts +97 -38
- package/src/Player/ClassManager.ts +95 -35
- package/src/Player/ComponentManager.ts +63 -21
- package/src/Player/EffectManager.ts +110 -27
- package/src/Player/ElementManager.ts +126 -25
- package/src/Player/GoldManager.ts +32 -35
- package/src/Player/GuiManager.ts +36 -13
- package/src/Player/ItemFixture.ts +4 -5
- package/src/Player/ItemManager.ts +39 -26
- package/src/Player/MoveManager.ts +40 -31
- package/src/Player/ParameterManager.ts +35 -25
- package/src/Player/Player.ts +75 -35
- package/src/Player/SkillManager.ts +44 -23
- package/src/Player/StateManager.ts +210 -95
- package/src/Player/VariableManager.ts +180 -48
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isInstanceOf, isString, type Constructor } from "@rpgjs/common";
|
|
1
|
+
import { isInstanceOf, isString, PlayerCtor, type Constructor } from "@rpgjs/common";
|
|
2
2
|
import { RpgCommonPlayer, Matter, SeekAvoid } from "@rpgjs/common";
|
|
3
3
|
import { signal, type WritableArraySignal } from "@signe/reactive";
|
|
4
4
|
import { ATK, PDEF, SDEF } from "../presets";
|
|
@@ -13,41 +13,51 @@ interface StateManagerDependencies {
|
|
|
13
13
|
removeState(stateClass: StateClass | string, chance?: number): void;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
* Interface defining what MoveManager adds to a class
|
|
18
|
-
*/
|
|
19
|
-
export interface IStateManager {
|
|
20
|
-
statesDefense: { rate: number; state: any }[];
|
|
21
|
-
statesEfficiency: WritableArraySignal<any[]>;
|
|
22
|
-
applyStates(
|
|
23
|
-
player: RpgPlayer,
|
|
24
|
-
states: { addStates?: any[]; removeStates?: any[] }
|
|
25
|
-
): void;
|
|
26
|
-
getState(stateClass: StateClass | string): any;
|
|
27
|
-
addState(stateClass: StateClass | string, chance?: number): object | null;
|
|
28
|
-
removeState(stateClass: StateClass | string, chance?: number): void;
|
|
29
|
-
}
|
|
16
|
+
|
|
30
17
|
|
|
31
18
|
type StateClass = { new (...args: any[]) };
|
|
32
19
|
|
|
33
20
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
21
|
+
* State Manager Mixin
|
|
22
|
+
*
|
|
23
|
+
* Provides state management capabilities to any class. This mixin handles
|
|
24
|
+
* player states (buffs/debuffs), state defense from equipment, and state
|
|
25
|
+
* efficiency modifiers. It manages the complete state system including
|
|
26
|
+
* application, removal, and resistance mechanics.
|
|
27
|
+
*
|
|
28
|
+
* @param Base - The base class to extend with state management
|
|
29
|
+
* @returns Extended class with state management methods
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* class MyPlayer extends WithStateManager(BasePlayer) {
|
|
34
|
+
* constructor() {
|
|
35
|
+
* super();
|
|
36
|
+
* // State system is automatically initialized
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* const player = new MyPlayer();
|
|
41
|
+
* player.addState(Paralyze);
|
|
42
|
+
* console.log(player.getState(Paralyze));
|
|
43
|
+
* ```
|
|
40
44
|
*/
|
|
41
|
-
export function WithStateManager<
|
|
42
|
-
|
|
43
|
-
>(Base: TBase): Constructor<IStateManager> & TBase {
|
|
44
|
-
return class extends Base implements IStateManager {
|
|
45
|
+
export function WithStateManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
46
|
+
return class extends Base {
|
|
45
47
|
_statesEfficiency = signal<any[]>([]);
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Recovers the player's states defense on inventory. This list is generated from the `statesDefense` property defined on the weapons or armors equipped.
|
|
49
51
|
* If several items have the same element, only the highest rate will be taken into account.
|
|
50
52
|
*
|
|
53
|
+
* Gets the defensive capabilities against various states from equipped items.
|
|
54
|
+
* The system automatically consolidates multiple defensive items, keeping only
|
|
55
|
+
* the highest protection rate for each state type. This provides comprehensive
|
|
56
|
+
* protection against debuffs and negative status effects.
|
|
57
|
+
*
|
|
58
|
+
* @returns Array of state defense objects with rate and state properties
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
51
61
|
* ```ts
|
|
52
62
|
* import { Armor, State } from '@rpgjs/server'
|
|
53
63
|
*
|
|
@@ -74,19 +84,29 @@ export function WithStateManager<
|
|
|
74
84
|
* player.equip(FireShield)
|
|
75
85
|
*
|
|
76
86
|
* console.log(player.statesDefense) // [{ rate: 1, state: instance of Paralyze }]
|
|
87
|
+
*
|
|
88
|
+
* // Check specific state defense
|
|
89
|
+
* const paralyzeDefense = player.statesDefense.find(def => def.state instanceof Paralyze);
|
|
90
|
+
* if (paralyzeDefense) {
|
|
91
|
+
* console.log(`Paralyze defense rate: ${paralyzeDefense.rate}`);
|
|
92
|
+
* }
|
|
77
93
|
* ```
|
|
78
|
-
|
|
79
|
-
* @prop {Array<{ rate: number, state: StateClass}>} player.statesDefense
|
|
80
|
-
* @readonly
|
|
81
|
-
* @memberof StateManager
|
|
82
|
-
* */
|
|
94
|
+
*/
|
|
83
95
|
get statesDefense(): { rate: number; state: any }[] {
|
|
84
|
-
return this.getFeature("statesDefense", "state");
|
|
96
|
+
return (this as any).getFeature("statesDefense", "state");
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
/**
|
|
88
100
|
* Set or retrieves all the states where the player is vulnerable or not.
|
|
89
101
|
*
|
|
102
|
+
* Manages the player's state efficiency modifiers, which determine how
|
|
103
|
+
* effective different states are against this player. Values greater than 1
|
|
104
|
+
* indicate vulnerability, while values less than 1 indicate resistance.
|
|
105
|
+
* This combines both class-based efficiency and player-specific modifiers.
|
|
106
|
+
*
|
|
107
|
+
* @returns Array of state efficiency objects with rate and state properties
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
90
110
|
* ```ts
|
|
91
111
|
* import { Class, State } from '@rpgjs/server'
|
|
92
112
|
*
|
|
@@ -113,11 +133,16 @@ export function WithStateManager<
|
|
|
113
133
|
* player.statesEfficiency = [{ rate: 2, state: Sleep }]
|
|
114
134
|
*
|
|
115
135
|
* console.log(player.statesEfficiency) // [{ rate: 1, state: instance of Paralyze }, { rate: 2, state: instance of Sleep }]
|
|
136
|
+
*
|
|
137
|
+
* // Check for vulnerabilities
|
|
138
|
+
* const vulnerabilities = player.statesEfficiency.filter(eff => eff.rate > 1);
|
|
139
|
+
* console.log('Vulnerable to states:', vulnerabilities.map(v => v.state.name));
|
|
140
|
+
*
|
|
141
|
+
* // Check for resistances
|
|
142
|
+
* const resistances = player.statesEfficiency.filter(eff => eff.rate < 1);
|
|
143
|
+
* console.log('Resistant to states:', resistances.map(r => r.state.name));
|
|
116
144
|
* ```
|
|
117
|
-
|
|
118
|
-
* @prop {Array<{ rate: number, state: StateClass}>} player.statesEfficiency
|
|
119
|
-
* @memberof StateManager
|
|
120
|
-
* */
|
|
145
|
+
*/
|
|
121
146
|
get statesEfficiency() {
|
|
122
147
|
return this._statesEfficiency;
|
|
123
148
|
}
|
|
@@ -126,38 +151,87 @@ export function WithStateManager<
|
|
|
126
151
|
this._statesEfficiency = val;
|
|
127
152
|
}
|
|
128
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Apply states to a player from skill or item effects
|
|
156
|
+
*
|
|
157
|
+
* Processes state application and removal based on skill or item effects.
|
|
158
|
+
* This method handles both adding beneficial states and removing negative ones,
|
|
159
|
+
* with proper chance calculation and resistance checks.
|
|
160
|
+
*
|
|
161
|
+
* @param player - The target player to apply states to
|
|
162
|
+
* @param states - Object containing arrays of states to add or remove
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* // Apply states from a healing skill
|
|
167
|
+
* const healingStates = {
|
|
168
|
+
* addStates: [{ state: Regeneration, rate: 0.8 }],
|
|
169
|
+
* removeStates: [{ state: Poison, rate: 1.0 }]
|
|
170
|
+
* };
|
|
171
|
+
* player.applyStates(targetPlayer, healingStates);
|
|
172
|
+
*
|
|
173
|
+
* // Apply debuff from an enemy attack
|
|
174
|
+
* const debuffStates = {
|
|
175
|
+
* addStates: [
|
|
176
|
+
* { state: Paralyze, rate: 0.3 },
|
|
177
|
+
* { state: Slow, rate: 0.5 }
|
|
178
|
+
* ]
|
|
179
|
+
* };
|
|
180
|
+
* player.applyStates(targetPlayer, debuffStates);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
129
183
|
applyStates(
|
|
130
|
-
player: RpgPlayer
|
|
184
|
+
player: RpgPlayer,
|
|
131
185
|
{ addStates, removeStates }
|
|
132
186
|
) {
|
|
133
187
|
if (addStates) {
|
|
134
188
|
for (let { state, rate } of addStates) {
|
|
135
|
-
player.addState(state, rate);
|
|
189
|
+
(player as any).addState(state, rate);
|
|
136
190
|
}
|
|
137
191
|
}
|
|
138
192
|
if (removeStates) {
|
|
139
193
|
for (let { state, rate } of removeStates) {
|
|
140
|
-
player.removeState(state, rate);
|
|
194
|
+
(player as any).removeState(state, rate);
|
|
141
195
|
}
|
|
142
196
|
}
|
|
143
197
|
}
|
|
144
198
|
|
|
145
199
|
/**
|
|
146
200
|
* Get a state to the player. Returns `null` if the state is not present on the player
|
|
201
|
+
*
|
|
202
|
+
* Retrieves a specific state instance from the player's active states.
|
|
203
|
+
* This is useful for checking state properties, duration, or performing
|
|
204
|
+
* state-specific operations. Returns null if the state is not currently active.
|
|
205
|
+
*
|
|
206
|
+
* @param stateClass - The state class constructor or state ID to search for
|
|
207
|
+
* @returns The state instance if found, null otherwise
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
147
210
|
* ```ts
|
|
148
211
|
* import Paralyze from 'your-database/states/paralyze'
|
|
149
212
|
*
|
|
150
|
-
* player
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
213
|
+
* // Check if player has a specific state
|
|
214
|
+
* const paralyzeState = player.getState(Paralyze);
|
|
215
|
+
* if (paralyzeState) {
|
|
216
|
+
* console.log('Player is paralyzed');
|
|
217
|
+
* console.log('Remaining duration:', paralyzeState.duration);
|
|
218
|
+
* }
|
|
219
|
+
*
|
|
220
|
+
* // Check using string ID
|
|
221
|
+
* const poisonState = player.getState('poison');
|
|
222
|
+
* if (poisonState) {
|
|
223
|
+
* console.log('Player is poisoned');
|
|
224
|
+
* }
|
|
225
|
+
*
|
|
226
|
+
* // Use in conditional logic
|
|
227
|
+
* if (player.getState(Sleep)) {
|
|
228
|
+
* console.log('Player cannot act while sleeping');
|
|
229
|
+
* return; // Skip player turn
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
158
232
|
*/
|
|
159
233
|
getState(stateClass: StateClass | string) {
|
|
160
|
-
if (isString(stateClass)) stateClass = this.databaseById(stateClass);
|
|
234
|
+
if (isString(stateClass)) stateClass = (this as any).databaseById(stateClass);
|
|
161
235
|
return this.states().find((state) => {
|
|
162
236
|
if (isString(stateClass)) {
|
|
163
237
|
return state.id == stateClass;
|
|
@@ -168,37 +242,56 @@ export function WithStateManager<
|
|
|
168
242
|
|
|
169
243
|
/**
|
|
170
244
|
* Adds a state to the player. Set the chance between 0 and 1 that the state can apply
|
|
245
|
+
*
|
|
246
|
+
* Attempts to apply a state to the player with a specified success chance.
|
|
247
|
+
* The method considers state resistance, efficiency modifiers, and random chance
|
|
248
|
+
* to determine if the state is successfully applied. If successful, the state
|
|
249
|
+
* is added to the player's active states list.
|
|
250
|
+
*
|
|
251
|
+
* @param stateClass - The state class constructor or state ID to apply
|
|
252
|
+
* @param chance - Probability of successful application (0-1, default 1)
|
|
253
|
+
* @returns The state instance if successfully applied, null if already present
|
|
254
|
+
* @throws StateLog.addFailed if the chance roll fails
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
171
257
|
* ```ts
|
|
172
258
|
* import Paralyze from 'your-database/states/paralyze'
|
|
173
259
|
*
|
|
174
260
|
* try {
|
|
175
|
-
*
|
|
261
|
+
* // Attempt to apply paralyze with 100% chance
|
|
262
|
+
* const state = player.addState(Paralyze);
|
|
263
|
+
* if (state) {
|
|
264
|
+
* console.log('Paralyze applied successfully');
|
|
265
|
+
* }
|
|
266
|
+
* } catch (err) {
|
|
267
|
+
* console.log('Failed to apply paralyze:', err.msg);
|
|
176
268
|
* }
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* @method player.addState(stateClass,chance=1)
|
|
184
|
-
* @param {StateClass | string} stateClass state class or state id
|
|
185
|
-
* @param {number} [chance] 1 by default
|
|
186
|
-
* @throws {StateLog} addFailed
|
|
187
|
-
* If the chance to add the state has failed (defined with the `chance` param)
|
|
188
|
-
* ```
|
|
189
|
-
* {
|
|
190
|
-
* id: ADD_STATE_FAILED,
|
|
191
|
-
* msg: '...'
|
|
269
|
+
*
|
|
270
|
+
* // Apply with reduced chance
|
|
271
|
+
* try {
|
|
272
|
+
* player.addState(Poison, 0.3); // 30% chance
|
|
273
|
+
* } catch (err) {
|
|
274
|
+
* console.log('Poison application failed');
|
|
192
275
|
* }
|
|
276
|
+
*
|
|
277
|
+
* // Apply multiple states with different chances
|
|
278
|
+
* const debuffs = [
|
|
279
|
+
* { state: Slow, chance: 0.8 },
|
|
280
|
+
* { state: Weak, chance: 0.6 }
|
|
281
|
+
* ];
|
|
282
|
+
* debuffs.forEach(({ state, chance }) => {
|
|
283
|
+
* try {
|
|
284
|
+
* player.addState(state, chance);
|
|
285
|
+
* } catch (err) {
|
|
286
|
+
* // Handle failed applications
|
|
287
|
+
* }
|
|
288
|
+
* });
|
|
193
289
|
* ```
|
|
194
|
-
* @returns {instance of StateClass}
|
|
195
|
-
* @memberof StateManager
|
|
196
|
-
* @todo
|
|
197
290
|
*/
|
|
198
291
|
addState(stateClass: StateClass | string, chance = 1): object | null {
|
|
199
292
|
const state = this.getState(stateClass);
|
|
200
293
|
if (isString(stateClass)) {
|
|
201
|
-
stateClass = this.databaseById(stateClass);
|
|
294
|
+
stateClass = (this as any).databaseById(stateClass);
|
|
202
295
|
}
|
|
203
296
|
if (!state) {
|
|
204
297
|
if (Math.random() > chance) {
|
|
@@ -215,39 +308,49 @@ export function WithStateManager<
|
|
|
215
308
|
|
|
216
309
|
/**
|
|
217
310
|
* Remove a state to the player. Set the chance between 0 and 1 that the state can be removed
|
|
311
|
+
*
|
|
312
|
+
* Attempts to remove a state from the player with a specified success chance.
|
|
313
|
+
* This is useful for cure spells, items, or time-based state removal.
|
|
314
|
+
* The method considers removal resistance and random chance.
|
|
315
|
+
*
|
|
316
|
+
* @param stateClass - The state class constructor or state ID to remove
|
|
317
|
+
* @param chance - Probability of successful removal (0-1, default 1)
|
|
318
|
+
* @throws StateLog.removeFailed if the chance roll fails
|
|
319
|
+
* @throws StateLog.notApplied if the state is not currently active
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
218
322
|
* ```ts
|
|
219
323
|
* import Paralyze from 'your-database/states/paralyze'
|
|
220
324
|
*
|
|
221
325
|
* try {
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* @param {StateClass|string} stateClass class state or state id
|
|
232
|
-
* @param {number} [chance] 1 by default
|
|
233
|
-
* @throws {StateLog} removeFailed
|
|
234
|
-
* If the chance to remove the state has failed (defined with the `chance` param)
|
|
235
|
-
* ```
|
|
236
|
-
* {
|
|
237
|
-
* id: REMOVE_STATE_FAILED,
|
|
238
|
-
* msg: '...'
|
|
326
|
+
* // Attempt to remove paralyze with 100% chance
|
|
327
|
+
* player.removeState(Paralyze);
|
|
328
|
+
* console.log('Paralyze removed successfully');
|
|
329
|
+
* } catch (err) {
|
|
330
|
+
* if (err.id === 'STATE_NOT_APPLIED') {
|
|
331
|
+
* console.log('Player was not paralyzed');
|
|
332
|
+
* } else {
|
|
333
|
+
* console.log('Failed to remove paralyze:', err.msg);
|
|
334
|
+
* }
|
|
239
335
|
* }
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* {
|
|
245
|
-
*
|
|
246
|
-
* msg: '...'
|
|
336
|
+
*
|
|
337
|
+
* // Remove with reduced chance (for weak cure spells)
|
|
338
|
+
* try {
|
|
339
|
+
* player.removeState(Poison, 0.7); // 70% chance
|
|
340
|
+
* } catch (err) {
|
|
341
|
+
* console.log('Cure failed');
|
|
247
342
|
* }
|
|
343
|
+
*
|
|
344
|
+
* // Remove all negative states (cure-all effect)
|
|
345
|
+
* const negativeStates = [Poison, Paralyze, Sleep, Slow];
|
|
346
|
+
* negativeStates.forEach(state => {
|
|
347
|
+
* try {
|
|
348
|
+
* player.removeState(state);
|
|
349
|
+
* } catch (err) {
|
|
350
|
+
* // State wasn't active, continue
|
|
351
|
+
* }
|
|
352
|
+
* });
|
|
248
353
|
* ```
|
|
249
|
-
* @returns {instance of StateClass}
|
|
250
|
-
* @memberof StateManager
|
|
251
354
|
*/
|
|
252
355
|
removeState(stateClass: StateClass | string, chance = 1) {
|
|
253
356
|
const index = this.states().findIndex((state) => {
|
|
@@ -266,10 +369,22 @@ export function WithStateManager<
|
|
|
266
369
|
}
|
|
267
370
|
}
|
|
268
371
|
|
|
269
|
-
|
|
372
|
+
/**
|
|
373
|
+
* Find state efficiency modifier for a specific state class
|
|
374
|
+
*
|
|
375
|
+
* @param stateClass - The state class to find efficiency for
|
|
376
|
+
* @returns The efficiency object if found, undefined otherwise
|
|
377
|
+
*/
|
|
378
|
+
findStateEfficiency(stateClass) {
|
|
270
379
|
return this.statesEfficiency().find((state) =>
|
|
271
380
|
isInstanceOf(state.state, stateClass)
|
|
272
381
|
);
|
|
273
382
|
}
|
|
274
|
-
};
|
|
383
|
+
} as unknown as TBase;
|
|
275
384
|
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Type helper to extract the interface from the WithStateManager mixin
|
|
388
|
+
* This provides the type without duplicating method signatures
|
|
389
|
+
*/
|
|
390
|
+
export type IStateManager = InstanceType<ReturnType<typeof WithStateManager>>;
|
|
@@ -1,75 +1,207 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RpgCommonPlayer } from "@rpgjs/common";
|
|
1
|
+
import { Constructor, PlayerCtor } from "@rpgjs/common";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
4
|
+
* Variable Manager Mixin
|
|
5
|
+
*
|
|
6
|
+
* Provides variable management capabilities to any class. Variables are key-value
|
|
7
|
+
* pairs that can store any type of data associated with the player, such as
|
|
8
|
+
* quest progress, game flags, inventory state, and custom game data.
|
|
9
|
+
*
|
|
10
|
+
* @param Base - The base class to extend with variable management
|
|
11
|
+
* @returns Extended class with variable management methods
|
|
13
12
|
*
|
|
14
|
-
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* class MyPlayer extends WithVariableManager(BasePlayer) {
|
|
16
|
+
* constructor() {
|
|
17
|
+
* super();
|
|
18
|
+
* // Variables are automatically initialized
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
15
21
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
22
|
+
* const player = new MyPlayer();
|
|
23
|
+
* player.setVariable('questCompleted', true);
|
|
24
|
+
* ```
|
|
18
25
|
*/
|
|
19
|
-
export function WithVariableManager<TBase extends
|
|
20
|
-
return class extends Base
|
|
21
|
-
variables: Map<string, any> = new Map()
|
|
26
|
+
export function WithVariableManager<TBase extends PlayerCtor>(Base: TBase) {
|
|
27
|
+
return class extends Base {
|
|
28
|
+
variables: Map<string, any> = new Map();
|
|
22
29
|
|
|
23
30
|
/**
|
|
24
31
|
* Assign a variable to the player
|
|
25
32
|
*
|
|
33
|
+
* Stores a key-value pair in the player's variable map. This is useful for
|
|
34
|
+
* tracking game state, quest progress, flags, and other player-specific data.
|
|
35
|
+
* The variable system provides a flexible way to store any type of data
|
|
36
|
+
* associated with the player that persists throughout the game session.
|
|
37
|
+
*
|
|
38
|
+
* @param key - The variable identifier (string key to reference the variable)
|
|
39
|
+
* @param val - The value to store (can be any type: boolean, number, string, object, array)
|
|
40
|
+
* @returns void
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
26
43
|
* ```ts
|
|
27
|
-
*
|
|
44
|
+
* // Set different types of variables
|
|
45
|
+
* player.setVariable('CHEST_OPENED', true);
|
|
46
|
+
* player.setVariable('playerLevel', 5);
|
|
47
|
+
* player.setVariable('questProgress', { step: 1, completed: false });
|
|
48
|
+
* player.setVariable('inventory', ['sword', 'potion', 'key']);
|
|
49
|
+
* player.setVariable('lastSaveTime', new Date().toISOString());
|
|
28
50
|
* ```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @param {string} key
|
|
33
|
-
* @param {any} val
|
|
34
|
-
* @returns {void}
|
|
35
|
-
* @memberof VariableManager
|
|
36
|
-
* */
|
|
37
|
-
setVariable(key: string, val) {
|
|
38
|
-
this.variables.set(key, val)
|
|
51
|
+
*/
|
|
52
|
+
setVariable(key: string, val: any): void {
|
|
53
|
+
this.variables.set(key, val);
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
/**
|
|
42
|
-
* Get a variable
|
|
57
|
+
* Get a variable value
|
|
58
|
+
*
|
|
59
|
+
* Retrieves the value associated with the given key from the player's variables.
|
|
60
|
+
* Returns undefined if the variable doesn't exist. This method is type-safe
|
|
61
|
+
* and can be used with generic types for better TypeScript support.
|
|
62
|
+
*
|
|
63
|
+
* @param key - The variable identifier to retrieve
|
|
64
|
+
* @returns The stored value or undefined if not found
|
|
43
65
|
*
|
|
66
|
+
* @example
|
|
44
67
|
* ```ts
|
|
45
|
-
*
|
|
46
|
-
*
|
|
68
|
+
* // Get variables with type inference
|
|
69
|
+
* const hasKey = player.getVariable('CHEST_OPENED'); // boolean | undefined
|
|
70
|
+
* const level = player.getVariable('playerLevel'); // number | undefined
|
|
71
|
+
* const quest = player.getVariable('questProgress'); // object | undefined
|
|
72
|
+
* const missing = player.getVariable('nonexistent'); // undefined
|
|
47
73
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return this.variables.get(key)
|
|
74
|
+
* // Use with default values
|
|
75
|
+
* const level = player.getVariable('playerLevel') ?? 1;
|
|
76
|
+
* const isChestOpened = player.getVariable('CHEST_OPENED') ?? false;
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
getVariable<U = any>(key: string): U | undefined {
|
|
80
|
+
return this.variables.get(key);
|
|
56
81
|
}
|
|
57
82
|
|
|
58
83
|
/**
|
|
59
84
|
* Remove a variable
|
|
60
85
|
*
|
|
86
|
+
* Deletes a variable from the player's variable map. This is useful for
|
|
87
|
+
* cleaning up temporary flags, resetting certain game states, or managing
|
|
88
|
+
* memory by removing unused variables. The method returns a boolean indicating
|
|
89
|
+
* whether the variable existed and was successfully removed.
|
|
90
|
+
*
|
|
91
|
+
* @param key - The variable identifier to remove
|
|
92
|
+
* @returns true if a variable existed and has been removed, false if the variable does not exist
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* // Remove variables and check if they existed
|
|
97
|
+
* const removed = player.removeVariable('CHEST_OPENED'); // true if existed
|
|
98
|
+
* const notFound = player.removeVariable('nonexistent'); // false
|
|
99
|
+
*
|
|
100
|
+
* // Clean up temporary variables
|
|
101
|
+
* player.removeVariable('tempQuestFlag');
|
|
102
|
+
* player.removeVariable('battleTempData');
|
|
103
|
+
*
|
|
104
|
+
* // Conditional removal
|
|
105
|
+
* if (player.getVariable('questCompleted')) {
|
|
106
|
+
* player.removeVariable('questProgress');
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
removeVariable(key: string): boolean {
|
|
111
|
+
return this.variables.delete(key);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if a variable exists
|
|
116
|
+
*
|
|
117
|
+
* Determines whether a variable with the given key exists in the player's
|
|
118
|
+
* variable map, regardless of its value (including falsy values like false, 0, '').
|
|
119
|
+
* This is useful when you need to distinguish between a variable that doesn't
|
|
120
|
+
* exist and one that has a falsy value.
|
|
121
|
+
*
|
|
122
|
+
* @param key - The variable identifier to check
|
|
123
|
+
* @returns true if the variable exists, false otherwise
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
61
126
|
* ```ts
|
|
62
|
-
*
|
|
127
|
+
* // Check variable existence
|
|
128
|
+
* player.setVariable('flag', false);
|
|
129
|
+
* player.hasVariable('flag'); // true (even though value is false)
|
|
130
|
+
* player.hasVariable('missing'); // false
|
|
131
|
+
*
|
|
132
|
+
* // Use in conditional logic
|
|
133
|
+
* if (player.hasVariable('questStarted')) {
|
|
134
|
+
* // Quest has been started, check progress
|
|
135
|
+
* const progress = player.getVariable('questProgress');
|
|
136
|
+
* } else {
|
|
137
|
+
* // Quest not started yet
|
|
138
|
+
* player.setVariable('questStarted', true);
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
hasVariable(key: string): boolean {
|
|
143
|
+
return this.variables.has(key);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get all variable keys
|
|
148
|
+
*
|
|
149
|
+
* Returns an array of all variable keys currently stored for this player.
|
|
150
|
+
* This is useful for debugging, serialization, or iterating over all variables.
|
|
151
|
+
* The keys are returned in insertion order.
|
|
152
|
+
*
|
|
153
|
+
* @returns Array of all variable keys
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* // Get all variable keys
|
|
158
|
+
* const keys = player.getVariableKeys();
|
|
159
|
+
* console.log('Player has variables:', keys);
|
|
160
|
+
*
|
|
161
|
+
* // Iterate over all variables
|
|
162
|
+
* keys.forEach(key => {
|
|
163
|
+
* const value = player.getVariable(key);
|
|
164
|
+
* console.log(`${key}: ${value}`);
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* // Filter specific variable types
|
|
168
|
+
* const questKeys = keys.filter(key => key.startsWith('quest_'));
|
|
63
169
|
* ```
|
|
170
|
+
*/
|
|
171
|
+
getVariableKeys(): string[] {
|
|
172
|
+
return Array.from(this.variables.keys());
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Clear all variables
|
|
64
177
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* @
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
178
|
+
* Removes all variables from the player's variable map. This is useful for
|
|
179
|
+
* resetting the player state, cleaning up before saving, or starting fresh.
|
|
180
|
+
* Use with caution as this operation cannot be undone.
|
|
181
|
+
*
|
|
182
|
+
* @returns void
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* // Clear all variables (use with caution)
|
|
187
|
+
* player.clearVariables();
|
|
188
|
+
*
|
|
189
|
+
* // Clear variables conditionally
|
|
190
|
+
* if (gameReset) {
|
|
191
|
+
* player.clearVariables();
|
|
192
|
+
* // Re-initialize essential variables
|
|
193
|
+
* player.setVariable('gameStarted', true);
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
clearVariables(): void {
|
|
198
|
+
this.variables.clear();
|
|
73
199
|
}
|
|
74
|
-
};
|
|
200
|
+
} as unknown as TBase;
|
|
75
201
|
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Type helper to extract the interface from the WithVariableManager mixin
|
|
205
|
+
* This provides the type without duplicating method signatures
|
|
206
|
+
*/
|
|
207
|
+
export type IVariableManager = InstanceType<ReturnType<typeof WithVariableManager>>;
|