Name | Type | is_array | initial_value |
i | integer | No | |
u | unit | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Inventory /* v2.1a -- hiveworkshop.com/threads/bag-v1-6-1.252002/
*/ requires /* Credits
*/ VectorT /* Bannar -- hiveworkshop.com/threads/containers-vector-t.248942/
*/ RegisterPlayerUnitEvent /* Bannar (new version) -- http://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/
or
Magtherigon96 (old version) -- hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
*/ Table /* Bribe -- hiveworkshop.com/threads/snippet-new-table.188084/
*/ UnitDex /* TriggerHappy -- hiveworkshop.com/threads/system-unitdex-unit-indexer.248209/
VectorT requires Alloc module.
Example: http://www.hiveworkshop.com/threads/unique-id-allocation.260897/
Information
¯¯¯¯¯¯¯¯¯¯¯
Inventory is an improvement of the normal hero inventory.
It extends the treatment with items in inventory, (stack/split)
and also adds the possibilty to add abstract inventories.
Mechanics
¯¯¯¯¯¯¯¯¯¯¯
Each unit can have infinite inventories.
Each inventory can have infinte items.
So each unit has a vector of inventories, and
each inventory has a vector of items in itself.
With both vectors you can use the VecotorT's API.
When adding a new item to an inventory,
the item will be hided automaticaly, and when removed from the inventory,
it will be unhided again, and moved to unit's position.
When an item is added there is a default procedure.
It goes from step 1 to 4 and in case one step succeed, it will stop.
1) Try to stack item with current inventory.
2) Try to stack item with all inventories of the unit.
3) Try to find a free slot in current inventory.
4) Try to find a free slot in any inventory of the unit.
If none of the steps was succesfull it means that the item was not added.
*/
// --- API ---
//! novjass
// read StackConfig trigger for stack API
// read SplitConfig trigger for stack API
// read Fully Inventory Order trigger for FullInventory API
struct InventoryData
readonly ItemVector item
// vector of items
// to read, VectorAPI can be used, item[0] -> returns first element
readonly Inventory inventory // represents the unit's entire inventory
// this is actually the UnitId of the unit where the inventory is applied.
// so when using GetUnitById() of UnitIndexer function we can retrive the respective unit.
// all the getSlot functions return "-1" if wanted slot doesnt exist
method init takes integer size returns nothing
// inits the vector with empty slots
method getFreeSlot takes nothing returns integer
// returns an empty slot
method getItemSlot takes item it returns integer
// which slot item has
method addItem takes item it returns boolean
// returns if item was succesfully added
method addItemAtSlot takes item it, integer slot returns boolean
// returns if item was succesfully added
method stackItem takes item it returns boolean
// tries to stack item with any items inside the vector
method getItemStackableSlot takes item it returns integer
// returns an slot with which item could stack with
method switchItems takes integer slot1, integer slot2 returns boolean
// you can switch slots of two items
method hasItem takes item it returns boolean
// does this vector contain the item
method removeItem takes item it returns boolean
// returns if item was succesfully removed
method flush takes nothing returns nothing
// removed all items from the vector
static method isItemOwned takes item it returns boolean
// returns if this item is part of ANY inventory already
static method getItemVector takes item it returns thistype
// returns the vector the item belongs to
struct Inventory
static constant group GROUP
// defines all units which have a custom inventory applied
readonly InventoryVector inventory
// vector of "InventoryData" , see struct above
// you may read for example, with the vector api inventory[0] -> returns first element
public integer vectorPos
// current position in vector
// this can be used to keep track of current inventory
// it always starts with "0"
static method operator[] takes unit u returns thistype
// Functions to handle inventories.
method setInventoryAmount takes integer amount returns boolean
// set amount of inventories
method getInventoryAmount takes nothing returns integer
// how many custom inventories the unit has
method addInventory takes integer amount returns boolean
// to add/remove custom inventories
method removeInventory takes integer whichInventory returns boolean
// remove a certain inventory from vector
method flush takes nothing returns boolean
// removes all inventories from the unit
// Functions to handle inventory content.
// all the getSlot functions return "-1" if wanted slot doesnt exist
method hasFreeSlot takes nothing returns boolean
// returns if there is any inventory left with a free slot
method hasItem takes item it returns boolean
// returns if the item is part of any of the unit's inventory
method hasStackableItem takes item it returns boolean
// returns if there is any item with which "it" could stack
method stackItem takes item it returns boolean
// stack item "it" with any items inside any inventory until it's used up
// returns if item could be completly stacked
method addItem takes item it returns boolean
// 1. tries to stack the item with whole inventory
// 2. if item still exists, it will get a free slot anywhere
// 3. if item was not stacked and could not be added, return false
// You can registder code that runs when a item is added to an inventory.
static method register takes boolexpr bx returns triggercondition
static method unregister takes triggercondition tc returns nothing
//inside the code refer to:
static unit Unit
// inventory unit
static integer InitialCharges
// charges the item had originaly, before it tried to apply
static item InitialItem
// item itself (can be removed, too, in case it was fully stacked)
static integer InitialItemId
// itemId of item that was added
struct UnitInventory
// UnitInventory works only with the current/actual inventory of the unit,
// instead of "Inventory" struct, which works with all inventories.
// all the getSlot functions return "-1" if wanted slot doesnt exist
static method getFreeSlot takes unit u returns integer
// get free slot
static method getItemSlot takes unit u, item it returns integer
// which slot the item has
static method stackItem takes unit u, item it returns boolean
// stack item "it" with any items inside any inventory until it's used up
// returns if item could be completly stacked
static method getItemStackableSlot takes unit u, item it returns integer
// returns an slot with which "it" could stack with
// method operator to enable/disable triggers:
// The system works with some events, such as drop, pickup, and inventory orders
// to properly stack/split, and add/remove items automaticaly from/in the inventory.
// if you manipulate some data on your own, such as "Bag" library does,
// you may require some functions to toggle some system triggers.
static method operator order_enabled= takes boolean flag returns nothing
// toggle the Inventory_Order trigger
static method operator pickUp_enabled= takes boolean flag returns nothing
// toogle the Item_Pick_Up trigger
static method operator drop_enabled= takes boolean flag returns nothing
// toggle the Item_Drop trigger
//! endnovjass
// ==== End API ====
// _g suffix means global, not struct specific
// _p suffix means private, to avoid name collision in case there is something (same) public
globals
private boolean pickup_enabled_p = true
private boolean drop_enabled_p = true
private boolean order_enabled_p = true
endglobals
native UnitAlive takes unit id returns boolean
// fast init, so stack/split modules work
private module Init_T
private static method onInit takes nothing returns nothing
set table = Table.create()
endmethod
endmodule
struct ItemSplit extends array
private static Table table
private static method SetSplitAmount takes integer itemType, integer amount returns nothing
set table.integer[itemType] = amount
endmethod
public static method operator [] takes integer itemType returns integer
if table.integer.has(itemType) then
return table.integer[itemType]
else
return 1
endif
endmethod
public static method exists takes integer itemType returns boolean
return table.integer.has(itemType)
endmethod
implement Init_T
implement ItemSplitConfig
endstruct
struct ItemStack extends array
private static Table table
private static method SetStackLimit takes integer itemType, integer limit returns nothing
set table.integer[itemType] = limit
endmethod
public static method operator [] takes integer itemType returns integer
if table.integer.has(itemType) then
return table.integer[itemType]
else
return DEFAULT_STACK_LIMIT
endif
endmethod
public static method exists takes integer itemType returns boolean
return table.integer.has(itemType)
endmethod
implement Init_T
implement ItemStackConfig
public static method isStackable takes item it returns boolean
return GetItemCharges(it) > 0 and GetItemCharges(it) < thistype[GetItemTypeId(it)]
endmethod
// return if item was fully stacked.
public static method stackItems takes item oldItem, item newItem returns boolean
local integer max
local integer charges_old
local integer charges_new = GetItemCharges(newItem)
if (not isStackable(oldItem) or charges_new < 1 or GetItemTypeId(oldItem) != GetItemTypeId(newItem) or oldItem == null) then
return false
endif
set max = ItemStack[GetItemTypeId(oldItem)]
set charges_old = GetItemCharges(oldItem)
if (charges_old + charges_new) > max then
// charges is too big, stack only partialy
call SetItemCharges(newItem, max - charges_old)
call SetItemCharges(oldItem, max)
return false
else
// items can completly stack, we can remove one
call SetItemCharges(oldItem, charges_old + charges_new)
// clean from inventory
if InventoryData.isItemOwned(newItem) then
call InventoryData.getItemVector(newItem).removeItem(newItem)
endif
set UnitInventory.drop_enabled = false
call RemoveItem(newItem)
set UnitInventory.drop_enabled = true
return true
endif
endmethod
endstruct
//! runtextmacro DEFINE_VECTOR("", "ItemVector", "item")
struct InventoryData
readonly ItemVector item
readonly Inventory inventory
private static Table table
implement Init_T
// just the read the unit later, by it's id
method operator Inventory= takes Inventory i returns nothing
set inventory = i
if .item == 0 then
set .item = ItemVector.create()
endif
endmethod
// we create empty slots
public method init takes integer size returns nothing
local integer max = .item.size()
loop
exitwhen (max > size)
call .item.push(null)
set max = max + 1
endloop
endmethod
public static method isItemOwned takes item it returns boolean
return table.has(GetHandleId(it))
endmethod
public method hasItem takes item it returns boolean
return table[GetHandleId(it)] == this
endmethod
public static method getItemVector takes item it returns thistype
return table[GetHandleId(it)]
endmethod
// find item slot
public method getItemSlot takes item it returns integer
if .hasItem(it) then
return table[-GetHandleId(it)]
endif
return -1
endmethod
// find any free slot
public method getFreeSlot takes nothing returns integer
local integer max = .item.size() - 1
local integer i = 0
loop
exitwhen (i > max)
if (.item[i] == null) then
return i
endif
set i = i + 1
endloop
return -1
endmethod
// find slot with same item type that is stackable
public method getItemStackableSlot takes item it returns integer
local integer max
local integer i
local integer iType
if (it == null or GetItemTypeId(it) == 0 or GetItemCharges(it) < 1) then
return -1
endif
set max = .item.size() - 1
set i = 0
set iType = GetItemTypeId(it)
loop
exitwhen (i > max)
if iType == GetItemTypeId(.item[i]) and ItemStack.isStackable(.item[i]) and it != .item[i] then
return i
endif
set i = i + 1
endloop
return -1
endmethod
// stack item until it's used up
public method stackItem takes item it returns boolean
local integer slot
if (GetItemTypeId(it) == 0 or GetItemCharges(it) < 1) then
return false
endif
loop
set slot = .getItemStackableSlot(it)
exitwhen (slot ==-1)
call ItemStack.stackItems(.item[slot], it)
if (GetItemTypeId(it) == 0) then
return true
endif
endloop
return false
endmethod
// adds item at specific slot
public method addItemAtSlot takes item it, integer slot returns boolean
if (slot >= item.size() or slot < 0) then
return false
endif
if (.item[slot] != null) then
call .removeItem(.item[slot])
endif
set .item[slot] = it
// link data to item
if it != null then
set table.integer[GetHandleId(it)] = this
set table.integer[-GetHandleId(it)] = slot
// always hide added items
call SetItemVisible(it, false)
endif
return true
endmethod
// adds item at empty slot
public method addItem takes item it returns boolean
local integer slot = .getFreeSlot()
if (slot != -1) then
return .addItemAtSlot(it, slot)
endif
return false
endmethod
public method removeItem takes item it returns boolean
local integer handleId
local unit u
if (GetItemTypeId(it) == 0 or it == null) then
return false
endif
if .hasItem(it) then
set handleId = GetHandleId(it)
if not IsItemOwned(it) then
// only move items that are somewhere on map,
// else they will be dropped
set u = GetUnitById(this.inventory)
call SetItemVisible(it, true)
call SetItemPosition(it, GetUnitX(u), GetUnitY(u))
set u = null
endif
set .item[table[-handleId]] = null
// unlink data from item
call table.integer.remove(handleId)
call table.integer.remove(-handleId)
return true
endif
return false
endmethod
public method switchItems takes integer slot1, integer slot2 returns boolean
local item it1
local item it2
if slot1 >= item.size() or slot1 < 0 or slot2 >= item.size() or slot2 < 0 then
return false
endif
set it1 = .item[slot1]
set it2 = .item[slot2]
call .removeItem(.item[slot1])
call .removeItem(.item[slot2])
call .addItemAtSlot(it2, slot1)
call .addItemAtSlot(it1, slot2)
set it1 = null
set it2 = null
return true
endmethod
// removes all items from an inventory
public method flush takes nothing returns nothing
local integer i = .item.size() - 1
loop
exitwhen (i < 0)
call .removeItem(.item[i])
set i = i - 1
endloop
endmethod
endstruct
//! runtextmacro DEFINE_STRUCT_VECTOR("", "InventoryVector", "InventoryData")
struct Inventory extends array
readonly InventoryVector inventory
public integer vectorPos // current popsition in vector
public static constant group GROUP = CreateGroup() // all units that use custom inventories
private static constant trigger Handler = CreateTrigger()
public static unit Unit
public static integer InitialCharges
public static item InitialItem
public static integer InitialItemId
public static method register takes boolexpr bx returns triggercondition
return TriggerAddCondition(Handler, bx)
endmethod
public static method unregister takes triggercondition tc returns nothing
call TriggerRemoveCondition(Handler, tc)
endmethod
public method getInventoryAmount takes nothing returns integer
if IsUnitInGroup(GetUnitById(this), GROUP) then
return .inventory.size() - 1
else
return 0
endif
endmethod
public method hasFreeSlot takes nothing returns boolean
local integer i
if IsUnitInGroup(GetUnitById(this), GROUP) then
set i = .getInventoryAmount()
loop
exitwhen (i < 0)
if (.inventory[i].getFreeSlot()!= -1) then
return true
endif
set i = i - 1
endloop
endif
return false
endmethod
// if item is in any inventory
public method hasItem takes item it returns boolean
local integer i
if IsUnitInGroup(GetUnitById(this), GROUP) then
set i = .getInventoryAmount()
loop
exitwhen (i < 0)
if (.inventory[i].hasItem(it)) then
return true
endif
set i = i - 1
endloop
endif
return false
endmethod
// has any inventory a stackable item
public method hasStackableItem takes item it returns boolean
local integer i
if not IsUnitInGroup(GetUnitById(this), GROUP) or GetItemCharges(it) < 1 then
return false
endif
set i = .getInventoryAmount()
loop
exitwhen (i < 0)
if (.inventory[i].getItemStackableSlot(it) != -1) then
return true
endif
set i = i - 1
endloop
return false
endmethod
// stack item with any other items in any inventory
public method stackItem takes item it returns boolean
local integer i
local integer max
if IsUnitInGroup(GetUnitById(this), GROUP) then
set i = 0
set max = .getInventoryAmount()
loop
exitwhen (i > max)
if .inventory[i].stackItem(it) then
return true
else
set i = i + 1
endif
endloop
endif
return false
endmethod
public method addItem takes item it returns boolean
local integer max
local integer i
local integer slot
local unit u = GetUnitById(this)
set Unit = u
set InitialItem = it
set InitialItemId = GetItemTypeId(it)
set InitialCharges = GetItemCharges(it)
if InitialCharges > 0 then
// try to stack with items in current inventory
if UnitInventory.stackItem(u, it) then
call TriggerEvaluate(Handler)
set u = null
return true
endif
// try to stack with items in any inventory
if .stackItem(it) then
call TriggerEvaluate(Handler)
set u = null
return true
endif
endif
// item didn't stack -- try to find a free slot
if UnitHasItem(u, it) then
set slot = UnitInventory.getItemSlot(u, it)
call .inventory[.vectorPos].addItemAtSlot(it, slot)
call TriggerEvaluate(Handler)
set u = null
return true
else
set slot = UnitInventory.getFreeSlot(u)
if(slot != -1) then
if IsUnitInGroup(u, GROUP) then
call .inventory[.vectorPos].addItemAtSlot(it, slot)
endif
call TriggerEvaluate(Handler)
set u = null
return true
endif
endif
// find free slot in any inventory
set i = 0
set max = .getInventoryAmount()
loop
exitwhen i > max
if .inventory[i].addItem(it) then
call TriggerEvaluate(Handler)
set u = null
return true
endif
set i = i + 1
endloop
if (GetItemTypeId(it) != 0) and InitialCharges != GetItemCharges(it) then
// if this runs item was partialy added
call TriggerEvaluate(Handler)
else
// item was not added at all
endif
set u = null
return false
endmethod
// just adds a new inventory to the vector
// "_p" because there is also such a public method to add x inventories
private method addInventory_p takes nothing returns nothing
local InventoryData ID = InventoryData.create()
set ID.Inventory = this
call .inventory.push(ID)
endmethod
public method removeInventory takes integer whichInventory returns boolean
if (whichInventory < 1) or (whichInventory > .getInventoryAmount()) then
return false
endif
call .inventory[whichInventory].flush()
call .inventory[whichInventory].item.destroy()
call .inventory.erase(whichInventory, 1)
// fix current inventory position
if whichInventory == .vectorPos then
set .vectorPos = .vectorPos - 1
endif
return true
endmethod
// clears unit from all inventories
public method flush takes nothing returns boolean
local integer i
if IsUnitInGroup(GetUnitById(this), GROUP) then
set i = getInventoryAmount()
loop
exitwhen (i < 0)
call .inventory[i].flush()
call .inventory[i].item.destroy()
set i = i - 1
endloop
call .inventory.destroy()
call GroupRemoveUnit(GROUP, GetUnitById(this))
set .vectorPos = 0
return true
else
return false
endif
endmethod
private method apply takes nothing returns nothing
set .inventory = InventoryVector.create()
// immediatly create an inventory, so the
// current inventory can be applied
call .addInventory_p()
set .vectorPos = 0
call GroupAddUnit(GROUP, GetUnitById(this))
endmethod
public method setInventoryAmount takes integer amount returns boolean
local integer size
if (GetUnitTypeId(GetUnitById(this)) == 0) then
return false
endif
if (amount < 1) then
return .flush()
endif
if not IsUnitInGroup(GetUnitById(this), GROUP) then
call .apply()
endif
set size = .getInventoryAmount()
if (size == amount) then
return true
endif
if (amount > size) then
// add inventories
loop
exitwhen (size >= amount)
call .addInventory_p()
set size = size + 1
endloop
else
// amount < size
// remove inventories
loop
exitwhen (size <= amount)
call .removeInventory(size)
set size = size - 1
endloop
endif
return true
endmethod
public method addInventory takes integer amount returns boolean
return .setInventoryAmount(.getInventoryAmount() + amount)
endmethod
public static method operator[] takes unit u returns thistype
return GetUnitId(u)
endmethod
private static method onDeindex takes nothing returns boolean
return thistype(GetIndexedUnitId()).flush()
endmethod
private static method onInit takes nothing returns nothing
call OnUnitDeindex(function thistype.onDeindex)
endmethod
endstruct
struct UnitInventory extends array
// finds an other item than "it" in current inventory to stack with
public static method getItemStackableSlot takes unit u, item it returns integer
local integer i
local integer max
local integer iType
local item temp
if (GetItemTypeId(it) == 0 or GetItemCharges(it) < 1) then
return -1
endif
set max = UnitInventorySize(u)
set i = 0
set iType = GetItemTypeId(it)
loop
exitwhen (i >= max)
set temp = UnitItemInSlot(u, i)
if GetItemTypeId(temp) == iType and it != temp and ItemStack.isStackable(temp) then
set temp = null
return i
endif
set i = i + 1
endloop
set temp = null
return -1
endmethod
public static method getFreeSlot takes unit u returns integer
local integer i = 0
local integer max = UnitInventorySize(u)
loop
exitwhen i >= max
if UnitItemInSlot(u, i) == null then
return i
endif
set i = i + 1
endloop
return -1
endmethod
public static method getItemSlot takes unit u, item it returns integer
local integer i = 0
local integer max = UnitInventorySize(u)
loop
exitwhen i >= max
if UnitItemInSlot(u, i) == it then
return i
endif
set i = i + 1
endloop
return -1
endmethod
// tries to stack the item with current inventory until it's used up
public static method stackItem takes unit u, item it returns boolean
local integer slot
if (GetItemTypeId(it) == 0 or GetItemCharges(it) < 1) then
return false
endif
loop
set slot = getItemStackableSlot(u, it)
exitwhen (slot ==-1)
call ItemStack.stackItems(UnitItemInSlot(u, slot), it)
if (GetItemTypeId(it) == 0) then
return true
endif
endloop
return false
endmethod
private static method convertoToInventoryOrderId takes integer orderId returns integer
return (orderId - 852002)
endmethod
public static method operator order_enabled= takes boolean flag returns nothing
set order_enabled_p = flag
endmethod
// just to save some redundancy -- used to clean next function
//! textmacro UNIT_INTERFACE_ON_ORDER_CLEAN
set u = null
set itemTarget = null
set itemOrigin = null
return
//! endtextmacro
private static method onOrder takes nothing returns nothing
local item itemOrigin
local item itemTarget
local integer slot
local integer charges
local integer stackCharges
local integer itemType
local integer slotTarget
local integer slotOrigin
local unit u
local Inventory this
local integer max
local integer i
if order_enabled_p then
set itemOrigin = GetOrderTargetItem()
set itemType = GetItemTypeId(itemOrigin)
set slotTarget = convertoToInventoryOrderId(GetIssuedOrderId())
set u = GetTriggerUnit()
set this = GetUnitId(u)
if (slotTarget > -1 and slotTarget < 6) then
// get slot of item that is moved.
set slotOrigin = 0
loop
exitwhen UnitItemInSlot(u, slotOrigin) == itemOrigin
set slotOrigin = slotOrigin + 1
endloop
set charges = GetItemCharges(itemOrigin)
// potential split
if (slotOrigin == slotTarget) then
if charges > 1 then
// split
// we first abstractly try to split the item,
// so we can stack the split amount with other items
// without even creating a new item
set stackCharges = ItemSplit[itemType]
if (GetItemCharges(itemOrigin) <= stackCharges) then
set stackCharges = 1
endif
call SetItemCharges(itemOrigin, charges - stackCharges)
// try stack with current inventory
loop
set slot = UnitInventory.getItemStackableSlot(u, itemOrigin)
exitwhen (slot == -1)
set itemTarget = UnitItemInSlot(u, slot)
set max = ItemStack[GetItemTypeId(itemTarget)]
if max >= (GetItemCharges(itemTarget) + stackCharges) then
call SetItemCharges(itemTarget, GetItemCharges(itemTarget) + stackCharges)
//! runtextmacro UNIT_INTERFACE_ON_ORDER_CLEAN()
else
set stackCharges = stackCharges - (max - GetItemCharges(itemTarget))
call SetItemCharges(itemTarget, max)
endif
endloop
// try stack with any inventory
if IsUnitInGroup(u, Inventory.GROUP) then
set i = 0
set max = this.getInventoryAmount()
loop
exitwhen i > max
loop
set slot = this.inventory[i].getItemStackableSlot(itemOrigin)
exitwhen (slot == -1)
set itemTarget = this.inventory[i].item[slot]
set max = ItemStack[GetItemTypeId(itemTarget)]
if max >= (GetItemCharges(itemTarget) + stackCharges) then
call SetItemCharges(itemTarget, GetItemCharges(itemTarget) + stackCharges)
//! runtextmacro UNIT_INTERFACE_ON_ORDER_CLEAN()
else
set stackCharges = stackCharges - (max - GetItemCharges(itemTarget))
call SetItemCharges(itemTarget, max)
endif
endloop
set i = i + 1
endloop
endif
// Item didn't stack, or did stack only partialy.
// We create the rest of the split and try to find a free slot
set itemTarget = CreateItem(itemType, GetUnitX(u), GetUnitY(u))
call SetItemCharges(itemTarget, stackCharges)
// in current incentory
set slot = UnitInventory.getFreeSlot(u)
if(slot != -1) then
set pickup_enabled_p = false
call UnitAddItem(u, itemTarget)
set pickup_enabled_p = true
if IsUnitInGroup(u, Inventory.GROUP) then
call this.inventory[this.vectorPos].addItemAtSlot(itemTarget, slot)
endif
//! runtextmacro UNIT_INTERFACE_ON_ORDER_CLEAN()
endif
// find free slot in any inventory
if IsUnitInGroup(u, Inventory.GROUP) then
set i = 0
set max = this.getInventoryAmount()
loop
exitwhen i > max
if this.inventory[i].addItem(itemTarget) then
//! runtextmacro UNIT_INTERFACE_ON_ORDER_CLEAN()
endif
set i = i + 1
endloop
endif
// if this runs, the split was dropped at unit's position
else
// not splitable, do nothing
endif
else
// order was on other slot, try to strack
if not ItemStack.stackItems(itemOrigin, UnitItemInSlot(u, slotTarget)) then
if IsUnitInGroup(u, Inventory.GROUP) then
set drop_enabled = false
call this.inventory[this.vectorPos].switchItems(slotOrigin, slotTarget)
set drop_enabled = true
endif
endif
endif
endif
//! runtextmacro UNIT_INTERFACE_ON_ORDER_CLEAN()
endif
endmethod
public static method operator pickUp_enabled= takes boolean flag returns nothing
set pickup_enabled_p = flag
endmethod
private static method onPickup takes nothing returns nothing
if pickup_enabled_p then
call Inventory[GetTriggerUnit()].addItem(GetManipulatedItem())
endif
endmethod
public static method operator drop_enabled= takes boolean flag returns nothing
set drop_enabled_p = flag
endmethod
// clean from inventory
private static method onDrop takes nothing returns nothing
local item it
if drop_enabled_p then
if IsUnitInGroup(GetTriggerUnit(), Inventory.GROUP) then
set it = GetManipulatedItem()
if InventoryData.isItemOwned(it) then
call InventoryData.getItemVector(it).removeItem(it)
endif
set it = null
endif
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.onPickup)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Bag /* v2.1a -- related: hiveworkshop.com/threads/bag-v1-6-1.252002/
*/ requires /*
*/ Inventory /* hiveworkshop.com/threads/bag-v1-6-1.252002/
Information
¯¯¯¯¯¯¯¯¯¯¯
Extenstion library to "Inventory".
It allows units the usage of the Bag Abilty,
and handles all kind of item drop and pickup internaly with using the Inventor's API.
Mechanics
¯¯¯¯¯¯¯¯¯¯
Items registered in Inventory are hidden by default.
The Bag library switches between the current items inside the unit inventory,
and the hidden items from Inventory, depending on the usage of the Bag ability.
Importing
¯¯¯¯¯¯¯¯¯¯
Copy the bag ability to your map.
Ensure that ABILITY_ID (directly after API docu) hold the bag's rawcode.
*/
// --- API ---
//! novjass
struct Bag
// Functions to handle bags. (The bag ability will be added/removed automaticaly)
static method getBagAmount takes unit u returns integer
static method setBagAmount takes unit u, integer amount returns boolean
static method addBag takes unit u, integer amount returns nothing
static method getCurrentBag takes unit u returns integer
static method setCurrentBag takes unit u, integer whichBag returns boolean
static method removeBag takes unit u, integer whichBag returns boolean
// Functions to handle inventory.
static method getItem takes unit u, integer whichBag, integer whichSlot returns item
static method setItem takes unit u, item it, integer whichBag, integer whichSlot returns boolean
static method removeItem takes unit u, integer whichBag, item it returns boolean
// The size of a bag equals the "UnitInventorySize()" of the unit when registered.
// You can registder code that runs when a unit uses bag ability.
static method register takes boolexpr bx returns triggercondition
static method unregister takes triggercondition tc returns nothing
//inside the code refer to:
static unit Unit
//! endnovjass
// ==== End API ====
struct Bag extends array
private static constant integer ABILITY_ID = 'A000'
private static constant trigger Handler = CreateTrigger()
public static unit Unit
public static method register takes boolexpr bx returns triggercondition
return TriggerAddCondition(Handler, bx)
endmethod
public static method unregister takes triggercondition tc returns nothing
call TriggerRemoveCondition(Handler, tc)
endmethod
public static method getBagAmount takes unit u returns integer
return Inventory[u].getInventoryAmount()
endmethod
public static method setBagAmount takes unit u, integer amount returns boolean
local Inventory this
local integer size = getBagAmount(u)
local integer i
local boolean initCurrentBag
if amount == size then
return true
endif
set this = GetUnitId(u)
set initCurrentBag = false
if amount < 1 then
if size < 1 then
return true
endif
// Remove all bags from unit
if getCurrentBag(u) != 0 then
call setCurrentBag(u, 0)
set Unit = u
call TriggerEvaluate(Handler)
endif
call UnitRemoveAbility(u, ABILITY_ID)
return Inventory[u].flush()
endif
if size > 0 then
// Remove some bags from unit
if amount < size then
if amount < getCurrentBag(u) then
call setCurrentBag(u, amount)
set Unit = u
call TriggerEvaluate(Handler)
endif
loop
exitwhen amount >= size
call Inventory[u].removeInventory(size)
set size = size - 1
endloop
endif
else
set initCurrentBag = UnitAddAbility(u, ABILITY_ID)
endif
call Inventory[u].setInventoryAmount(amount)
loop
exitwhen size > amount
call this.inventory[size].init(5)
set size = size + 1
endloop
if initCurrentBag then
// apply current inventory to first bag
set size = UnitInventorySize(u)
loop
exitwhen size < 0
call this.inventory[0].addItemAtSlot(UnitItemInSlot(u, size), size)
set size = size - 1
endloop
endif
return true
endmethod
public static method addBag takes unit u, integer amount returns nothing
call setBagAmount(u, getBagAmount(u) + amount)
endmethod
private static constant integer SLOT_OFFSET = 852002
private static method openInventory takes unit u, integer vectorPos returns nothing
local Inventory this = GetUnitId(u)
local integer i = this.inventory[vectorPos].item.size() - 1
local item it
set UnitInventory.pickUp_enabled = false
set UnitInventory.order_enabled = false
loop
exitwhen i < 0
set it = this.inventory[vectorPos].item[i]
if it != null then
call SetItemVisible(it, true)
call UnitAddItem(u, it)
// For safety, move item to wanted slot
call IssueTargetOrderById(u, SLOT_OFFSET + i, it)
endif
set it = null
set i = i - 1
endloop
set UnitInventory.pickUp_enabled = true
set UnitInventory.order_enabled = true
set it = null
endmethod
private static method dropCurrentInventory takes unit u returns nothing
local integer i = UnitInventorySize(u)
local item it
set UnitInventory.drop_enabled = false
loop
exitwhen i < 0
set it = UnitItemInSlot(u, i)
if (it != null) then
call UnitRemoveItem(u, it)
call SetItemVisible(it, false)
endif
set i = i - 1
endloop
set UnitInventory.drop_enabled = true
endmethod
public static method getCurrentBag takes unit u returns integer
if getBagAmount(u) == 0 then
return -1
else
return Inventory[u].vectorPos
endif
endmethod
public static method setCurrentBag takes unit u, integer whichBag returns boolean
if (getBagAmount(u) == 0 or (not UnitAlive(u)) or (whichBag > getBagAmount(u)) )then
return false
endif
if (whichBag == getCurrentBag(u) ) then
return true
endif
call dropCurrentInventory(u)
set Inventory[u].vectorPos = whichBag
call openInventory(u, whichBag)
return true
endmethod
private static method onCast takes nothing returns nothing
local unit u
if (GetSpellAbilityId() == ABILITY_ID) then
set u = GetTriggerUnit()
if getCurrentBag(u) == getBagAmount(u) then
// open 1st bag
call setCurrentBag(u, 0)
else
// open next bag
call setCurrentBag(u, getCurrentBag(u) + 1)
endif
set Unit = u
call TriggerEvaluate(Handler)
endif
set u = null
endmethod
public static method removeBag takes unit u, integer whichBag returns boolean
return Inventory[u].removeInventory(whichBag)
endmethod
public static method getItem takes unit u, integer whichBag, integer whichSlot returns item
return Inventory[u].inventory[whichBag].item[whichSlot]
endmethod
public static method removeItem takes unit u, integer whichBag, item it returns boolean
return Inventory[u].inventory[whichBag].removeItem(it)
endmethod
public static method setItem takes unit u, item it, integer whichBag, integer whichSlot returns boolean
return Inventory[u].inventory[whichBag].addItemAtSlot(it, whichSlot)
endmethod
private static method onInit takes nothing returns nothing
//call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function thistype.onCast)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library FullInventory /* v1.1a -- related: hiveworkshop.com/threads/bag-v1-6-1.252002/
*/ requires /*
*/ Inventory /* hiveworkshop.com/threads/bag-v1-6-1.252002/
*/ OrderType /* hiveworkshop.com/threads/ordertype.291223/
*/ TimerUtils /* Vexorian -- wc3c.net/showthread.php?t=101322
Information
¯¯¯¯¯¯¯¯¯¯¯
Extenstion library to "Inventory".
It allows to pickup/stack items with having full inventory.
The default wc3 mechnaics don't allow picking up items with full inventory.
Mechanics
¯¯¯¯¯¯¯¯¯¯
When a unit gets a move/smart order towards an item, and at same time
it has full inventory, the unit would stop with error "Full Inventory".
The system ignores this error, and orders the unit to move to x/y of wanted item,
so it looks like the unit accpeted the first order. When the unit is close enough
of the target item, the system will emulate a possible pickup/stacking with the item.
ATTENTION.
The default wc3 mechanis will play an eror sound and display a error message,
when a unit tries to pickup an item with full inventory.
You easily can disable both.
GameInterface -> Text-Message-FullInventory -> Shift-double click it, and write in a space character.
GameInterface -> Sound-FullInventory -> Shift-double click it, and write in a space character.
*/
// API -- You can registder code that runs when a unit tries to add an item to a full inventory.
//! novjass
struct FullInventory
static method register takes boolexpr bx returns triggercondition
static method unregister takes triggercondition tc returns nothing
//inside the code refer to:
static unit Unit
//! endnovjass
// ==== End API ====
struct FullInventory extends array
// set this to something close to the value inside your gameplay constants
private static constant real PICKUP_RANGE = 120.
// ============================================================== //
private unit whichUnit
private item whichItem
private real x
private real y
private timer clock
private static constant trigger Handler = CreateTrigger()
public static unit Unit
public static method register takes boolexpr bx returns triggercondition
return TriggerAddCondition(Handler, bx)
endmethod
public static method unregister takes triggercondition tc returns nothing
call TriggerRemoveCondition(Handler, tc)
endmethod
private method destroy takes nothing returns nothing
if IsUnitInGroup(.whichUnit, GROUP) then
call GroupRemoveUnit(GROUP, .whichUnit)
call ReleaseTimer(.clock)
set .whichItem = null
set .whichUnit = null
endif
endmethod
// check if item is still available to be picked up
private static method itemValidate takes item it returns boolean
return GetItemTypeId(it) != 0 and IsItemVisible(it) and not IsItemOwned(it)
endmethod
// callback perodicly checks distance from unit and item, and then adds to inventory
private static constant real INTERVAL = 0.1
private static method callback takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if (itemValidate(.whichItem)) then
if (IsUnitInRangeXY(.whichUnit, .x, .y, PICKUP_RANGE)) then
// double check with the current x/y of the item, to ensure the item wasn't moved somewhere else, however
if IsUnitInRangeXY(.whichUnit, GetItemX(.whichItem), GetItemY(.whichItem), PICKUP_RANGE + 1) then
call Inventory[.whichUnit].addItem(.whichItem)
endif
set cancel_enabled_p = false
call IssueImmediateOrderById(.whichUnit, ORDER_stop)
set cancel_enabled_p = true
call .destroy()
endif
else
set cancel_enabled_p = false
call IssueImmediateOrderById(.whichUnit, ORDER_stop)
set cancel_enabled_p = true
call .destroy()
endif
endmethod
// start periodic callback
private static constant group GROUP = CreateGroup()
private static method create takes unit u, item it returns thistype
local thistype this = GetUnitId(u)
set .whichUnit = u
set .whichItem = it
set .x = GetItemX(it)
set .y = GetItemY(it)
set cancel_enabled_p = false
call IssuePointOrderById(u, ORDER_move, .x, .y)
set cancel_enabled_p = true
if not IsUnitInGroup(u, GROUP) then
set .clock = NewTimerEx(this)
call TimerStart(.clock, INTERVAL, true, function thistype.callback)
call GroupAddUnit(GROUP, u)
endif
return this
endmethod
// kein patrol, no
private static method isMoveOrder takes integer orderId returns boolean
return orderId == ORDER_smart or orderId == ORDER_move
endmethod
// onTargetOrder actually
private static method onOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
local item it = GetOrderTargetItem()
if it != null and isMoveOrder(GetIssuedOrderId()) and (UnitInventory.getFreeSlot(u) == -1) then
// order was on item, and inventory is full
if (it != thistype(GetUnitId(u)).whichItem) then
if IsUnitInGroup(u, Inventory.GROUP) then
if (Inventory[u].hasFreeSlot() or Inventory[u].hasStackableItem(it)) then
// start callback
call create(u, it)
else
set Unit = u
call TriggerEvaluate(Handler)
endif
elseif (UnitInventory.getItemStackableSlot(u, it) != -1) then
// start callback
call create(u, it)
else
set Unit = u
call TriggerEvaluate(Handler)
endif
else
// targeted same item, do nothing
// actually we must order unit to move again,
// because by default it would stop, as it received a move order on an item with having ful inventory
set cancel_enabled_p = false
call IssuePointOrderById(u, ORDER_move, GetItemX(it), GetItemY(it))
set cancel_enabled_p = true
endif
elseif IsUnitInGroup(u, GROUP) then
// targeted something different, stop callback
call thistype(GetUnitId(u)).destroy()
endif
set u = null
set it = null
endmethod
/*
onCancel will cancel the periodic check for any new no-target, or point-orders the unit gets
because then, the unit obviously doesn't wanna pick up the item anymore.
problem:
The problem is that the unit has currently a "move" order onto a point,
instead of a default itemTarget-order.
So, when a Queue-Order like Avatar finished, then it will automaticaly order this normal move-point order again.
The problem is, by nature we don't trust move orders, and usually cancel the periodic check.
So the trick is, after we ordered a Queue-Order, we allow the same unit to make ONE move order,
and if the move order is exactly the same as the old, means same x/y and onto a point, then we allow it.
We also make a item validation check, to check if item visible at that very position, and pickable.
These together hopefully ensure not to fail.
*/
private static boolean cancel_enabled_p = true
private boolean dirtyTrick
private static method onCancel takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer orderId = GetIssuedOrderId()
local thistype this
if IsUnitInGroup(u, GROUP) and cancel_enabled_p and OrderType[orderId] != OrderType.INSTANT then
set this = thistype(GetUnitId(u))
if OrderType[orderId] == OrderType.QUEUE then
set .dirtyTrick = true
elseif not .dirtyTrick or not (orderId == ORDER_move) or not (GetOrderPointX() == .x) or not (GetOrderPointY() == .y) and itemValidate(.whichItem) then
set .dirtyTrick = false
call .destroy()
endif
endif
set u = null
endmethod
private static method onDeindex takes nothing returns boolean
if IsUnitInGroup(GetIndexedUnit(), GROUP) then
call thistype(GetUnitId(GetIndexedUnit())).destroy()
endif
return false
endmethod
private static method onInit takes nothing returns nothing
//call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onCancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onCancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onCancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onCancel)
call OnUnitDeindex(function thistype.onDeindex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
module ItemStackConfig /* v1.0a -- related: hiveworkshop.com/threads/bag-v1-6-1.252002/
If no specific limit is defined the DEFAULT_STACK_LIMIT will be applied.
*/
public static constant integer DEFAULT_STACK_LIMIT = 3
//! novjass
struct ItemStack
static method operator [] takes integer itemType returns integer
// returns stack limit for this item type
static method exists takes integer itemType returns boolean
// returns if a stack limit was defined
static method SetStackLimit takes integer itemType, integer limit returns nothing
// only here in this onInit allowed to be used
//! endnovjass
private static method onInit takes nothing returns nothing
// Example for big healing potion:
// call SetStackLimit('pghe', 4)
call SetStackLimit('pghe', 4)
endmethod
endmodule
//TESH.scrollpos=0
//TESH.alwaysfold=0
module ItemSplitConfig /* v1.0a -- related: hiveworkshop.com/threads/bag-v1-6-1.252002/
If no specific limit is defined the default split amount will be "1".
Also, if the item does have less stacks than the defined amount it will also result in an "1" amount split.
*/
//! novjass
struct ItemSplit
static method operator [] takes integer itemType returns integer
// returns split amount for this item type
static method exists takes integer itemType returns boolean
// returns if a split amount was defined
static method SetSplitAmount takes integer itemType, integer amount returns nothing
// only here in this onInit allowed to be used
//! endnovjass
private static method onInit takes nothing returns nothing
// Example for big healing potion:
//call SetSplitAmount('pghe', 2)
call SetSplitAmount('pghe', 2)
endmethod
endmodule
//TESH.scrollpos=25
//TESH.alwaysfold=0
library OrderType /* v0.1 hiveworkshop.com/threads/ordertype.291223/
Can be used to get destinguish "no target" orders.
Other types are not really supported (yet?).
*/ requires /*
*/ OrderIds /* hiveworkshop.com/threads/orders-repo.290882/
related:
OrderTypes: hiveworkshop.com/threads/snippet-order-types.169593/
^This "OrderTypes" library can be used for getting UNIT_TARGET, POINT_TARGET, and UNIT_POINT_TARGET.
*/
// ========== API ==========
//! novjass
struct OrderType
constant integer INSTANT // Real instant orders.
constant integer QUEUE // Not instant orders, but they will
// queue orders like move/attack/smart after finished.
// All spell orders, though, like channeling will
// be interrupted, and won't continue.
// example orders: bearform/metamorphosis
// Getters
static method operator[] takes integer orderId returns integer
static method GetType takes integer orderId returns integer
// Example
if OrderType[GetSpellAbilityId()] == OrderType.INSTANT then
// innstant order
endif
//! endnovjass
// ========== END API ==========
globals
private constant integer OFFSET = 851900
endglobals
struct OrderType extends array
// used
public static constant integer INSTANT = 1
public static constant integer QUEUE = 2
// not used
private static constant integer UNIT_TARGET = 3
private static constant integer POINT_TARGET = 4
private static constant integer UNIT_POINT_TARGET = 5
private static integer array Data
public static method operator[] takes integer orderId returns integer
return Data[orderId - OFFSET]
endmethod
public static method GetType takes integer orderId returns integer
return Data[orderId - OFFSET]
endmethod
private static method onInit takes nothing returns nothing
if (GetExpiredTimer() == null) then
call TimerStart(CreateTimer(), 0, false, function thistype.onInit)
return
endif
/*
==== no target - instant ====
*/
set Data[ORDER_berserk - OFFSET] = INSTANT
set Data[ORDER_defend - OFFSET] = INSTANT
set Data[ORDER_undefend - OFFSET] = INSTANT
set Data[ORDER_divineshield - OFFSET] = INSTANT
set Data[ORDER_undivineshield - OFFSET] = INSTANT
set Data[ORDER_windwalk - OFFSET] = INSTANT
set Data[ORDER_unwindwalk - OFFSET] = INSTANT
set Data[ORDER_manashieldon - OFFSET] = INSTANT
set Data[ORDER_manashieldoff - OFFSET] = INSTANT
set Data[ORDER_autodispel - OFFSET] = INSTANT
set Data[ORDER_autodispeloff - OFFSET] = INSTANT
set Data[ORDER_immolation - OFFSET] = INSTANT
set Data[ORDER_unimmolation - OFFSET] = INSTANT
set Data[ORDER_barkskinon - OFFSET] = INSTANT
set Data[ORDER_barkskinoff - OFFSET] = INSTANT
set Data[ORDER_blackarrowon - OFFSET] = INSTANT
set Data[ORDER_blackarrowoff - OFFSET] = INSTANT
set Data[ORDER_bloodluston - OFFSET] = INSTANT
set Data[ORDER_bloodlustoff - OFFSET] = INSTANT
set Data[ORDER_carrionscarabsinstant - OFFSET] = INSTANT //?
set Data[ORDER_carrionscarabson - OFFSET] = INSTANT
set Data[ORDER_carrionscarabsoff - OFFSET] = INSTANT
set Data[ORDER_creephealon - OFFSET] = INSTANT
set Data[ORDER_creephealoff - OFFSET] = INSTANT
set Data[ORDER_ensnareon - OFFSET] = INSTANT
set Data[ORDER_ensnareoff - OFFSET] = INSTANT
set Data[ORDER_faeriefireon - OFFSET] = INSTANT
set Data[ORDER_faeriefireoff - OFFSET] = INSTANT
set Data[ORDER_flamingarrows - OFFSET] = INSTANT
set Data[ORDER_unflamingarrows - OFFSET] = INSTANT
set Data[ORDER_flamingattack - OFFSET] = INSTANT
set Data[ORDER_unflamingattack - OFFSET] = INSTANT
set Data[ORDER_frenzyon - OFFSET] = INSTANT
set Data[ORDER_frenzyoff - OFFSET] = INSTANT
set Data[ORDER_frostarmoron - OFFSET] = INSTANT
set Data[ORDER_frostarmoroff - OFFSET] = INSTANT
set Data[ORDER_healoff - OFFSET] = INSTANT
set Data[ORDER_healon - OFFSET] = INSTANT
set Data[ORDER_incineratearrowoff - OFFSET] = INSTANT
set Data[ORDER_incineratearrowon - OFFSET] = INSTANT
set Data[ORDER_innerfireon - OFFSET] = INSTANT
set Data[ORDER_innerfireoff - OFFSET] = INSTANT
set Data[ORDER_instant - OFFSET] = INSTANT //?
set Data[ORDER_manaflareon - OFFSET] = INSTANT
set Data[ORDER_manaflareoff - OFFSET] = INSTANT
set Data[ORDER_parasiteon - OFFSET] = INSTANT
set Data[ORDER_parasiteoff - OFFSET] = INSTANT
set Data[ORDER_phaseshiftinstant - OFFSET] = INSTANT //?
set Data[ORDER_phaseshiftoff - OFFSET] = INSTANT
set Data[ORDER_phaseshifton - OFFSET] = INSTANT
set Data[ORDER_raisedeadon - OFFSET] = INSTANT
set Data[ORDER_raisedeadoff - OFFSET] = INSTANT
set Data[ORDER_rechargeon - OFFSET] = INSTANT
set Data[ORDER_rechargeoff - OFFSET] = INSTANT
set Data[ORDER_renewon - OFFSET] = INSTANT
set Data[ORDER_renewoff - OFFSET] = INSTANT
set Data[ORDER_repairon - OFFSET] = INSTANT
set Data[ORDER_repairoff - OFFSET] = INSTANT
set Data[ORDER_replenishlifeon - OFFSET] = INSTANT
set Data[ORDER_replenishlifeoff - OFFSET] = INSTANT
set Data[ORDER_replenishon - OFFSET] = INSTANT
set Data[ORDER_replenishoff - OFFSET] = INSTANT
set Data[ORDER_restorationon - OFFSET] = INSTANT
set Data[ORDER_restorationoff - OFFSET] = INSTANT
set Data[ORDER_selfdestructon - OFFSET] = INSTANT
set Data[ORDER_selfdestructoff - OFFSET] = INSTANT
set Data[ORDER_slowon - OFFSET] = INSTANT
set Data[ORDER_slowoff - OFFSET] = INSTANT
set Data[ORDER_spellstealon - OFFSET] = INSTANT
set Data[ORDER_spellstealoff - OFFSET] = INSTANT
set Data[ORDER_poisonarrows - OFFSET] = INSTANT
set Data[ORDER_unpoisonarrows - OFFSET] = INSTANT
set Data[ORDER_vengeanceoff - OFFSET] = INSTANT
set Data[ORDER_vengeanceon - OFFSET] = INSTANT
set Data[ORDER_webon - OFFSET] = INSTANT
set Data[ORDER_weboff - OFFSET] = INSTANT
set Data[ORDER_whirlwind - OFFSET] = INSTANT
set Data[ORDER_moveslot1 - OFFSET] = INSTANT
set Data[ORDER_moveslot2 - OFFSET] = INSTANT
set Data[ORDER_moveslot3 - OFFSET] = INSTANT
set Data[ORDER_moveslot4 - OFFSET] = INSTANT
set Data[ORDER_moveslot5 - OFFSET] = INSTANT
set Data[ORDER_moveslot6 - OFFSET] = INSTANT
set Data[ORDER_useslot1 - OFFSET] = INSTANT
set Data[ORDER_useslot2 - OFFSET] = INSTANT
set Data[ORDER_useslot3 - OFFSET] = INSTANT
set Data[ORDER_useslot4 - OFFSET] = INSTANT
set Data[ORDER_useslot5 - OFFSET] = INSTANT
set Data[ORDER_useslot6 - OFFSET] = INSTANT
// ????
set Data[ORDER_instant1 - OFFSET] = INSTANT
set Data[ORDER_instant2 - OFFSET] = INSTANT
set Data[ORDER_instant3 - OFFSET] = INSTANT
set Data[ORDER_instant4 - OFFSET] = INSTANT
/*
==== no target - queue ====
*/
set Data[ORDER_avatar - OFFSET] = QUEUE
set Data[ORDER_unavatar - OFFSET] = QUEUE
set Data[ORDER_battleroar - OFFSET] = QUEUE
set Data[ORDER_bearform - OFFSET] = QUEUE
set Data[ORDER_unbearform - OFFSET] = QUEUE
set Data[ORDER_etherealform - OFFSET] = QUEUE
set Data[ORDER_unetherealform - OFFSET] = QUEUE
set Data[ORDER_metamorphosis - OFFSET] = QUEUE
set Data[ORDER_ravenform - OFFSET] = QUEUE
set Data[ORDER_unravenform - OFFSET] = QUEUE
set Data[ORDER_roar - OFFSET] = QUEUE
set Data[ORDER_robogoblin - OFFSET] = QUEUE
set Data[ORDER_unrobogoblin - OFFSET] = QUEUE
set Data[ORDER_stoneform - OFFSET] = QUEUE
set Data[ORDER_unstoneform - OFFSET] = QUEUE
set Data[ORDER_stomp - OFFSET] = QUEUE
set Data[ORDER_thunderclap - OFFSET] = QUEUE
endmethod
endstruct
endlibrary
//TESH.scrollpos=160
//TESH.alwaysfold=0
library OrderIds //v1.0 hiveworkshop.com/threads/orders-repo.290882/
globals
constant integer ORDER_wandillusion=852274
constant integer ORDER_absorb=852529
constant integer ORDER_acidbomb=852662
constant integer ORDER_acolyteharvest=852185
constant integer ORDER_AImove=851988
constant integer ORDER_ambush=852131
constant integer ORDER_ancestralspirit=852490
constant integer ORDER_ancestralspirittarget=852491
constant integer ORDER_animatedead=852217
constant integer ORDER_antimagicshell=852186
constant integer ORDER_attack=851983
constant integer ORDER_attackground=851984
constant integer ORDER_attackonce=851985
constant integer ORDER_attributemodskill=852576
constant integer ORDER_auraunholy=852215
constant integer ORDER_auravampiric=852216
constant integer ORDER_autodispel=852132
constant integer ORDER_autodispeloff=852134
constant integer ORDER_autodispelon=852133
constant integer ORDER_autoentangle=852505
constant integer ORDER_autoentangleinstant=852506
constant integer ORDER_autoharvestgold=852021
constant integer ORDER_autoharvestlumber=852022
constant integer ORDER_avatar=852086
constant integer ORDER_avengerform=852531
constant integer ORDER_awaken=852466
constant integer ORDER_banish=852486
constant integer ORDER_barkskin=852135
constant integer ORDER_barkskinoff=852137
constant integer ORDER_barkskinon=852136
constant integer ORDER_battleroar=852099
constant integer ORDER_battlestations=852099
constant integer ORDER_bearform=852138
constant integer ORDER_berserk=852100
constant integer ORDER_blackarrow=852577
constant integer ORDER_blackarrowoff=852579
constant integer ORDER_blackarrowon=852578
constant integer ORDER_blight=852187
constant integer ORDER_blink=852525
constant integer ORDER_blizzard=852089
constant integer ORDER_bloodlust=852101
constant integer ORDER_bloodlustoff=852103
constant integer ORDER_bloodluston=852102
constant integer ORDER_board=852043
constant integer ORDER_breathoffire=852580
constant integer ORDER_breathoffrost=852560
constant integer ORDER_build=851994
constant integer ORDER_burrow=852533
constant integer ORDER_cannibalize=852188
constant integer ORDER_carrionscarabs=852551
constant integer ORDER_carrionscarabsinstant=852554
constant integer ORDER_carrionscarabsoff=852553
constant integer ORDER_carrionscarabson=852552
constant integer ORDER_carrionswarm=852218
constant integer ORDER_chainlightning=852119
constant integer ORDER_channel=852600
constant integer ORDER_charm=852581
constant integer ORDER_chemicalrage=852663
constant integer ORDER_cloudoffog=852473
constant integer ORDER_clusterrockets=852652
constant integer ORDER_coldarrows=852244
constant integer ORDER_coldarrowstarg=852243
constant integer ORDER_controlmagic=852474
constant integer ORDER_corporealform=852493
constant integer ORDER_corrosivebreath=852140
constant integer ORDER_coupleinstant=852508
constant integer ORDER_coupletarget=852507
constant integer ORDER_creepanimatedead=852246
constant integer ORDER_creepdevour=852247
constant integer ORDER_creepheal=852248
constant integer ORDER_creephealoff=852250
constant integer ORDER_creephealon=852249
constant integer ORDER_creepthunderbolt=852252
constant integer ORDER_creepthunderclap=852253
constant integer ORDER_cripple=852189
constant integer ORDER_curse=852190
constant integer ORDER_curseoff=852192
constant integer ORDER_curseon=852191
constant integer ORDER_cyclone=852144
constant integer ORDER_darkconversion=852228
constant integer ORDER_darkportal=852229
constant integer ORDER_darkritual=852219
constant integer ORDER_darksummoning=852220
constant integer ORDER_deathanddecay=852221
constant integer ORDER_deathcoil=852222
constant integer ORDER_deathpact=852223
constant integer ORDER_decouple=852509
constant integer ORDER_defend=852055
constant integer ORDER_detectaoe=852015
constant integer ORDER_detonate=852145
constant integer ORDER_devour=852104
constant integer ORDER_devourmagic=852536
constant integer ORDER_disassociate=852240
constant integer ORDER_disenchant=852495
constant integer ORDER_dismount=852470
constant integer ORDER_dispel=852057
constant integer ORDER_divineshield=852090
constant integer ORDER_doom=852583
constant integer ORDER_drain=852487
constant integer ORDER_dreadlordinferno=852224
constant integer ORDER_dropitem=852001
constant integer ORDER_drunkenhaze=852585
constant integer ORDER_earthquake=852121
constant integer ORDER_eattree=852146
constant integer ORDER_elementalfury=852586
constant integer ORDER_ensnare=852106
constant integer ORDER_ensnareoff=852108
constant integer ORDER_ensnareon=852107
constant integer ORDER_entangle=852147
constant integer ORDER_entangleinstant=852148
constant integer ORDER_entanglingroots=852171
constant integer ORDER_etherealform=852496
constant integer ORDER_evileye=852105
constant integer ORDER_faeriefire=852149
constant integer ORDER_faeriefireoff=852151
constant integer ORDER_faeriefireon=852150
constant integer ORDER_fanofknives=852526
constant integer ORDER_farsight=852122
constant integer ORDER_fingerofdeath=852230
constant integer ORDER_firebolt=852231
constant integer ORDER_flamestrike=852488
constant integer ORDER_flamingarrows=852174
constant integer ORDER_flamingarrowstarg=852173
constant integer ORDER_flamingattack=852540
constant integer ORDER_flamingattacktarg=852539
constant integer ORDER_flare=852060
constant integer ORDER_forceboard=852044
constant integer ORDER_forceofnature=852176
constant integer ORDER_forkedlightning=852586
constant integer ORDER_freezingbreath=852195
constant integer ORDER_frenzy=852561
constant integer ORDER_frenzyoff=852563
constant integer ORDER_frenzyon=852562
constant integer ORDER_frostarmor=852225
constant integer ORDER_frostarmoroff=852459
constant integer ORDER_frostarmoron=852458
constant integer ORDER_frostnova=852226
constant integer ORDER_getitem=851981
constant integer ORDER_gold2lumber=852233
constant integer ORDER_grabtree=852511
constant integer ORDER_harvest=852018
constant integer ORDER_heal=852063
constant integer ORDER_healingspray=852664
constant integer ORDER_healingward=852109
constant integer ORDER_healingwave=852501
constant integer ORDER_healoff=852065
constant integer ORDER_healon=852064
constant integer ORDER_hex=852502
constant integer ORDER_holdposition=851993
constant integer ORDER_holybolt=852092
constant integer ORDER_howlofterror=852588
constant integer ORDER_humanbuild=851995
constant integer ORDER_immolation=852177
constant integer ORDER_impale=852555
constant integer ORDER_incineratearrow=852670
constant integer ORDER_incineratearrowoff=852672
constant integer ORDER_incineratearrowon=852671
constant integer ORDER_inferno=852232
constant integer ORDER_innerfire=852066
constant integer ORDER_innerfireoff=852068
constant integer ORDER_innerfireon=852067
constant integer ORDER_instant=852200
constant integer ORDER_invisibility=852069
constant integer ORDER_lavamonster=852667
constant integer ORDER_lightningshield=852110
constant integer ORDER_load=852046
constant integer ORDER_loadarcher = 852142
constant integer ORDER_loadcorpse=852050
constant integer ORDER_loadcorpseinstant=852053
constant integer ORDER_locustswarm=852556
constant integer ORDER_lumber2gold=852234
constant integer ORDER_magicdefense=852478
constant integer ORDER_magicleash=852480
constant integer ORDER_magicundefense=852479
constant integer ORDER_manaburn=852179
constant integer ORDER_manaflareoff=852513
constant integer ORDER_manaflareon=852512
constant integer ORDER_manashieldoff=852590
constant integer ORDER_manashieldon=852589
constant integer ORDER_massteleport=852093
constant integer ORDER_mechanicalcritter=852564
constant integer ORDER_metamorphosis=852180
constant integer ORDER_militia=852072
constant integer ORDER_militiaconvert=852071
constant integer ORDER_militiaoff=852073
constant integer ORDER_militiaunconvert=852651
constant integer ORDER_mindrot=852565
constant integer ORDER_mirrorimage=852123
constant integer ORDER_monsoon=852591
constant integer ORDER_mount=852469
constant integer ORDER_mounthippogryph=852143
constant integer ORDER_move=851986
constant integer ORDER_nagabuild=852467
constant integer ORDER_neutraldetectaoe=852023
constant integer ORDER_neutralinteract=852566
constant integer ORDER_neutralspell=852630
constant integer ORDER_nightelfbuild=851997
constant integer ORDER_orcbuild=851996
constant integer ORDER_parasite=852601
constant integer ORDER_parasiteoff=852603
constant integer ORDER_parasiteon=852602
constant integer ORDER_patrol=851990
constant integer ORDER_phaseshift=852514
constant integer ORDER_phaseshiftinstant=852517
constant integer ORDER_phaseshiftoff=852516
constant integer ORDER_phaseshifton=852515
constant integer ORDER_phoenixfire=852481
constant integer ORDER_phoenixmorph=852482
constant integer ORDER_poisonarrows=852255
constant integer ORDER_poisonarrowstarg=852254
constant integer ORDER_polymorph=852074
constant integer ORDER_possession=852196
constant integer ORDER_preservation=852568
constant integer ORDER_purge=852111
constant integer ORDER_rainofchaos=852237
constant integer ORDER_rainoffire=852238
constant integer ORDER_raisedead=852197
constant integer ORDER_raisedeadoff=852199
constant integer ORDER_raisedeadon=852198
constant integer ORDER_ravenform=852155
constant integer ORDER_recharge=852157
constant integer ORDER_rechargeoff=852159
constant integer ORDER_rechargeon=852158
constant integer ORDER_rejuvination=852160
constant integer ORDER_renew=852161
constant integer ORDER_renewoff=852163
constant integer ORDER_renewon=852162
constant integer ORDER_repair=852024
constant integer ORDER_repairoff=852026
constant integer ORDER_repairon=852025
constant integer ORDER_replenish=852542
constant integer ORDER_replenishlife=852545
constant integer ORDER_replenishlifeoff=852547
constant integer ORDER_replenishlifeon=852546
constant integer ORDER_replenishmana=852548
constant integer ORDER_replenishmanaoff=852550
constant integer ORDER_replenishmanaon=852549
constant integer ORDER_replenishoff=852544
constant integer ORDER_replenishon=852543
constant integer ORDER_request_hero=852239
constant integer ORDER_requestsacrifice=852201
constant integer ORDER_restoration=852202
constant integer ORDER_restorationoff=852204
constant integer ORDER_restorationon=852203
constant integer ORDER_resumebuild=851999
constant integer ORDER_resumeharvesting=852017
constant integer ORDER_resurrection=852094
constant integer ORDER_returnresources=852020
constant integer ORDER_revenge=852241
constant integer ORDER_revive=852039
constant integer ORDER_roar=852164
constant integer ORDER_robogoblin=852656
constant integer ORDER_root=852165
constant integer ORDER_sacrifice=852205
constant integer ORDER_sanctuary=852569
constant integer ORDER_scout=852181
constant integer ORDER_selfdestruct=852040
constant integer ORDER_selfdestructoff=852042
constant integer ORDER_selfdestructon=852041
constant integer ORDER_sentinel=852182
constant integer ORDER_setrally=851980
constant integer ORDER_shadowsight=852570
constant integer ORDER_shadowstrike=852527
constant integer ORDER_shockwave=852125
constant integer ORDER_silence=852592
constant integer ORDER_sleep=852227
constant integer ORDER_slow=852075
constant integer ORDER_slowoff=852077
constant integer ORDER_slowon=852076
constant integer ORDER_smart=851971
constant integer ORDER_soulburn=852668
constant integer ORDER_soulpreservation=852242
constant integer ORDER_spellshield=852571
constant integer ORDER_spellshieldaoe=852572
constant integer ORDER_spellsteal=852483
constant integer ORDER_spellstealoff=852485
constant integer ORDER_spellstealon=852484
constant integer ORDER_spies=852235
constant integer ORDER_spiritlink=852499
constant integer ORDER_spiritofvengeance=852528
constant integer ORDER_spirittroll=852573
constant integer ORDER_spiritwolf=852126
constant integer ORDER_stampede=852593
constant integer ORDER_standdown=852113
constant integer ORDER_starfall=852183
constant integer ORDER_stasistrap=852114
constant integer ORDER_steal=852574
constant integer ORDER_stomp=852127
constant integer ORDER_stoneform=852206
constant integer ORDER_stop=851972
constant integer ORDER_submerge=852604
constant integer ORDER_summonfactory=852658
constant integer ORDER_summongrizzly=852594
constant integer ORDER_summonphoenix=852489
constant integer ORDER_summonquillbeast=852595
constant integer ORDER_summonwareagle=852596
constant integer ORDER_tankdroppilot=852079
constant integer ORDER_tankloadpilot=852080
constant integer ORDER_tankpilot=852081
constant integer ORDER_taunt=852520
constant integer ORDER_thunderbolt=852095
constant integer ORDER_thunderclap=852096
constant integer ORDER_tornado=852597
constant integer ORDER_townbelloff=852083
constant integer ORDER_townbellon=852082
constant integer ORDER_tranquility=852184
constant integer ORDER_transmute=852665
constant integer ORDER_unavatar=852087
constant integer ORDER_unavengerform=852532
constant integer ORDER_unbearform=852139
constant integer ORDER_unburrow=852534
constant integer ORDER_uncoldarrows=852245
constant integer ORDER_uncorporealform=852494
constant integer ORDER_undeadbuild=851998
constant integer ORDER_undefend=852056
constant integer ORDER_undivineshield=852091
constant integer ORDER_unetherealform=852497
constant integer ORDER_unflamingarrows=852175
constant integer ORDER_unflamingattack=852541
constant integer ORDER_unholyfrenzy=852209
constant integer ORDER_unimmolation=852178
constant integer ORDER_unload=852047
constant integer ORDER_unloadall=852048
constant integer ORDER_unloadallcorpses=852054
constant integer ORDER_unloadallinstant=852049
constant integer ORDER_unpoisonarrows=852256
constant integer ORDER_unravenform=852156
constant integer ORDER_unrobogoblin=852657
constant integer ORDER_unroot=852166
constant integer ORDER_unstableconcoction=852500
constant integer ORDER_unstoneform=852207
constant integer ORDER_unsubmerge=852605
constant integer ORDER_unsummon=852210
constant integer ORDER_unwindwalk=852130
constant integer ORDER_vengeance=852521
constant integer ORDER_vengeanceinstant=852524
constant integer ORDER_vengeanceoff=852523
constant integer ORDER_vengeanceon=852522
constant integer ORDER_volcano=852669
constant integer ORDER_voodoo=852503
constant integer ORDER_ward=852504
constant integer ORDER_waterelemental=852097
constant integer ORDER_wateryminion=852598
constant integer ORDER_web=852211
constant integer ORDER_weboff=852213
constant integer ORDER_webon=852212
constant integer ORDER_whirlwind=852128
constant integer ORDER_windwalk=852129
constant integer ORDER_wispharvest=852214
constant integer ORDER_scrollofspeed=852285
constant integer ORDER_cancel=851976
constant integer ORDER_moveslot1=852002
constant integer ORDER_moveslot2=852003
constant integer ORDER_moveslot3=852004
constant integer ORDER_moveslot4=852005
constant integer ORDER_moveslot5=852006
constant integer ORDER_moveslot6=852007
constant integer ORDER_useslot1=852008
constant integer ORDER_useslot2=852009
constant integer ORDER_useslot3=852010
constant integer ORDER_useslot4=852011
constant integer ORDER_useslot5=852012
constant integer ORDER_useslot6=852013
constant integer ORDER_skillmenu=852000
constant integer ORDER_stunned=851973
constant integer ORDER_instant1=851991 //patrol sub-order
constant integer ORDER_instant2=851987 //?
constant integer ORDER_instant3=851975 //?
constant integer ORDER_instant4=852019 //?
endglobals
endlibrary
//TESH.scrollpos=206
//TESH.alwaysfold=0
/*****************************************************************************
*
* Vector<T> v1.1.6.6
* by Bannar aka Spinnaker
*
* Dynamic contiguous array.
*
******************************************************************************
*
* Requirements:
*
* Table by Bribe
* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
* Alloc - choose whatever you like
*
******************************************************************************
*
* Implementation:
*
* macro DEFINE_STRUCT_VECTOR takes ACCESS, NAME, TYPE
*
* macro DEFINE_VECTOR takes ACCESS, NAME, TYPE
*
* ACCESS - encapsulation, choose retriction access
* NAME - name of vector type
* TYPE - type of values stored
*
******************************************************************************
*
* struct API:
*
* General:
*
* | static method create takes nothing returns thistype
* | default ctor
* |
* | static method operator [] takes thistype vec returns thistype
* | copy ctor
* |
* | method destroy takes nothing returns nothing
* | default dctor
* |
* | method empty takes nothing returns boolean
* | checks whether the vector is empty
* |
* | method size takes nothing returns integer
* | returns size of a vector
*
*
* Access:
*
* | method operator [] takes integer index returns $TYPE$
* | returns item at position index
* |
* | method operator []= takes integer index, $TYPE$ value returns nothing
* | sets item at index to value
* |
* | method front takes nothing returns $TYPE$
* | retrieves first element
* |
* | method back takes nothing returns $TYPE$
* | retrieves last element
* |
* | method data takes nothing returns Table
* | returns the underlying Table object
*
*
* Modifiers:
*
* | method clear takes nothing returns nothing
* | performs a flush operation on data table
* |
* | method push takes $TYPE$ value returns thistype
* | adds elements to the end
* |
* | method pop takes nothing returns thistype
* | removes the last element
* |
* | method assign takes integer count, $TYPE$ value returns thistype
* | assigns count elements replacing current data
* |
* | method insert takes integer pos, integer count, $TYPE$ value returns thistype
* | inserts count elements before position pos
* |
* | method erase takes integer pos, integer count returns thistype
* | erase count elements starting at position pos
*
*
*****************************************************************************/
library VectorT requires Table, Alloc
// Run here any global vector types you want to be defined.
//! runtextmacro DEFINE_VECTOR("", "IntegerVector", "integer")
//! textmacro_once DEFINE_STRUCT_VECTOR takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$ extends array
private delegate IntegerVector parent
method operator[] takes integer index returns $TYPE$
return parent[index]
endmethod
method front takes nothing returns $TYPE$
return parent.front()
endmethod
method back takes nothing returns $TYPE$
return parent.back()
endmethod
static method create takes nothing returns thistype
local thistype this = IntegerVector.create()
set parent = this
return this
endmethod
endstruct
//! endtextmacro
//! textmacro_once DEFINE_VECTOR takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$ extends array
private Table table
private integer length
implement Alloc
private method seT takes integer index, $TYPE$ value returns nothing
call table.$TYPE$.remove(index)
set table.$TYPE$[index] = value
endmethod
private method get takes integer index returns $TYPE$
return table.$TYPE$[index]
endmethod
private method assert_pos takes integer pos, string f returns boolean
debug if ( pos < 0 and pos >= length ) then
debug call DisplayTimedTextFromPlayer(GetLocalPlayer(),0,0,60,"$NAME$::assert_pos failed at "+f+" for instance "+I2S(this)+". Invalid index at position: "+I2S(pos)+".")
debug endif
return ( pos >= 0 and pos < length )
endmethod
private method assert_range takes integer pos, string f returns boolean
debug if ( pos < 0 or pos > length ) then
debug call DisplayTimedTextFromPlayer(GetLocalPlayer(),0,0,60,"$NAME$::assert_range failed at "+f+" for instance "+I2S(this)+". Invalid iterator at position: "+I2S(pos)+".")
debug endif
return ( pos >= 0 and pos <= length )
endmethod
method operator [] takes integer index returns $TYPE$
debug if not assert_pos(index, "operator []") then
debug return get(-1)
debug endif
return get(index)
endmethod
method operator []= takes integer index, $TYPE$ value returns nothing
debug if not assert_pos(index, "operator []=") then
debug return
debug endif
call seT(index, value)
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set table = Table.create()
set length = 0
return this
endmethod
method empty takes nothing returns boolean
return length == 0
endmethod
method size takes nothing returns integer
return length
endmethod
static method operator [] takes thistype vec returns thistype
local thistype this = create()
loop
exitwhen length >= vec.size()
call seT(length, vec[length])
set length = length + 1
endloop
return this
endmethod
method clear takes nothing returns nothing
set length = 0
call table.flush()
endmethod
method destroy takes nothing returns nothing
call clear()
call table.destroy()
set table = 0
call deallocate()
endmethod
method front takes nothing returns $TYPE$
return this[0]
endmethod
method back takes nothing returns $TYPE$
return this[length-1]
endmethod
method data takes nothing returns Table
return this.table
endmethod
method push takes $TYPE$ value returns thistype
call seT(length, value)
set length = length + 1
return this
endmethod
method pop takes nothing returns thistype
if ( length > 0 ) then
set length = length - 1
call table.$TYPE$.remove(length)
call table.real.remove(0)
endif
return this
endmethod
method assign takes integer count, $TYPE$ value returns thistype
if ( count > 0 ) then
call clear()
loop
exitwhen length >= count
call push(value)
endloop
endif
return this
endmethod
method insert takes integer pos, integer count, $TYPE$ value returns thistype
local integer i
if assert_range(pos, "insert") then
if ( count > 0 ) then
set length = length + count
set i = length - 1
loop
exitwhen i < (pos + count)
call seT(i, get(i-count))
set i = i - 1
endloop
set i = 0
loop
exitwhen i >= count
call seT(pos+i, value)
set i = i + 1
endloop
endif
endif
return this
endmethod
method erase takes integer pos, integer count returns thistype
if assert_pos(pos, "erase") then
if ( count > 0 ) then
if ( pos + count > length ) then
set count = length - pos
endif
set pos = pos + count
loop
exitwhen pos >= length
call seT(pos-count, get(pos))
set pos = pos + 1
endloop
loop
exitwhen count <= 0
call pop()
set count = count - 1
endloop
endif
endif
return this
endmethod
endstruct
//! endtextmacro
endlibrary
//TESH.scrollpos=149
//TESH.alwaysfold=0
library UnitDex uses optional WorldBounds, optional GroupUtils
/***************************************************************
*
* v1.2.1, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex assigns every unit an unique integer. It attempts to make that number within the
* maximum array limit so you can associate it with one.
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map, save it, then restart the editor and comment out the line below.
*/
//! external ObjectMerger w3a Adef uDex anam "Detect Leave" ansf "(UnitDex)" aart "" acat "" arac 0
/* ________________________________________________________________________
* 2. Configuration
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
private module UnitDexConfig
// The raw code of the leave detection ability.
static constant integer DETECT_LEAVE_ABILITY = 'uDex'
// Allow debug messages (debug mode must also be on)
static constant boolean ALLOW_DEBUGGING = true
// Uncomment the lines below to define a filter for units being indexed
/*static method onFilter takes unit u returns boolean
return true
endmethod*/
endmodule
/* _________________________________________________________________________
* 3. Function API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Every function inlines except for UnitDexRemove
*
* function GetUnitId takes unit whichUnit returns integer
* function GetUnitById takes integer index returns unit
*
* function UnitDexEnable takes boolean flag returns nothing
* function UnitDexRemove takes unit u, boolean runEvents returns boolean
*
* function IsUnitIndexed takes unit u returns boolean
* function IsIndexingEnabled takes nothing returns boolean
*
* function GetIndexedUnit takes nothing returns unit
* function GetIndexedUnitId takes nothing returns integer
*
* function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns indexevent
* function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
*
* function OnUnitIndex takes code func returns triggercondition
* function OnUnitDeidex takes code func returns triggercondition
* _________________________________________________________________________
* 4. Struct API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex.Enabled = false // toggle the indexer
* UnitDex.Initialized // returns true if the preload timer has finished
* UnitDex.Count // returns the amount of units indexed
* UnitDex.Unit[0] // access the UnitDex array directly
* UnitDex.Group // a unit group containing every indexed unit (for enumeration)
* UnitDex.LastIndex // returns the last indexed unit's id
* _________________________________________________________________________
* 5. Public Variables
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* These are to be used with the "eventtype" argument of the event API:
*
* constant integer EVENT_UNIT_INDEX = 0
* constant integer EVENT_UNIT_DEINDEX = 1
* _________________________________________________________________________
* 6. Examples
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Associate a unit with a variable
*
* set UnitFlag[GetUnitId(yourUnit)] = true
*
* 2. Allocate a struct instance using a units assigned ID
*
* local somestruct data = GetUnitId(yourUnit)
*
* 3. Detect when a unit leaves the map
*
* function Exit takes nothing returns nothing
* call BJDebugMsg("The unit " + GetUnitName(GetIndexedUnit()) + " has left the map.")
* endfunction
*
* call OnUnitDeindex(function Exit)
* // or
* call RegisterUnitIndexEvent(Filter(function Exit), EVENT_UNIT_DEINDEX)
*
*
* _________________________________________________________________________
* 7. How it works
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Enumerate all preplaced units
* 2. TriggerRegisterEnterRegion native to detect when a unit enters the map
* 3. Assign each unit that enters the map a unique integer
* 4. Give every unit an ability based off of defend. There is no native to accurately
* detect when a unit leaves the map but when a unit dies or is removed from the game
* they are issued the "undefend" order
* 5. Catch the "undefend" order and remove unit from the queue
* _________________________________________________________________________
* 8. Notes
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - This system is compatable with GUI because it utilizes UnitUserData (custom values for units).
* - The object merger line should be commented out after saving and restarting.
* - All public functions are inlined except UnitDexRemove.
*
* -http://www.hiveworkshop.com/forums/submissions-414/unitdex-lightweight-unit-indexer-248209/
*
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
globals
// Event types
constant integer EVENT_UNIT_INDEX = 0
constant integer EVENT_UNIT_DEINDEX = 1
// System variables
private trigger array IndexTrig
private integer Index = 0
private real E=-1
private boolexpr FilterEnter
endglobals
function GetUnitId takes unit whichUnit returns integer
return GetUnitUserData(whichUnit)
endfunction
function GetUnitById takes integer index returns unit
return UnitDex.Unit[index]
endfunction
function GetIndexedUnit takes nothing returns unit
return UnitDex.Unit[UnitDex.LastIndex]
endfunction
function GetIndexedUnitId takes nothing returns integer
return UnitDex.LastIndex
endfunction
function IsUnitIndexed takes unit u returns boolean
return (GetUnitById(GetUnitId(u)) != null)
endfunction
function UnitDexEnable takes boolean flag returns nothing
set UnitDex.Enabled = flag
endfunction
function IsIndexingEnabled takes nothing returns boolean
return UnitDex.Enabled
endfunction
function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns triggercondition
return TriggerAddCondition(IndexTrig[eventtype], func)
endfunction
function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
call TriggerRemoveCondition(IndexTrig[eventtype], c)
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "E", EQUAL, eventtype)
endfunction
function OnUnitIndex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_INDEX], Filter(func))
endfunction
function OnUnitDeindex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_DEINDEX], Filter(func))
endfunction
function UnitDexRemove takes unit u, boolean runEvents returns boolean
return UnitDex.Remove(u, runEvents)
endfunction
/****************************************************************/
private keyword UnitDexCore
struct UnitDex extends array
static boolean Enabled = true
readonly static integer LastIndex
readonly static boolean Initialized=false
readonly static group Group=CreateGroup()
readonly static unit array Unit
readonly static integer Count = 0
readonly static integer array List
implement UnitDexConfig
private static integer Counter = 0
implement UnitDexCore
endstruct
/****************************************************************/
private module UnitDexCore
static method Remove takes unit u, boolean runEvents returns boolean
local integer i
if (IsUnitIndexed(u)) then
set i = GetUnitId(u)
set UnitDex.List[i] = Index
set Index = i
call GroupRemoveUnit(UnitDex.Group, u)
call SetUnitUserData(u, 0)
if (runEvents) then
set UnitDex.LastIndex = i
set E = EVENT_UNIT_DEINDEX
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
set E = -1
endif
set UnitDex.Unit[i] = null
set UnitDex.Count = UnitDex.Count - 1
return true
endif
return false
endmethod
private static method onGameStart takes nothing returns nothing
local integer i = 0
static if (not LIBRARY_GroupUtils) then // Check if GroupUtils exists so we can use it's enumeration group.
local group ENUM_GROUP = CreateGroup() // If not, create the group.
endif
// Index preplaced units
loop
call GroupEnumUnitsOfPlayer(ENUM_GROUP, Player(i), FilterEnter)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
static if (not LIBRARY_GroupUtils) then
call DestroyGroup(ENUM_GROUP)
set ENUM_GROUP = null
endif
// run init triggers
set i = 1
loop
exitwhen i > Counter
set LastIndex = i
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
set E = EVENT_UNIT_INDEX
set E = -1
set i = i + 1
endloop
set LastIndex = Counter
set Initialized = true
set FilterEnter = null
call DestroyTimer(GetExpiredTimer())
endmethod
private static method onEnter takes nothing returns boolean
local unit u = GetFilterUnit()
local integer i = GetUnitId(u)
local integer t = Index
if (i == 0 and thistype.Enabled) then
// If a filter was defined pass the unit through it.
static if (thistype.onFilter.exists) then
if (not thistype.onFilter(u)) then
set u = null
return false // check failed
endif
endif
// Handle debugging
static if (thistype.DEBUG_MODE and thistype.ALLOW_DEBUGGING) then
if (t == 0 and Counter+1 >= JASS_MAX_ARRAY_SIZE) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "UnitDex: Maximum number of units reached!")
set u = null
return false
endif
endif
// Add to group of indexed units
call GroupAddUnit(thistype.Group, u)
// Give unit the leave detection ability
call UnitAddAbility(u, thistype.DETECT_LEAVE_ABILITY)
call UnitMakeAbilityPermanent(u, true, thistype.DETECT_LEAVE_ABILITY)
// Allocate index
if (Index != 0) then
set Index = List[t]
else
set Counter = Counter + 1
set t = Counter
endif
set List[t] = -1
set LastIndex = t
set thistype.Unit[t] = u
set Count = Count + 1
// Store the index
call SetUnitUserData(u, t)
if (thistype.Initialized) then
// Execute custom events registered with RegisterUnitIndexEvent
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_INDEX
// Reset so the event can occur again
set E = -1
endif
endif
set u = null
return false
endmethod
private static method onLeave takes nothing returns boolean
local unit u
local integer i
// Check if order is undefend.
if (thistype.Enabled and GetIssuedOrderId() == 852056) then
set u = GetTriggerUnit()
// If unit was killed (not removed) then don't continue
if (GetUnitAbilityLevel(u, thistype.DETECT_LEAVE_ABILITY) != 0) then
set u = null
return false
endif
set i = GetUnitId(u)
// If unit has been indexed then deindex it
if (i > 0 and i <= Counter and u == GetUnitById(i)) then
// Recycle the index
set List[i] = Index
set Index = i
set LastIndex = i
// Remove to group of indexed units
call GroupRemoveUnit(thistype.Group, u)
// Execute custom events without any associated triggers
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_DEINDEX
// Remove entry
call SetUnitUserData(u, 0)
set thistype.Unit[i] = null
// Decrement unit count
set Count = Count - 1
// Reset so the event can occur again
set E = -1
endif
set u = null
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local player p
local unit u
static if (not LIBRARY_WorldBounds) then // Check if WorldBounts exists, if not then define the necessary vars
local region reg = CreateRegion() // If WorldBounds wasn't found, create the region manually
local rect world = GetWorldBounds()
endif
set FilterEnter = Filter(function thistype.onEnter)
// Begin to index units when they enter the map
static if (LIBRARY_WorldBounds) then
call TriggerRegisterEnterRegion(CreateTrigger(), WorldBounds.worldRegion, FilterEnter)
else
call RegionAddRect(reg, world)
call TriggerRegisterEnterRegion(CreateTrigger(), reg, FilterEnter)
call RemoveRect(world)
set world = null
endif
call TriggerAddCondition(t, Filter(function thistype.onLeave))
set IndexTrig[EVENT_UNIT_INDEX] = CreateTrigger()
set IndexTrig[EVENT_UNIT_DEINDEX] = CreateTrigger()
loop
set p = Player(i)
// Detect "undefend"
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
// Hide the detect ability from players
call SetPlayerAbilityAvailable(p, thistype.DETECT_LEAVE_ABILITY, false)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TimerStart(CreateTimer(), 0, false, function thistype.onGameStart)
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Alloc /* v1.3.1.1
*************************************************************************************
*
* */ uses /*
*
* */ optional ErrorMessage /* github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
* */ optional MemoryAnalysis /*
*
*************************************************************************************
*
* Minimizes code generation and global variables while maintaining
* excellent performance.
*
* local thistype this = recycler[0]
*
* if (recycler[this] == 0) then
* set recycler[0] = this + 1
* else
* set recycler[0] = recycler[this]
* endif
*
************************************************************************************
*
* module Alloc
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* The Following Require Error Message To Be In The Map
* --------------------------------------------------------
*
* debug readonly boolean allocated
*
* The Following Require Memory Analysis To Be In The Map
* --------------------------------------------------------
*
* debug readonly integer monitorCount
* - the amount of global memory being monitored by this
* debug readonly integer monitorString
* - gets a string representation of all global memory being monitored by this
* debug readonly integer address
* - global memory address for debugging
* - used with monitor and stopMonitor
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
* debug method monitor takes string label, integer address returns nothing
* - monitor a global memory address with a label
* - used to identify memory leaks
* - should be memory that ought to be destroyed by the time this is destroyed
* debug method stopMonitor takes integer address returns nothing
* - stops monitoring global memory
* debug method stopMonitorValue takes handle monitoredHandle returns nothing
* - stops monitoring handle values
*
* The Following Are Used To Monitor Handle Values
*
* debug method monitor_widget takes string label, widget handleToTrack returns nothing
* debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
* debug method monitor_item takes string label, item handleToTrack returns nothing
* debug method monitor_unit takes string label, unit handleToTrack returns nothing
* debug method monitor_timer takes string label, timer handleToTrack returns nothing
* debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
* debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
* debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
* debug method monitor_force takes string label, force handleToTrack returns nothing
* debug method monitor_group takes string label, group handleToTrack returns nothing
* debug method monitor_location takes string label, location handleToTrack returns nothing
* debug method monitor_rect takes string label, rect handleToTrack returns nothing
* debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
* debug method monitor_effect takes string label, effect handleToTrack returns nothing
* debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
* debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
* debug method monitor_quest takes string label, quest handleToTrack returns nothing
* debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
* debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
* debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
* debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
* debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
* debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
* debug method monitor_button takes string label, button handleToTrack returns nothing
* debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
* debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
* debug method monitor_image takes string label, image handleToTrack returns nothing
* debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
* debug method monitor_region takes string label, region handleToTrack returns nothing
* debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
* debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
*
************************************************************************************/
module Alloc
/*
* stack
*/
private static integer array recycler
static if LIBRARY_MemoryAnalysis then
debug private MemoryMonitor globalAddress
debug method operator address takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "Alloc", "address", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress
debug endmethod
endif
/*
* allocation
*/
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
static if LIBRARY_ErrorMessage then
debug call ThrowError(this == 8192, "Alloc", "allocate", "thistype", 0, "Overflow.")
endif
if (recycler[this] == 0) then
set recycler[0] = this + 1
else
set recycler[0] = recycler[this]
endif
static if LIBRARY_ErrorMessage then
debug set recycler[this] = -1
endif
static if LIBRARY_MemoryAnalysis then
debug set globalAddress = MemoryMonitor.allocate("thistype")
endif
return this
endmethod
method deallocate takes nothing returns nothing
static if LIBRARY_ErrorMessage then
debug call ThrowError(recycler[this] != -1, "Alloc", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
endif
static if LIBRARY_MemoryAnalysis then
debug call globalAddress.deallocate()
debug set globalAddress = 0
endif
set recycler[this] = recycler[0]
set recycler[0] = this
endmethod
static if LIBRARY_MemoryAnalysis then
debug method monitor takes string label, integer address returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor(label, address)
debug endmethod
debug method stopMonitor takes integer address returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "stopMonitor", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitor(address)
debug endmethod
debug method stopMonitorValue takes handle monitoredHandle returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "stopMonitorValue", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.stopMonitorValue(monitoredHandle)
debug endmethod
debug method operator monitorCount takes nothing returns integer
debug call ThrowError(recycler[this] != -1, "Alloc", "monitorCount", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorCount
debug endmethod
debug method operator monitorString takes nothing returns string
debug call ThrowError(recycler[this] != -1, "Alloc", "monitorString", "thistype", this, "Attempted To Access Null Instance.")
debug return globalAddress.monitorString
debug endmethod
debug method monitor_widget takes string label, widget handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_widget", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_widget(label, handleToTrack)
debug endmethod
debug method monitor_destructable takes string label, destructable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_destructable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_destructable(label, handleToTrack)
debug endmethod
debug method monitor_item takes string label, item handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_item", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_item(label, handleToTrack)
debug endmethod
debug method monitor_unit takes string label, unit handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_unit", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unit(label, handleToTrack)
debug endmethod
debug method monitor_timer takes string label, timer handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_timer", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timer(label, handleToTrack)
debug endmethod
debug method monitor_trigger takes string label, trigger handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_trigger", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_trigger(label, handleToTrack)
debug endmethod
debug method monitor_triggercondition takes string label, triggercondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_triggercondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggercondition(label, handleToTrack)
debug endmethod
debug method monitor_triggeraction takes string label, triggeraction handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_triggeraction", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_triggeraction(label, handleToTrack)
debug endmethod
debug method monitor_force takes string label, force handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_force", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_force(label, handleToTrack)
debug endmethod
debug method monitor_group takes string label, group handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_group", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_group(label, handleToTrack)
debug endmethod
debug method monitor_location takes string label, location handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_location", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_location(label, handleToTrack)
debug endmethod
debug method monitor_rect takes string label, rect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_rect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_rect(label, handleToTrack)
debug endmethod
debug method monitor_boolexpr takes string label, boolexpr handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_boolexpr", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_boolexpr(label, handleToTrack)
debug endmethod
debug method monitor_effect takes string label, effect handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_effect", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_effect(label, handleToTrack)
debug endmethod
debug method monitor_unitpool takes string label, unitpool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_unitpool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_unitpool(label, handleToTrack)
debug endmethod
debug method monitor_itempool takes string label, itempool handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_itempool", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_itempool(label, handleToTrack)
debug endmethod
debug method monitor_quest takes string label, quest handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_quest", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_quest(label, handleToTrack)
debug endmethod
debug method monitor_defeatcondition takes string label, defeatcondition handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_defeatcondition", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_defeatcondition(label, handleToTrack)
debug endmethod
debug method monitor_timerdialog takes string label, timerdialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_timerdialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_timerdialog(label, handleToTrack)
debug endmethod
debug method monitor_leaderboard takes string label, leaderboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_leaderboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_leaderboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboard takes string label, multiboard handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_multiboard", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboard(label, handleToTrack)
debug endmethod
debug method monitor_multiboarditem takes string label, multiboarditem handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_multiboarditem", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_multiboarditem(label, handleToTrack)
debug endmethod
debug method monitor_dialog takes string label, dialog handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_dialog", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_dialog(label, handleToTrack)
debug endmethod
debug method monitor_button takes string label, button handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_button", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_button(label, handleToTrack)
debug endmethod
debug method monitor_texttag takes string label, texttag handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_texttag", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_texttag(label, handleToTrack)
debug endmethod
debug method monitor_lightning takes string label, lightning handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_lightning", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_lightning(label, handleToTrack)
debug endmethod
debug method monitor_image takes string label, image handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_image", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_image(label, handleToTrack)
debug endmethod
debug method monitor_ubersplat takes string label, ubersplat handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_ubersplat", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_ubersplat(label, handleToTrack)
debug endmethod
debug method monitor_region takes string label, region handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_region", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_region(label, handleToTrack)
debug endmethod
debug method monitor_fogmodifier takes string label, fogmodifier handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_fogmodifier", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_fogmodifier(label, handleToTrack)
debug endmethod
debug method monitor_hashtable takes string label, hashtable handleToTrack returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "monitor_hashtable", "thistype", this, "Attempted To Access Null Instance.")
debug call globalAddress.monitor_hashtable(label, handleToTrack)
debug endmethod
static if DEBUG_MODE then
//! runtextmacro optional MEMORY_ANALYSIS_STATIC_FIELD_NEW("recycler")
static method calculateMemoryUsage takes nothing returns integer
return calculateAllocatedMemory__recycler()
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
return allocatedMemoryString__recycler()
endmethod
endif
endif
/*
* analysis
*/
static if LIBRARY_ErrorMessage then
debug method operator allocated takes nothing returns boolean
debug return recycler[this] == -1
debug endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
set recycler[0] = 1
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*****************************************************************************
*
* RegisterNativeEvent v1.0.0.0
* by Bannar aka Spinnaker
*
* Storage of trigger handles for native events.
*
******************************************************************************
*
* Optional requirements:
*
* Table by Bribe
* hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
*
******************************************************************************
*
* Important:
*
* Avoid using TriggerSleepAction within functions registered
* Destroy native event trigger on your own responsibility
*
******************************************************************************
*
* Functions:
*
* function IsNativeEventRegistered takes integer whichIndex, integer eventId returns boolean
* whether index whichIndex has already been attached to event with id eventId
*
* function RegisterNativeEvent takes integer whichIndex, integer eventId returns boolean
* attaches index whichIndex to eventId if it hasn't been attached already and creates new trigger handle if needed
*
* function GetNativeEventTrigger takes integer eventId returns trigger
* retrieves trigger handle for event with id eventId
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table
globals
private trigger array triggers
endglobals
private module NativeEventInit
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set table = TableArray[122]
endif
endmethod
endmodule
private struct NativeEvent extends array
static if LIBRARY_Table then
static TableArray table
else
static hashtable table = InitHashtable()
endif
// 122 native events, unfortunatelly ids are not continuous
static method operator[] takes integer eventId returns integer
if ( eventId > 286 ) then
return eventId - 174
elseif ( eventId > 259 ) then
return eventId - 165
elseif ( eventId > 91 ) then
return eventId - 164
endif
return eventId
endmethod
implement NativeEventInit
endstruct
private function RegisterEvent takes integer whichIndex, integer eventId returns nothing
static if LIBRARY_Table then
set NativeEvent.table[NativeEvent[eventId]].integer[whichIndex] = eventId
else
call SaveInteger(NativeEvent.table, NativeEvent[eventId], whichIndex, eventId)
endif
endfunction
function IsNativeEventRegistered takes integer whichIndex, integer eventId returns boolean
static if LIBRARY_Table then
return NativeEvent.table[NativeEvent[eventId]].has(whichIndex)
else
return HaveSavedInteger(NativeEvent.table, NativeEvent[eventId], whichIndex)
endif
endfunction
function RegisterNativeEvent takes integer whichIndex, integer eventId returns boolean
if not IsNativeEventRegistered(whichIndex, eventId) then
call RegisterEvent(whichIndex, eventId)
if ( triggers[eventId] == null ) then
set triggers[eventId] = CreateTrigger()
endif
return true
endif
return false
endfunction
function GetNativeEventTrigger takes integer eventId returns trigger
return triggers[eventId]
endfunction
endlibrary
//TESH.scrollpos=8
//TESH.alwaysfold=0
/******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/forums/submissions-414/snippet-registerevent-pack-250266/
*
******************************************************************************
*
* constant boolean RPUE_VERSION_NEW
* Defines API style. Choose between compatibility with standard RPUE or Blizzard alike interface
*
*
* Functions:
*
* function Register(Any)PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
* registers generic playerunitevent whichEvent adding code cb as callback
*
* function RegisterPlayerUnitEvent(ForPlayer) takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing
* registers playerunitevent whichEvent for player whichPlayer adding code cb as callback
*
* function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* retrieves trigger handle for playerunitevent whichEvent
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent
globals
constant boolean RPUE_VERSION_NEW = false
endglobals
//! textmacro_once DEFINE_REGISTER_PLAYER_UNIT_EVENT takes GENERIC, SPECIFIC
function Register$GENERIC$PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
local integer eventId = GetHandleId(whichEvent)
local integer index = 0
loop
if RegisterNativeEvent(index, eventId) then
call TriggerRegisterPlayerUnitEvent(GetNativeEventTrigger(eventId), Player(index), whichEvent, null)
endif
set index = index + 1
exitwhen index == 16
endloop
call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction
function RegisterPlayerUnitEvent$SPECIFIC$ takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEvent(GetPlayerId(whichPlayer), eventId) then
call TriggerRegisterPlayerUnitEvent(GetNativeEventTrigger(eventId), whichPlayer, whichEvent, null)
endif
call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
//! endtextmacro
static if RPUE_VERSION_NEW then
//! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("Any", "")
else
//! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("", "ForPlayer")
endif
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=9
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.1.0
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BagSwitch initializer Init /*v1.1
used libraries
Inventory -- hiveworkshop.com/threads/bag-v1-6-1.252002/
*/
globals
private constant string COLOR = "|c00d0f680"
endglobals
private function onInventorySwitch takes nothing returns boolean
local integer bag = Bag.getCurrentBag(Bag.Unit)
local string s
if (bag == 0) then
set s = COLOR + "Open Inventory"
else
set s = COLOR + "Bag " + I2S(bag)
endif
set s = s + "|r"
call DisplayTimedTextToPlayer(GetOwningPlayer(Bag.Unit), 0, 0, 6, s)
return false
endfunction
private function Init takes nothing returns nothing
call Bag.register(Condition(function onInventorySwitch))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope FullInventoryError initializer Init /*v1.1
used libraries
FullInventory -- hiveworkshop.com/threads/bag-v1-6-1.252002/
RapidSound -- hiveworkshop.com/threads/snippet-rapidsound.258991/
*/
globals
private constant string COLOR = "|c00FF4444"
private constant string TEXT = "Full Inventory"
private RSound Sound
endglobals
private function onFullInventory takes nothing returns boolean
call DisplayTimedTextToPlayer(GetOwningPlayer(FullInventory.Unit), 0, 0, 6, COLOR + TEXT + "|r")
call Sound.play(GetUnitX(FullInventory.Unit), GetUnitY(FullInventory.Unit), 0, 200)
return false
endfunction
private function Init takes nothing returns nothing
call FullInventory.register(Condition(function onFullInventory))
set Sound = RSound.create("Sound\\Interface\\Error.wav", false, false, 0, 0)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope InventoryEvent initializer Init /*v1.1
used libraries
Inventory -- hiveworkshop.com/threads/bag-v1-6-1.252002/
RapidSound -- hiveworkshop.com/threads/snippet-rapidsound.258991/
*/
globals
private constant string COLOR = "|c0044FF44"
private RSound Sound
endglobals
private function onFullInventory takes nothing returns boolean
local string s
local string name = GetObjectName(Inventory.InitialItemId)
local integer charges
if GetItemTypeId(Inventory.InitialItem) == 0 then
// Item is removed -> it must have been stacked
set s = "Picked up " + COLOR + name + "[+" + I2S(Inventory.InitialCharges) + "]"
else
// Item does still exist
// but we don't know yet if item was partialy added (stacked) or completly added
if Inventory.InitialCharges == 0 then
// item had no charges -> was normaly picked up
set s = "Picked up " + COLOR + name
else
// item with charges was fully added, or patialy added
if UnitHasItem(Inventory.Unit, Inventory.InitialItem) or Inventory[Inventory.Unit].hasItem(Inventory.InitialItem) then
// item was fully added
if GetItemCharges(Inventory.InitialItem) == Inventory.InitialCharges then
// item was fully added, without any stack
set s = "Picked up " + COLOR + name + "[" + I2S(Inventory.InitialCharges) + "]"
else
// item was fully added, but also partialy stacked with other item(s)
set s = "Picked up " + COLOR + name + "[+" + I2S(Inventory.InitialCharges) + "]"
endif
else
// item was partialy added
set charges = Inventory.InitialCharges - (Inventory.InitialCharges - GetItemCharges(Inventory.InitialItem))
set s = "Picked up " + COLOR + name + "[+" + I2S(charges) + "]"
endif
endif
endif
set s = s + "|r"
call DisplayTimedTextToPlayer(GetOwningPlayer(Inventory.Unit), 0, 0, 6, s)
call Sound.play(GetUnitX(Inventory.Unit), GetUnitY(Inventory.Unit), 0, 200)
return false
endfunction
private function Init takes nothing returns nothing
call Inventory.register(Condition(function onFullInventory))
set Sound = RSound.create("Sound\\Interface\\PickUpItem.wav", false, false, 0, 0)
endfunction
endscope
//TESH.scrollpos=9
//TESH.alwaysfold=0
library RapidSound requires optional TimerUtils
globals
// Actually, just leave this value
private constant real MIN_DELAY_FACTOR = 4.0
endglobals
/* v1.6
Description
¯¯¯¯¯¯¯¯¯¯¯
Allows you to play sounds rapidly and flawlessly without limit.
Remember one sound file can only have one RSound instance.
External Dependencies
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
(Optional)
TimerUtils by Vexorian
wc3c.net/showthread.php?t=101322
User API
¯¯¯¯¯¯¯¯
struct RSound
Instantiate an RapidSound instance
| static method create takes string fileName, boolean is3D, boolean autoStop, integer inRate, integer outRate returns thistype
autoStop => stop when sound is out of range
inRate => fade in rate
outRate => fade out rate
Play the sound at given coordinate
| method play takes real x, real y, real z, integer volume returns nothing
Stop sound
| method stop takes boolean fadeOut returns nothing
Destroy RapidSound instance
| method kill takes nothing returns nothing
Sound file duration (in second)
| method operator duration takes nothing returns real
Resource Link
¯¯¯¯¯¯¯¯¯¯¯¯¯
hiveworkshop.com/threads/snippet-rapidsound.258991/
*/
struct RSound
private static constant integer MAX_COUNT = 4
private static integer Counter = -1
private static string array StrLib
private static thistype array StrDex
private integer ct
private integer lib
private integer dex
private real dur
private sound array snd[thistype.MAX_COUNT]
private timer array tmr[thistype.MAX_COUNT]
method operator duration takes nothing returns real
return .dur*MIN_DELAY_FACTOR
endmethod
method kill takes nothing returns nothing
local integer i
set .ct = .ct - 1
if .ct == 0 then
set i = 0
loop
exitwhen i == MAX_COUNT
call StopSound(.snd[i], true, false)
static if LIBRARY_TimerUtils then
call ReleaseTimer(.tmr[i])
else
call DestroyTimer(.tmr[i])
endif
set .snd[i] = null
set .tmr[i] = null
set i = i + 1
endloop
set StrLib[.lib] = StrLib[Counter]
set StrDex[.lib] = StrDex[Counter]
set Counter = Counter - 1
call deallocate()
endif
endmethod
method stop takes boolean fadeOut returns nothing
local integer i = 0
loop
exitwhen i == MAX_COUNT
call StopSound(.snd[i], false, fadeOut)
set i = i + 1
endloop
endmethod
method play takes real x, real y, real z, integer volume returns nothing
set .dex = .dex + 1
if .dex == MAX_COUNT then
set .dex = 0
endif
if TimerGetRemaining(.tmr[.dex]) == 0 then
call StopSound(.snd[.dex], false, false)
call SetSoundPosition(.snd[.dex], x, y, z)
call SetSoundVolume(.snd[.dex], volume)
call StartSound(.snd[.dex])
call TimerStart(.tmr[.dex], .dur, false, null)
endif
endmethod
static method create takes string fileName, boolean is3D, boolean autoStop, integer inRate, integer outRate returns thistype
local thistype this
local integer i = 0
local boolean b = true
loop
exitwhen i > Counter
if fileName == StrLib[i] then
set b = false
exitwhen true
endif
set i = i + 1
endloop
if b then
set this = allocate()
set Counter = Counter + 1
set StrLib[Counter] = fileName
set StrDex[Counter] = this
set .ct = 1
set .dex = -1
set .lib = Counter
set .dur = I2R(GetSoundFileDuration(fileName))/(1000.*MIN_DELAY_FACTOR)
set i = 0
loop
exitwhen i == MAX_COUNT
set .snd[i] = CreateSound(fileName, false, is3D, autoStop, inRate, outRate, "")
static if LIBRARY_TimerUtils then
set .tmr[i] = NewTimer()
call TimerStart(.tmr[i], 0, false, null)
call PauseTimer(.tmr[i])
else
set .tmr[i] = CreateTimer()
endif
set i = i + 1
endloop
else
set this = StrDex[i]
set .ct = .ct + 1
endif
return this
endmethod
endstruct
endlibrary