forked from tdauth/dmdf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStruct Unit Inventory.j
2984 lines (2658 loc) · 121 KB
/
Struct Unit Inventory.j
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
library AStructSystemsInventoryUnitInventory requires AStructCoreGeneralHashTable, AStructCoreGeneralList, AStructCoreGeneralVector, ALibraryCoreGeneralItem, ALibraryCoreGeneralUnit, AStructCoreStringFormat, ALibraryCoreInterfaceMisc, ALibraryCoreInterfaceTextTag, AStructSystemsInventoryItemType
/**
* \brief This structure is used to store all item information of one slot in inventory.
*/
struct AUnitInventoryItemData
// dynamic members
private integer m_itemTypeId
private integer m_charges
private integer m_dropId
private boolean m_invulnerable
private real m_life
private boolean m_pawnable
private player m_player
private integer m_userData
private boolean m_visible
// members
private itemtype m_itemType
public method setItemTypeId takes integer itemTypeId returns nothing
set this.m_itemTypeId = itemTypeId
endmethod
public method itemTypeId takes nothing returns integer
return this.m_itemTypeId
endmethod
public method setCharges takes integer charges returns nothing
set this.m_charges = IMaxBJ(charges, 0)
endmethod
public method charges takes nothing returns integer
return this.m_charges
endmethod
public method setDropId takes integer dropId returns nothing
set this.m_dropId = dropId
endmethod
public method dropId takes nothing returns integer
return this.m_dropId
endmethod
public method setInvulnerable takes boolean invulnerable returns nothing
set this.m_invulnerable = invulnerable
endmethod
public method invulnerable takes nothing returns boolean
return this.m_invulnerable
endmethod
public method setLife takes real life returns nothing
set this.m_life = life
endmethod
public method life takes nothing returns real
return this.m_life
endmethod
public method setPawnable takes boolean pawnable returns nothing
set this.m_pawnable = pawnable
endmethod
public method pawnable takes nothing returns boolean
return this.m_pawnable
endmethod
public method setPlayer takes player user returns nothing
set this.m_player = user
endmethod
public method player takes nothing returns player
return this.m_player
endmethod
public method setUserData takes integer userData returns nothing
set this.m_userData = userData
endmethod
public method userData takes nothing returns integer
return this.m_userData
endmethod
public method setVisible takes boolean visible returns nothing
set this.m_visible = visible
endmethod
public method visible takes nothing returns boolean
return this.m_visible
endmethod
public method itemType takes nothing returns itemtype
return this.m_itemType
endmethod
/**
* Creates an item based on the item inventory data at a given position.
* \param x The X coordinate of the position.
* \param y The Y coordinate of the position.
* \return Returns a newly created item.
*/
public method createItem takes real x, real y returns item
local item result = CreateItem(this.m_itemTypeId, x, y)
call SetItemCharges(result, this.m_charges)
call SetItemDropID(result, this.m_dropId)
call SetItemInvulnerable(result, this.m_invulnerable)
call SetWidgetLife(result, this.m_life)
call SetItemPawnable(result, this.m_pawnable)
call SetItemPlayer(result, this.m_player, true)
call SetItemUserData(result, this.m_userData)
call SetItemVisible(result, this.m_visible)
return result
endmethod
public method addItemDataCharges takes thistype other returns integer
call this.setCharges(this.charges() + other.charges())
return this.charges()
endmethod
public method removeItemDataCharges takes thistype other returns integer
call this.setCharges(this.charges() - other.charges())
return this.charges()
endmethod
/**
* Assigns all stored data to another item except the item type ID since it cannot be changed dynamically.
* \param usedItem The item which the data is assigned to.
*/
public method assignToItem takes item usedItem returns nothing
debug if (this.m_itemTypeId != GetItemTypeId(usedItem)) then
debug call Print("Item type " + GetObjectName(this.m_itemTypeId) + " does not equal " + GetObjectName(GetItemTypeId(usedItem)))
debug endif
call SetItemCharges(usedItem, this.m_charges)
call SetItemDropID(usedItem, this.m_dropId)
call SetItemInvulnerable(usedItem, this.m_invulnerable)
call SetWidgetLife(usedItem, this.m_life)
call SetItemPawnable(usedItem, this.m_pawnable)
call SetItemPlayer(usedItem, this.m_player, true)
call SetItemUserData(usedItem, this.m_userData)
call SetItemVisible(usedItem, this.m_visible)
endmethod
public method store takes gamecache cache, string missionKey, string labelPrefix returns nothing
call StoreInteger(cache, missionKey, labelPrefix + "ItemTypeId", this.m_itemTypeId)
call StoreInteger(cache, missionKey, labelPrefix + "Charges", this.m_charges)
call StoreInteger(cache, missionKey, labelPrefix + "DropId", this.m_dropId)
call StoreBoolean(cache, missionKey, labelPrefix + "Invulnerable", this.m_invulnerable)
call StoreReal(cache, missionKey, labelPrefix + "Life", this.m_life)
call StoreBoolean(cache, missionKey, labelPrefix + "Pawnable", this.m_pawnable)
call StoreInteger(cache, missionKey, labelPrefix + "PlayerId", GetPlayerId(this.m_player))
call StoreInteger(cache, missionKey, labelPrefix + "UserData", this.m_userData)
call StoreBoolean(cache, missionKey, labelPrefix + "Visible", this.m_visible)
endmethod
public method restore takes gamecache cache, string missionKey, string labelPrefix returns nothing
set this.m_itemTypeId = GetStoredInteger(cache, missionKey, labelPrefix + "ItemTypeId")
set this.m_charges = GetStoredInteger(cache, missionKey, labelPrefix + "Charges")
set this.m_dropId = GetStoredInteger(cache, missionKey, labelPrefix + "DropId")
set this.m_invulnerable = GetStoredBoolean(cache, missionKey, labelPrefix + "Invulnerable")
set this.m_life = GetStoredReal(cache, missionKey, labelPrefix + "Life")
set this.m_pawnable = GetStoredBoolean(cache, missionKey, labelPrefix + "Pawnable")
set this.m_player = Player(GetStoredInteger(cache, missionKey, labelPrefix + "PlayerId"))
set this.m_userData = GetStoredInteger(cache, missionKey, labelPrefix + "UserData")
set this.m_visible = GetStoredBoolean(cache, missionKey, labelPrefix + "Visible")
endmethod
/**
* Creates a inventory item data based on item \p usedItem and carrying unit \p usedUnit.
*/
public static method create takes item usedItem, unit usedUnit returns thistype
local thistype this = thistype.allocate()
// dynamic members
set this.m_itemTypeId = GetItemTypeId(usedItem)
set this.m_charges = GetItemCharges(usedItem)
set this.m_dropId = GetUnitTypeId(usedUnit)
set this.m_invulnerable = IsItemInvulnerable(usedItem)
set this.m_life = GetWidgetLife(usedItem)
set this.m_pawnable = IsItemPawnable(usedItem)
set this.m_player = GetItemPlayer(usedItem)
set this.m_userData = GetItemUserData(usedItem)
set this.m_visible = IsItemVisible(usedItem)
// members
set this.m_itemType = GetItemType(usedItem)
return this
endmethod
public static method createRestored takes gamecache cache, string missionKey, string labelPrefix returns thistype
local thistype this = thistype.allocate()
call this.restore(cache, missionKey, labelPrefix)
return this
endmethod
public method onDestroy takes nothing returns nothing
// members
set this.m_itemType = null
endmethod
endstruct
/**
* Function interface for a function which is called when an item is added to the inventory. Can be used for equipment items or backpack items.
* \param inventory The corresponding inventory which it is added to.
* \param index The index of the added item (either the equipment slot, or the absolute backpack item index).
* \param firstTime This value is true if the item was not in the inventory before. Otherwise it is false.
* \todo Should be a part of \ref AUnitInventory, vJass bug.
*/
function interface AUnitInventoryItemAddFunction takes AUnitInventory inventory, integer index, boolean firstTime returns nothing
/**
* \brief This structure provides an interface to a unit's inventory which is based on the default Warcraft III: The Frozen Throne inventory with 6 slots.
* A unit ability can be used to open and close backpack.
* The backpack uses the same interface as the equipment since there are only 6 available item slots in Warcraft III.
* Abilities of the equipment will be kept when the unit is opening its backpack.
* Backpack item abilities have no effect but backpack items can be used (for example potions).
* In the backpack all item charges do start at 1 and there aren't any with 0, so the number of charges is always the real number.
* In equipment there shouldn't be any charges since only one item can be equipped per slot.
* If you add an item to the unit, triggers will be run and at first it will be tried to equip the added item to the unit.
* If this doesn't work (e. g. it has not an equipable custom item type) it will be added to backpack.
* You do not have to care if the backpack is open at that moment or not. The abilities remain and therefore all the effects of the equipment.
* \note Usable items which do not remain in the inventory after using them should always have type \ref ITEM_TYPE_CHARGED! They need special treatment since they are consumed.
* \note Do not forget to create \ref AItemType instances for all equipable item types!
* \note If you don't want an icon of an equipment ability to be added to the unit when the backpack is opened, use a disabled spellbook ability with the same ID for every equipment item. Then add an enabled empty spellbook ability with the same ID to the unit in the beginning. All equipment ability icons will appear in this spellbook.
* \todo Use \ref UnitDropItemSlot instead of item removals.
* \todo Maybe there should be an implementation of equipment pages, too (for more than 5 equipment types). You could add something like AEquipmentType.
* \todo Test if shop events work even with a full inventory. At the moment the player has to select the shop but computer controlled players won't do that. For human players it should work.
*
* The mouse and ability controls for the inventory are the following:
* <ul>
* <li>Casting the ability opens the backpack or the equipment. Both use the same unit inventory.</li>
* <li>Using the page items changes the page of the backpack to the next or the previous.</li>
* <li>Drag and Drop an equipped item at the same slot -> unequips the item</li>
* <li>Drag and Drop a backpack item at a free slot -> destacks one charge at the slot</li>
* <li>Drop a backpack item -> drops it with all charges on the ground. The owner becomes neutral passive</li>
* <li>Pawn a backpack item -> pawns the item with all charges (The remaining gold for non usable items is added by the system).</li>
* <li>Give an item to another unit -> drops the item with all charges.</li>
* <li>Drag and Drop a backpack item at a page item, moves the item will all charges to the previous or next page if there is a free slot.</li>
* <li>If the player selects a shop to buy items, the inventory items are cleared out that there is a free slot and he can buy as many items as he wants to. Of course the equipment effects stay.</li>
* </ul>
* \note Drag and Drop works by right clicking on an item in the inventory and left clicking on its target slot, item or unit or the ground.
* \note Every unit can only have one inventory. Use \ref thistype.getUnitsInventory() to get a unit's inventory.
*/
struct AUnitInventory
// static constant members, useful for GUIs
/**
* No empty slot is required since picking up items with full inventory is supported as well as buying items with a full inventory as long as the shop is selected by the player before.
* If no empty slot is used the items however can not be dropped with all stacks at once (which the empty slot was used for).
* \ref AItemType.equipmentTypeAmulet gets the last two slots. Therefore two amulets can be carried. \todo \ref AItemType.maxEuqipmentTypes, vJass bug
*/
public static constant integer maxEquipmentTypes = 6
/// maxBackpackItems / maxBackpackItemsPerPage
public static constant integer maxBackpackPages = 30
/**
* Picking up an item is still possible although all slots are used by detecting the order and running some code manually.
*/
public static constant integer maxBackpackItemsPerPage = 4
/// TODO thistype.maxBackpackPages * thistype.maxBackpackItemsPerPage
public static constant integer maxBackpackItems = 120
public static constant integer previousPageItemSlot = 4
public static constant integer nextPageItemSlot = 5
// static construction members
private static integer m_leftArrowItemType
private static integer m_rightArrowItemType
private static integer m_openBackpackAbilityId
private static boolean m_allowPickingUpFromOthers
private static string m_textUnableToEquipItem
private static string m_textEquipItem
private static string m_textUnableToAddBackpackItem
private static string m_textAddItemToBackpack
private static string m_textUnableToMoveBackpackItem
private static string m_textDropPageItem
private static string m_textMovePageItem
private static string m_textOwnedByOther
private static string m_textPreviousPageIsFull
private static string m_textNextPageIsFull
// static members
/**
* Stores all instances of \ref thistype.
*/
private static AIntegerList m_inventories
private static timer m_pickupTimer
private static boolean m_pickupTimerHasStarted
/// The item which should currently be picked up by the unit.
private item m_targetItem = null
// construction members
private unit m_unit
private player m_player
// dynamic members
/**
* The item type ID of the placeholder items for the equipment.
*/
private integer array m_equipmentItemTypeId[thistype.maxEquipmentTypes]
private AIntegerVector m_onEquipFunctions
private AIntegerVector m_onAddToBackpackFunctions
// members
private AUnitInventoryItemData array m_equipmentItemData[thistype.maxEquipmentTypes]
private AUnitInventoryItemData array m_backpackItemData[thistype.maxBackpackItems]
private trigger m_openTrigger
private trigger m_orderTrigger
private trigger m_useTrigger // show next page, show previous page, disable in equipment
private trigger m_pickupOrderTrigger
/**
* Since we use all slots in the inventory we have to manually create a pickup function.
* Unfortunately this does not work for buying items which would still lead to the error "inventory is full" if all slots are used.
* Therefore whenever the player selects a shop to buy items, all items in the slots are hidden.
* When the shop is deselected the items will be shown again.
*
* Since the player cannot interact with the inventory anyway when selecting a shop this does not bother the player.
* \{
*/
private trigger m_shopSelectionTrigger
private unit m_shop
private trigger m_shopDeselectionTrigger
/**
* \}
*/
private trigger m_pickupTrigger
private trigger m_dropTrigger
private trigger m_pawnTrigger
/**
* The UI has to be updated when the unit is being revived. It might have happened that some items could not by added by \ref unitAddItemToSlotById()
* since the unit was already dead. Therefore all inventory slots has to be updated on revival.
*/
private trigger m_revivalTrigger
/**
* Stores the currently open backpack page.
*/
private integer m_backpackPage
/**
* This flag indicates if the backpack is shown or the equipment is shown instead.
*/
private boolean m_backpackIsEnabled
/**
* If this flag is true, the equipped items won't have any effect and items cannot be equipped.
*/
private boolean m_onlyBackpackIsEnabled
/*
* A list of all currently pawned item handle IDs required by the drop trigger to not accidentelly refresh a pawned item.
*/
private AIntegerList m_pawnedItems
//! runtextmacro optional A_STRUCT_DEBUG("\"AUnitInventory\"")
// static members
/**
* \return Returns a list of all existing unit inventories.
* \note Convert the instances to \ref thistype.
*/
public static method inventories takes nothing returns AIntegerList
return thistype.m_inventories
endmethod
// static methods
/**
* Every unit can only have one inventory. This method can be used to get a unit's inventory.
* \param whichUnit The unit for which the inventory is returned.
* \return Returns the inventory created for the unit. If none exists it returns 0.
*/
public static method getUnitsInventory takes unit whichUnit returns thistype
return thistype(AHashTable.global().handleInteger(whichUnit, A_HASHTABLE_KEY_INVENTORY))
endmethod
// construction members
/**
* \return Returns the unit which owns the inventory.
*/
public method unit takes nothing returns unit
return this.m_unit
endmethod
/**
* \return Returns the player who owns the unit which owns the inventory.
*/
public method player takes nothing returns player
return this.m_player
endmethod
// dynamic members
/**
* Replaces the current unit of the inventory by \p newUnit.
* This does also change the owning player.
* Note that it does not add the ability nor add any items to the unit.
*/
public method replaceUnit takes unit newUnit returns nothing
call AHashTable.global().removeHandleInteger(this.m_unit, A_HASHTABLE_KEY_INVENTORY)
set this.m_unit = newUnit
call AHashTable.global().setHandleInteger(newUnit, A_HASHTABLE_KEY_INVENTORY, this)
set this.m_player = GetOwningPlayer(newUnit)
endmethod
/**
* Sets the item type of a placeholder item for equipment type \p equipmentType to \p itemTypeId.
* If the item type ID is not 0 the placeholder item will be shown whenever there is no item equipped of that certain type instead of an empty slot.
*/
public method setEquipmentTypePlaceholder takes integer equipmentType, integer itemTypeId returns nothing
set this.m_equipmentItemTypeId[equipmentType] = itemTypeId
endmethod
public method equipmentTypePlaceholder takes integer equipmentType returns integer
return this.m_equipmentItemTypeId[equipmentType]
endmethod
/**
* \return Returns true if the backpack is open. Otherwise if the equipment is shown it returns false.
*/
public method backpackIsEnabled takes nothing returns boolean
return this.m_backpackIsEnabled
endmethod
/**
* \return Returns true if the backpack is open, the equipment has no effect and no items can be equipped at the moment.
*/
public method onlyBackpackIsEnabled takes nothing returns boolean
return this.m_onlyBackpackIsEnabled
endmethod
/**
* \return Returns the item data of an equipped item of type \p equipmentType. If no item is equipped of that type it should return 0.
*/
public method equipmentItemData takes integer equipmentType returns AUnitInventoryItemData
debug if (equipmentType >= thistype.maxEquipmentTypes or equipmentType < 0) then
debug call this.print("Wrong equipment type: " + I2S(equipmentType) + ".")
debug return 0
debug endif
return this.m_equipmentItemData[equipmentType]
endmethod
/**
* \return Returns item data of an item in the backpack with \p index. If no item is placed under that index it should return 0.
*/
public method backpackItemData takes integer index returns AUnitInventoryItemData
debug if (index >= thistype.maxBackpackItems or index < 0) then
debug call this.print("Wrong backpack index: " + I2S(index) + ".")
debug return 0
debug endif
return this.m_backpackItemData[index]
endmethod
/**
* Counts all equipment items and returns the result.
* Complexity of O(n).
* \return Returns the total number of equipped items.
*/
public method totalEquipmentItems takes nothing returns integer
local integer result = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.m_equipmentItemData[i] != 0) then
set result = result + 1
endif
set i = i + 1
endloop
return result
endmethod
/**
* Counts all filled item slots in backpack and returns the result.
* Complexity of O(n).
* \note This does not consider any charges! It considers only filled slots.
* \note This does not consider any page items.
* \return Returns the total number of filled slots in the backpack. It does not consider any charges in those slots.
* \sa totalBackpackItemCharges()
*/
public method totalBackpackItems takes nothing returns integer
local integer result = 0
local integer i = 0
loop
exitwhen (i == thistype.maxBackpackItems)
if (this.m_backpackItemData[i] != 0) then
set result = result + 1
endif
set i = i + 1
endloop
return result
endmethod
/**
* Counts all filled item charges in backpack and returns the result.
* Complexity of O(n).
* \note This does consider all item charges from all backpack slots except for the page items.
* \return Returns the total number of charges by filled slots in the backpack.
* \sa totalBackpackItems()
*/
public method totalBackpackItemCharges takes nothing returns integer
local integer result = 0
local integer i = 0
loop
exitwhen (i == thistype.maxBackpackItems)
if (this.m_backpackItemData[i] != 0) then
set result = result + this.m_backpackItemData[i].charges()
endif
set i = i + 1
endloop
return result
endmethod
public method totalBackpackItemTypeCharges takes integer itemTypeId returns integer
local integer result = 0
local integer i = 0
loop
exitwhen (i == thistype.maxBackpackItems)
if (this.m_backpackItemData[i] != 0 and this.m_backpackItemData[i].itemTypeId() == itemTypeId) then
set result = result + this.m_backpackItemData[i].charges()
endif
set i = i + 1
endloop
return result
endmethod
/**
* \return Returns the total number of charges from all equipped item of typ \p itemTypeId.
* \note Usually each equipment item has only one charge.
*/
public method totalEquipmentItemTypeCharges takes integer itemTypeId returns integer
local integer result = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.m_equipmentItemData[i] != 0 and this.m_equipmentItemData[i].itemTypeId() == itemTypeId) then
set result = result + this.m_equipmentItemData[i].charges()
endif
set i = i + 1
endloop
return result
endmethod
public method totalItemTypeCharges takes integer itemTypeId returns integer
return this.totalBackpackItemTypeCharges(itemTypeId) + this.totalEquipmentItemTypeCharges(itemTypeId)
endmethod
/**
* Adds a new callback function which is called via .evaluate() whenever an item is equipped.
* \param callback The function which is called.
*/
public method addOnEquipFunction takes AUnitInventoryItemAddFunction callback returns nothing
call this.m_onEquipFunctions.pushBack(callback)
endmethod
/**
* Adds a new callback function which is called via .evaluate() whenever an item is added to the backpack.
* \param callback The function which is called.
*/
public method addOnAddToBackpackFunction takes AUnitInventoryItemAddFunction callback returns nothing
call this.m_onAddToBackpackFunctions.pushBack(callback)
endmethod
/**
* Called via .evaluate() whenever an item is equipped. This is called after the equipment, so all data can be retrieved.
* \param equipmentType The equipment type of the item which is equipped.
* \param firstTime If this value is true, the item has not been in the inventory before.
*/
public stub method onEquipItem takes integer equipmentType, boolean firstTime returns nothing
local integer i = 0
loop
exitwhen (i == this.m_onEquipFunctions.size())
call AUnitInventoryItemAddFunction(this.m_onEquipFunctions[i]).evaluate(this, equipmentType, firstTime)
set i = i + 1
endloop
endmethod
/**
* Called via .evaluate() whenever an item is added to the backpack. This is called after the adding, so all data can be retrieved.
* \param firstTime If this value is true, the item has not been in the inventory before.
*/
public stub method onAddBackpackItem takes integer backpackItemIndex, boolean firstTime returns nothing
local integer i = 0
loop
exitwhen (i == this.m_onAddToBackpackFunctions.size())
call AUnitInventoryItemAddFunction(this.m_onAddToBackpackFunctions[i]).evaluate(this, backpackItemIndex, firstTime)
set i = i + 1
endloop
endmethod
/// \return Returns the page of a backpack item by index.
public static method itemBackpackPage takes integer index returns integer
debug if (index >= thistype.maxBackpackItems or index < 0) then
debug call thistype.staticPrint("Wrong backpack index: " + I2S(index) + ".")
debug return 0
debug endif
return index / thistype.maxBackpackItemsPerPage
endmethod
/// \return Returns the Warcraft inventory slot number by a backpack item index.
public method backpackItemSlot takes integer index returns integer
debug if (index >= thistype.maxBackpackItems or index < 0) then
debug call this.print("Wrong backpack index: " + I2S(index) + ".")
debug return 0
debug endif
return index - this.m_backpackPage * thistype.maxBackpackItemsPerPage
endmethod
/// \return Returns the backpack item index by the slot number.
public method backpackItemIndex takes integer slot returns integer
return this.m_backpackPage * thistype.maxBackpackItemsPerPage + slot
endmethod
/// Just required for the move order and for item dropping.
private static method hasItemIndex takes item usedItem returns boolean
return AHashTable.global().hasHandleInteger(usedItem, A_HASHTABLE_KEY_INVENTORYINDEX)
endmethod
/// Just required for the move order and for item dropping.
private static method clearItemIndex takes item usedItem returns nothing
debug if (not thistype.hasItemIndex(usedItem)) then
debug call Print("Item " + GetItemName(usedItem) + " has no item index on removal.")
debug endif
call AHashTable.global().removeHandleInteger(usedItem, A_HASHTABLE_KEY_INVENTORYINDEX)
endmethod
/// Just required for the move order and for item dropping.
private static method setItemIndex takes item usedItem, integer index returns nothing
call AHashTable.global().setHandleInteger(usedItem, A_HASHTABLE_KEY_INVENTORYINDEX, index)
endmethod
/// Just required for the move order and for item dropping.
private static method itemIndex takes item usedItem returns integer
if (not thistype.hasItemIndex(usedItem)) then
return -1
debug call Print("Item " + GetItemName(usedItem) + " has no item index on getting it.")
endif
return AHashTable.global().handleInteger(usedItem, A_HASHTABLE_KEY_INVENTORYINDEX)
endmethod
/**
* Removes item from unit \p whichUnit even if it is paused and disables the drop event during the removal.
*/
private method unitRemoveItem takes unit whichUnit, item whichItem returns nothing
local boolean isBeingPaused
// Workaround (the unit inventory system has to work - adding items - when the unit is being paused e. g. during talks)
if (IsUnitPaused(whichUnit)) then
set isBeingPaused = true
call PauseUnit(whichUnit, false)
else
set isBeingPaused = false
endif
call DisableTrigger(this.m_dropTrigger)
call RemoveItem(whichItem)
if (isBeingPaused) then
call PauseUnit(whichUnit, true)
endif
call EnableTrigger(this.m_dropTrigger)
endmethod
/**
* Drops item without firing the drop event for the system and even if unit is paused.
* TODO It seems that the drop event is fired anyway.
* TODO UnitDropItemPoint() does not always succeed but it always returns true.
*/
private method unitDropItemPoint takes unit whichUnit, item whichItem, real x, real y returns boolean
local boolean result
local boolean isBeingPaused
// Workaround (the unit inventory system has to work - adding items - when the unit is being paused e. g. during talks)
if (IsUnitPaused(whichUnit)) then
set isBeingPaused = true
call PauseUnit(whichUnit, false)
else
set isBeingPaused = false
endif
call DisableTrigger(this.m_dropTrigger)
/*
* Tests showed that UnitDropItemPoint() does not always succeed but always returns true.
* It is safer to call UnitRemoveItem() instead.
* Old code: set result = UnitDropItemPoint(whichUnit, whichItem, x, y)
*/
call UnitRemoveItem(whichUnit, whichItem)
set result = true
debug if (result and UnitHasItem(whichUnit, whichItem)) then
debug call this.print("Unit " + GetUnitName(whichUnit) + " still has item " + GetItemName(whichItem) + " although dropped.")
debug endif
if (isBeingPaused) then
call PauseUnit(whichUnit, true)
endif
call EnableTrigger(this.m_dropTrigger)
return result
endmethod
/**
* Adds one item of type \p itemType to unit \p whichUnit into slot \p slot without firing the pickup event for this system and even if the unit is paused.
* \return Returns true if the item has been added to the slot successfully.
* \note If there is already an item in the slot it will be dropped and therefore the drop trigger might be disabled and enabled again.
*/
private method unitAddItemToSlotById takes unit whichUnit, integer itemType, integer slot returns boolean
local boolean result
local boolean isBeingPaused
/// Cannot be added if the unit is dead.
if (IsUnitDeadBJ(whichUnit)) then
debug call Print("unit is dead")
return false
endif
// Workaround (the unit inventory system has to work - adding items - when the unit is being paused e. g. during talks)
if (IsUnitPaused(whichUnit)) then
set isBeingPaused = true
call PauseUnit(whichUnit, false)
else
set isBeingPaused = false
endif
call DisableTrigger(this.m_pickupTrigger)
if (UnitItemInSlot(whichUnit, slot) != null) then
debug call this.print("Unit " + GetUnitName(whichUnit) + " has already an item in slot " + I2S(slot))
if (not this.unitDropItemPoint(whichUnit, UnitItemInSlot(whichUnit, slot), GetUnitX(this.unit()), GetUnitY(this.unit()))) then
debug call this.print("Unknown error on dropping the item")
endif
endif
set result = UnitAddItemToSlotById(whichUnit, itemType, slot)
if (isBeingPaused) then
call PauseUnit(whichUnit, true)
endif
call EnableTrigger(this.m_pickupTrigger)
return result
endmethod
/**
* Clears equipment type \p equipmentType without dropping or removing the item from the unit's inventory.
*/
private method clearEquipmentType takes integer equipmentType returns nothing
local unit whichUnit = null
local AItemType itemType = 0
if (this.m_equipmentItemData[equipmentType] != 0) then
set whichUnit = this.unit()
set itemType = AItemType.itemTypeOfItemTypeId(this.m_equipmentItemData[equipmentType].itemTypeId())
call this.m_equipmentItemData[equipmentType].destroy()
set this.m_equipmentItemData[equipmentType] = 0
// unequip first since it might have some effects on the unit and show placeholder afterwards
call itemType.onUnequipItem.evaluate(whichUnit, equipmentType)
call this.checkEquipment.evaluate() // added
if (not this.backpackIsEnabled()) then
debug call Print("Show placeholder")
// show place holder
call this.showEquipmentPlaceholder.evaluate(equipmentType)
endif
set whichUnit = null
endif
endmethod
/**
* Clears the backpack slot \p index without dropping or removing the item from the unit's inventory.
* It simply destroys the corresponding \ref AUnitInventoryItemData instance.
* \return Returns true if there has been an instance at the given index. Otherwise it returns false.
*/
private method clearBackpackSlot takes integer index returns boolean
if (this.m_backpackItemData[index] != 0) then
call this.m_backpackItemData[index].destroy()
set this.m_backpackItemData[index] = 0
return true
endif
return false
endmethod
/**
* Clears backpack item at \p index and drops it if specified.
* \param drop If this value is true the item will be dropped by the unit. Otherwise it simply will be removed.
*/
private method clearBackpackItem takes integer index, boolean drop returns nothing
local item slotItem = null
if (this.m_backpackIsEnabled and this.m_backpackPage == this.itemBackpackPage(index)) then
set slotItem = UnitItemInSlot(this.unit(), this.backpackItemSlot(index))
if (slotItem != null) then
call thistype.clearItemIndex(slotItem)
if (drop) then
call this.unitDropItemPoint(this.unit(), slotItem, GetUnitX(this.unit()), GetUnitY(this.unit()))
if (GetItemType(slotItem) != ITEM_TYPE_CHARGED) then
call SetItemCharges(slotItem, GetItemCharges(slotItem) - 1)
endif
else
call DisableTrigger(this.m_dropTrigger)
call RemoveItem(slotItem)
call EnableTrigger(this.m_dropTrigger)
endif
set slotItem = null
endif
endif
call this.clearBackpackSlot(index)
endmethod
/// \return Returns the backpack item index by a Warcraft inventory slot number.
public method slotBackpackIndex takes integer slot returns integer
debug if (slot >= thistype.maxBackpackItemsPerPage or slot < 0) then
debug call this.print("Wrong inventory slot: " + I2S(slot) + ".")
debug return 0
debug endif
return this.m_backpackPage * thistype.maxBackpackItemsPerPage + slot
endmethod
private method disableEquipmentAbilities takes nothing returns nothing
local AItemType itemType = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.equipmentItemData(i) != 0 and AItemType.itemTypeIdHasItemType(this.equipmentItemData(i).itemTypeId())) then
set itemType = AItemType.itemTypeOfItemTypeId(this.equipmentItemData(i).itemTypeId())
if (itemType != 0) then
call itemType.removeAbilities(this.unit())
endif
endif
set i = i + 1
endloop
endmethod
private method enableEquipmentAbilities takes nothing returns nothing
local AItemType itemType = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.equipmentItemData(i) != 0 and AItemType.itemTypeIdHasItemType(this.equipmentItemData(i).itemTypeId())) then
set itemType = AItemType.itemTypeOfItemTypeId(this.equipmentItemData(i).itemTypeId())
if (itemType != 0) then
call itemType.addAbilities(this.unit())
endif
endif
set i = i + 1
endloop
endmethod
private method onUnequipForAllEquipment takes nothing returns nothing
local AItemType itemType = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.equipmentItemData(i) != 0 and AItemType.itemTypeIdHasItemType(this.equipmentItemData(i).itemTypeId())) then
set itemType = AItemType.itemTypeOfItemTypeId(this.equipmentItemData(i).itemTypeId())
if (itemType != 0) then
call itemType.onUnequipItem.evaluate(this.unit(), i)
endif
endif
set i = i + 1
endloop
endmethod
private method onEquipForAllEquipment takes nothing returns nothing
local AItemType itemType = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.equipmentItemData(i) != 0 and AItemType.itemTypeIdHasItemType(this.equipmentItemData(i).itemTypeId())) then
set itemType = AItemType.itemTypeOfItemTypeId(this.equipmentItemData(i).itemTypeId())
if (itemType != 0) then
call itemType.onEquipItem.evaluate(this.unit(), i)
endif
endif
set i = i + 1
endloop
endmethod
private method hideEquipmentItem takes integer equipmentType, boolean addAbilities returns nothing
local item slotItem = UnitItemInSlot(this.unit(), equipmentType)
local AItemType itemType = 0
if (slotItem != null) then
set itemType = AItemType.itemTypeOfItem(slotItem)
call thistype.clearItemIndex(slotItem)
call DisableTrigger(this.m_dropTrigger)
debug call Print("Removing slot item: " + GetItemName(slotItem))
call RemoveItem(slotItem)
call EnableTrigger(this.m_dropTrigger)
// equipped items must always have an item type, otherwise something went wrong
if (itemType != 0 and addAbilities) then
call itemType.addAbilities(this.unit())
debug elseif (itemType == 0) then
debug call this.print("Equipped item of equipment type " + I2S(equipmentType) + " has no custom item type which should not be possible.")
endif
debug elseif (this.equipmentItemData(equipmentType) != 0) then
debug call this.print("Equipment type " + I2S(equipmentType) + " is not 0 but has no slot item.")
endif
set slotItem = null
endmethod
private method hideEquipmentPlaceholder takes integer equipmentType returns nothing
local item slotItem = UnitItemInSlot(this.unit(), equipmentType)
if (slotItem != null) then
call DisableTrigger(this.m_dropTrigger)
debug call Print("Removing slot item: " + GetItemName(slotItem))
call RemoveItem(slotItem)
call EnableTrigger(this.m_dropTrigger)
debug elseif (this.equipmentItemData(equipmentType) == 0) then
//debug call this.print("Equipment type placeholder " + I2S(equipmentType) + " is not 0 but has no slot item with type " + GetObjectName(this.m_equipmentItemTypeId[equipmentType]))
endif
set slotItem = null
endmethod
/**
* Hides the equipment.
* \param addAbilities If this value is true the permanent abilities of all equipped item types will be added to the unit. Otherwise they disappear with the items.
*/
private method disableEquipment takes boolean addAbilities returns nothing
local AItemType itemType = 0
local integer i = 0
loop
exitwhen (i == thistype.maxEquipmentTypes)
if (this.m_equipmentItemData[i] != 0) then
call this.hideEquipmentItem(i, addAbilities)
set itemType = AItemType.itemTypeOfItemTypeId(this.equipmentItemData(i).itemTypeId())
if (itemType != 0) then
call itemType.onUnequipItem.evaluate(this.unit(), i)
endif
else
call this.hideEquipmentPlaceholder(i)
endif
set i = i + 1
endloop
endmethod
private method hideBackpackItem takes integer index returns nothing
local integer slot = this.backpackItemSlot(index)
local item slotItem = UnitItemInSlot(this.unit(), slot)
if (slotItem != null) then
call thistype.clearItemIndex(slotItem)
call DisableTrigger(this.m_dropTrigger)
call RemoveItem(slotItem)
call EnableTrigger(this.m_dropTrigger)
set slotItem = null
debug else
debug call this.print("Item in slot " + I2S(slot) + " does not exist.")
endif
endmethod
private method hideCurrentBackpackPage takes nothing returns nothing
local integer i = this.m_backpackPage * thistype.maxBackpackItemsPerPage
local integer exitValue = i + thistype.maxBackpackItemsPerPage
loop
exitwhen (i == exitValue)
if (this.m_backpackItemData[i] != 0) then
call this.hideBackpackItem(i)
endif
set i = i + 1
endloop
endmethod
private method hidePageItem takes boolean left returns boolean
local boolean result = false
local integer slot
local item slotItem
if (not this.backpackIsEnabled()) then
return false
endif
if (left) then
set slot = thistype.previousPageItemSlot
else
set slot = thistype.nextPageItemSlot
endif
set slotItem = UnitItemInSlot(this.unit(), slot)
if (slotItem == null) then
return false
endif
call DisableTrigger(this.m_dropTrigger)
call RemoveItem(slotItem)
set slotItem = null
call EnableTrigger(this.m_dropTrigger)
return true
endmethod
private method disableBackpack takes nothing returns nothing
if (this.m_backpackIsEnabled) then
call this.hidePageItem(true)
call this.hidePageItem(false)
call this.hideCurrentBackpackPage()
set this.m_backpackIsEnabled = false
debug else
debug call this.print("Disabling backpack although it is not even enabled.")
endif
endmethod
/**
* Usually you do not have to call this method. The system handles itself.
*/
public stub method disable takes nothing returns nothing