library ItemUtils initializer Init requires Itemdex, ItemHolder, xebasic //=========================================================================== // Information: //============== // // This library was created as a collection of useful item handling // functions and events. It contains several functions that should have // already been natives or BJs, along with events to abstract away the // annoying steps involved in detecting item dragging, trading, and usage. // ItemUtils uses the values 0-5 to represent inventory slots and -1 for // no slot. // // By the way, please don't deliberately kill any items in your map, // as there is no reason to do so and it may cause various errors. Just // remove items you are finished with. Don't worry about players destroy- // ing items with attacks, since that won't cause issues. // //=========================================================================== // ItemUtils functions: //====================== // // HideItem(item, flag) // Hides the specified item if the flag is true; otherwise unhides it. // (This doesn't have the same issues as the SetItemVisible native.) If // an item is hidden while in a unit's inventory, it will be removed // from the inventory. When that item is unhidden, it will attempt to // return itself to the unit's inventory. If the inventory is full, it // will drop to the ground instead. // // GetTriggerItem() -> item // This function is an event response for EVENT_PLAYER_UNIT_SPELL_CHANNEL/ // CAST/EFFECT/FINISH/ENDCAST triggers which returns the the item that // was used to cast the spell. Returns null if no item was used. // // GetItemSlot(item) -> integer // Returns the slot that the specified item occupies in the inventory // of whichever unit is holding the item. Returns -1 if no unit is // holding the item. (Does not work with powerup items.) // // GetItemPrevSlot(item) -> integer // Returns the previous value of GetItemSlot for the specified item. // Returns -1 if the item was previously not held by the unit curr- // ently holding the item. (Does not work with powerup items.) // // GetItemOwningUnit(item) -> unit // Returns the unit carrying the specified item. Returns null if no // unit is carrying the item. (Does not work with powerup items.) // // GetItemPrevOwningUnit(item) -> unit // Returns the previous value of GetItemOwningUnit for the specified // item. Returns null if the item was previously not held by a unit. // (Does not work with powerup items.) // // UnitGetFirstFreeSlot(unit) -> integer // Returns the first empty slot in the specified unit's inventory. // Returns -1 if the unit has no empty inventory slots. // // UnitGetRandomItem(unit) -> item // Returns a random item from the inventory of the specified unit. // Returns null if the unit isn't carrying any items. // // UnitGetItemOfTypeSlot(unit, itemid) -> integer // Returns the first slot containing an item of the specified type in // the inventory of the specified unit. // // UnitGetItemOfType(unit, itemid) -> item // Returns the first item matching the specified item-type carried by // the specified unit. // // UnitCountItemsOfType(unit, itemid) -> integer // Returns the number of items matching the specified item-type on the // specified unit. // // UnitFreeInventoryCount(unit) -> integer // Returns the number of free inventory slots of the specified unit. // Use UnitInventoryCount, a BJ function, to get the occupied slots. // // UnitSwapInventorySlots(unit, slot, toslot) -> boolean // Moves the item contained in the specified slot to the other spec- // ified slot. If an item is contained in the destination slot, the // two items will swap positions. Returns a boolean indicating succ- // ess or failure. Unlike the native function UnitDropItemSlot, this // function will not interrupt the unit's current order. // // UnitAddItemToSlot(unit, item, slot) -> boolean // Adds the specified item to the specified slot of the specified // unit. If an item is already in the specified slot, that item will be // moved to the first free slot, or dropped if the inventory is full. // Returns a boolean indicating success or failure. // // UnitAddItemOfTypeToSlot(unit, itemid, slot) -> boolean // Creates a new item of the specified type, then adds it to the unit's // inventory as in UnitAddItemToSlot(). // //=========================================================================== // ItemUtils events: //=================== // // The following functions are registration functions for item-related // events. They use the following function interfaces: // // function interface ItemFunc takes unit u, item it returns nothing // function interface SwapItemsFunc takes unit u, item dragged, item draggedto returns nothing // function interface UseItemFunc takes unit u, item it, real x, real y, unit utarget, item itarget, destructable dtarget returns nothing // // (Note that none of the following events will be triggered by xe dummy // units. This means using ItemHolder's holdItem() and releaseItem() methods // will not trigger Pickup or Drop events.) // // OnUnitPickupPowerup(ItemFunc) // Runs the specified ItemFunc when a unit picks up a powerup item. // // OnUnitPickupItem(ItemFunc) // Runs the specified ItemFunc when a unit picks up an item. // // OnUnitDropItem(ItemFunc) // Runs the specified ItemFunc when a unit drops an item. // // OnUnitReceiveItem(ItemFunc) // Runs the specified ItemFunc when a unit recieves an item direct- // ly from another unit. OnUnitDropItem will fire for the giving unit, // and OnUnitPickUpItem will fire for the recieving unit before this // event fires. GetItemPrevOwner will indicate the unit from whom the // item was received. // // OnUnitDragItem(ItemFunc) // Runs the specified ItemFunc when a unit drags an item. GetItemPrevSlot // and GetItemSlot will indicate the old and new slots of the item. // // OnUnitSwapItems(SwapItemsFunc) // Runs the specified SwapItemsFunc when a unit drags one item to the // slot currently occupied by another item. OnUnitDragItem will also // fire for both individual items before this event fires. You can // use this event to detect when one item is "dropped onto" another. // // OnUnitUseItem(UseItemFunc) // Runs the specified UseItemFunc when a unit uses an item. (This // event runs before any USE_ITEM triggers.) Using an item can // have a variety of targets, so a UseItemFunc must take enough // parameters to cover all possible targets: // -unit u: The unit using the item. // -item it: The item being used. // -real x: The x coordinate of the item order. 0 if no target. // -real y: The y coordinate of the item order. 0 if no target. // -unit utarget: The unit target of the item order. Null if a unit wasn't targeted. // -item itarget: The item target of the item order. Null if an item wasn't targeted. // -destructable dtarget: The destructable target of the item order. Null if a destructable wasn't targeted. // //=========================================================================== // Configuration: //================ globals private constant integer DummyItemType = 'wtlg' //This must be set to any valid item ID, preferably one that won't //cause issues in your map if used as a dummy item. Wirt's leg is //used by default. endglobals //=========================================================================== globals private constant integer held = 0x28829022 //Totally random integer that no one will ever use. //Used to differentiate the dummy items. private ItemHolder array holders private integer holders_n = 5 //Equal to the number of dummy items used. Only 5 are needed. private trigger pickupitem = CreateTrigger() private trigger dropitem = CreateTrigger() //These triggers need to be enabled/disabled. endglobals //=========================================================================== private function UnitAddDummyItems takes unit u, integer max returns nothing local integer i = 0 call DisableTrigger(pickupitem) //This function shouldn't fire item events. loop //Fill any blank spaces in the unit's inventory (up to max) with dummy items. exitwhen i > max if UnitItemInSlot(u, i) == null then set holders_n = holders_n - 1 call UnitAddItem(u, holders[holders_n].releaseItem(0., 0.)) endif set i = i + 1 endloop call EnableTrigger(pickupitem) endfunction private function UnitRemoveDummyItems takes unit u returns nothing local integer max = UnitInventorySize(u) - 1 local integer i = 0 call DisableTrigger(dropitem) //This function shouldn't fire item events. loop //Release all dummy items in the unit's inventory. exitwhen i > max if GetItemUserData(UnitItemInSlot(u, i)) == held then call holders[holders_n].holdItem(UnitItemInSlot(u, i)) set holders_n = holders_n + 1 endif set i = i + 1 endloop call EnableTrigger(dropitem) endfunction //========================================================================== //! textmacro SlotFunc takes NAME globals private integer array $NAME$ endglobals private function SetItem$NAME$ takes item it, integer slot returns nothing set $NAME$[GetItemId(it)] = slot + 1 //Store with a +1 offset. endfunction function GetItem$NAME$ takes item it returns integer if it == null then //Can't enrage Itemdex by passing a null item. return -1 endif return $NAME$[GetItemId(it)] - 1 //-1 offset makes the default value of 0 return -1. endfunction //! endtextmacro //Instantiate set/get functions for item slot and previous slot. //! runtextmacro SlotFunc("Slot") //! runtextmacro SlotFunc("PrevSlot") //! textmacro OwnerFunc takes NAME private struct Item$NAME$ unit owner private method onDestroy takes nothing returns nothing set .owner = null endmethod implement Itemdex endstruct private function SetItem$NAME$ takes item it, unit owner returns nothing set Item$NAME$[it].owner = owner endfunction function GetItem$NAME$ takes item it returns unit if it == null then return null endif return Item$NAME$[it].owner endfunction //! endtextmacro //Instantiate set/get functions for item owner and previous owner. //Itemdex module is used for attachment to prevent unit reference leaks. //! runtextmacro OwnerFunc("OwningUnit") //! runtextmacro OwnerFunc("PrevOwningUnit") //========================================================================== function interface ItemFunc takes unit u, item it returns nothing function interface SwapItemsFunc takes unit u, item dragged, item draggedto returns nothing function interface UseItemFunc takes unit u, item it, real x, real y, unit utarget, item itarget, destructable dtarget returns nothing //! textmacro ItemEvent takes NAME, TYPE globals private $TYPE$ array $NAME$funcs private integer $NAME$funcs_n = -1 endglobals function OnUnit$NAME$ takes $TYPE$ func returns nothing set $NAME$funcs_n = $NAME$funcs_n + 1 set $NAME$funcs[$NAME$funcs_n] = func endfunction //! endtextmacro //Instantiate all of the functions to register item-related events. //! runtextmacro ItemEvent("PickupPowerup", "ItemFunc") //! runtextmacro ItemEvent("PickupItem", "ItemFunc") //! runtextmacro ItemEvent("DropItem", "ItemFunc") //! runtextmacro ItemEvent("DragItem", "ItemFunc") //! runtextmacro ItemEvent("ReceiveItem", "ItemFunc") //! runtextmacro ItemEvent("SwapItems", "SwapItemsFunc") //! runtextmacro ItemEvent("UseItem", "UseItemFunc") //! textmacro RunItemEvent takes NAME, PARAMS set n = 0 loop exitwhen n < 0 call $NAME$funcs[n].evaluate($PARAMS$) set n = n - 1 endloop //! endtextmacro //Running this textmacro executes one of the above events. //========================================================================== globals private timer clearitemowner = CreateTimer() private item array items private unit array owners private integer items_n = -1 endglobals private function ClearItemOwnerDelayed_Sub takes nothing returns nothing local item it loop exitwhen items_n < 0 set it = items[items_n] if GetItemTypeId(it) != 0 and owners[items_n] == GetItemOwningUnit(it) then call SetItemOwningUnit(it, null) endif set items[items_n] = null set owners[items_n] = null set items_n = items_n - 1 endloop set it = null endfunction private function ClearItemOwnerDelayed takes item it returns nothing set items_n = items_n + 1 //Add the item to a queue. After a delay, check if the item is now owned by another unit. set items[items_n] = it //If not, the item is still on the ground, so set its owner to null. set owners[items_n] = GetItemOwningUnit(it) call TimerStart(clearitemowner, 0., false, function ClearItemOwnerDelayed_Sub) endfunction private function UnitGetItemSlot takes unit u, item it returns integer local integer max = UnitInventorySize(u) - 1 local integer i = 0 //Scan the unit's inventory to find the current slot of a specific item. loop //Private because the user will be using the O(1) function GetItemSlot(). exitwhen i > max if UnitItemInSlot(u, i) == it then return i endif set i = i + 1 endloop return -1 endfunction //=========================================================================== private struct ItemHider ItemHolder holder = 0 unit owner real x real y private method onDestroy takes nothing returns nothing if holder != 0 then call holder.destroy() set owner = null endif endmethod implement Itemdex endstruct function HideItem takes item it, boolean hide returns nothing local ItemHider ih if it == null then return //Invalid parameter, so just return. endif set ih = ItemHider[it] //Get the ItemHider struct for this item. if hide and ih.holder == 0 then //If hiding and the item wasn't hidden... set ih.owner = GetItemOwningUnit(it) set ih.x = GetItemX(it) //Record the x/y coordinates of the item. set ih.y = GetItemY(it) set ih.holder = ItemHolder.holdItem(it) //Store the item in an ItemHolder. elseif not hide and ih.holder != 0 then //If not hiding and the item is hidden... call ih.holder.releaseItem(ih.x, ih.y) //Release the item to its coordinates. if ih.owner != null then //If the item has an owner, attempt to return it. if not UnitAddItem(ih.owner, it) then //If returning the item fails, move the item to the owner's position. call SetItemPosition(it, GetUnitX(ih.owner), GetUnitY(ih.owner)) endif endif set ih.holder = 0 set ih.owner = null endif endfunction //=========================================================================== globals private hashtable ht = InitHashtable() private timer cleartriggeritem = CreateTimer() private unit array triggerunits private integer triggerunits_n = -1 endglobals private function SetTriggerItem takes item it returns nothing call SaveItemHandle(ht, GetHandleId(GetTriggerUnit()), 0, it) endfunction private function ClearTriggerItemDelayed_Sub takes nothing returns nothing loop exitwhen triggerunits_n < 0 call RemoveSavedHandle(ht, GetHandleId(triggerunits[triggerunits_n]), 0) set triggerunits_n = triggerunits_n - 1 endloop endfunction private function ClearTriggerItemDelayed takes nothing returns nothing //Add the casting unit to a queue; after a 0. sec delay, clear its TriggerItem. set triggerunits_n = triggerunits_n + 1 set triggerunits[triggerunits_n] = GetTriggerUnit() call TimerStart(cleartriggeritem, 0., false, function ClearTriggerItemDelayed_Sub) endfunction function GetTriggerItem takes nothing returns item //Returns the TriggerItem currently attached to the casting unit. return LoadItemHandle(ht, GetHandleId(GetTriggerUnit()), 0) endfunction //=========================================================================== function UnitGetFirstFreeSlot takes unit u returns integer local integer max = UnitInventorySize(u) - 1 local integer i = 0 loop exitwhen i > max if UnitItemInSlot(u, i) == null then return i endif set i = i + 1 endloop return -1 endfunction function UnitGetRandomItem takes unit u returns item local integer max = UnitInventorySize(u) - 1 local integer i = 0 local integer array slots local integer slots_n = -1 loop exitwhen i > max if UnitItemInSlot(u, i) != null then set slots_n = slots_n + 1 set slots[slots_n] = i endif set i = i + 1 endloop if slots_n == -1 then return null endif return UnitItemInSlot(u, slots[GetRandomInt(0, slots_n)]) endfunction function UnitGetItemOfTypeSlot takes unit u, integer itemid returns integer local integer max = UnitInventorySize(u) - 1 local integer i = 0 loop exitwhen i > max if GetItemTypeId(UnitItemInSlot(u, i)) == itemid then return i endif set i = i + 1 endloop return -1 endfunction function UnitGetItemOfType takes unit u, integer itemid returns item local integer max = UnitInventorySize(u) - 1 local integer i = 0 loop exitwhen i > max if GetItemTypeId(UnitItemInSlot(u, i)) == itemid then return UnitItemInSlot(u, i) endif set i = i + 1 endloop return null endfunction function UnitCountItemsOfType takes unit u, integer itemid returns integer local integer max = UnitInventorySize(u) - 1 local integer i = 0 local integer count = 0 loop exitwhen i > max if GetItemTypeId(UnitItemInSlot(u, i)) == itemid then set count = count + 1 endif set i = i + 1 endloop return count endfunction function UnitFreeInventoryCount takes unit u returns integer return UnitInventorySize(u) - UnitInventoryCount(u) endfunction //=========================================================================== function UnitSwapInventorySlots takes unit u, integer slot, integer toslot returns boolean local item dragged local item draggedto local integer n if u == null or slot < 0 or slot > UnitInventorySize(u) - 1 or toslot < 0 or toslot > UnitInventorySize(u) - 1 then return false //One or more parameters were invalid, return false. endif if slot == toslot or (UnitItemInSlot(u, slot) == null and UnitItemInSlot(u, toslot) == null) then return true //Swap is completed without needing to take any actions, return true. endif if toslot > slot then //Fill the inventory of the unit (up 'till the higher slot) with dummy items. call UnitAddDummyItems(u, toslot) else call UnitAddDummyItems(u, slot) endif //Find the dragged items. set dragged = UnitItemInSlot(u, slot) set draggedto = UnitItemInSlot(u, toslot) //Drop both of the swapped items, disabling the dropitem trigger. call DisableTrigger(dropitem) call UnitRemoveItem(u, dragged) call UnitRemoveItem(u, draggedto) call EnableTrigger(dropitem) //Pickup the items in reverse order, disabling the pickupitem trigger. call DisableTrigger(pickupitem) if toslot > slot then call UnitAddItem(u, draggedto) call UnitAddItem(u, dragged) else call UnitAddItem(u, dragged) call UnitAddItem(u, draggedto) endif call EnableTrigger(pickupitem) //Release the dummy items to re-create gaps in the inventory. call UnitRemoveDummyItems(u) //Consider dummy items as null items. if GetItemUserData(dragged) == held then set dragged = null endif if GetItemUserData(draggedto) == held then set draggedto = null endif if dragged != null then //If there was an item in the first swapped slot... //Update its previous slot and current slot information. call SetItemPrevSlot(dragged, GetItemSlot(dragged)) call SetItemSlot(dragged, toslot) //Run the DragItem event. //! runtextmacro RunItemEvent("DragItem", "u, dragged") endif if draggedto != null then //If there was an item in the second swapped slot... //Update its previous slot and current slot information. call SetItemPrevSlot(draggedto, GetItemSlot(draggedto)) call SetItemSlot(draggedto, slot) //Run the DragItem event. //! runtextmacro RunItemEvent("DragItem", "u, draggedto") endif if dragged != null and draggedto != null then //If there were items in both swapped slots, run the SwapItems event. //! runtextmacro RunItemEvent("SwapItems", "u, dragged, draggedto") endif set dragged = null set draggedto = null return true endfunction function UnitAddItemToSlot takes unit u, item it, integer slot returns boolean if u == null or it == null or slot < 0 or slot > UnitInventorySize(u) - 1 then return false //One or more parameters were invalid, return false. endif if UnitHasItem(u, it) then //The unit already has the item; swap it to the destination slot. return UnitSwapInventorySlots(u, GetItemSlot(it), slot) endif if UnitFreeInventoryCount(u) == 0 then //The unit's inventory is full. call UnitRemoveItem(u, UnitItemInSlot(u, slot)) //Drop the item in the destination slot. call UnitAddItem(u, it) //Pickup the added item, since it will go to the destination slot. return true endif //If an item is occupying the destination slot, move it into the first free inventory slot. call UnitSwapInventorySlots(u, slot, UnitGetFirstFreeSlot(u)) call UnitAddDummyItems(u, slot - 1) //Fill each empty slot lower than the destination slot with a dummy item. call UnitAddItem(u, it) //Now pickup the item, and it will wind up in the destination slot. call UnitRemoveDummyItems(u) //Get rid of the dummy items. return true endfunction function UnitAddItemOfTypeToSlot takes unit u, integer itemid, integer slot returns boolean return UnitAddItemToSlot(u, CreateItem(itemid, GetUnitX(u), GetUnitY(u)), slot) endfunction //=========================================================================== private function OnPickupItem takes nothing returns boolean local unit u = GetTriggerUnit() local item it = GetManipulatedItem() local integer slot local unit from local integer n if IsItemPowerup(it) then //If the item was a powerup, run the PickupPowerup event then return. //! runtextmacro RunItemEvent("PickupPowerup", "u, it") return false endif set slot = UnitGetItemSlot(u, it) set from = GetItemOwningUnit(it) //Clear the item's previous slot, and assign its current slot. call SetItemPrevSlot(it, -1) call SetItemSlot(it, slot) //Assign the item's previous and current owner. call SetItemPrevOwningUnit(it, from) //from will be null unless the item was traded from another unit. call SetItemOwningUnit(it, u) //Run the PickupItem event. //! runtextmacro RunItemEvent("PickupItem", "u, it") if from != null then //If the item was recieved from another unit, run the RecieveItem event. //! runtextmacro RunItemEvent("ReceiveItem", "u, it") set from = null endif set u = null set it = null return false endfunction private function OnDropItem takes nothing returns boolean local unit u = GetTriggerUnit() local item it = GetManipulatedItem() local integer slot local integer n if IsItemPowerup(it) then return false //If the dropped item is a powerup, ignore it. endif if GetWidgetLife(it) < 0.405 then //If the dropped item is dead, "revive" it. call SetWidgetLife(it, 1.) //This prevents Itemdex from throwing errors. endif //Items die when running out of charges. set slot = GetItemSlot(it) //Clear the item's current slot, and assign its previous slot. call SetItemPrevSlot(it, slot) call SetItemSlot(it, -1) //Clear the item's current owner, and assign its previous owner. call SetItemPrevOwningUnit(it, u) call SetItemOwningUnit(it, null) //Run the DropItem event. //! runtextmacro RunItemEvent("DropItem", "u, it") //Re-assign the current owner to the dropping unit, then clear it after a 0. second delay. If the //OnPickupItem function runs before the item's owner has been cleared, the item was traded between //two units; otherwise, the item's owner will be set to null again. call SetItemOwningUnit(it, GetItemPrevOwningUnit(it)) call ClearItemOwnerDelayed(it) set u = null set it = null return false endfunction //=========================================================================== private function OnIssuedItemOrder takes nothing returns boolean local unit u = GetTriggerUnit() local integer id = GetIssuedOrderId() local integer slot local item it local integer toslot local item toit local integer n if id >= 852008 then //This is a use item event; find the used item, then run the UseItem event. set it = UnitItemInSlot(u, id - 852008) call SetTriggerItem(it) //Assign the result of GetTriggerItem() for this unit. //! runtextmacro RunItemEvent("UseItem", "u, it, GetOrderPointX(), GetOrderPointY(), GetOrderTargetUnit(), GetOrderTargetItem(), GetOrderTargetDestructable()") else //This is a drag item event; find the exchanged slots. set slot = GetItemSlot(GetOrderTargetItem()) set toslot = id - 852002 //If the slots are identical, nothing happened. if slot == toslot then set u = null return false endif //Get the dragged item(s). set it = UnitItemInSlot(u, slot) set toit = UnitItemInSlot(u, toslot) //Update the slot information of the dragged item. call SetItemPrevSlot(it, slot) call SetItemSlot(it, toslot) //Run the DragItem event. //! runtextmacro RunItemEvent("DragItem", "u, it") //If there was an item in the destination slot, it was dragged too. if toit != null then //Update the slot information of the second dragged item. call SetItemPrevSlot(toit, toslot) call SetItemSlot(toit, slot) //Run the DragItem event for the second item. //! runtextmacro RunItemEvent("DragItem", "u, toit") //Run the SwapItems event for the pair of items. //! runtextmacro RunItemEvent("SwapItems", "u, it, toit") set toit = null endif endif set it = null set u = null return false endfunction private function IsItemOrder takes nothing returns boolean //Allow OnIssuedItemOrder to run if the order id falls within the appropriate range. Ignore xe dummy units. return GetUnitTypeId(GetFilterUnit()) != XE_DUMMY_UNITID and GetIssuedOrderId() >= 852002 and GetIssuedOrderId() <= 852013 endfunction private function OnSpellEndcast takes nothing returns boolean call ClearTriggerItemDelayed() //After a 0. sec delay, clear the trigger item for this unit. This allows other return false //ENDCAST triggers to finish using the trigger item before it gets cleared. endfunction //Somehow, the ENDCAST event always runs when a unit stops casting a spell, even if it was removed //from the game or died mid-cast. This means the trigger item will never fail to be cleared. //=========================================================================== private function NotXeDummyUnit takes nothing returns boolean return GetUnitTypeId(GetTriggerUnit()) != XE_DUMMY_UNITID endfunction private function Init takes nothing returns nothing local trigger order = CreateTrigger() local trigger endcast = CreateTrigger() local integer i = holders_n - 1 loop //Create the 5 dummy items and store them within ItemHolders. exitwhen i < 0 set holders[i] = ItemHolder.holdItem(CreateItem(DummyItemType, 0., 0.)) //Set the dummy items' UserData to held, so that they can be differentiated from user items. call SetItemUserData(holders[i].heldItem, held) set i = i - 1 endloop set i = 15 //Register the drop and pickup item events, ignoring xe dummy units. loop exitwhen i < 0 call TriggerRegisterPlayerUnitEvent(pickupitem, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null) call TriggerRegisterPlayerUnitEvent(dropitem, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null) call TriggerRegisterPlayerUnitEvent(endcast, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null) call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null) call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null) call TriggerRegisterPlayerUnitEvent(order, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null) set i = i - 1 endloop call TriggerAddCondition(pickupitem, And(function NotXeDummyUnit, function OnPickupItem)) call TriggerAddCondition(dropitem, And(function NotXeDummyUnit, function OnDropItem)) call TriggerAddCondition(endcast, And(function NotXeDummyUnit, function OnSpellEndcast)) call TriggerAddCondition(order, And(function IsItemOrder, function OnIssuedItemOrder)) endfunction endlibrary