@rpgjs/server 5.0.0-alpha.2 → 5.0.0-alpha.20

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 (53) hide show
  1. package/dist/Gui/DialogGui.d.ts +4 -0
  2. package/dist/Gui/index.d.ts +1 -0
  3. package/dist/Player/BattleManager.d.ts +32 -22
  4. package/dist/Player/ClassManager.d.ts +31 -18
  5. package/dist/Player/ComponentManager.d.ts +123 -0
  6. package/dist/Player/Components.d.ts +345 -0
  7. package/dist/Player/EffectManager.d.ts +40 -0
  8. package/dist/Player/ElementManager.d.ts +31 -0
  9. package/dist/Player/GoldManager.d.ts +22 -0
  10. package/dist/Player/GuiManager.d.ts +176 -0
  11. package/dist/Player/ItemFixture.d.ts +6 -0
  12. package/dist/Player/ItemManager.d.ts +164 -10
  13. package/dist/Player/MoveManager.d.ts +32 -44
  14. package/dist/Player/ParameterManager.d.ts +343 -14
  15. package/dist/Player/Player.d.ts +266 -8
  16. package/dist/Player/SkillManager.d.ts +27 -19
  17. package/dist/Player/StateManager.d.ts +28 -35
  18. package/dist/Player/VariableManager.d.ts +30 -0
  19. package/dist/RpgServer.d.ts +227 -1
  20. package/dist/decorators/event.d.ts +46 -0
  21. package/dist/decorators/map.d.ts +177 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +17436 -18167
  24. package/dist/index.js.map +1 -1
  25. package/dist/rooms/map.d.ts +486 -8
  26. package/package.json +17 -15
  27. package/src/Gui/DialogGui.ts +7 -2
  28. package/src/Gui/index.ts +3 -1
  29. package/src/Player/BattleManager.ts +97 -38
  30. package/src/Player/ClassManager.ts +95 -35
  31. package/src/Player/ComponentManager.ts +425 -19
  32. package/src/Player/Components.ts +380 -0
  33. package/src/Player/EffectManager.ts +110 -27
  34. package/src/Player/ElementManager.ts +126 -25
  35. package/src/Player/GoldManager.ts +32 -35
  36. package/src/Player/GuiManager.ts +187 -140
  37. package/src/Player/ItemFixture.ts +4 -5
  38. package/src/Player/ItemManager.ts +363 -48
  39. package/src/Player/MoveManager.ts +323 -308
  40. package/src/Player/ParameterManager.ts +499 -99
  41. package/src/Player/Player.ts +719 -80
  42. package/src/Player/SkillManager.ts +44 -23
  43. package/src/Player/StateManager.ts +210 -95
  44. package/src/Player/VariableManager.ts +180 -48
  45. package/src/RpgServer.ts +236 -1
  46. package/src/core/context.ts +1 -0
  47. package/src/decorators/event.ts +61 -0
  48. package/src/decorators/map.ts +198 -0
  49. package/src/index.ts +5 -1
  50. package/src/module.ts +24 -0
  51. package/src/rooms/map.ts +1054 -54
  52. package/dist/Player/Event.d.ts +0 -0
  53. package/src/Player/Event.ts +0 -0
@@ -1,8 +1,9 @@
1
- import { isInstanceOf, isString, Item, type Constructor } from "@rpgjs/common";
1
+ import { isInstanceOf, isString, Item, PlayerCtor, type Constructor } from "@rpgjs/common";
2
2
  import { RpgCommonPlayer, Matter } from "@rpgjs/common";
3
3
  import { ATK, PDEF, SDEF } from "../presets";
4
4
  import { ItemLog } from "../logs";
5
5
  import { ArmorInstance, ItemClass, ItemInstance, WeaponInstance } from "@rpgjs/database";
6
+ import { RpgPlayer } from "./Player";
6
7
 
7
8
  // Ajout des enums manquants
8
9
  enum Effect {
@@ -13,27 +14,180 @@ enum ClassHooks {
13
14
  canEquip = 'canEquip'
14
15
  }
15
16
 
17
+ type Inventory = { nb: number; item: ItemInstance };
18
+
16
19
  /**
17
- * Interface defining what MoveManager adds to a class
20
+ * Interface defining the hooks that can be implemented on item classes or objects
21
+ *
22
+ * These hooks are called at specific moments during the item lifecycle:
23
+ * - `onAdd`: When the item is added to the player's inventory
24
+ * - `onUse`: When the item is successfully used
25
+ * - `onUseFailed`: When the item usage fails (e.g., chance roll failed)
26
+ * - `onRemove`: When the item is removed from the inventory
27
+ * - `onEquip`: When the item is equipped or unequipped
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const itemHooks: ItemHooks = {
32
+ * onAdd(player) {
33
+ * console.log('Item added to inventory');
34
+ * },
35
+ * onUse(player) {
36
+ * player.hp += 100;
37
+ * }
38
+ * };
39
+ * ```
18
40
  */
19
- export interface IItemManager {
20
- databaseById(id: string): ItemClass;
41
+ export interface ItemHooks {
42
+ /**
43
+ * Called when the item is added to the player's inventory
44
+ *
45
+ * @param player - The player receiving the item
46
+ */
47
+ onAdd?: (player: RpgPlayer) => void | Promise<void>;
48
+
49
+ /**
50
+ * Called when the item is successfully used
51
+ *
52
+ * @param player - The player using the item
53
+ */
54
+ onUse?: (player: RpgPlayer) => void | Promise<void>;
55
+
56
+ /**
57
+ * Called when the item usage fails (e.g., chance roll failed)
58
+ *
59
+ * @param player - The player attempting to use the item
60
+ */
61
+ onUseFailed?: (player: RpgPlayer) => void | Promise<void>;
62
+
63
+ /**
64
+ * Called when the item is removed from the inventory
65
+ *
66
+ * @param player - The player losing the item
67
+ */
68
+ onRemove?: (player: RpgPlayer) => void | Promise<void>;
69
+
70
+ /**
71
+ * Called when the item is equipped or unequipped
72
+ *
73
+ * @param player - The player equipping/unequipping the item
74
+ * @param equip - true if equipping, false if unequipping
75
+ */
76
+ onEquip?: (player: RpgPlayer, equip: boolean) => void | Promise<void>;
21
77
  }
22
78
 
23
- type Inventory = { nb: number; item: ItemInstance };
79
+ /**
80
+ * Base properties that can be included in an item object
81
+ *
82
+ * This interface defines the common properties that items can have.
83
+ * Use this as a base and extend it with specific item types.
84
+ *
85
+ * @template T - Additional properties specific to the item type
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * interface PotionData extends ItemData {
90
+ * hpValue: number;
91
+ * mpValue: number;
92
+ * }
93
+ *
94
+ * const potion: ItemObject<PotionData> = {
95
+ * name: 'Health Potion',
96
+ * description: 'Restores 100 HP',
97
+ * price: 200,
98
+ * hpValue: 100,
99
+ * mpValue: 0,
100
+ * onUse(player) {
101
+ * player.hp += this.hpValue;
102
+ * }
103
+ * };
104
+ * ```
105
+ */
106
+ export interface ItemData {
107
+ /** Item name */
108
+ name?: string;
109
+ /** Item description */
110
+ description?: string;
111
+ /** Item price */
112
+ price?: number;
113
+ /** HP value restored when used */
114
+ hpValue?: number;
115
+ /** MP/SP value restored when used */
116
+ mpValue?: number;
117
+ /** Chance to successfully use the item (0-1) */
118
+ hitRate?: number;
119
+ /** Whether the item is consumable */
120
+ consumable?: boolean;
121
+ /** States to add when used */
122
+ addStates?: any[];
123
+ /** States to remove when used */
124
+ removeStates?: any[];
125
+ /** Elemental properties */
126
+ elements?: any[];
127
+ /** Parameter modifiers */
128
+ paramsModifier?: Record<string, any>;
129
+ /** Item type (for equipment validation) */
130
+ _type?: 'item' | 'weapon' | 'armor';
131
+ }
132
+
133
+ /**
134
+ * Item object type that combines data properties with hooks
135
+ *
136
+ * This type allows you to create item objects directly without needing a class.
137
+ * The object can contain both item data properties and lifecycle hooks.
138
+ *
139
+ * @template T - Additional properties specific to the item type (extends ItemData)
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const potion: ItemObject = {
144
+ * name: 'Health Potion',
145
+ * description: 'Restores 100 HP',
146
+ * price: 200,
147
+ * hpValue: 100,
148
+ * consumable: true,
149
+ * onAdd(player) {
150
+ * console.log('Potion added!');
151
+ * },
152
+ * onUse(player) {
153
+ * player.hp += 100;
154
+ * }
155
+ * };
156
+ *
157
+ * player.addItem(potion);
158
+ * ```
159
+ */
160
+ export type ItemObject<T extends ItemData = ItemData> = T & ItemHooks & {
161
+ /** Item identifier (required if not using class or string) */
162
+ id?: string;
163
+ };
24
164
 
25
165
  /**
26
- * Move Manager mixin
166
+ * Item Manager Mixin
27
167
  *
28
- * Adds methods to manage player movement
168
+ * Provides comprehensive item management capabilities to any class. This mixin handles
169
+ * inventory management, item usage, equipment, buying/selling, and item effects.
170
+ * It manages the complete item system including restrictions, transactions, and equipment.
29
171
  *
30
- * @param Base - The base class to extend
31
- * @returns A new class with move management capabilities
172
+ * @param Base - The base class to extend with item management
173
+ * @returns Extended class with item management methods
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * class MyPlayer extends WithItemManager(BasePlayer) {
178
+ * constructor() {
179
+ * super();
180
+ * // Item system is automatically initialized
181
+ * }
182
+ * }
183
+ *
184
+ * const player = new MyPlayer();
185
+ * player.addItem('potion', 5);
186
+ * player.useItem('potion');
187
+ * ```
32
188
  */
33
- export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
34
- Base: TBase
35
- ): Constructor<IItemManager> & TBase {
36
- return class extends Base implements IItemManager {
189
+ export function WithItemManager<TBase extends PlayerCtor>(Base: TBase) {
190
+ return class extends Base {
37
191
 
38
192
  /**
39
193
  * Retrieves the information of an object: the number and the instance
@@ -54,7 +208,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
54
208
  */
55
209
  getItem(itemClass: ItemClass | string): Item {
56
210
  const index: number = this._getItemIndex(itemClass);
57
- return this.items()[index];
211
+ return (this as any).items()[index];
58
212
  }
59
213
 
60
214
  /**
@@ -77,7 +231,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
77
231
  }
78
232
 
79
233
  _getItemIndex(itemClass: ItemClass | string): number {
80
- return this.items().findIndex((it: Item): boolean => {
234
+ return (this as any).items().findIndex((it: Item): boolean => {
81
235
  if (isString(itemClass)) {
82
236
  return it.id() == itemClass;
83
237
  }
@@ -87,34 +241,149 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
87
241
  /**
88
242
  * Add an item in the player's inventory. You can give more than one by specifying `nb`
89
243
  *
90
- * `onAdd()` method is called on the ItemClass
244
+ * Supports three ways to add items:
245
+ * 1. **String**: Pass a string ID to retrieve the item from the database (requires item to be registered in `@RpgModule` database).
246
+ * 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.
247
+ * 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.
248
+ *
249
+ * For classes and objects, if they don't exist in the database, they are automatically added using `map.addInDatabase()`.
250
+ * This allows dynamic item creation without requiring pre-registration in the module database.
251
+ *
252
+ * `onAdd()` method is called on the ItemClass or ItemObject
91
253
  *
92
254
  * @title Add Item
93
255
  * @method player.addItem(item,nb=1)
94
- * @param {ItemClass} itemClass
256
+ * @param {ItemClass | ItemObject | string} item - Item class, object, or string identifier
95
257
  * @param {number} [nb] Default 1
96
- * @returns {{ nb: number, item: instance of ItemClass }}
258
+ * @returns {Item} The item instance added to inventory
97
259
  * @memberof ItemManager
98
260
  * @example
99
261
  *
100
262
  * ```ts
101
263
  * import Potion from 'your-database/potion'
264
+ *
265
+ * // Using string ID (retrieves from database - item must be in @RpgModule database)
266
+ * player.addItem('Potion', 5)
267
+ *
268
+ * // Using class (creates instance, auto-adds to map database if not present)
102
269
  * player.addItem(Potion, 5)
270
+ *
271
+ * // Using object directly (auto-adds to map database if not present)
272
+ * player.addItem({
273
+ * id: 'custom-potion',
274
+ * name: 'Custom Potion',
275
+ * description: 'A custom potion',
276
+ * price: 150,
277
+ * hpValue: 50,
278
+ * consumable: true,
279
+ * onAdd(player) {
280
+ * console.log('Custom potion added!');
281
+ * },
282
+ * onUse(player) {
283
+ * player.hp += 50;
284
+ * }
285
+ * }, 3)
286
+ *
287
+ * // Object without ID (auto-generates ID and adds to database)
288
+ * player.addItem({
289
+ * name: 'Dynamic Item',
290
+ * price: 100,
291
+ * onUse(player) {
292
+ * console.log('Dynamic item used!');
293
+ * }
294
+ * })
103
295
  * ```
104
296
  */
105
- addItem(itemId: string, nb: number = 1): Item {
106
- const data = this.databaseById(itemId);
107
- const item = this.items().find((it) => it.id() == itemId);
297
+ addItem(item: ItemClass | ItemObject | string, nb: number = 1): Item {
298
+ const map = (this as any).getCurrentMap();
299
+ if (!map) {
300
+ throw new Error('Player must be on a map to add items');
301
+ }
302
+
303
+ let itemId: string;
304
+ let data: any;
305
+ let itemInstance: any = null;
306
+
307
+ // Handle string: retrieve from database
308
+ if (isString(item)) {
309
+ itemId = item as string;
310
+ data = (this as any).databaseById(itemId);
311
+ if (!data) {
312
+ throw new Error(
313
+ `The ID=${itemId} data is not found in the database. Add the data in the property "database"`
314
+ );
315
+ }
316
+ }
317
+ // Handle class: create instance and add to database if needed
318
+ else if (typeof item === 'function' || (item as any).prototype) {
319
+ itemId = (item as any).name;
320
+
321
+ // Check if already in database
322
+ const existingData = map.database()[itemId];
323
+ if (existingData) {
324
+ // Use existing data from database
325
+ data = existingData;
326
+ } else {
327
+ // Add the class to the database (it will be retrieved later via databaseById)
328
+ map.addInDatabase(itemId, item as ItemClass);
329
+ // Use the class as data (it will be used to create Item instance)
330
+ data = item as ItemClass;
331
+ }
332
+
333
+ // Create instance of the class for hooks
334
+ itemInstance = new (item as ItemClass)();
335
+ }
336
+ // Handle object: use directly and add to database if needed
337
+ else {
338
+ const itemObj = item as ItemObject;
339
+ itemId = itemObj.id || `item-${Date.now()}`;
340
+
341
+ // Check if already in database
342
+ const existingData = map.database()[itemId];
343
+ if (existingData) {
344
+ // Merge with existing data and force update
345
+ data = { ...existingData, ...itemObj };
346
+ // Update database with merged data (force overwrite)
347
+ map.addInDatabase(itemId, data, { force: true });
348
+ } else {
349
+ // Add the object to the database
350
+ map.addInDatabase(itemId, itemObj);
351
+ // Use object directly as data
352
+ data = itemObj;
353
+ }
354
+
355
+ itemInstance = itemObj;
356
+ }
357
+
358
+ // Find existing item in inventory
359
+ const existingItem = (this as any).items().find((it: Item) => it.id() == itemId);
108
360
  let instance: Item;
109
- if (item) {
110
- instance = item;
361
+
362
+ if (existingItem) {
363
+ // Item already exists, just update quantity
364
+ instance = existingItem;
111
365
  instance.quantity.update((it) => it + nb);
112
366
  } else {
367
+ // Create new item instance
113
368
  instance = new Item(data);
114
369
  instance.id.set(itemId);
115
- this.items().push(instance);
370
+
371
+ // Attach hooks from class instance or object
372
+ if (itemInstance) {
373
+ // Store the original instance for hook execution
374
+ (instance as any)._itemInstance = itemInstance;
375
+
376
+ // Attach onAdd hook directly for immediate use
377
+ if (itemInstance.onAdd) {
378
+ instance.onAdd = itemInstance.onAdd.bind(itemInstance);
379
+ }
380
+ };
381
+ (this as any).items().push(instance);
116
382
  }
117
- this["execMethod"]("onAdd", [this], instance);
383
+
384
+ // Call onAdd hook - use stored instance if available
385
+ const hookTarget = (instance as any)._itemInstance || instance;
386
+ (this as any)["execMethod"]("onAdd", [this], hookTarget);
118
387
  return instance;
119
388
  }
120
389
 
@@ -165,7 +434,9 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
165
434
  } else {
166
435
  this.items()[itemIndex].quantity.update((it) => it - nb);
167
436
  }
168
- this["execMethod"]("onRemove", [this], item);
437
+ // Call onRemove hook - use stored instance if available
438
+ const hookTarget = (item as any)._itemInstance || item;
439
+ this["execMethod"]("onRemove", [this], hookTarget);
169
440
  return this.items()[itemIndex];
170
441
  }
171
442
 
@@ -176,7 +447,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
176
447
  *
177
448
  * @title Buy Item
178
449
  * @method player.buyItem(item,nb=1)
179
- * @param {ItemClass | string} itemClass string is item id
450
+ * @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
180
451
  * @param {number} [nb] Default 1
181
452
  * @returns {{ nb: number, item: instance of ItemClass }}
182
453
  * @throws {ItemLog} haveNotPrice
@@ -202,15 +473,38 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
202
473
  * import Potion from 'your-database/potion'
203
474
  *
204
475
  * try {
476
+ * // Using class
205
477
  * player.buyItem(Potion)
478
+ *
479
+ * // Using string ID
480
+ * player.buyItem('Potion')
206
481
  * }
207
482
  * catch (err) {
208
483
  * console.log(err)
209
484
  * }
210
485
  * ```
211
486
  */
212
- buyItem(itemId: string, nb = 1): Item {
213
- const data = this.databaseById(itemId);
487
+ buyItem(item: ItemClass | ItemObject | string, nb = 1): Item {
488
+ let itemId: string;
489
+ let data: any;
490
+
491
+ if (isString(item)) {
492
+ itemId = item as string;
493
+ data = (this as any).databaseById(itemId);
494
+ } else if (typeof item === 'function' || (item as any).prototype) {
495
+ itemId = (item as any).name;
496
+ data = (this as any).databaseById(itemId);
497
+ } else {
498
+ const itemObj = item as ItemObject;
499
+ itemId = itemObj.id || `item-${Date.now()}`;
500
+ try {
501
+ const dbData = (this as any).databaseById(itemId);
502
+ data = { ...dbData, ...itemObj };
503
+ } catch {
504
+ data = itemObj;
505
+ }
506
+ }
507
+
214
508
  if (!data.price) {
215
509
  throw ItemLog.haveNotPrice(itemId);
216
510
  }
@@ -219,7 +513,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
219
513
  throw ItemLog.notEnoughGold(itemId, nb);
220
514
  }
221
515
  this._gold.update((gold) => gold - totalPrice);
222
- return this.addItem(itemId, nb);
516
+ return this.addItem(item, nb);
223
517
  }
224
518
 
225
519
  /**
@@ -229,7 +523,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
229
523
  *
230
524
  * @title Sell Item
231
525
  * @method player.sellItem(item,nb=1)
232
- * @param {ItemClass | string} itemClass string is item id
526
+ * @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
233
527
  * @param {number} [nbToSell] Default 1
234
528
  * @returns {{ nb: number, item: instance of ItemClass }}
235
529
  * @throws {ItemLog} haveNotPrice
@@ -264,16 +558,20 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
264
558
  *
265
559
  * try {
266
560
  * player.addItem(Potion)
561
+ * // Using class
267
562
  * player.sellItem(Potion)
563
+ * // Using string ID
564
+ * player.sellItem('Potion')
268
565
  * }
269
566
  * catch (err) {
270
567
  * console.log(err)
271
568
  * }
272
569
  * ```
273
570
  */
274
- sellItem(itemId: string, nbToSell = 1): Item {
275
- const data = this.databaseById(itemId);
276
- const inventory = this.getItem(itemId);
571
+ sellItem(itemClass: ItemClass | string, nbToSell = 1): Item {
572
+ const itemId = isString(itemClass) ? itemClass : (itemClass as any).name;
573
+ const data = (this as any).databaseById(itemId);
574
+ const inventory = this.getItem(itemClass);
277
575
  if (!inventory) {
278
576
  throw ItemLog.notInInventory(itemId);
279
577
  }
@@ -285,7 +583,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
285
583
  throw ItemLog.haveNotPrice(itemId);
286
584
  }
287
585
  this._gold.update((gold) => gold + (data.price / 2) * nbToSell);
288
- this.removeItem(itemId, nbToSell);
586
+ this.removeItem(itemClass, nbToSell);
289
587
  return inventory;
290
588
  }
291
589
 
@@ -343,7 +641,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
343
641
  *
344
642
  * @title Use an Item
345
643
  * @method player.useItem(item,nb=1)
346
- * @param {ItemClass | string} itemClass string is item id
644
+ * @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
347
645
  * @returns {{ nb: number, item: instance of ItemClass }}
348
646
  * @throws {ItemLog} restriction
349
647
  * If the player has the `Effect.CAN_NOT_ITEM` effect
@@ -389,15 +687,19 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
389
687
  *
390
688
  * try {
391
689
  * player.addItem(Potion)
690
+ * // Using class
392
691
  * player.useItem(Potion)
692
+ * // Using string ID
693
+ * player.useItem('Potion')
393
694
  * }
394
695
  * catch (err) {
395
696
  * console.log(err)
396
697
  * }
397
698
  * ```
398
699
  */
399
- useItem(itemId: string): Item {
400
- const inventory = this.getItem(itemId);
700
+ useItem(itemClass: ItemClass | string): Item {
701
+ const itemId = isString(itemClass) ? itemClass : (itemClass as any).name;
702
+ const inventory = this.getItem(itemClass);
401
703
  if ((this as any).hasEffect?.(Effect.CAN_NOT_ITEM)) {
402
704
  throw ItemLog.restriction(itemId);
403
705
  }
@@ -409,15 +711,16 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
409
711
  throw ItemLog.notUseItem(itemId);
410
712
  }
411
713
  const hitRate = (item as any).hitRate ?? 1;
714
+ const hookTarget = (item as any)._itemInstance || item;
412
715
  if (Math.random() > hitRate) {
413
- this.removeItem(itemId);
414
- this["execMethod"]("onUseFailed", [this], item);
716
+ this.removeItem(itemClass);
717
+ this["execMethod"]("onUseFailed", [this], hookTarget);
415
718
  throw ItemLog.chanceToUseFailed(itemId);
416
719
  }
417
720
  (this as any).applyEffect?.(item);
418
721
  (this as any).applyStates?.(this, item);
419
- this["execMethod"]("onUse", [this], item);
420
- this.removeItem(itemId);
722
+ this["execMethod"]("onUse", [this], hookTarget);
723
+ this.removeItem(itemClass);
421
724
  return inventory;
422
725
  }
423
726
 
@@ -428,7 +731,7 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
428
731
  *
429
732
  * @title Equip Weapon or Armor
430
733
  * @method player.equip(itemClass,equip=true)
431
- * @param {ItemClass | string} itemClass string is item id
734
+ * @param {ItemClass | string} itemClass Identifier of the object if the parameter is a string
432
735
  * @param {number} [equip] Equip the object if true or un-equipped if false
433
736
  * @returns {void}
434
737
  * @throws {ItemLog} notInInventory
@@ -463,7 +766,10 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
463
766
  *
464
767
  * try {
465
768
  * player.addItem(Sword)
769
+ * // Using class
466
770
  * player.equip(Sword)
771
+ * // Using string ID
772
+ * player.equip('Sword')
467
773
  * }
468
774
  * catch (err) {
469
775
  * console.log(err)
@@ -471,14 +777,15 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
471
777
  * ```
472
778
  */
473
779
  equip(
474
- itemId: string,
780
+ itemClass: ItemClass | string,
475
781
  equip: boolean = true
476
782
  ): void {
477
- const inventory: Item = this.getItem(itemId);
783
+ const itemId = isString(itemClass) ? itemClass : (itemClass as any).name;
784
+ const inventory: Item = this.getItem(itemClass);
478
785
  if (!inventory) {
479
786
  throw ItemLog.notInInventory(itemId);
480
787
  }
481
- const data = this.databaseById(itemId);
788
+ const data = (this as any).databaseById(itemId);
482
789
  if (data._type == "item") {
483
790
  throw ItemLog.invalidToEquiped(itemId);
484
791
  }
@@ -506,7 +813,15 @@ export function WithItemManager<TBase extends Constructor<RpgCommonPlayer>>(
506
813
  } else {
507
814
  this.equipments().push(item);
508
815
  }
509
- this["execMethod"]("onEquip", [this, equip], item);
816
+ // Call onEquip hook - use stored instance if available
817
+ const hookTarget = (item as any)._itemInstance || item;
818
+ this["execMethod"]("onEquip", [this, equip], hookTarget);
510
819
  }
511
- };
820
+ } as unknown as TBase;
512
821
  }
822
+
823
+ /**
824
+ * Type helper to extract the interface from the WithItemManager mixin
825
+ * This provides the type without duplicating method signatures
826
+ */
827
+ export type IItemManager = InstanceType<ReturnType<typeof WithItemManager>>;