@rpgjs/server 5.0.0-alpha.0 → 5.0.0-alpha.10

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.
Files changed (40) hide show
  1. package/dist/Player/BattleManager.d.ts +32 -22
  2. package/dist/Player/ClassManager.d.ts +31 -18
  3. package/dist/Player/ComponentManager.d.ts +60 -0
  4. package/dist/Player/EffectManager.d.ts +40 -0
  5. package/dist/Player/ElementManager.d.ts +31 -0
  6. package/dist/Player/GoldManager.d.ts +22 -0
  7. package/dist/Player/GuiManager.d.ts +176 -0
  8. package/dist/Player/ItemFixture.d.ts +6 -0
  9. package/dist/Player/ItemManager.d.ts +27 -13
  10. package/dist/Player/MoveManager.d.ts +31 -43
  11. package/dist/Player/ParameterManager.d.ts +27 -19
  12. package/dist/Player/Player.d.ts +123 -8
  13. package/dist/Player/SkillManager.d.ts +27 -19
  14. package/dist/Player/StateManager.d.ts +28 -35
  15. package/dist/Player/VariableManager.d.ts +30 -0
  16. package/dist/RpgServer.d.ts +224 -1
  17. package/dist/index.js +1097 -636
  18. package/dist/index.js.map +1 -1
  19. package/dist/rooms/map.d.ts +70 -1
  20. package/package.json +8 -8
  21. package/src/Player/BattleManager.ts +97 -38
  22. package/src/Player/ClassManager.ts +95 -35
  23. package/src/Player/ComponentManager.ts +64 -20
  24. package/src/Player/EffectManager.ts +110 -27
  25. package/src/Player/ElementManager.ts +126 -25
  26. package/src/Player/GoldManager.ts +32 -35
  27. package/src/Player/GuiManager.ts +187 -140
  28. package/src/Player/ItemFixture.ts +4 -5
  29. package/src/Player/ItemManager.ts +39 -26
  30. package/src/Player/MoveManager.ts +40 -31
  31. package/src/Player/ParameterManager.ts +35 -25
  32. package/src/Player/Player.ts +184 -39
  33. package/src/Player/SkillManager.ts +44 -23
  34. package/src/Player/StateManager.ts +210 -95
  35. package/src/Player/VariableManager.ts +180 -48
  36. package/src/RpgServer.ts +232 -1
  37. package/src/core/context.ts +1 -0
  38. package/src/rooms/map.ts +76 -8
  39. package/dist/Player/Event.d.ts +0 -0
  40. package/src/Player/Event.ts +0 -0
@@ -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
- * Move Manager mixin
35
- *
36
- * Adds methods to manage player movement
37
- *
38
- * @param Base - The base class to extend
39
- * @returns A new class with move management capabilities
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
- TBase extends Constructor<RpgCommonPlayer & StateManagerDependencies>
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
- * @title Get States Defense
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
- * @title Set/Get States Efficiency
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 & IStateManager,
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.getState(Paralyze)
151
- * ```
152
- *
153
- * @title Get State
154
- * @method player.getState(stateClass)
155
- * @param {StateClass | string} stateClass or state id
156
- * @returns {instance of StateClass | null}
157
- * @memberof StateManager
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
- * player.addState(Paralyze)
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
- * catch (err) {
178
- * console.log(err)
179
- * }
180
- * ```
181
- *
182
- * @title Add State
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
- * player.removeState(Paralyze)
223
- * }
224
- * catch (err) {
225
- * console.log(err)
226
- * }
227
- * ```
228
- *
229
- * @title Remove State
230
- * @method player.removeState(stateClass,chance=1)
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
- * @throws {StateLog} notApplied
242
- * If the status does not exist
243
- * ```
244
- * {
245
- * id: STATE_NOT_APPLIED,
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
- private findStateEfficiency(stateClass) {
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 { type Constructor } from "@rpgjs/common";
2
- import { RpgCommonPlayer } from "@rpgjs/common";
1
+ import { Constructor, PlayerCtor } from "@rpgjs/common";
3
2
 
4
3
  /**
5
- * Interface defining what MoveManager adds to a class
6
- */
7
- export interface IWithVariableManager {
8
- variables: Map<string, any>
9
- }
10
-
11
- /**
12
- * Move Manager mixin
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
- * Adds methods to manage player movement
13
+ * @example
14
+ * ```ts
15
+ * class MyPlayer extends WithVariableManager(BasePlayer) {
16
+ * constructor() {
17
+ * super();
18
+ * // Variables are automatically initialized
19
+ * }
20
+ * }
15
21
  *
16
- * @param Base - The base class to extend
17
- * @returns A new class with move management capabilities
22
+ * const player = new MyPlayer();
23
+ * player.setVariable('questCompleted', true);
24
+ * ```
18
25
  */
19
- export function WithVariableManager<TBase extends Constructor<RpgCommonPlayer>>(Base: TBase) {
20
- return class extends Base implements IWithVariableManager {
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
- * player.setVariable('OPEN_CHEST', true)
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
- * @title Set variable
31
- * @method player.setVariable(key,val)
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
- * const val = player.getVariable('OPEN_CHEST')
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
- * @title Get variable
49
- * @method player.setVariable(key,val)
50
- * @param {string} key
51
- * @returns {any}
52
- * @memberof VariableManager
53
- * */
54
- getVariable(key: string) {
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
- * player.removeVariable('OPEN_CHEST')
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
- * @title Remove variable
66
- * @method player.removeVariable(key)
67
- * @param {string} key
68
- * @returns {boolean} true if a variable existed and has been removed, or false if the variable does not exist.
69
- * @memberof VariableManager
70
- * */
71
- removeVariable(key: string) {
72
- return this.variables.delete(key)
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>>;