Name | Type | is_array | initial_value |
/*****************************************************************************
*
* Inventory v1.0.8
* by SmitingDevil
*
* Custom inventory that is compatible with the vanilla one
*
******************************************************************************
*
* Requirements:
*
* Table by Bribe
* https://www.hiveworkshop.com/threads/lua-vjass-new-table.188084/
*
* Alloc - choose whatever you like
* e.g.: by AGD https://www.hiveworkshop.com/threads/global-alloc.324937/
*
* HoverOriginButton by Tasyen
* https://www.hiveworkshop.com/threads/hoveroriginbutton.337965/
*
* GetMainSelectedUnit (vJASS) by Tasyen
* https://www.hiveworkshop.com/threads/getmainselectedunit.325337/
*
* Sync by TriggerHappy
* https://www.hiveworkshop.com/threads/sync-game-cache.279148/
*
* List<T> by Bannar
* https://www.hiveworkshop.com/threads/containers-list-t.249011/
*
* InventoryEvent by Bannar
* https://www.hiveworkshop.com/threads/snippet-inventoryevent.287084/
*
* StringIterator by edo494
* https://www.hiveworkshop.com/threads/snippet-stringiterator.246143/
*
* WorldBounds by Nestharus
* https://raw.githubusercontent.com/nestharus/JASS/master/jass/Systems/WorldBounds/script.j
*
* TimerUtils by Magtheridon96/Vexorian/Bribe
* https://www.hiveworkshop.com/threads/system-timerutilsex.204500/#post-2019478
*
******************************************************************************
*
* Inventory Struct API:
*
* General:
*
* | static method create takes nothing returns thistype
* | Default constructor.
* |
* | static method createEx takes integer slotCount, integer cols, real buttonSize, real spaceGap, real borderSize, real titleSize, real posX, real posY returns thistype
* | Constructor that builds the inventory in one go.
* |
* | method destroy takes nothing returns nothing
* | Default destructor.
*
*
* Access:
*
* | readonly emptySlotTexture
* | readonly slotIndicatorModel
* | readonly backdrop
* | readonly buttonSize
*
*
* Modifiers:
*
* [Design]
*
* | method setSlotCount takes integer count returns thistype
* | Sets the number of inventory slots.
* |
* | method setSlotEmptyTexture takes string texture returns thistype
* | Sets the default texture for slots.
* |
* | method setSlotIndicatorModel takes string str returns thistype
* | Sets the model that shows a slot is selected.
* |
* | method setButtonSize takes real size returns thistype
* | Sets the size of the inventory slots and other buttons.
* |
* | method setButtonSpaceGap takes real size returns thistype
* | Sets the size of the space between inventory slots.
* |
* | method setColumnCount takes integer cols returns thistype
* | Sets the number of slots in a row.
* |
* | method setTitle takes string str returns thistype
* | Sets the name of the inventory.
* |
* | method setTitleSize takes real size returns thistype
* | Sets the size of the title's margins.
* |
* | method setBorderSize takes real size returns thistype
* | Sets the size of the inventory's margins.
|
* | method setOpenButtonPosition takes real x, real y returns thistype
* | Sets the position of the open button icon.
* |
* | method setOpenButtonTexture takes string str returns thistype
* | Sets the texture for open button icon.
* |
* | method build takes nothing returns nothing
* | Creates the inventory and all its elements.
* | All methods for design must be called before running this method.
* | They cannot be modified after build.
* | Only title name and methods for the open button are the only exceptions.
* | They can be modified before and after build and are optional.
*
* [Technical]
*
* | method setPosition takes real x, real y returns thistype
* | Moves the inventory to given point on the screen
* |
* | method show takes boolean flag returns nothing
* | Hides or displays the inventory
* |
* | method showEx takes player p, boolean flag returns nothing
* | Hides or displays the inventory for specific player only
* | Links the inventory to player as the one being displayed
*
*
*****************************************************************************/
library Inventory initializer Init requires TimerUtilsEx, WorldBounds, ListT, StringIterator, Sync, InventoryEvent, HoverOriginButton, GetMainSelectedUnit
globals
private framehandle dummyFrame
private framehandle dummyFrameEx
private framehandle dummyIcon
private framehandle array playerFrame
private integer originItemSlot = -1
private integer originItemSlotEx = -1
private Table player2Inventory
//private Table item2Unit
player LOCAL_PLAYER
framehandle GAME_UI
framehandle ORIGIN_ITEM_BUTTON_ONE
//private integer count = 0
endglobals
function IsFrameEnabled takes framehandle frame, player p returns boolean
if GetLocalPlayer() == p or p == null then
return BlzFrameGetEnable(frame)
else
return false
endif
endfunction
function UnfocusFrame takes framehandle frame, player p returns nothing
if IsFrameEnabled(frame, p) then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
else
call BlzFrameSetEnable(frame, true)
call BlzFrameSetEnable(frame, false)
endif
endfunction
function print takes string msg returns nothing
call DisplayTimedTextToPlayer(LOCAL_PLAYER, 0, 0, 3, msg)
endfunction
private function IsMouseDraggingItem takes nothing returns boolean
local integer i = 0
loop
if BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_COMMAND_BUTTON, i)) then
exitwhen true
endif
set i = i + 1
exitwhen i == 12
endloop
return i == 11
endfunction
private module MyModule
private static method onInit takes nothing returns nothing
//this is run on map init
call init()
endmethod
endmodule
private struct Frame extends array
implement Alloc
framehandle handle
static method create takes framehandle frame returns thistype
local thistype this = allocate()
set handle = frame
return this
endmethod
method destroy takes nothing returns nothing
set handle = null
call deallocate()
endmethod
endstruct
private struct UnitItem extends array
implement Alloc
item itemHandle
unit unitHandle
static method create takes unit u, item it returns thistype
local thistype this = allocate()
set unitHandle = u
set itemHandle = it
return this
endmethod
method destroy takes nothing returns nothing
set unitHandle = null
set itemHandle = null
call deallocate()
endmethod
endstruct
private struct Slot extends array
implement Alloc
private framehandle actionButton
private framehandle icon
private framehandle tooltipParent
private framehandle tooltipText
private framehandle tooltipBackdrop
readonly framehandle indicator
readonly Inventory parent
readonly static Table frame2Slot
readonly static Table frame2Item
readonly static Table unit2Item
readonly static Table player2Unit
readonly static Table data2Frame
private static trigger actionTrigger
private static trigger enterTrigger
//private static framehandle clickedFrame
static method create takes real size, real x, real y, Inventory parent returns thistype
local thistype this = allocate()
set actionButton = BlzCreateFrame("ScriptDialogButton", parent.backdrop, 0, 0)
call BlzFrameSetSize(actionButton, size, size)
call BlzFrameSetPoint(actionButton, FRAMEPOINT_TOPLEFT, parent.backdrop, FRAMEPOINT_TOPLEFT, x, y)
set frame2Slot[GetHandleId(actionButton)] = this
set frame2Item[GetHandleId(actionButton)] = Table.create()
set icon = BlzCreateFrameByType("BACKDROP", "SlotIcon", actionButton, "", 0)
call BlzFrameSetAllPoints(icon, actionButton)
call BlzFrameSetTexture(icon, parent.emptySlotTexture, 0, true)
set tooltipParent = BlzCreateFrameByType("FRAME", "SlotTooltipParent", actionButton, "", 0)
call BlzFrameSetTooltip(actionButton, tooltipParent)
set tooltipBackdrop = BlzCreateFrameByType("BACKDROP", "SlotTooltipBackdrop", tooltipParent, "", 0)
call BlzFrameSetVisible(tooltipBackdrop, false)
set tooltipText = BlzCreateFrameByType("TEXT", "SlotTooltipText", tooltipBackdrop, "", 0)
call BlzFrameSetSize(tooltipText, 0.2, 0)
call BlzFrameSetPoint(tooltipText, FRAMEPOINT_TOPLEFT, actionButton, FRAMEPOINT_TOPRIGHT, 0, 0)
call BlzFrameSetPoint(tooltipBackdrop, FRAMEPOINT_TOPLEFT, tooltipText, FRAMEPOINT_TOPLEFT, -0.007, 0.007)
call BlzFrameSetPoint(tooltipBackdrop, FRAMEPOINT_BOTTOMRIGHT, tooltipText, FRAMEPOINT_BOTTOMRIGHT, 0.007, -0.007)
call BlzFrameSetTexture(tooltipBackdrop, "UI\\Widgets\\ToolTips\\Human\\human-tooltip-background.blp", 0, true)
set indicator = BlzCreateFrameByType("SPRITE", "SlotIndicator", actionButton, "", 0)
call BlzFrameSetAllPoints(indicator, actionButton)
call BlzFrameSetScale(indicator, parent.buttonSize/0.036)
call BlzFrameSetVisible(indicator, false)
call BlzFrameSetModel(indicator, parent.slotIndicatorModel, 0)
call BlzTriggerRegisterFrameEvent(actionTrigger, actionButton, FRAMEEVENT_CONTROL_CLICK)
set .parent = parent
return this
endmethod
private method update takes item itm returns nothing
if itm != null then
call BlzFrameSetTexture(icon, BlzGetItemIconPath(itm), 0, true)
call BlzFrameSetVisible(tooltipBackdrop, true)
call BlzFrameSetText(tooltipText, GetLocalizedString("|cffffcc00" + GetItemName(itm) + "|r\n\n" + BlzGetAbilityExtendedTooltip(GetItemTypeId(itm), 0)))
else
call BlzFrameSetTexture(icon, parent.emptySlotTexture, 0, true)
call BlzFrameSetVisible(tooltipBackdrop, false)
endif
endmethod
private static method onExpired takes nothing returns nothing
local UnitItem data = ReleaseTimer(GetExpiredTimer())
call SetItemVisible(data.itemHandle, true)
call UnitAddItem(data.unitHandle, data.itemHandle)
call UnitDropItemSlot(data.unitHandle, data.itemHandle, 0)
call data.destroy()
endmethod
private static method clickAction takes nothing returns nothing
local SyncData d = GetSyncedData()
local StringIterator iter = StringIterator.create(d.readString(0))
local Frame clickedFrame = data2Frame[d]
local integer originSlot
local integer pid
local integer selectedIndex = S2I(iter.read())
local unit mainSelectedUnit = GetMainSelectedUnit(selectedIndex)
local framehandle frame
local framehandle pFrame
local boolean itemOnMouse
local player syncer
local item itemInOriginSlot
local item slotItem
local item item0
local thistype slot
local thistype pSlot
local Table table
local Table tb
call data2Frame.remove(d)
//call print("Click Action: " + GetUnitName(mainSelectedUnit))
//call ClearTextMessages()
//call print("------------------------------------------------------")
if mainSelectedUnit != null then
set frame = clickedFrame.handle
set syncer = d.from
set pid = GetPlayerId(syncer)
set table = frame2Item[GetHandleId(frame)]
set slot = frame2Slot[GetHandleId(frame)]
set originSlot = S2I(iter.read())
if iter.read() == "true" then
set itemOnMouse = true
else
set itemOnMouse = false
endif
if itemOnMouse then
set itemInOriginSlot = UnitItemInSlot(mainSelectedUnit, originSlot)
if itemInOriginSlot != null then
set pFrame = playerFrame[pid]
set playerFrame[pid] = null
call SetItemPosition(itemInOriginSlot, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(itemInOriginSlot, false)
if LOCAL_PLAYER == syncer then
call slot.update(itemInOriginSlot)
set originItemSlot = -1
set originItemSlotEx = -1
endif
set slotItem = table.item[GetHandleId(mainSelectedUnit)]
set table.item[GetHandleId(mainSelectedUnit)] = itemInOriginSlot
set playerFrame[pid] = pFrame
if pFrame == null then
if slotItem != null then
//call print("Click Slot - itemOnMouse - no pFrame: " + GetItemName(slotItem))
call UnitAddItem(mainSelectedUnit, slotItem)
call UnitDropItemSlot(mainSelectedUnit, slotItem, originSlot)
endif
else
if originSlot == 0 then
set playerFrame[pid] = null
set slot = frame2Slot[GetHandleId(pFrame)]
set tb = frame2Item[GetHandleId(pFrame)]
if slotItem == null then
call tb.item.remove(GetHandleId(mainSelectedUnit))
else
set tb.item[GetHandleId(mainSelectedUnit)] = slotItem
endif
//call print("Click Slot - itemOnMouse - pFrame - originSlot 0: " + GetItemName(slotItem))
if LOCAL_PLAYER == syncer then
call slot.update(slotItem)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
call BlzFrameSetVisible(slot.indicator, false)
endif
if unit2Item.item.has(GetHandleId(mainSelectedUnit)) then
set item0 = unit2Item.item[GetHandleId(mainSelectedUnit)]
call TimerStart(NewTimerEx(UnitItem.create(mainSelectedUnit, item0)), 0, false, function thistype.onExpired)
//call UnitAddItem(mainSelectedUnit, item0)
//call UnitDropItemSlot(mainSelectedUnit, item0, 0)
call unit2Item.item.remove(GetHandleId(mainSelectedUnit))
endif
else
set playerFrame[pid] = null
if slotItem != null then
call UnitAddItem(mainSelectedUnit, slotItem)
call UnitDropItemSlot(mainSelectedUnit, slotItem, originSlot)
endif
set playerFrame[pid] = pFrame
endif
set pFrame = null
endif
endif
set itemInOriginSlot = null
else
if table.item.has(GetHandleId(mainSelectedUnit)) then
if playerFrame[GetPlayerId(syncer)] != null then
set pFrame = playerFrame[GetPlayerId(syncer)]
set playerFrame[GetPlayerId(syncer)] = null
set pSlot = frame2Slot[GetHandleId(pFrame)]
set tb = frame2Item[GetHandleId(pFrame)]
set slotItem = tb.item[GetHandleId(mainSelectedUnit)]
call SetItemPosition(slotItem, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(slotItem, false)
if LOCAL_PLAYER == syncer then
call BlzFrameSetVisible(pSlot.indicator, false)
endif
if unit2Item.item.has(GetHandleId(mainSelectedUnit)) then
set item0 = unit2Item.item[GetHandleId(mainSelectedUnit)]
call UnitAddItem(mainSelectedUnit, item0)
call UnitDropItemSlot(mainSelectedUnit, item0, 0)
call unit2Item.item.remove(GetHandleId(mainSelectedUnit))
endif
endif
if LOCAL_PLAYER == syncer then
call BlzFrameSetVisible(slot.indicator, true)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, frame)
set originItemSlot = -1
set originItemSlotEx = -1
call BlzFrameSetEnable(dummyFrameEx, true)
endif
set slotItem = UnitItemInSlot(mainSelectedUnit, 0)
if slotItem != null then
set unit2Item.item[GetHandleId(mainSelectedUnit)] = slotItem
//set item2Unit.unit[GetHandleId(slotItem)] = mainSelectedUnit
//call print("Clicked slot no item on mouse: " + GetItemName(slotItem))
if LOCAL_PLAYER == syncer then
call BlzFrameSetTexture(dummyIcon, BlzGetAbilityIcon(GetItemTypeId(slotItem)), 0, true)
call BlzFrameSetVisible(dummyIcon, true)
endif
call SetItemPosition(slotItem, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(slotItem, false)
set slotItem = null
endif
set slotItem = table.item[GetHandleId(mainSelectedUnit)]
call UnitAddItem(mainSelectedUnit, slotItem)
call UnitDropItemSlot(mainSelectedUnit, slotItem, 0)
set slotItem = null
set playerFrame[GetPlayerId(syncer)] = frame
endif
endif
set frame = null
set mainSelectedUnit = null
set syncer = null
endif
call d.destroy()
call clickedFrame.destroy()
endmethod
private static method onClick takes nothing returns nothing
local SyncData req = SyncData.create(GetTriggerPlayer())
local string str
set data2Frame[req] = Frame.create(BlzGetTriggerFrame())
call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
if frame2Slot.has(GetHandleId(BlzGetTriggerFrame())) then
set str = ""
if LOCAL_PLAYER == GetTriggerPlayer() then
set str = I2S(GetSelectedUnitIndex()) + " "
set str = str + I2S(originItemSlot) + " "
if IsMouseDraggingItem() then
set str = str + "true"
else
set str = str + "false"
endif
endif
set req.onComplete = Filter(function thistype.clickAction)
call req.syncString(str, StringLength(str))
//call SyncStr(str, GetTriggerPlayer(), function thistype.clickAction)
endif
endmethod
private static method onEnter takes nothing returns nothing
call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
if BlzGetTriggerFrame() == dummyFrameEx then
if IsMouseDraggingItem() then
set originItemSlotEx = 0
endif
endif
endmethod
private static method onItemMove takes nothing returns nothing
local item item0
local unit u = GetInventoryManipulatingUnit()
local item itm
local item swapped
local integer slotFrom
local integer slotTo = GetInventorySlotTo()
local player p = GetOwningPlayer(u)
local integer pid = GetPlayerId(p)
local thistype slot
local framehandle pFrame
local Table tb
if LOCAL_PLAYER == p then
set originItemSlot = slotTo
endif
set pFrame = playerFrame[pid]
set playerFrame[pid] = null
if pFrame != null then
//call print("Item Move: " + GetItemName(GetInventoryManipulatedItem()))
set itm = GetInventoryManipulatedItem()
set swapped = GetInventorySwappedItem()
set slot = frame2Slot[GetHandleId(pFrame)]
set slotFrom = GetInventorySlotFrom()
if slotTo == slotFrom then
else
call BlzFrameSetEnable(dummyFrame, true)
set tb = frame2Item[GetHandleId(pFrame)]
if slotFrom == 0 then
if swapped != null then
set tb.item[GetHandleId(u)] = swapped
call SetItemPosition(swapped, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(swapped, false)
if LOCAL_PLAYER == p then
call slot.update(swapped)
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
//set originItemSlot = -1
set originItemSlotEx = -1
endif
else
call tb.item.remove(GetHandleId(u))
if LOCAL_PLAYER == p then
call slot.update(null)
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
//set originItemSlot = -1
set originItemSlotEx = -1
endif
endif
elseif slotTo == 0 then
set tb.item[GetHandleId(u)] = itm
call print("sloTo 0 - swapped item: " + GetItemName(itm))
call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(itm, false)
if LOCAL_PLAYER == p then
call slot.update(itm)
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
//set originItemSlot = -1
set originItemSlotEx = -1
endif
call UnitDropItemSlot(u, swapped, slotFrom)
endif
if slotFrom == 0 or slotTo == 0 then
set pFrame = null
set item0 = unit2Item.item[GetHandleId(u)]
//call print("sloTo 0 - item0: " + GetItemName(item0))
if item0 != null then
call unit2Item.item.remove(GetHandleId(u))
call SetItemVisible(item0, true)
call UnitAddItem(u, item0)
call UnitDropItemSlot(u, item0, 0)
set item0 = null
endif
endif
endif
endif
set u = null
set itm = null
set swapped = null
set playerFrame[pid] = pFrame
set pFrame = null
endmethod
private static method onItemDrop takes nothing returns nothing
local item itm = GetManipulatedItem()
local item item0
local unit u = GetTriggerUnit()
local integer pid = GetPlayerId(GetTriggerPlayer())
local thistype slot
local framehandle pFrame = playerFrame[pid]
local Table tb
if pFrame != null and UnitItemInSlot(u, 0) == itm then
set playerFrame[pid] = null
//call print("Item Drop: " + GetItemName(itm))
call BlzFrameSetEnable(dummyFrame, true)
set slot = frame2Slot[GetHandleId(pFrame)]
set tb = frame2Item[GetHandleId(pFrame)]
call tb.item.remove(GetHandleId(u))
if LOCAL_PLAYER == GetTriggerPlayer() then
call slot.update(null)
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
set originItemSlot = -1
set originItemSlotEx = -1
endif
set item0 = unit2Item.item[GetHandleId(u)]
if item0 != null then
//call print("Item Drop - item0: " + GetItemName(item0))
call unit2Item.item.remove(GetHandleId(u))
call TimerStart(NewTimerEx(UnitItem.create(u, item0)), 0, false, function thistype.onExpired)
set item0 = null
endif
endif
endmethod
private static method mouseAction takes nothing returns nothing
local SyncData d = GetSyncedData()
local StringIterator iter = StringIterator.create(d.readString(0))
local IntegerListItem node
local Inventory inv
local Table tb
local player p = d.from
local integer pid = GetPlayerId(p)
local integer selectedIndex
local integer originSlot
local thistype slot
local boolean itemOnMouse
local item item0
local item itm
local unit u
local unit mainUnit
local string str = iter.read()
local framehandle pFrame
call d.destroy()
if not player2Inventory.has(pid) then
return
endif
if str == "true" then
set itemOnMouse = true
else
set itemOnMouse = false
endif
set originSlot = S2I(iter.read())
set selectedIndex = S2I(iter.read())
//set count = count + 1
if itemOnMouse then
//call print("Main Selected Unit Index: " + I2S(selectedIndex))
if playerFrame[pid] != null and originSlot == 0 then
set u = GetMainSelectedUnit(selectedIndex)
set slot = frame2Slot[GetHandleId(playerFrame[pid])]
set item0 = unit2Item.item[GetHandleId(u)]
set tb = frame2Item[GetHandleId(playerFrame[pid])]
if item0 == null then
call tb.item.remove(GetHandleId(u))
else
call unit2Item.item.remove(GetHandleId(u))
set tb.item[GetHandleId(u)] = item0
endif
if LOCAL_PLAYER == p then
call slot.update(item0)
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
set originItemSlot = -1
set originItemSlotEx = -1
call ForceUICancel()
call BlzFrameSetEnable(dummyFrameEx, true)
endif
set item0 = null
set u = null
set playerFrame[pid] = null
endif
else
set pFrame = playerFrame[pid]
set playerFrame[pid] = null
set mainUnit = GetMainSelectedUnit(selectedIndex)
set u = player2Unit.unit[pid]
set player2Unit.unit[pid] = mainUnit
if mainUnit != u and u != null then
if unit2Item.item.has(GetHandleId(u)) then
set item0 = unit2Item.item[GetHandleId(u)]
set itm = UnitItemInSlot(u, 0)
call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(itm, false)
call UnitAddItem(u, item0)
call UnitDropItemSlot(u, item0, 0)
call unit2Item.item.remove(GetHandleId(u))
set itm = null
set item0 = null
endif
set inv = player2Inventory[pid]
set node = inv.slots.first
loop
exitwhen node == 0
set slot = node.data
set tb = frame2Item[GetHandleId(slot.actionButton)]
set itm = tb.item[GetHandleId(mainUnit)]
if itm != null then
call SetItemPosition(itm, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(itm, false)
endif
if LOCAL_PLAYER == p then
call slot.update(itm)
endif
set itm = null
set node = node.next
endloop
if unit2Item.item.has(GetHandleId(mainUnit)) then
set item0 = unit2Item.item[GetHandleId(mainUnit)]
//call print("mainUnit - item0: " + GetItemName(item0))
call UnitAddItem(mainUnit, item0)
call UnitDropItemSlot(mainUnit, item0, 0)
call unit2Item.item.remove(GetHandleId(mainUnit))
set item0 = null
endif
if pFrame != null then
set slot = frame2Slot[GetHandleId(pFrame)]
set pFrame = null
if LOCAL_PLAYER == p then
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
set originItemSlot = -1
set originItemSlotEx = -1
call BlzFrameSetEnable(dummyFrameEx, true)
endif
endif
endif
set playerFrame[pid] = pFrame
endif
endmethod
private static method onMouseClick takes nothing returns nothing
local SyncData req = SyncData.create(GetTriggerPlayer())
local string str = ""
if LOCAL_PLAYER == GetTriggerPlayer() then
if IsMouseDraggingItem() then
set str = "true "
else
set str = "false "
endif
set str = str + I2S(originItemSlotEx) + " "
set str = str + I2S(GetSelectedUnitIndex())
endif
set req.onComplete = Filter(function thistype.mouseAction)
call req.syncString(str, StringLength(str))
//call print(str + ": " + I2S(StringLength(str)) + " characters")
//call SyncStr(str, GetTriggerPlayer(), function thistype.mouseAction)
endmethod
private static method onInit takes nothing returns nothing
set frame2Slot = Table.create()
set frame2Item = Table.create()
set unit2Item = Table.create()
set player2Unit = Table.create()
set data2Frame = Table.create()
set actionTrigger = CreateTrigger()
set enterTrigger = CreateTrigger()
call TriggerAddCondition(actionTrigger, function thistype.onClick)
call TriggerAddCondition(enterTrigger, function thistype.onEnter)
set ORIGIN_ITEM_BUTTON_ONE = BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)
set dummyFrame = BlzCreateFrameByType("GLUETEXTBUTTON", "DummyFrame", GAME_UI, "", 0)
call BlzFrameSetSize(dummyFrame, 0.030, 0.031)
call BlzFrameSetAbsPoint(dummyFrame, FRAMEPOINT_CENTER, 0.5318, 0.097)
set dummyIcon = BlzCreateFrameByType("BACKDROP", "DummyIcon", dummyFrame, "", 0)
call BlzFrameSetAllPoints(dummyIcon, dummyFrame)
call BlzFrameSetVisible(dummyIcon, false)
set dummyFrameEx = BlzCreateFrameByType("GLUETEXTBUTTON", "DummyFrame", dummyFrame, "", 0)
call BlzFrameSetSize(dummyFrameEx, 0.04, 0.04)
call BlzFrameSetAbsPoint(dummyFrameEx, FRAMEPOINT_CENTER, 0.5318, 0.097)
call BlzTriggerRegisterFrameEvent(enterTrigger, dummyFrameEx, FRAMEEVENT_MOUSE_ENTER)
call RegisterNativeEvent(EVENT_ITEM_INVENTORY_MOVE, function thistype.onItemMove)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onItemDrop)
call RegisterAnyPlayerEvent(EVENT_PLAYER_MOUSE_UP, function thistype.onMouseClick)
endmethod
endstruct
struct Inventory extends array
implement Alloc
private static trigger closeTrigger
private static trigger openTrigger
private static Table frame2Inventory
private framehandle title
private framehandle closeButton
private framehandle openIcon
private framehandle nextButton
private framehandle prevButton
private framehandle pageNumber
private integer slotCount
private integer columns
private real borderSize
private real titleSize
private real spaceGap
readonly string emptySlotTexture
readonly string slotIndicatorModel
readonly framehandle backdrop
readonly real buttonSize
framehandle openButton
IntegerList slots
method setSlotCount takes integer count returns thistype
set slotCount = count
return this
endmethod
method setColumnCount takes integer cols returns thistype
set columns = cols
return this
endmethod
method setTitle takes string str returns thistype
call BlzFrameSetText(title, GetLocalizedString(str))
return this
endmethod
method setTitleSize takes real size returns thistype
set titleSize = size
return this
endmethod
method setBorderSize takes real size returns thistype
set borderSize = size
return this
endmethod
method setButtonSize takes real size returns thistype
set buttonSize = size
return this
endmethod
method setButtonSpaceGap takes real size returns thistype
set spaceGap = size
return this
endmethod
method setSlotEmptyTexture takes string texture returns thistype
set emptySlotTexture = texture
return this
endmethod
method setPosition takes real x, real y returns thistype
call BlzFrameSetAbsPoint(backdrop, FRAMEPOINT_CENTER, x, y)
return this
endmethod
method setOpenButtonPosition takes real x, real y returns thistype
call BlzFrameSetAbsPoint(openButton, FRAMEPOINT_CENTER, x, y)
return this
endmethod
method setOpenButtonTexture takes string str returns thistype
call BlzFrameSetTexture(openIcon, str, 0, true)
return this
endmethod
method setSlotIndicatorModel takes string str returns thistype
set slotIndicatorModel = str
return this
endmethod
method show takes boolean flag returns nothing
call BlzFrameSetVisible(backdrop, flag)
endmethod
method showEx takes player p, boolean flag returns nothing
if LOCAL_PLAYER == p then
call BlzFrameSetVisible(backdrop, flag)
endif
if flag then
set player2Inventory[GetPlayerId(p)] = this
else
call player2Inventory.remove(GetPlayerId(p))
endif
endmethod
method build takes nothing returns nothing
local integer rows = slotCount/columns
local integer i = 0
local integer j = 0
local real x = borderSize
local real y = -borderSize - titleSize
call BlzFrameSetSize(backdrop, columns*buttonSize + (columns - 1)*spaceGap + 2*borderSize, rows*buttonSize + (rows - 1)*spaceGap + 2*borderSize + titleSize)
loop
exitwhen i == slotCount
call slots.push(Slot.create(buttonSize, x, y, this))
set x = x + spaceGap + buttonSize
set j = j + 1
if j == columns then
set j = 0
set x = borderSize
set y = y - spaceGap - buttonSize
endif
set i = i + 1
endloop
call BlzFrameSetSize(openButton, buttonSize, buttonSize)
call BlzFrameSetSize(title, 0, titleSize)
call BlzFrameSetPoint(title, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_TOP, 0, -borderSize*.75)
//call BlzFrameSetSize(pageNumber, 0, titleSize)
//call BlzFrameSetPoint(pageNumber, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_BOTTOM, 0, borderSize)
call BlzFrameSetSize(openButton, buttonSize, buttonSize)
call BlzTriggerRegisterFrameEvent(openTrigger, openButton, FRAMEEVENT_CONTROL_CLICK)
call BlzFrameSetPoint(closeButton, FRAMEPOINT_TOPRIGHT, backdrop, FRAMEPOINT_TOPRIGHT, 0, 0)
call BlzFrameSetSize(closeButton, buttonSize, buttonSize)
call BlzFrameSetText(closeButton, "X")
call BlzTriggerRegisterFrameEvent(closeTrigger, closeButton, FRAMEEVENT_CONTROL_CLICK)
// call BlzFrameSetPoint(nextButton, FRAMEPOINT_BOTTOMRIGHT, backdrop, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
// call BlzFrameSetSize(nextButton, buttonSize, buttonSize)
// call BlzFrameSetText(nextButton, ">")
//
// call BlzFrameSetPoint(prevButton, FRAMEPOINT_BOTTOMLEFT, backdrop, FRAMEPOINT_BOTTOMLEFT, 0, 0)
// call BlzFrameSetSize(prevButton, buttonSize, buttonSize)
// call BlzFrameSetText(prevButton, "<")
endmethod
private static method closeAction takes nothing returns nothing
local SyncData d = GetSyncedData()
local integer pid = GetPlayerId(d.from)
local thistype this = player2Inventory[pid]
local unit selectedUnit = GetMainSelectedUnit(d.readInt(0))
local item item0
local item itemSlot
local framehandle pFrame
local Slot slot
local Table tb
if LOCAL_PLAYER == GetTriggerPlayer() then
call BlzFrameSetVisible(this.backdrop, false)
endif
call player2Inventory.remove(pid)
set pFrame = playerFrame[pid]
set playerFrame[pid] = null
if pFrame != null then
set slot = Slot.frame2Slot[GetHandleId(pFrame)]
set tb = Slot.frame2Item[GetHandleId(pFrame)]
set itemSlot = tb.item[GetHandleId(selectedUnit)]
call SetItemPosition(itemSlot, WorldBounds.minX, WorldBounds.minY)
call SetItemVisible(itemSlot, false)
set itemSlot = null
set pFrame = null
if LOCAL_PLAYER == GetTriggerPlayer() then
call BlzFrameSetVisible(slot.indicator, false)
call BlzFrameSetVisible(dummyIcon, false)
call BlzFrameSetAllPoints(ORIGIN_ITEM_BUTTON_ONE, dummyFrame)
call BlzFrameSetEnable(dummyFrameEx, true)
endif
set item0 = Slot.unit2Item.item[GetHandleId(selectedUnit)]
if item0 != null then
call UnitAddItem(selectedUnit, item0)
call UnitDropItemSlot(selectedUnit, item0, 0)
call Slot.unit2Item.item.remove(GetHandleId(selectedUnit))
set item0 = null
endif
endif
set selectedUnit = null
call d.destroy()
endmethod
private static method close takes nothing returns nothing
local SyncData req = SyncData.create(GetTriggerPlayer())
call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
set req.onComplete = Filter(function thistype.closeAction)
call req.syncInt(GetSelectedUnitIndex())
endmethod
private static method open takes nothing returns nothing
local thistype this = frame2Inventory[GetHandleId(BlzGetTriggerFrame())]
call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
if LOCAL_PLAYER == GetTriggerPlayer() then
call BlzFrameSetVisible(.backdrop, true)
endif
set player2Inventory[GetPlayerId(GetTriggerPlayer())] = this
endmethod
static method createEx takes integer slotCount, integer cols, real buttonSize, real spaceGap, real borderSize, real titleSize, real posX, real posY returns thistype
local thistype this = allocate()
local integer rows = slotCount/columns
local integer i = 0
local integer j = 0
local real x = borderSize
local real y = -borderSize - titleSize
set .slotCount = slotCount
set .columns = cols
set .buttonSize = buttonSize
set .spaceGap = spaceGap
set .buttonSize = buttonSize
set .borderSize = borderSize
set .titleSize = titleSize
set backdrop = BlzCreateFrame("QuestButtonBackdropTemplate", GAME_UI, 0, this)
call BlzFrameSetSize(backdrop, columns*buttonSize + (columns - 1)*spaceGap + 2*borderSize, rows*buttonSize + (rows - 1)*spaceGap + 2*borderSize + titleSize)
call BlzFrameSetAbsPoint(backdrop, FRAMEPOINT_CENTER, posX, posY)
set title = BlzCreateFrameByType("TEXT", "InventoryTitle", backdrop, "", this)
call BlzFrameSetSize(title, 0, titleSize)
call BlzFrameSetPoint(title, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_TOP, 0, -borderSize*.75)
call BlzFrameSetTextAlignment(title, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_TOP)
call BlzFrameSetScale(title, 1.2)
// set pageNumber = BlzCreateFrameByType("TEXT", "InventoryPage", backdrop, "", this)
// call BlzFrameSetSize(pageNumber, 0, titleSize)
// call BlzFrameSetPoint(pageNumber, FRAMEPOINT_CENTER, backdrop, FRAMEPOINT_BOTTOM, 0, borderSize)
// call BlzFrameSetTextAlignment(pageNumber, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
// call BlzFrameSetText(pageNumber, "1")
set openButton = BlzCreateFrameByType("GLUETEXTBUTTON", "InventoryOpen", GAME_UI, "", this)
set openIcon = BlzCreateFrameByType("BACKDROP", "InventoryOpenIcon", openButton, "", this)
call BlzFrameSetAllPoints(openIcon, openButton)
set closeButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
call BlzFrameSetPoint(closeButton, FRAMEPOINT_TOPRIGHT, backdrop, FRAMEPOINT_TOPRIGHT, 0, 0)
call BlzFrameSetSize(closeButton, buttonSize, buttonSize)
call BlzFrameSetText(closeButton, "X")
call BlzTriggerRegisterFrameEvent(closeTrigger, closeButton, FRAMEEVENT_CONTROL_CLICK)
// set nextButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
// call BlzFrameSetPoint(nextButton, FRAMEPOINT_BOTTOMRIGHT, backdrop, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
// call BlzFrameSetSize(nextButton, buttonSize, buttonSize)
// call BlzFrameSetText(nextButton, "→")
//
// set prevButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
// call BlzFrameSetPoint(prevButton, FRAMEPOINT_BOTTOMLEFT, backdrop, FRAMEPOINT_BOTTOMLEFT, 0, 0)
// call BlzFrameSetSize(prevButton, buttonSize, buttonSize)
// call BlzFrameSetText(prevButton, "←")
// call BlzFrameSetVisible(prevButton, false)
set slots = IntegerList.create()
loop
exitwhen i == slotCount
call slots.push(Slot.create(buttonSize, x, y, this))
set x = x + spaceGap + buttonSize
set j = j + 1
if j == columns then
set j = 0
set x = borderSize
set y = y - spaceGap - buttonSize
endif
set i = i + 1
endloop
call BlzFrameSetVisible(backdrop, false)
return this
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set backdrop = BlzCreateFrame("QuestButtonBackdropTemplate", GAME_UI, 0, this)
set title = BlzCreateFrameByType("TEXT", "InventoryTitle", backdrop, "", this)
call BlzFrameSetTextAlignment(title, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_TOP)
call BlzFrameSetScale(title, 1.2)
// set pageNumber = BlzCreateFrameByType("TEXT", "InventoryPage", backdrop, "", this)
// call BlzFrameSetTextAlignment(pageNumber, TEXT_JUSTIFY_MIDDLE, TEXT_JUSTIFY_CENTER)
// call BlzFrameSetText(pageNumber, "1")
set openButton = BlzCreateFrameByType("GLUETEXTBUTTON", "InventoryOpen", GAME_UI, "", this)
set openIcon = BlzCreateFrameByType("BACKDROP", "InventoryOpenIcon", openButton, "", this)
call BlzFrameSetAllPoints(openIcon, openButton)
set frame2Inventory[GetHandleId(openButton)] = this
set closeButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
//set nextButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
//set prevButton = BlzCreateFrame("ScriptDialogButton", backdrop, 0, this)
set slots = IntegerList.create()
call BlzFrameSetVisible(backdrop, false)
return this
endmethod
private static method init takes nothing returns nothing
set GAME_UI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
set LOCAL_PLAYER = GetLocalPlayer()
set player2Inventory = Table.create()
set closeTrigger = CreateTrigger()
call TriggerAddCondition(closeTrigger, Filter(function thistype.close))
set openTrigger = CreateTrigger()
call TriggerAddCondition(openTrigger, Filter(function thistype.open))
set frame2Inventory = Table.create()
endmethod
implement MyModule
endstruct
private function MouseOnItem takes nothing returns nothing
local integer index = HoverOriginButton_CurrentSelectedButtonIndex - HoverOriginButton_ItemButtonOffset
if not IsMouseDraggingItem() then
set originItemSlot = index
endif
if index > 0 then
call BlzFrameSetEnable(dummyFrameEx, true)
set originItemSlotEx = index
endif
endfunction
private function MouseLeftItem takes nothing returns nothing
if not IsMouseDraggingItem() then
set originItemSlot = -1
endif
set originItemSlotEx = -1
endfunction
private function Init takes nothing returns nothing
call HoverOriginButtonAdd(false, function MouseOnItem)
call HoverOriginButtonAddClose(function MouseLeftItem)
//set item2Unit = Table.create()
endfunction
endlibrary
library TimerUtilsEx requires optional Table
/*************************************************
*
* TimerUtilsEx
* v2.1.0.2
* By Vexorian, Bribe & Magtheridon96
*
* Original version by Vexorian.
*
* Flavors:
* Hashtable:
* - RAM: Minimal
* - TimerData: Slow
*
* Array:
* - RAM: Maximal
* - TimerData: Fast
*
* All the functions have O(1) complexity.
* The Array version is the fastest, but the hashtable
* version is the safest. The Array version is still
* quite safe though, and I would recommend using it.
* The system is much slower in debug mode.
*
* Optional Requirement:
* - Table by Bribe
* - hiveworkshop.com/forums/showthread.php?t=188084
*
* API:
* ----
* - function NewTimer takes nothing returns timer
* - Returns a new timer from the stack.
* - function NewTimerEx takes integer i returns timer
* - Returns a new timer from the stack and attaches a value to it.
* - function ReleaseTimer takes timer t returns integer
* - Throws a timer back into the stack. Also returns timer data.
* - function SetTimerData takes timer t, integer value returns nothing
* - Attaches a value to a timer.
* - function GetTimerData takes timer t returns integer
* - Returns the attached value.
*
*************************************************/
// Configuration
globals
// Use hashtable, or fast array?
private constant boolean USE_HASH = false
// Max Number of Timers Held in Stack
private constant integer QUANTITY = 256
endglobals
globals
private timer array tT
private integer tN = 0
endglobals
private module Init
private static method onInit takes nothing returns nothing
static if not USE_HASH then
local integer i = QUANTITY
loop
set i = i - 1
set tT[i] = CreateTimer()
exitwhen i == 0
endloop
set tN = QUANTITY
elseif LIBRARY_Table then
set tb = Table.create()
endif
endmethod
endmodule
// JassHelper doesn't support static ifs for globals.
private struct Data extends array
static if not USE_HASH then
static integer array data
endif
static if LIBRARY_Table then
static Table tb = 0
else
static hashtable ht = InitHashtable()
endif
implement Init
endstruct
// Double free protection
private function ValidTimer takes integer i returns boolean
static if LIBRARY_Table then
return Data.tb.boolean[-i]
else
return LoadBoolean(Data.ht, i, 1)
endif
endfunction
private function Get takes integer id returns integer
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to get data from invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
return Data.tb[id]
else
return LoadInteger(Data.ht, id, 0)
endif
else
return Data.data[id - 0x100000]
endif
endfunction
private function Set takes integer id, integer data returns nothing
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to attach data to invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
set Data.tb[id] = data
else
call SaveInteger(Data.ht, id, 0, data)
endif
else
set Data.data[id - 0x100000] = data
endif
endfunction
function SetTimerData takes timer t, integer data returns nothing
call Set(GetHandleId(t), data)
endfunction
function GetTimerData takes timer t returns integer
return Get(GetHandleId(t))
endfunction
function NewTimerEx takes integer data returns timer
local integer id
if tN == 0 then
static if USE_HASH then
set tT[0] = CreateTimer()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: No Timers In The Stack! You must increase 'QUANTITY'")
return null
endif
else
set tN = tN - 1
endif
set id = GetHandleId(tT[tN])
static if LIBRARY_Table then
set Data.tb.boolean[-id] = true
else
call SaveBoolean(Data.ht, id, 1, true)
endif
call Set(id, data)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
function ReleaseTimer takes timer t returns integer
local integer id = GetHandleId(t)
local integer data = 0
// Pause the timer just in case.
call PauseTimer(t)
// Make sure the timer is valid.
if ValidTimer(id) then
// Get the timer's data.
set data = Get(id)
// Unmark handle id as a valid timer.
static if LIBRARY_Table then
call Data.tb.boolean.remove(-id)
else
call RemoveSavedBoolean(Data.ht, id, 1)
endif
//If it's not run in USE_HASH mode, this next block is useless.
static if USE_HASH then
//At least clear hash memory while it's in the recycle stack.
static if LIBRARY_Table then
call Data.tb.remove(id)
else
call RemoveSavedInteger(Data.ht, id, 0)
endif
// If the recycle limit is reached
if tN == QUANTITY then
// then we destroy the timer.
call DestroyTimer(t)
return data
endif
endif
//Recycle the timer.
set tT[tN] = t
set tN = tN + 1
//Tried to pass a bad timer.
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to release non-active timer!")
endif
//Return Timer Data.
return data
endfunction
endlibrary
library TimerUtils requires TimerUtilsEx
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
library GetMainSelectedUnit initializer init_function // By Tasyen
globals
private framehandle containerFrame
private framehandle array frames
private group Group = CreateGroup()
private unit array units
private integer unitsCount = 0
private filterfunc filter
endglobals
function GetUnitOrderValue takes unit u returns integer
//heroes use the handleId
if IsUnitType(u, UNIT_TYPE_HERO) then
return GetHandleId(u)
else
//units use unitCode
return GetUnitTypeId(u)
endif
endfunction
private function FilterFunction takes nothing returns boolean
local unit u = GetFilterUnit()
local real prio = BlzGetUnitRealField(u, UNIT_RF_PRIORITY)
local boolean found = false
local integer loopA = 1
local integer loopB = 0
// compare the current u with allready found, to place it in the right slot
loop
exitwhen loopA > unitsCount
if BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) < prio then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
// equal prio and better colisions Value
elseif BlzGetUnitRealField(units[loopA], UNIT_RF_PRIORITY) == prio and GetUnitOrderValue(units[loopA]) > GetUnitOrderValue(u) then
set unitsCount = unitsCount + 1
set loopB = unitsCount
loop
exitwhen loopB <= loopA
set units[loopB] = units[loopB - 1]
set loopB = loopB - 1
endloop
set units[loopA] = u
set found = true
exitwhen true
endif
set loopA = loopA + 1
endloop
// not found add it at the end
if not found then
set unitsCount = unitsCount + 1
set units[unitsCount] = u
endif
set u = null
return false
endfunction
function GetSelectedUnitIndex takes nothing returns integer
local integer i = 0
// local player is in group selection?
if BlzFrameIsVisible(containerFrame) then
// find the first visible yellow Background Frame
loop
exitwhen i > 11
if BlzFrameIsVisible(frames[i]) then
return i
endif
set i = i + 1
endloop
endif
return -1
endfunction
function GetMainSelectedUnit takes integer index returns unit
if index >= 0 then
call GroupEnumUnitsSelected(Group, GetLocalPlayer(), filter)
set bj_groupRandomCurrentPick = units[index + 1]
//clear table
loop
exitwhen unitsCount <= 0
set units[unitsCount] = null
set unitsCount = unitsCount - 1
endloop
return bj_groupRandomCurrentPick
else
call GroupEnumUnitsSelected(Group, GetLocalPlayer(), null)
return FirstOfGroup(Group)
endif
endfunction
// returns the local current main selected unit, using it in a sync gamestate relevant manner breaks the game.
function GetMainSelectedUnitEx takes nothing returns unit
return GetMainSelectedUnit(GetSelectedUnitIndex())
endfunction
private function init_functionAt0s takes nothing returns nothing
local integer i = 0
local framehandle console = BlzGetFrameByName("ConsoleUI", 0)
local framehandle bottomUI = BlzFrameGetChild(console, 1)
local framehandle groupframe = BlzFrameGetChild(bottomUI, 5)
local framehandle buttonContainer
//globals
set containerFrame = BlzFrameGetChild(groupframe, 0)
set Group = CreateGroup()
// give this frames a handleId
loop
exitwhen i >= BlzFrameGetChildrenCount(containerFrame) - 1
set buttonContainer = BlzFrameGetChild(containerFrame, i)
set frames[i] = BlzFrameGetChild(buttonContainer, 0)
set i = i + 1
endloop
call DestroyTimer(GetExpiredTimer())
endfunction
private function init_function takes nothing returns nothing
set filter = Filter(function FilterFunction)
call TimerStart(CreateTimer(), 0, false, function init_functionAt0s)
endfunction
endlibrary
library HoverOriginButton initializer Init requires optional FrameLoader
/* HoverOriginButton by Tasyen
This System gives a easy way to setup callbacks when a Command/Item Button is hovered. It uses Tooltips hence the executed callbacks are async.
I created this because one can do this Tooltip approach to know hovering only once per map so that systems don't have to fight over that feature but use it.
function HoverOriginButtonAdd takes boolean forCommandButton, code action returns triggercondition
the action happens when the user starts hovering a button
forCommandButton (true) add to commandButton Actions
action the callback
use HoverOriginButton_CurrentSelectedButtonIndex to know the current hovered Button
Beaware that for itemsButtons ItemButtonOffset is included
function()
yourCode
yourCode
end
returns the new objects can be used for HoverOriginButtonRemove
function HoverOriginButtonAddClose takes code action returns triggercondition
add a callback that happens when the user stops hoveringer a Command/Item Button, async.
function()
yourCode
yourCode
end
function HoverOriginButtonRemove takes triggercondition action returns nothing
removes the table from the callback List
*/
globals
public framehandle array Frames
public timer Timer
public trigger ActionsItem
public trigger ActionsCommand
public trigger ActionsClose
public integer CurrentSelectedButtonIndex = -1
public integer ItemButtonOffset = 30
endglobals
private function TimerAction takes nothing returns nothing
local boolean selectedAnything = false
local integer int
local integer tableIndex
set int = 0
loop
exitwhen int > 11
if BlzFrameIsVisible(Frames[int]) then
set selectedAnything = true
// the new selected is not the same as the current one?
if CurrentSelectedButtonIndex != int then
set CurrentSelectedButtonIndex = int
call TriggerEvaluate(ActionsCommand)
endif
endif
set int = int + 1
endloop
set int = 0
loop
exitwhen int > 5
set tableIndex = int + ItemButtonOffset
if BlzFrameIsVisible(Frames[tableIndex]) then
set selectedAnything = true
// the new selected is not the same as the current one?
if CurrentSelectedButtonIndex != tableIndex then
set CurrentSelectedButtonIndex = tableIndex
call TriggerEvaluate(ActionsItem)
endif
endif
set int = int + 1
endloop
// now selects nothing?
if not selectedAnything and CurrentSelectedButtonIndex != - 1 then
call TriggerEvaluate(ActionsClose)
set CurrentSelectedButtonIndex = -1
endif
endfunction
private function InitFrames takes nothing returns nothing
local framehandle frame
local framehandle buttonFrame
local integer int
//create one tooltip frame for each command button
set int = 0
loop
exitwhen int > 11
set buttonFrame = BlzGetOriginFrame(ORIGIN_FRAME_COMMAND_BUTTON, int)
set frame = BlzCreateFrameByType("SIMPLEFRAME", "", buttonFrame, "", 0)
call BlzFrameSetTooltip(buttonFrame, frame)
call BlzFrameSetVisible(frame, false)
set Frames[int] = frame
set int = int + 1
endloop
//create one tooltip frame for each command button
set int = 0
loop
exitwhen int > 5
set buttonFrame = BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, int)
set frame = BlzCreateFrameByType("SIMPLEFRAME", "", buttonFrame, "", 0)
call BlzFrameSetTooltip(buttonFrame, frame)
call BlzFrameSetVisible(frame, false)
set Frames[int + ItemButtonOffset] = frame
set int = int + 1
endloop
set buttonFrame = null
set frame = null
call TimerStart(Timer, 1.0/32, true, function TimerAction)
endfunction
private function At0s takes nothing returns nothing
call InitFrames()
endfunction
private function Init takes nothing returns nothing
set Timer = CreateTimer()
set ActionsCommand = CreateTrigger()
set ActionsClose = CreateTrigger()
set ActionsItem = CreateTrigger()
call TimerStart(Timer,0 ,false, function At0s)
// Frame related code actions are not saved/Loaded, probably repeat them after Loading the game
static if LIBRARY_FrameLoader then
call FrameLoaderAdd(function InitFrames)
endif
endfunction
function HoverOriginButtonAdd takes boolean forCommandButton, code action returns triggercondition
if forCommandButton then
return TriggerAddCondition(ActionsCommand, Condition(action) )
else
return TriggerAddCondition(ActionsItem, Condition(action) )
endif
endfunction
function HoverOriginButtonAddClose takes code action returns triggercondition
return TriggerAddCondition(ActionsClose, Condition(action) )
endfunction
function HoverOriginButtonRemove takes triggercondition action returns nothing
call TriggerRemoveCondition(ActionsCommand, action)
call TriggerRemoveCondition(ActionsItem, action)
call TriggerRemoveCondition(ActionsClose, action)
endfunction
endlibrary
library StringIterator
/*
Made by: edo494
Version: 1.0
Description:
This piece of code allows you to forward iterate over words in strings,
reading them out from the "container" depending on the delimiter.
API:
struct StringIterator
static method create takes string container returns thistype
- creates new instance
method setDelims takes string delimiters returns nothing
- sets the delimiters to characters in "delimiters"
- example: "abc" will make the instance treat any
a, b or c inside the string as delimiter
method read takes nothing returns string
- returns string containing charaters from "position"
up to "end" or until any delimiter is found
method peek takes nothing returns string
- returns string containing charaters from "position"
up to "end" or until any delimiter is found
- does not move "position" forward
method nextDelim takes nothing returns string
- returns upcomming delimiter pack
- so if 2 or more delimiters after each other occur
this function returns all of them
method operator string= takes string newContainer returns nothing
- sets internal container to "newContainer"
- call to this function resets position
method operator start takes nothing returns boolean
- returns whether the iterator is at the start or not
method operator end takes nothing returns boolean
- returns whether the iterator is at the end or not
method operator size takes nothing returns integer
- returns number of charaters inside the container
method operator position takes nothing returns integer
- returns the current position of the iterator inside container
method operator position= takes integer newPos returns boolean
- sets the position to the "newPos"
- in debug mode, if <0 or >size, returns false
otherwise true
- outside of debug mode, returns true
method reset takes nothing returns nothing
- returns the iterator to start
*/
struct StringIterator
private string myStr
private string myDelims
private integer pointer
private integer sSize
private integer dSize
static method create takes string s returns thistype
local thistype this = allocate()
set this.myStr = s
set this.myDelims = " "
set this.pointer = 0
set this.dSize = StringLength(this.myDelims)
set this.sSize = StringLength(s)
return this
endmethod
static method createEx takes string container, string delims returns thistype
local thistype this = allocate()
set this.myStr = container
set this.myDelims = delims
set this.pointer = 0
set this.dSize = StringLength(delims)
set this.sSize = StringLength(container)
return this
endmethod
method setDelims takes string s returns nothing
set this.myDelims = s
set this.dSize = StringLength(s)
endmethod
method operator start takes nothing returns boolean
return this.pointer <= 0
endmethod
method operator end takes nothing returns boolean
return this.pointer >= this.sSize
endmethod
method operator size takes nothing returns integer
return this.sSize
endmethod
method operator position takes nothing returns integer
return this.pointer
endmethod
private method isDelim takes string s returns boolean
local integer i = this.dSize
local string delims = this.myDelims
if s == null then
return true
endif
loop
exitwhen i == 0
if s == SubString(delims, i-1, i) then
return true
endif
set i = i - 1
endloop
return false
endmethod
private method readBool takes boolean b returns string
local string helper = ""
local string ths = this.myStr
local integer size = this.sSize
local integer current = this.pointer
local string cont = ""
//evade all remaining delimiters from the last read
loop
if current == size then
exitwhen true
endif
exitwhen not isDelim(SubString(ths, current, current+1))
set current = current + 1
endloop
//fill up the string
loop
exitwhen current == size
set helper = SubString(ths, current, current+1)
exitwhen isDelim(helper)
set cont = cont + helper
set current = current + 1
endloop
if b then
set this.pointer = current
endif
//return the string
return cont
endmethod
method read takes nothing returns string
return readBool(true)
endmethod
method peek takes nothing returns string
return readBool(false)
endmethod
method nextDelim takes nothing returns string
local string ths = this.myStr
local integer size = this.sSize
local integer current = this.pointer
local string s = ""
local string q = ""
if current == size then
return ""
endif
//evade all non delimiters
loop
set q = SubString(ths, current, current+1)
exitwhen current == size or not isDelim(q)
set current = current + 1
endloop
//read next delimiters
loop
set q = SubString(ths, current, current+1)
exitwhen current == size or not isDelim(q)
set s = s + q
set current = current + 1
endloop
//return them
return s
endmethod
method operator position= takes integer newPosition returns boolean
debug if newPosition > this.size or newPosition < 0 then
debug return false
debug endif
set this.pointer = newPosition
return true
endmethod
method reset takes nothing returns nothing
set this.pointer = 0
endmethod
method operator string= takes string s returns nothing
set this.myStr = s
set this.sSize = StringLength(s)
set this.pointer = 0
endmethod
endstruct
endlibrary
/*****************************************************************************
*
* List<T> v2.1.2.3
* by Bannar
*
* Doubly-linked list.
*
******************************************************************************
*
* Requirements:
*
* Table by Bribe
* hiveworkshop.com/threads/snippet-new-table.188084/
*
* Alloc - choose whatever you like
* e.g.: by Sevion hiveworkshop.com/threads/snippet-alloc.192348/
*
******************************************************************************
*
* Implementation:
*
* macro DEFINE_LIST takes ACCESS, NAME, TYPE
*
* macro DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
*
* ACCESS - encapsulation, choose restriction access
* NAME - name of list type
* TYPE - type of values stored
*
* Implementation notes:
*
* - DEFINE_STRUCT_LIST macro purpose is to provide natural typecasting syntax for struct types.
* - <NAME>Item structs inline directly into hashtable operations thus generate basically no code.
* - Lists defined with DEFINE_STRUCT_LIST are inlined nicely into single create method and single integer array.
*
******************************************************************************
*
* struct API:
*
* struct <NAME>Item:
*
* | <TYPE> data
* | <NAME>Item next
* | <NAME>Item prev
*
*
* General:
*
* | static method create takes nothing returns thistype
* | Default ctor.
* |
* | static method operator [] takes thistype other returns thistype
* | Copy ctor.
* |
* | method destroy takes nothing returns nothing
* | Default dctor.
* |
* | method empty takes nothing returns boolean
* | Checks whether the list is empty.
* |
* | method size takes nothing returns integer
* | Returns size of a list.
*
*
* Access:
*
* | readonly <NAME>Item first
* | readonly <NAME>Item last
* |
* | method front takes nothing returns $TYPE$
* | Retrieves first element.
* |
* | method back takes nothing returns $TYPE$
* | Retrieves last element.
*
*
* Modifiers:
*
* | method clear takes nothing returns nothing
* | Flushes list and recycles its nodes.
* |
* | method push takes $TYPE$ value returns thistype
* | Adds elements to the end.
* |
* | method unshift takes $TYPE$ value returns thistype
* | Adds elements to the front.
* |
* | method pop takes nothing returns thistype
* | Removes the last element.
* |
* | method shift takes nothing returns thistype
* | Removes the first element.
* |
* | method find takes $TYPE$ value returns $NAME$Item
* | Returns the first node which data equals value.
* |
* | method erase takes $NAME$Item node returns boolean
* | Removes node from the list, returns true on success.
* |
* | method removeElem takes $TYPE$ value returns thistype
* | Removes first element that equals value from the list.
*
*
*****************************************************************************/
library ListT requires Table, Alloc
//! runtextmacro DEFINE_LIST("", "IntegerList", "integer")
// Run here any global list types you want to be defined.
//! textmacro_once DEFINE_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
// No default ctor and dctor due to limited array size
method operator data takes nothing returns $TYPE$
return Table(this).$TYPE$[-1] // hashtable[ node, -1 ] = data
endmethod
method operator data= takes $TYPE$ value returns nothing
set Table(this).$TYPE$[-1] = value
endmethod
method operator next takes nothing returns thistype
return Table(this)[-2] // hashtable[ node, -2 ] = next
endmethod
method operator next= takes thistype value returns nothing
set Table(this)[-2] = value
endmethod
method operator prev takes nothing returns thistype
return Table(this)[-3] // hashtable[ node, -3 ] = prev
endmethod
method operator prev= takes thistype value returns nothing
set Table(this)[-3] = value
endmethod
endstruct
$ACCESS$ struct $NAME$ extends array
readonly $NAME$Item first
readonly $NAME$Item last
private integer count
implement Alloc
private static method setNodeOwner takes $NAME$Item node, $NAME$ owner returns nothing
set Table(node)[-4] = owner
endmethod
private static method getNodeOwner takes $NAME$Item node returns thistype
return Table(node)[-4]
endmethod
private method createNode takes $TYPE$ value returns $NAME$Item
local $NAME$Item node = Table.create()
set node.data = value
call setNodeOwner(node, this) // ownership
return node
endmethod
private method deleteNode takes $NAME$Item node returns nothing
call Table(node).destroy() // also removes ownership
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
set count = 0
return this
endmethod
method clear takes nothing returns nothing
local $NAME$Item node = first
local $NAME$Item temp
loop // recycle all Table indexes
exitwhen 0 == node
set temp = node.next
call deleteNode(node)
set node = temp
endloop
set first = 0
set last = 0
set count = 0
endmethod
method destroy takes nothing returns nothing
call clear()
call deallocate()
endmethod
method front takes nothing returns $TYPE$
return first.data
endmethod
method back takes nothing returns $TYPE$
return last.data
endmethod
method empty takes nothing returns boolean
return count == 0
endmethod
method size takes nothing returns integer
return count
endmethod
method push takes $TYPE$ value returns thistype
local $NAME$Item node = createNode(value)
if not empty() then
set last.next = node
set node.prev = last
else
set first = node
set node.prev = 0
endif
set last = node
set node.next = 0
set count = count + 1
return this
endmethod
method unshift takes $TYPE$ value returns thistype
local $NAME$Item node = createNode(value)
if not empty() then
set first.prev = node
set node.next = first
else
set last = node
set node.next = 0
endif
set first = node
set node.prev = 0
set count = count + 1
return this
endmethod
method pop takes nothing returns thistype
local $NAME$Item node
if not empty() then
set node = last
set last = last.prev
if last == 0 then
set first = 0
else
set last.next = 0
endif
call deleteNode(node)
set count = count - 1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::pop failed for instance "+I2S(this)+". List is empty.")
endif
return this
endmethod
method shift takes nothing returns thistype
local $NAME$Item node
if not empty() then
set node = first
set first = first.next
if first == 0 then
set last = 0
else
set first.prev = 0
endif
call deleteNode(node)
set count = count - 1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::shift failed for instance "+I2S(this)+". List is empty.")
endif
return this
endmethod
static method operator [] takes thistype other returns thistype
local thistype instance = create()
local $NAME$Item node = other.first
loop
exitwhen node == 0
call instance.push(node.data)
set node = node.next
endloop
return instance
endmethod
method find takes $TYPE$ value returns $NAME$Item
local $NAME$Item node = first
loop
exitwhen node == 0 or node.data == value
set node = node.next
endloop
return node
endmethod
method erase takes $NAME$Item node returns boolean
if getNodeOwner(node) == this then // match ownership
if node == first then
call shift()
elseif node == last then
call pop()
else
set node.prev.next = node.next
set node.next.prev = node.prev
call deleteNode(node)
set count = count - 1
endif
return true
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"$NAME$::erase failed for instance "+I2S(this)+". Attempted to remove invalid node "+I2S(node)+".")
endif
return false
endmethod
method remove takes $NAME$Item node returns boolean
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Method $NAME$::remove is obsolete, use $NAME$::erase instead.")
return erase(node)
endmethod
method removeElem takes $TYPE$ value returns thistype
local $NAME$Item node = find(value)
if node != 0 then
call erase(node)
endif
return this
endmethod
endstruct
//! endtextmacro
//! textmacro_once DEFINE_STRUCT_LIST takes ACCESS, NAME, TYPE
$ACCESS$ struct $NAME$Item extends array
// Cannot inherit methods via delegate due to limited array size
method operator data takes nothing returns $TYPE$
return IntegerListItem(this).data
endmethod
method operator data= takes $TYPE$ value returns nothing
set IntegerListItem(this).data = value
endmethod
method operator next takes nothing returns thistype
return IntegerListItem(this).next
endmethod
method operator next= takes thistype value returns nothing
set IntegerListItem(this).next = value
endmethod
method operator prev takes nothing returns thistype
return IntegerListItem(this).prev
endmethod
method operator prev= takes thistype value returns nothing
set IntegerListItem(this).prev = value
endmethod
endstruct
$ACCESS$ struct $NAME$ extends array
private delegate IntegerList parent
static method create takes nothing returns thistype
local thistype this = IntegerList.create()
set parent = this
return this
endmethod
method front takes nothing returns $TYPE$
return parent.front()
endmethod
method back takes nothing returns $TYPE$
return parent.back()
endmethod
endstruct
//! endtextmacro
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
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
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library Alloc /* v1.1.0 https://www.hiveworkshop.com/threads/324937/
*/uses /*
*/Table /* https://www.hiveworkshop.com/threads/188084/
*/optional ErrorMessage /* https://github.com/nestharus/JASS/blob/master/jass/Systems/ErrorMessage/main.j
*///! novjass
/*
Written by AGD, based on MyPad's allocation algorithm
A allocator module using a single global indexed stack. Allocated values are
within the JASS_MAX_ARRAY_SIZE. No more need to worry about code bloats behind
the module implementation as it generates the least code possible (6 lines of
code in non-DEBUG_MODE), nor does it use an initialization function. This system
also only uses ONE variable (for the whole map) for the hashtable.
*/
|-----|
| API |
|-----|
/*
*/module GlobalAlloc/*
- Uses a single stack globally
*/module Alloc/*
- Uses a unique stack per struct
*/debug readonly boolean allocated/* Is node allocated?
*/static method allocate takes nothing returns thistype/*
*/method deallocate takes nothing returns nothing/*
*///! endnovjass
/*===========================================================================*/
globals
private key stack
endglobals
static if DEBUG_MODE then
private function AssertError takes boolean condition, string methodName, string structName, integer node, string message returns nothing
static if LIBRARY_ErrorMessage then
call ThrowError(condition, SCOPE_PREFIX, methodName, structName, node, message)
else
if condition then
call BJDebugMsg("[Library: " + SCOPE_PREFIX + "] [Struct: " + structName + "] [Method: " + methodName + "] [Instance: " + I2S(node) + "] : |cffff0000" + message + "|r")
endif
endif
endfunction
public function IsAllocated takes integer typeId, integer node returns boolean
return node > 0 and Table(stack)[typeId*JASS_MAX_ARRAY_SIZE + node] == 0
endfunction
endif
public function Allocate takes integer typeId returns integer
local integer offset = typeId*JASS_MAX_ARRAY_SIZE
local integer node = Table(stack)[offset]
local integer stackNext = Table(stack)[offset + node]
debug call AssertError(typeId < 0, "allocate()", Table(stack).string[-typeId], 0, "Invalid struct ID (" + I2S(typeId) + ")")
if stackNext == 0 then
debug call AssertError(node == (JASS_MAX_ARRAY_SIZE - 1), "allocate()", Table(stack).string[-typeId], node, "Overflow")
set node = node + 1
set Table(stack)[offset] = node
else
set Table(stack)[offset] = stackNext
set Table(stack)[offset + node] = 0
endif
return node
endfunction
public function Deallocate takes integer typeId, integer node returns nothing
local integer offset = typeId*JASS_MAX_ARRAY_SIZE
debug call AssertError(node == 0, "deallocate()", Table(stack).string[-typeId], 0, "Null node")
debug call AssertError(Table(stack)[offset + node] > 0, "deallocate()", Table(stack).string[-typeId], node, "Double-free")
set Table(stack)[offset + node] = Table(stack)[offset]
set Table(stack)[offset] = node
endfunction
module Alloc
debug method operator allocated takes nothing returns boolean
debug return IsAllocated(thistype.typeid, this)
debug endmethod
static method allocate takes nothing returns thistype
return Allocate(thistype.typeid)
endmethod
method deallocate takes nothing returns nothing
call Deallocate(thistype.typeid, this)
endmethod
debug private static method onInit takes nothing returns nothing
debug set Table(stack).string[-thistype.typeid] = "thistype"
debug endmethod
endmodule
module GlobalAlloc
debug method operator allocated takes nothing returns boolean
debug return IsAllocated(0, this)
debug endmethod
static method allocate takes nothing returns thistype
debug call AssertError(Table(stack)[0] == (JASS_MAX_ARRAY_SIZE - 1), "allocate()", "thistype", JASS_MAX_ARRAY_SIZE - 1, "Overflow")
return Allocate(0)
endmethod
method deallocate takes nothing returns nothing
debug call AssertError(this == 0, "deallocate()", "thistype", 0, "Null node")
debug call AssertError(Table(stack)[this] > 0, "deallocate()", "thistype", this, "Double-free")
call Deallocate(0, this)
endmethod
endmodule
endlibrary
library Sync requires SyncInteger, optional PlayerUtils
/***************************************************************
*
* v1.3.0, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* This library allows you to quickly synchronize async data such as
* the contents of a local file to all players in the map by using the game cache.
*
* Full Documentation: -http://www.hiveworkshop.com/forums/pastebin.php?id=p4f84s
*
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it (requires JassHelper *or* JNGP)
*
* SyncInteger: https://www.hiveworkshop.com/threads/syncinteger.278674/
* PlayerUtils: https://www.hiveworkshop.com/threads/playerutils.278559/
* _________________________________________________________________________
* 2. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct SyncData
*
* method start takes nothing returns nothing
* method startChunk takes integer i, integer end returns nothing
* method refresh takes nothing returns nothing
* method destroy takes nothing returns nothing
*
* method addInt takes integer i returns nothing
* method addReal takes integer i returns nothing
* method addString takes string s, integer len returns nothing
* method addBool takes booleanflag returns nothing
*
* method readInt takes integer index returns integer
* method readReal takes integer index returns integer
* method readString takes integer index returns string
* method readBool takes integer index returns boolean
*
* method hasInt takes integer index returns boolean
* method hasReal takes integer index returns boolean
* method hasString takes integer index returns boolean
* method hasBool takes integer index returns boolean
*
* method syncInt takes integer i returns nothing
* method syncReal takes integer i returns nothing
* method syncString takes string s, integer len returns nothing
* method syncBool takes booleanflag returns nothing
*
* method isPlayerDone takes player p returns boolean
* method isPlayerIdDone takes integer pid returns boolean
*
* method addEventListener takes filterfunc func returns nothing
*
* ---------
*
* filterfunc onComplete
* filterfunc onError
* filterfunc onUpdate
* trigger trigger
*
* readonly player from
*
* readonly real timeStarted
* readonly real timeFinished
* readonly real timeElapsed
*
* readonly integer intCount
* readonly integer boolCount
* readonly integer strCount
* readonly integer realCount
* readonly integer playersDone
*
* readonly boolean buffering
*
* readonly static integer last
* readonly static player LocalPlayer
* readonly static boolean Initialized
*
* static method create takes player from returns SyncData
* static method destroy takes nothing returns nothing
* static method gameTime takes nothing returns real
*
* function GetSyncedData takes nothing returns SyncData
*
***************************************************************/
globals
// characters that can be synced (ascii)
private constant string ALPHABET = " !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"\t\n"
// safe characters for use in game cache keys
// (case sensitive)
private constant string SAFE_KEYS = " !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`{|}~\"\t\n"
// stop reading the string buffer when reaching this char (this char cannot be synced)
private constant string TERM_CHAR = "~"
// how fast the buffer updates
private constant real UPDATE_PERIOD = 0.03125
// automatically recycle indices when the syncing player leaves
private constant boolean AUTO_DESTROY_ON_LEAVE = true
// automatically stop buffering when an error occurs
private constant boolean STOP_BUFFERING_ON_ERROR = true
// preload game cache key strings on init
private constant boolean PRELOAD_STR_CACHE = true
// size of the alphabet
private constant integer ALPHABET_BASE = StringLength(ALPHABET)
// maximum number of strings *per instance*
private constant integer MAX_STRINGS = 8192 // or any arbitrary high number
// filenames for gc (short names have faster sync time)
private constant string CACHE_FILE = "i"
private constant string CACHE_FILE_STR = "s"
// don't edit below this line
constant integer EVENT_SYNC_CACHE = 3
constant integer SYNC_ERROR_TIMEOUT = 1
constant integer SYNC_ERROR_PLAYERLEFT = 2
private SelectionSync Synchronizer
endglobals
//**************************************************************
function GetSyncedData takes nothing returns SyncData
return SyncData(SyncData.Last)
endfunction
public function I2Char takes string alphabet, integer i returns string
return SubString(alphabet, i, i + 1)
endfunction
public function Char2I takes string alphabet, string c returns integer
local integer i = 0
local string s
local integer l = StringLength(alphabet)
loop
set s = I2Char(alphabet, i)
exitwhen i == l
if (s == c) then
return i
endif
set i = i + 1
endloop
return 0
endfunction
public function ConvertBase takes string alphabet, integer i returns string
local integer b
local string s = ""
local integer l = StringLength(alphabet)
if i < l then
return I2Char(alphabet, i)
endif
loop
exitwhen i <= 0
set b = i - ( i / l ) * l
set s = I2Char(alphabet, b) + s
set i = i / l
endloop
return s
endfunction
public function PopulateString takes string s, integer makeLen returns string
local integer i = 0
local integer l = StringLength(s)
if (l == makeLen) then
return s
endif
set l = makeLen-l
loop
exitwhen i > l
set s = s + TERM_CHAR
set i = i + 1
endloop
return s
endfunction
//**************************************************************
globals
// string table keys
private constant integer KEY_STR_POS = (0*MAX_STRINGS)
private constant integer KEY_STR_LEN = (1*MAX_STRINGS)
// pending data storage space
private constant integer KEY_STR_CACHE = (2*MAX_STRINGS)
endglobals
struct SyncData
real timeout
filterfunc onComplete
filterfunc onError
filterfunc onUpdate
trigger trigger
readonly integer lastError
readonly player from
readonly real timeStarted
readonly real timeFinished
readonly real timeElapsed
readonly integer intCount
readonly integer boolCount
readonly integer strCount
readonly integer realCount
readonly integer playersDone
readonly boolean buffering
readonly static boolean Initialized = false
readonly static integer Last = 0
readonly static player LocalPlayer
readonly static integer LocalPlayerID
private static integer Running = 0
private static real timeCounter = 0.00
private static trigger EventTrig = CreateTrigger()
private static hashtable Table
private static hashtable CharTable
private static gamecache array Cache
private static integer array PendingCount
private static timer Elapsed
private static timer BufferTimer
private static integer AlphaHash
private integer strBufferLen
private trigger eventTrig
private string mkey
private boolean localFinished
private thistype next
private thistype prev
static method bool2I takes boolean b returns integer
if (b) then
return 1
endif
return 0
endmethod
private static method hashString takes string c returns integer
return StringHash(I2S(bool2I(StringCase(c, true) == c)) + c)
endmethod
static method char2I takes string alphabet, string c returns integer // requires preloading table with data
return LoadInteger(SyncData.CharTable, .AlphaHash, .hashString(c))
endmethod
private method resetVars takes nothing returns nothing
set this.intCount = 0
set this.strCount = 0
set this.boolCount = 0
set this.realCount = 0
set this.playersDone = 0
set this.strBufferLen = 0
set this.timeStarted = 0
set this.timeFinished = 0
set this.lastError = 0
set this.onComplete = null
set this.onError = null
set this.onUpdate = null
set this.timeout = 0.00
set this.buffering = false
set this.localFinished = false
set this.trigger = null
endmethod
private static method getKey takes integer pos returns string
local string position=""
if (HaveSavedString(Table, KEY_STR_CACHE, pos)) then
return LoadStr(Table, KEY_STR_CACHE, pos)
endif
set position = ConvertBase(SAFE_KEYS, pos)
call SaveStr(Table, KEY_STR_CACHE, pos, position)
return position
endmethod
static method create takes player from returns thistype
local thistype this
// Player has to be playing because of GetLocalPlayer use.
if (GetPlayerController(from) != MAP_CONTROL_USER or GetPlayerSlotState(from) != PLAYER_SLOT_STATE_PLAYING) then
return 0
endif
set this = thistype.allocate()
set this.from = from
set this.mkey = getKey(this-1)
call this.resetVars()
set thistype(0).next.prev = this
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = 0
return this
endmethod
method refresh takes nothing returns nothing
local integer i = 0
local integer p = 0
loop
static if (LIBRARY_PlayerUtils) then
exitwhen i == User.AmountPlaying
set p = User.fromPlaying(i).id
else
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = i
endif
call RemoveSavedInteger(Table, this, KEY_STR_POS + p)
call RemoveSavedInteger(Table, this, KEY_STR_LEN + p)
call RemoveSavedBoolean(Table, p, this) // playerdone
set i = i + 1
endloop
call FlushStoredMission(Cache[0], this.mkey)
call FlushStoredMission(Cache[1], this.mkey)
call this.resetVars()
endmethod
method destroy takes nothing returns nothing
if (this.eventTrig != null) then
call DestroyTrigger(this.eventTrig)
set this.eventTrig=null
endif
call this.refresh()
set this.next.prev = this.prev
set this.prev.next = this.next
call this.deallocate()
endmethod
method hasInt takes integer index returns boolean
return HaveStoredInteger(Cache[0], this.mkey, getKey(index))
endmethod
method hasReal takes integer index returns boolean
return HaveStoredReal(Cache[0], this.mkey, getKey(index))
endmethod
method hasBool takes integer index returns boolean
return HaveStoredBoolean(Cache[0], this.mkey, getKey(index))
endmethod
method hasString takes integer index returns boolean
local integer i = LoadInteger(Table, this, KEY_STR_POS+index)
if (index > 0 and i == 0) then
return false
endif
return HaveStoredInteger(Cache[1], this.mkey, getKey(i + LoadInteger(Table, this, KEY_STR_LEN+index)))
endmethod
method addInt takes integer i returns nothing
local string position=getKey(intCount)
if (LocalPlayer == this.from) then
call StoreInteger(Cache[0], this.mkey, position, i)
endif
set intCount=intCount+1
endmethod
method addReal takes real i returns nothing
local string position=getKey(realCount)
if (LocalPlayer == this.from) then
call StoreReal(Cache[0], this.mkey, position, i)
endif
set realCount=realCount+1
endmethod
method addBool takes boolean flag returns nothing
local string position=getKey(boolCount)
if (LocalPlayer == this.from) then
call StoreBoolean(Cache[0], this.mkey, position, flag)
endif
set boolCount=boolCount+1
endmethod
// SyncStoredString doesn't work
method addStringEx takes string s, integer maxLen, boolean doSync returns nothing
local string position
local integer i = 0
local integer strPos = 0
local integer strLen = 0
if (StringLength(s) < maxLen) then
set s = PopulateString(s, maxLen)
endif
// store the string position in the table
if (strCount == 0) then
call SaveInteger(Table, this, KEY_STR_POS, 0)
else
set strLen = LoadInteger(Table, this, KEY_STR_LEN + (strCount-1)) + 1
set strPos = LoadInteger(Table, this, KEY_STR_POS + (strCount-1)) + strLen
call SaveInteger(Table, this, KEY_STR_POS + strCount, strPos)
endif
// convert each character in the string to an integer
loop
exitwhen i > maxLen
set position = getKey(strPos + i)
if (LocalPlayer == this.from) then
call StoreInteger(Cache[1], this.mkey, position, .char2I(ALPHABET, SubString(s, i, i + 1)))
if (doSync and LocalPlayer == this.from) then
call SyncStoredInteger(Cache[1], this.mkey, position)
endif
endif
set i = i + 1
endloop
set strBufferLen = strBufferLen + maxLen
call SaveInteger(Table, this, KEY_STR_LEN+strCount, maxLen) // store the length as well
set strCount=strCount+1
endmethod
method addString takes string s, integer maxLen returns nothing
call addStringEx(s, maxLen, false)
endmethod
method readInt takes integer index returns integer
return GetStoredInteger(Cache[0], this.mkey, getKey(index))
endmethod
method readReal takes integer index returns real
return GetStoredReal(Cache[0], this.mkey, getKey(index))
endmethod
method readBool takes integer index returns boolean
return GetStoredBoolean(Cache[0], this.mkey, getKey(index))
endmethod
method readString takes integer index returns string
local string s = ""
local string c
local integer i = 0
local integer strLen = LoadInteger(Table, this, KEY_STR_LEN+index)
local integer strPos
if (not hasString(index)) then
return null
endif
set strLen = LoadInteger(Table, this, KEY_STR_LEN+index)
set strPos = LoadInteger(Table, this, KEY_STR_POS+index)
loop
exitwhen i > strLen
set c = I2Char(ALPHABET, GetStoredInteger(Cache[1], this.mkey, getKey(strPos + i)))
if (c == TERM_CHAR) then
return s
endif
set s = s + c
set i = i + 1
endloop
return s
endmethod
private method fireListeners takes nothing returns nothing
set Last = this
if (this.eventTrig != null) then
call TriggerEvaluate(this.eventTrig)
endif
if (this.trigger != null and TriggerEvaluate(this.trigger)) then
call TriggerExecute(this.trigger)
endif
endmethod
private method fireEvent takes filterfunc func returns nothing
set Last = this
call TriggerAddCondition(EventTrig, func)
call TriggerEvaluate(EventTrig)
call TriggerClearConditions(EventTrig)
endmethod
method addEventListener takes filterfunc func returns nothing
if (this.eventTrig == null) then
set this.eventTrig = CreateTrigger()
endif
call TriggerAddCondition(this.eventTrig, func)
endmethod
public static method gameTime takes nothing returns real
return timeCounter + TimerGetElapsed(Elapsed)
endmethod
private method error takes integer errorId returns nothing
set this.lastError = errorId
if (this.onError != null) then
call this.fireEvent(this.onError)
endif
call this.fireListeners()
static if (STOP_BUFFERING_ON_ERROR) then
set this.buffering = false
endif
endmethod
private static method readBuffer takes nothing returns nothing
local boolean b = true
local integer i = 0
local thistype data = thistype(0).next
loop
exitwhen data == 0
// find the nearest instance that is still buffering
loop
exitwhen data.buffering or data == 0
set data=data.next
endloop
// if none are found, exit
if (not data.buffering) then
return
endif
set data.timeElapsed = data.timeElapsed + UPDATE_PERIOD
if (data.onUpdate != null) then
call data.fireEvent(data.onUpdate)
endif
if (data.timeout > 0 and data.timeElapsed > data.timeout) then
call data.error(SYNC_ERROR_TIMEOUT)
endif
// if the player has left, destroy the instance
if (GetPlayerSlotState(data.from) != PLAYER_SLOT_STATE_PLAYING) then
call data.error(SYNC_ERROR_PLAYERLEFT)
static if (AUTO_DESTROY_ON_LEAVE) then
call data.destroy()
endif
endif
set b = true
// make sure all integers have been synced
if (data.intCount > 0 and not data.hasInt(data.intCount-1)) then
set b = false
endif
// make sure all reals have been synced
if (data.realCount > 0 and not data.hasReal(data.realCount-1)) then
set b = false
endif
// check strings too
if (data.strCount > 0 and not data.hasString(data.strCount-1)) then
set b = false
endif
// and booleans
if (data.boolCount > 0 and not data.hasBool(data.boolCount-1)) then
set b = false
endif
// if everything has been synced
if (b) then
if (not data.localFinished) then // async
set data.localFinished = true
// notify everyone that the local player has recieved all of the data
call Synchronizer.syncValue(LocalPlayer, data)
endif
endif
set data = data.next
endloop
endmethod
public method initInstance takes nothing returns nothing
if (this.timeStarted != 0.00) then
return
endif
set this.timeStarted = gameTime()
set this.playersDone = 0
set this.buffering = true
set this.timeElapsed = (UPDATE_PERIOD - TimerGetElapsed(BufferTimer)) * -1
if (Running==0) then
call TimerStart(BufferTimer, UPDATE_PERIOD, true, function thistype.readBuffer)
call thistype.readBuffer()
endif
set Running=Running+1
endmethod
method syncInt takes integer i returns nothing
local string position = getKey(intCount)
call this.addInt(i)
if (LocalPlayer == this.from) then
call SyncStoredInteger(Cache[0], this.mkey, position)
endif
call this.initInstance()
endmethod
method syncReal takes real r returns nothing
local string position = getKey(realCount)
call this.addReal(r)
if (LocalPlayer == this.from) then
call SyncStoredReal(Cache[0], this.mkey, position)
endif
call this.initInstance()
endmethod
method syncBoolean takes boolean b returns nothing
local string position = getKey(boolCount)
call this.addBool(b)
if (LocalPlayer == this.from) then
call SyncStoredReal(Cache[0], this.mkey, position)
endif
call this.initInstance()
endmethod
method syncString takes string s, integer maxLen returns nothing
local string position = getKey(strCount)
call this.addStringEx(s, maxLen, true)
call this.initInstance()
endmethod
method startChunk takes integer i, integer end returns boolean
local integer n = 0
local integer j = 0
local integer p = 0
local string position
if (this.timeStarted != 0.00) then
return false
endif
// Begin syncing
loop
exitwhen i > end
set position = LoadStr(Table, KEY_STR_CACHE, i)
if (i < intCount and LocalPlayer == this.from) then
call SyncStoredInteger(Cache[0], this.mkey, position)
endif
if (i < realCount and LocalPlayer == this.from) then
call SyncStoredReal(Cache[0], this.mkey, position)
endif
if (i < boolCount and LocalPlayer == this.from) then
call SyncStoredBoolean(Cache[0], this.mkey, position)
endif
if (i < strCount and LocalPlayer == this.from) then
set n = LoadInteger(Table, this, KEY_STR_LEN + i)
set p = LoadInteger(Table, this, KEY_STR_POS + i)
set j = 0
loop
exitwhen j > n
set position = LoadStr(Table, KEY_STR_CACHE, p + j)
if (LocalPlayer == this.from) then
call SyncStoredInteger(Cache[1], this.mkey, position)
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
call this.initInstance()
return true
endmethod
method start takes nothing returns boolean
local integer l = intCount
// Find the highest count
if (l < realCount) then
set l = realCount
endif
if (l < strCount) then
set l = strCount
endif
if (l < boolCount) then
set l = boolCount
endif
return startChunk(0, l)
endmethod
method isPlayerIdDone takes integer pid returns boolean
return LoadBoolean(Table, pid, this)
endmethod
method isPlayerDone takes player p returns boolean
return isPlayerIdDone(GetPlayerId(p))
endmethod
private static method updateStatus takes nothing returns boolean
local integer i = 0
local integer p = GetSyncedPlayerId()
local boolean b = true
local boolean c = true
local thistype data = GetSyncedInteger()
local triggercondition tc
if (GetSyncedInstance() != Synchronizer or not data.buffering) then
return false
endif
set data.playersDone = data.playersDone + 1
call SaveBoolean(Table, p, data, true) // set playerdone
// check if everyone has received the data
loop
static if (LIBRARY_PlayerUtils) then
exitwhen i == User.AmountPlaying
set p = User.fromPlaying(i).id
set c = User.fromPlaying(i).isPlaying
else
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = i
set c = (GetPlayerController(Player(p)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING)
endif
if (c and not data.isPlayerIdDone(p)) then
set b = false // someone hasn't
endif
set i = i + 1
endloop
// if everyone has recieved the data
if (b) then
set Running = Running-1
if (Running == 0) then
call PauseTimer(BufferTimer)
endif
set data.buffering = false
set data.timeFinished = gameTime()
set data.timeElapsed = data.timeFinished - data.timeStarted
// fire events
if (data.onComplete != null) then
call data.fireEvent(data.onComplete)
endif
call data.fireListeners()
call SyncInteger_FireEvents(EVENT_SYNC_CACHE)
endif
return false
endmethod
private static method trackTime takes nothing returns nothing
set timeCounter = timeCounter + 10
endmethod
private static method preloadChar2I takes nothing returns nothing
local integer i = 0
local string c
set .AlphaHash = .hashString(ALPHABET)
loop
exitwhen i >= ALPHABET_BASE
set c = I2Char(ALPHABET, i)
call SaveInteger(SyncData.CharTable, .AlphaHash, .hashString(c), Char2I(ALPHABET, c))
set i = i + 1
endloop
endmethod
private static method onInit takes nothing returns nothing
static if (SyncInteger_DEFAULT_INSTANCE) then
set Synchronizer = SyncInteger_DefaultInstance
else
set Synchronizer = SelectionSync.create()
endif
set Table = InitHashtable()
set CharTable = InitHashtable()
set Cache[0] = InitGameCache(CACHE_FILE)
set Cache[1] = InitGameCache(CACHE_FILE_STR)
set Elapsed = CreateTimer()
set BufferTimer = CreateTimer()
static if (LIBRARY_PlayerUtils) then
set LocalPlayer = User.Local
set LocalPlayerID = User.fromLocal().id
else
set LocalPlayer = GetLocalPlayer()
set LocalPlayerID = GetPlayerId(LocalPlayer)
endif
call OnSyncInteger(Filter(function thistype.updateStatus))
call TimerStart(Elapsed, 10., true, function thistype.trackTime)
static if (PRELOAD_STR_CACHE) then
loop
exitwhen Last == ALPHABET_BASE
call getKey(Last)
set Last = Last + 1
endloop
set Last = 0
endif
call preloadChar2I()
set Initialized = true
endmethod
endstruct
endlibrary
library SyncInteger uses optional UnitDex /*or any unit indexer*/, optional GroupUtils, optional xebasic, optional PlayerUtils
/***************************************************************
*
* v1.2.1, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* This library allows you to send integers to all other players through
* unit selections.
*
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it (requires JassHelper *or* JNGP)
* _________________________________________________________________________
* 2. How it works
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Creates {DUMMY_COUNT} units and assigns {BASE} of them an integer from 0-{BASE}.
* The 2nd to last dummy is used to signal when the sequence of numbers is over and
* the last dummy signifies a negative number.
*
* 2. Breaks down the number you want to sync to one or more {BASE} integers,
* then selects each dummy unit assoicated with that integer.
*
* 4. The selection event fires for all players when the selection has been sycned
*
* 5. The ID of the selected unit is one of the {BASE} numbers. The current
* total (starts at 0) is multiplied by {BASE} and the latest synced integer is
* added to that. The process will repeat until it selects the 2nd to last dummy,
* and the total is our result.
* _________________________________________________________________________
* 3. Proper Usage
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - Avoid the SyncSelections native. It may cause the thread to hang or
* make some units un-able to move.
*
* - Dummies must be select-able (no locust)
*
* - Run the script in debug mode while testing
*
* _________________________________________________________________________
* 4. Struct API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct SelectionSync
*
* static method create takes nothing returns thistype
*
* method syncValue takes player p, integer number returns boolean
* method destroy takes nothing returns nothing
* _________________________________________________________________________
* 5. Function API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* function SyncInteger takes player p, integer number returns boolean
*
* function GetSyncedInteger takes nothing returns integer
* function GetSyncedInstance takes nothing returns integer
* function GetSyncedPlayer takes nothing returns player
* function GetSyncedPlayerId takes nothing returns integer
* function IsPlayerSyncing takes player p returns boolean
* function IsPlayerIdSyncing takes integer pid returns boolean
* function IsSyncEnabled takes nothing returns boolean
* function SyncIntegerToggle takes boolean flag returns nothing
* function SyncIntegerEnable takes nothing returns nothing
* function SyncIntegerDisable takes nothing returns nothing
*
* function OnSyncInteger takes code func returns triggercondition
* function RemoveSyncEvent takes triggercondition action returns nothing
* function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
*
* function SyncTerminate takes boolean destroyEvent returns nothing
*
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* -http://www.hiveworkshop.com/threads/syncinteger.278674/
*
*/
globals
// create a struct instance for global use
public constant boolean DEFAULT_INSTANCE = true
// owner of the dummy units
public constant player DUMMY_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE)
// Dummy can *not* have locust and must be selectabe.
// Anything should work (like 'hfoo'), but it's suggested
// to use a unit with a blank model so the user cannot select it manually.
public constant integer DUMMY_ID = 'hfoo'
// dummy ghost ability
public constant integer DUMMY_ABILITY = 'Aeth'
// allow debug messages (also requries JassHelper Debug Mode)
public constant boolean ALLOW_DEBUGGING = true
// higher == more dummies but less selections (faster)
public constant integer BASE = 10
// two higher than BASE (jasshelper doesn't allow BASE + 2)
public constant integer DUMMY_COUNT = 12
// endconfig
constant integer EVENT_SYNC_INTEGER = 1
public integer DefaultInstance = 0
private trigger OnSelectTrigger = CreateTrigger()
private trigger EventTrig = CreateTrigger()
private real FireEvent = 0
private group SelectionGroup
private integer LastPlayer
private integer LastSync
private integer LastInstance
private player LocalPlayer
private integer array ActiveSyncs
private real DUMMY_X = 0
private real DUMMY_Y = 0
private integer array DummyInstance
endglobals
function GetSyncedInteger takes nothing returns integer
return LastSync
endfunction
function GetSyncedPlayer takes nothing returns player
return Player(LastPlayer)
endfunction
function GetSyncedInstance takes nothing returns integer
return LastInstance
endfunction
function GetSyncedPlayerId takes nothing returns integer
return LastPlayer
endfunction
function IsPlayerIdSyncing takes integer pid returns boolean
return ActiveSyncs[pid] > 0
endfunction
function IsPlayerSyncing takes player p returns boolean
return ActiveSyncs[GetPlayerId(p)] > 0
endfunction
function IsSyncEnabled takes nothing returns boolean
return IsTriggerEnabled(OnSelectTrigger)
endfunction
function SyncIntegerEnable takes nothing returns nothing
call EnableTrigger(OnSelectTrigger)
endfunction
function SyncIntegerDisable takes nothing returns nothing
call DisableTrigger(OnSelectTrigger)
endfunction
function SyncIntegerToggle takes boolean flag returns nothing
if (flag) then
call EnableTrigger(OnSelectTrigger)
else
call DisableTrigger(OnSelectTrigger)
endif
endfunction
function OnSyncInteger takes filterfunc func returns triggercondition
return TriggerAddCondition(EventTrig, func)
endfunction
function RemoveSyncEvent takes triggercondition action returns nothing
call TriggerRemoveCondition(EventTrig, action)
endfunction
function TriggerRegisterSyncEvent takes trigger t, integer eventtype returns nothing
call TriggerRegisterVariableEvent(t, SCOPE_PREFIX + "FireEvent", EQUAL, eventtype)
endfunction
public function FireEvents takes real eventtype returns nothing
set FireEvent = eventtype
set FireEvent = 0
endfunction
// This function is called when a unit is selected.
private function OnSelect takes nothing returns boolean
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
local integer udata = GetUnitUserData(u)
local SelectionSync this = DummyInstance[udata]
local boolean isNeg = (this.Dummy[DUMMY_COUNT-1] == u)
local integer index = this.DummyID[udata] - 1
if (this <= 0 or (LocalPlayer == p and not IsPlayerIdSyncing(id))) then
return false
endif
if (isNeg) then
set this.SyncingValue[id] = this.SyncingValue[id]*-1
endif
if (isNeg or this.Dummy[DUMMY_COUNT-2] == u) then
set ActiveSyncs[id] = ActiveSyncs[id] - 1
// The number is finished syncing, fire the events
set LastPlayer = id
set LastSync = this.SyncingValue[id]
set LastInstance = this
set FireEvent = EVENT_SYNC_INTEGER
call TriggerEvaluate(EventTrig)
// Reset variables
set FireEvent = 0
set this.SyncingValue[id] = -1
else
if (this.SyncingValue[id] == -1) then
set this.SyncingValue[id] = 0
endif
// Build the number we are trying to sync
set this.SyncingValue[id] = this.SyncingValue[id] * BASE + index
endif
set u = null
return false
endfunction
private keyword SyncIntegerInit
// This struct allows us to dynamically create a group of units
// which we can use to synchronize our integer through unit selections.
struct SelectionSync
public unit array Dummy[DUMMY_COUNT]
public integer array DummyID[DUMMY_COUNT]
public integer array SyncingValue[12]
public static method debugger takes boolean b, string s returns nothing
static if (ALLOW_DEBUGGING and DEBUG_MODE) then
if (b) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|c00FF0000" + SCOPE_PREFIX + s + "|r")
endif
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer uid
debug call .debugger(OnSelectTrigger == null, "[SelectionSync.create()] OnSelectTrigger is null and has no events attached to it.")
debug call .debugger(this.Dummy[0] != null, "[SelectionSync.create()] Dummy not null!")
loop
exitwhen i >= DUMMY_COUNT
set this.Dummy[i] = CreateUnit(DUMMY_PLAYER, DUMMY_ID, DUMMY_X, DUMMY_Y, i)
set uid = GetUnitUserData(this.Dummy[i])
if (uid == 0) then
set uid = ( (this-1) * DUMMY_COUNT ) + (i + 1)
call SetUnitUserData(this.Dummy[i], uid)
endif
debug call .debugger((i == 0) and (this.Dummy[i] == null), "[SelectionSync.create()] Dummy unit is null (check DUMMY_ID).")
debug call .debugger((i == 0) and (GetUnitAbilityLevel(this.Dummy[i], 'Aloc') > 0), "[SelectionSync.create()] Dummy units must be selectable (detected locust).")
set this.DummyID[uid] = i + 1
set DummyInstance[uid] = this
call UnitAddAbility(this.Dummy[i], DUMMY_ABILITY)
call PauseUnit(this.Dummy[i], true)
call SetUnitScale(this.Dummy[i], 0, 0, 0)
set i = i + 1
endloop
return this
endmethod
method syncValue takes player p, integer number returns boolean
local integer x = number
local integer i = 0
local integer d = BASE
local integer j = 0
local integer n = 0
local integer l = 0
local integer playerId = GetPlayerId(p)
local unit u
local unit last
debug call .debugger(OnSelectTrigger == null, "[SelectionSync.syncValue()] OnSelectTrigger is destroyed.")
debug call .debugger(IsSyncEnabled() == false, "[SelectionSync.syncValue()] OnSelectTrigger is disabled.")
if (not IsSyncEnabled()) then
return false
endif
set ActiveSyncs[playerId] = ActiveSyncs[playerId] + 1
// Check if the number is negative
if (number < 0) then
set d = DUMMY_COUNT-1
set number = number * -1
endif
loop
set x = x/(BASE)
exitwhen x==0
set i=i+1
endloop
// Count how many units are selected
call GroupEnumUnitsSelected(SelectionGroup, p, null)
set bj_groupCountUnits = 0
set u = FirstOfGroup(SelectionGroup)
loop
exitwhen u == null
set last = u
call GroupRemoveUnit(SelectionGroup, u)
set bj_groupCountUnits = bj_groupCountUnits + 1
set u = FirstOfGroup(SelectionGroup)
endloop
// If the queue is full, de-select the last unit which
// will allow us to select a dummy, and hopefully
// avoid a flickering effect.
if (bj_groupCountUnits >= 12 and LocalPlayer == p) then
call SelectUnit(last, false)
endif
set j=R2I(Pow(BASE, i))
loop
set n = j
set x = number/n
set j = j / BASE
if (LocalPlayer == p) then
call SelectUnit(this.Dummy[x], true)
call SelectUnit(this.Dummy[x], false)
endif
set number = number-x*n
exitwhen i == 0
set i = i - 1
endloop
if (LocalPlayer == p) then
call SelectUnit(this.Dummy[d], true)
call SelectUnit(this.Dummy[d], false)
if (bj_groupCountUnits >= 12) then
call SelectUnit(last, true)
endif
endif
set u = null
set last = null
return true
endmethod
method destroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= DUMMY_COUNT
call RemoveUnit(this.Dummy[i])
set this.Dummy[i] = null
set i = i + 1
endloop
endmethod
implement SyncIntegerInit
endstruct
function SyncInteger takes player p, integer number returns boolean
debug call SelectionSync.debugger(DefaultInstance == 0, "[SyncInteger()] DefaultInstance is not initialized (make sure DEFAULT_INSTANCE is true")
return SelectionSync(DefaultInstance).syncValue(p, number)
endfunction
function SyncTerminate takes boolean destroyEvents returns boolean
local integer i = 0
if (OnSelectTrigger == null and EventTrig == null) then
return false
endif
if (destroyEvents) then
call DestroyTrigger(OnSelectTrigger)
call DestroyTrigger(EventTrig)
set OnSelectTrigger = null
set EventTrig = null
static if not LIBRARY_GroupUtils then
call DestroyGroup(SelectionGroup)
set SelectionGroup = null
endif
else
call SyncIntegerDisable()
endif
if (DefaultInstance > 0) then
call SelectionSync(DefaultInstance).destroy()
endif
return true
endfunction
//===========================================================================
private module SyncIntegerInit
private static method onInit takes nothing returns nothing
local integer i = 0
local integer j
loop
call TriggerRegisterPlayerUnitEvent(OnSelectTrigger, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
set i = i + 1
exitwhen i==bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(OnSelectTrigger, Filter(function OnSelect))
static if (LIBRARY_GroupUtils) then
set SelectionGroup=ENUM_GROUP
else
set SelectionGroup=CreateGroup()
endif
static if (LIBRARY_PlayerUtils) then
set LocalPlayer=User.Local
else
set LocalPlayer=GetLocalPlayer()
endif
set DUMMY_X = GetCameraBoundMaxX() + 2000
set DUMMY_Y = GetCameraBoundMaxY() + 2000
static if (DEFAULT_INSTANCE) then
set DefaultInstance = SelectionSync.create()
endif
endmethod
endmodule
endlibrary
library PlayerUtils
/**************************************************************
*
* v1.2.9 by TriggerHappy
*
* This library provides a struct which caches data about players
* as well as provides functionality for manipulating player colors.
*
* Constants
* ------------------
*
* force FORCE_PLAYING - Player group of everyone who is playing.
*
* Struct API
* -------------------
* struct User
*
* static method fromIndex takes integer i returns User
* static method fromLocal takes nothing returns User
* static method fromPlaying takes integer id returns User
*
* static method operator [] takes integer id returns User
* static method operator count takes nothing returns integer
*
* method operator name takes nothing returns string
* method operator name= takes string name returns nothing
* method operator color takes nothing returns playercolor
* method operator color= takes playercolor c returns nothing
* method operator defaultColor takes nothing returns playercolor
* method operator hex takes nothing returns string
* method operator nameColored takes nothing returns string
*
* method toPlayer takes nothing returns player
* method colorUnits takes playercolor c returns nothing
*
* readonly string originalName
* readonly boolean isPlaying
* readonly static player Local
* readonly static integer LocalId
* readonly static integer AmountPlaying
* readonly static playercolor array Color
* readonly static player array PlayingPlayer
*
**************************************************************/
globals
// automatically change unit colors when changing player color
private constant boolean AUTO_COLOR_UNITS = true
// use an array for name / color lookups (instead of function calls)
private constant boolean ARRAY_LOOKUP = false
// this only applies if ARRAY_LOOKUP is true
private constant boolean HOOK_SAFETY = false // disable for speed, but only use the struct to change name/color safely
constant force FORCE_PLAYING = CreateForce()
private string array Name
private string array Hex
private string array OriginalHex
private playercolor array CurrentColor
endglobals
private keyword PlayerUtilsInit
struct User extends array
static constant integer NULL = bj_MAX_PLAYER_SLOTS
readonly player handle
readonly integer id
readonly thistype next
readonly thistype prev
readonly string originalName
readonly boolean isPlaying
readonly static thistype first
readonly static thistype last
readonly static player Local
readonly static integer LocalId
readonly static integer AmountPlaying = 0
readonly static playercolor array Color
static if not (LIBRARY_GroupUtils) then
readonly static group ENUM_GROUP = CreateGroup()
endif
private static thistype array PlayingPlayer
private static integer array PlayingPlayerIndex
// similar to Player(#)
static method fromIndex takes integer i returns thistype
return thistype(i)
endmethod
// similar to GetLocalPlayer
static method fromLocal takes nothing returns thistype
return thistype(thistype.LocalId)
endmethod
// access active players array
static method fromPlaying takes integer index returns thistype
return PlayingPlayer[index]
endmethod
static method operator [] takes player p returns thistype
return thistype(GetPlayerId(p))
endmethod
method toPlayer takes nothing returns player
return this.handle
endmethod
method operator name takes nothing returns string
static if (ARRAY_LOOKUP) then
return Name[this]
else
return GetPlayerName(this.handle)
endif
endmethod
method operator name= takes string newName returns nothing
call SetPlayerName(this.handle, newName)
static if (ARRAY_LOOKUP) then
static if not (HOOK_SAFETY) then
set Name[this] = newName
endif
endif
endmethod
method operator color takes nothing returns playercolor
static if (ARRAY_LOOKUP) then
return CurrentColor[this]
else
return GetPlayerColor(this.handle)
endif
endmethod
method operator hex takes nothing returns string
return OriginalHex[GetHandleId(this.color)]
endmethod
method operator color= takes playercolor c returns nothing
call SetPlayerColor(this.handle, c)
static if (ARRAY_LOOKUP) then
set CurrentColor[this] = c
static if not (HOOK_SAFETY) then
static if (AUTO_COLOR_UNITS) then
call this.colorUnits(color)
endif
endif
endif
endmethod
method operator defaultColor takes nothing returns playercolor
return Color[this]
endmethod
method operator nameColored takes nothing returns string
return hex + this.name + "|r"
endmethod
method colorUnits takes playercolor c returns nothing
local unit u
call GroupEnumUnitsOfPlayer(ENUM_GROUP, this.handle, null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen u == null
call SetUnitColor(u, c)
call GroupRemoveUnit(ENUM_GROUP, u)
endloop
endmethod
static method onLeave takes nothing returns boolean
local thistype p = thistype[GetTriggerPlayer()]
local integer i = .PlayingPlayerIndex[p.id]
// clean up
call ForceRemovePlayer(FORCE_PLAYING, p.toPlayer())
// recycle index
set .AmountPlaying = .AmountPlaying - 1
set .PlayingPlayerIndex[i] = .PlayingPlayerIndex[.AmountPlaying]
set .PlayingPlayer[i] = .PlayingPlayer[.AmountPlaying]
if (.AmountPlaying == 1) then
set p.prev.next = User.NULL
set p.next.prev = User.NULL
else
set p.prev.next = p.next
set p.next.prev = p.prev
endif
set .last = .PlayingPlayer[.AmountPlaying]
set p.isPlaying = false
return false
endmethod
implement PlayerUtilsInit
endstruct
private module PlayerUtilsInit
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local thistype p
set thistype.Local = GetLocalPlayer()
set thistype.LocalId = GetPlayerId(thistype.Local)
set OriginalHex[0] = "|cffff0303"
set OriginalHex[1] = "|cff0042ff"
set OriginalHex[2] = "|cff1ce6b9"
set OriginalHex[3] = "|cff540081"
set OriginalHex[4] = "|cfffffc01"
set OriginalHex[5] = "|cfffe8a0e"
set OriginalHex[6] = "|cff20c000"
set OriginalHex[7] = "|cffe55bb0"
set OriginalHex[8] = "|cff959697"
set OriginalHex[9] = "|cff7ebff1"
set OriginalHex[10] = "|cff106246"
set OriginalHex[11] = "|cff4e2a04"
if (bj_MAX_PLAYERS > 12) then
set OriginalHex[12] = "|cff9B0000"
set OriginalHex[13] = "|cff0000C3"
set OriginalHex[14] = "|cff00EAFF"
set OriginalHex[15] = "|cffBE00FE"
set OriginalHex[16] = "|cffEBCD87"
set OriginalHex[17] = "|cffF8A48B"
set OriginalHex[18] = "|cffBFFF80"
set OriginalHex[19] = "|cffDCB9EB"
set OriginalHex[20] = "|cff282828"
set OriginalHex[21] = "|cffEBF0FF"
set OriginalHex[22] = "|cff00781E"
set OriginalHex[23] = "|cffA46F33"
endif
set thistype.first = User.NULL
loop
exitwhen i == bj_MAX_PLAYERS
set p = User(i)
set p.handle = Player(i)
set p.id = i
set thistype.Color[i] = GetPlayerColor(p.handle)
set CurrentColor[i] = thistype.Color[i]
if (GetPlayerController(p.handle) == MAP_CONTROL_USER and GetPlayerSlotState(p.handle) == PLAYER_SLOT_STATE_PLAYING) then
set .PlayingPlayer[AmountPlaying] = p
set .PlayingPlayerIndex[i] = .AmountPlaying
set .last = i
if (.first == User.NULL) then
set .first = i
set User(i).next = User.NULL
set User(i).prev = User.NULL
else
set User(i).prev = PlayingPlayer[AmountPlaying-1].id
set PlayingPlayer[AmountPlaying-1].next = User(i)
set User(i).next = User.NULL
endif
set p.isPlaying = true
call TriggerRegisterPlayerEvent(t, p.handle, EVENT_PLAYER_LEAVE)
call ForceAddPlayer(FORCE_PLAYING, p.handle)
set Hex[p] = OriginalHex[GetHandleId(thistype.Color[i])]
set .AmountPlaying = .AmountPlaying + 1
endif
set Name[p] = GetPlayerName(p.handle)
set p.originalName=Name[p]
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function thistype.onLeave))
endmethod
endmodule
//===========================================================================
static if (ARRAY_LOOKUP) then
static if (HOOK_SAFETY) then
private function SetPlayerNameHook takes player whichPlayer, string name returns nothing
set Name[GetPlayerId(whichPlayer)] = name
endfunction
private function SetPlayerColorHook takes player whichPlayer, playercolor color returns nothing
local User p = User[whichPlayer]
set Hex[p] = OriginalHex[GetHandleId(color)]
set CurrentColor[p] = color
static if (AUTO_COLOR_UNITS) then
call p.colorUnits(color)
endif
endfunction
hook SetPlayerName SetPlayerNameHook
hook SetPlayerColor SetPlayerColorHook
endif
endif
endlibrary
scope SyncBenchmark initializer Init
globals
private constant integer SYNC_AMOUNT = 5000 //20kb
private boolean running = false
private integer TrackLastIndex = 0
endglobals
private function GetTotalSyncedIntegers takes SyncData d returns integer
local integer i = TrackLastIndex
local integer c = 0
loop
exitwhen i > d.intCount
if (d.hasInt(i)) then
set c = c + 1
else
set TrackLastIndex = i
return i
endif
set i = i + 1
endloop
set TrackLastIndex = c
return c
endfunction
private function CallbackComplete takes nothing returns boolean
local SyncData d = GetSyncedData()
set running = false
call ClearTextMessages()
call BJDebugMsg("Synced instance #" + I2S(d) + " from " + GetPlayerName(d.from) + " in " + R2S(d.timeElapsed) + " seconds\n")
call BJDebugMsg("=========================")
call BJDebugMsg("Started : " + R2S(d.timeStarted))
call BJDebugMsg("Finished : " + R2S(d.timeFinished))
call BJDebugMsg(" ")
call BJDebugMsg("Size : " + I2S( (d.intCount * 4) ) + " bytes.")
call BJDebugMsg("Speed : " + R2S( (d.intCount * 4) / d.timeElapsed) + " bytes per second\n")
call BJDebugMsg(" ")
call BJDebugMsg("First/Last = " + I2S(d.readInt(0)) + " / " + I2S(d.readInt(d.intCount-1)))
// clean up
call d.destroy()
return false
endfunction
private function CallbackError takes nothing returns boolean
local SyncData d = GetSyncedData()
set running = false
if (d.lastError == SYNC_ERROR_TIMEOUT) then
call BJDebugMsg("SYNC ERROR: The request has timed out.")
elseif (d.lastError == SYNC_ERROR_PLAYERLEFT) then
call BJDebugMsg("SYNC ERROR: The syncing player has left.")
else
call BJDebugMsg("SYNC ERROR: Unknown error.")
endif
return false
endfunction
private function ShowProgress takes nothing returns boolean
local SyncData d = GetSyncedData()
local integer done = GetTotalSyncedIntegers(d)
local real percent = (I2R(done) / I2R(d.intCount)) * 100.
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Progress: " + " %" + R2S(percent) + " " + I2S(done) + "/" + I2S(d.intCount))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Players Done: " + " " + I2S(d.playersDone))
return false
endfunction
private function StartTest takes nothing returns nothing
local SyncData req
local string s = ""
local integer i = 0
local integer c = 0
if (running) then
call BJDebugMsg("Please wait...")
return
endif
set TrackLastIndex = 0
set running = true
set req = SyncData.create(GetTriggerPlayer())
set req.timeout = 300 // 5 minutes
set req.onComplete = Filter(function CallbackComplete)
set req.onError = Filter(function CallbackError)
set req.onUpdate = Filter(function ShowProgress)
loop
exitwhen i >= SYNC_AMOUNT
call req.syncInt(i + 1)
set i = i + 1
endloop
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local User user = User.first
loop
exitwhen user == User.NULL
call TriggerRegisterPlayerEvent( t, user.toPlayer(), EVENT_PLAYER_END_CINEMATIC)
set user = user.next
endloop
call TriggerAddAction(t, function StartTest)
endfunction
endscope
/*****************************************************************************
*
* InventoryEvent v1.0.1.8
* by Bannar
*
* For intuitive inventory event handling.
*
******************************************************************************
*
* Requirements:
*
* RegisterPlayerUnitEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
* ExtensionMethods by Bannar
* https://www.hiveworkshop.com/pastebin/a998754d6441bc4e70a39a229111d6a7.15770
*
******************************************************************************
*
* Event API:
*
* integer EVENT_ITEM_INVENTORY_MOVE
* integer EVENT_ITEM_INVENTORY_USE
*
* Use RegisterNativeEvent or RegisterIndexNativeEvent for event registration.
* GetNativeEventTrigger and GetIndexNativeEventTrigger provide access to trigger handles.
*
*
* function GetInventoryManipulatingUnit takes nothing returns unit
* Returns unit which manipulated event item.
*
* function GetInventoryManipulatedItem takes nothing returns item
* Returns manupilated event item.
*
* function GetInventorySlotFrom takes nothing returns integer
* Returns slot index of manipulated item from which it was moved or used.
*
* function GetInventorySlotTo takes nothing returns integer
* Returns slot index of manipulated item to which it was moved.
*
* function GetInventorySwappedItem takes nothing returns item
* Returns item which manipulated item switched position with if any.
*
*****************************************************************************/
library InventoryEvent requires RegisterPlayerUnitEvent, ExtensionMethods
globals
integer EVENT_ITEM_INVENTORY_MOVE
integer EVENT_ITEM_INVENTORY_USE
endglobals
globals
private unit eventUnit = null
private item eventItem = null
private integer eventSlotFrom = -1
private integer eventSlotTo = -1
endglobals
function GetInventoryManipulatingUnit takes nothing returns unit
return eventUnit
endfunction
function GetInventoryManipulatedItem takes nothing returns item
return eventItem
endfunction
function GetInventorySlotFrom takes nothing returns integer
return eventSlotFrom
endfunction
function GetInventorySlotTo takes nothing returns integer
return eventSlotTo
endfunction
function GetInventorySwappedItem takes nothing returns item
return UnitItemInSlot(eventUnit, eventSlotTo)
endfunction
function GetEventInventoryUnit takes nothing returns unit
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventoryUnit is obsolete, use GetInventoryManipulatingUnit instead.")
return GetInventoryManipulatingUnit()
endfunction
function GetEventInventoryItem takes nothing returns item
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventoryItem is obsolete, use GetInventoryManipulatedItem instead.")
return GetInventoryManipulatedItem()
endfunction
function GetEventInventorySlotFrom takes nothing returns integer
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySlotFrom is obsolete, use GetInventorySlotFrom instead.")
return GetInventorySlotFrom()
endfunction
function GetEventInventorySlotTo takes nothing returns integer
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySlotTo is obsolete, use GetInventorySlotTo instead.")
return GetInventorySlotTo()
endfunction
function GetEventInventorySwapped takes nothing returns item
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetEventInventorySwapped is obsolete, use GetInventorySwappedItem instead.")
return GetInventorySwappedItem()
endfunction
function GetInventoryEventTrigger takes integer whichEvent returns trigger
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function GetInventoryEventTrigger is obsolete, use GetNativeEventTrigger instead.")
return GetNativeEventTrigger(whichEvent)
endfunction
function RegisterInventoryEvent takes code func, integer whichEvent returns nothing
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Function RegisterInventoryEvent is obsolete, use RegisterNativeEvent instead.")
call RegisterNativeEvent(whichEvent, func)
endfunction
private function FireEvent takes integer evt, unit u, item itm, integer slotFrom, integer slotTo returns nothing
local unit prevUnit = eventUnit
local item prevItem = eventItem
local integer prevSlotFrom = eventSlotFrom
local integer prevSlotTo = eventSlotTo
local integer playerId = GetPlayerId(GetOwningPlayer(u))
set eventUnit = u
set eventItem = itm
set eventSlotFrom = slotFrom
set eventSlotTo = slotTo
call TriggerEvaluate(GetNativeEventTrigger(evt))
if IsNativeEventRegistered(playerId, evt) then
call TriggerEvaluate(GetIndexNativeEventTrigger(playerId, evt))
endif
set eventUnit = prevUnit
set eventItem = prevItem
set eventSlotFrom = prevSlotFrom
set eventSlotTo = prevSlotTo
set prevUnit = null
set prevItem = null
endfunction
private function OnItemOrder takes nothing returns nothing
local integer order = GetIssuedOrderId()
local unit u = GetTriggerUnit()
local item itm
local integer slotFrom
local integer slotTo
if order >= 852002 and order <= 852007 then // between moveslot1 and moveslot6
set itm = GetOrderTargetItem()
set slotFrom = GetUnitItemSlot(u, itm)
set slotTo = order - 852002 // moveslot1
call FireEvent(EVENT_ITEM_INVENTORY_MOVE, u, itm, slotFrom, slotTo)
else
set slotFrom = order - 852008 // useslot1
set itm = UnitItemInSlot(u, slotFrom)
call FireEvent(EVENT_ITEM_INVENTORY_USE, u, itm, slotFrom, -1)
endif
set u = null
set itm = null
endfunction
private function OnAnyOrder takes nothing returns nothing
local integer order = GetIssuedOrderId()
if order >= 852002 and order <= 852013 then // between moveslot1 and useslot6
call OnItemOrder()
endif
endfunction
private module InventoryEventInit
private static method onInit takes nothing returns nothing
set EVENT_ITEM_INVENTORY_MOVE = CreateNativeEvent()
set EVENT_ITEM_INVENTORY_USE = CreateNativeEvent()
set MOVED = EVENT_ITEM_INVENTORY_MOVE
set USED = EVENT_ITEM_INVENTORY_USE
// MOVED is order of type TARGET_ORDER yet USED can be anyone of them
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function OnAnyOrder)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function OnAnyOrder)
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function OnAnyOrder)
endmethod
endmodule
struct InventoryEvent extends array
// Events below are depreated in favor of EVENT_ alike globals
readonly static integer MOVED
readonly static integer USED
implement InventoryEventInit
endstruct
endlibrary
/*****************************************************************************
*
* ExtensionMethods
*
* General purpose functions that extend native jass interface.
*
******************************************************************************
*
* Item handle extension methods:
*
* function GetUnitItemCount takes unit whichUnit returns integer
* Returns the number of items equipped.
*
* function IsUnitInventoryFull takes unit whichUnit returns boolean
* Checks if unit inventory is full.
*
* function GetUnitItemSlot takes unit whichUnit, item whichItem returns integer
* Retrieves slot number of specified item equiped by unit whichUnit or -1 if not found.
*
* function IsItemAlive takes item whichItem returns boolean
* Returns value indicating whether specified item is alive.
*
* function IsItemPickupable takes item whichItem returns boolean
* Returns value indicating whether specified item can be picked up.
*
*****************************************************************************/
library ExtensionMethods
function GetUnitItemCount takes unit whichUnit returns integer
local integer size = UnitInventorySize(whichUnit)
local integer slot = 0
local integer result = 0
loop
exitwhen slot >= size
if UnitItemInSlot(whichUnit, slot) != null then
set result = result + 1
endif
set slot = slot + 1
endloop
return result
endfunction
function IsUnitInventoryFull takes unit whichUnit returns boolean
return GetUnitItemCount(whichUnit) == UnitInventorySize(whichUnit)
endfunction
function GetUnitItemSlot takes unit whichUnit, item whichItem returns integer
local integer slot = 0
local integer size
if UnitHasItem(whichUnit, whichItem) then
set size = UnitInventorySize(whichUnit)
loop
if UnitItemInSlot(whichUnit, slot) == whichItem then
return slot
endif
set slot = slot + 1
exitwhen slot >= size
endloop
endif
return -1 // NOT_FOUND
endfunction
function IsItemAlive takes item whichItem returns boolean
return GetItemTypeId(whichItem) != 0 and GetWidgetLife(whichItem) > 0.405
endfunction
function IsItemPickupable takes item whichItem returns boolean
return IsItemAlive(whichItem) and not IsItemOwned(whichItem) and IsItemVisible(whichItem)
endfunction
endlibrary
/*****************************************************************************
*
* RegisterNativeEvent v1.1.1.5
* by Bannar
*
* Storage of trigger handles for native events.
*
******************************************************************************
*
* Optional requirements:
*
* Table by Bribe
* hiveworkshop.com/threads/snippet-new-table.188084/
*
******************************************************************************
*
* Important:
*
* Avoid using TriggerSleepAction within functions registered.
* Destroy native event trigger on your own responsibility.
*
******************************************************************************
*
* Core:
*
* function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
* Whether index whichIndex has already been attached to event whichEvent.
*
* function RegisterNativeEventTrigger takes integer whichIndex, integer eventId returns boolean
* Registers whichIndex within whichEvent scope and assigns new trigger handle for it.
*
* function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
* Retrieves trigger handle for event whichEvent specific to provided index whichIndex.
*
* function GetNativeEventTrigger takes integer whichEvent returns trigger
* Retrieves trigger handle for event whichEvent.
*
*
* Custom events:
*
* function CreateNativeEvent takes nothing returns integer
* Returns unique id for new event and registers it with RegisterNativeEvent.
*
* function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
* Registers new event handler func for event whichEvent specific to index whichIndex.
*
* function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
* Registers new event handler func for specified event whichEvent.
*
* function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
* Unregisters specified event handler for event whichEvent. Requires Warcraft 1.30.4+.
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table
globals
private integer eventIndex = 500 // 0-499 reserved for Blizzard native events
endglobals
private module NativeEventInit
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set table = TableArray[0x2000]
endif
endmethod
endmodule
private struct NativeEvent extends array
static if LIBRARY_Table then
static TableArray table
else
static hashtable table = InitHashtable()
endif
implement NativeEventInit
endstruct
function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
static if LIBRARY_Table then
return NativeEvent.table[whichEvent].trigger.has(whichIndex)
else
return HaveSavedHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction
function RegisterNativeEventTrigger takes integer whichIndex, integer whichEvent returns boolean
if not IsNativeEventRegistered(whichIndex, whichEvent) then
static if LIBRARY_Table then
set NativeEvent.table[whichEvent].trigger[whichIndex] = CreateTrigger()
else
call SaveTriggerHandle(NativeEvent.table, whichEvent, whichIndex, CreateTrigger())
endif
return true
endif
return false
endfunction
function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
static if LIBRARY_Table then
return NativeEvent.table[whichEvent].trigger[whichIndex]
else
return LoadTriggerHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction
function GetNativeEventTrigger takes integer whichEvent returns trigger
return GetIndexNativeEventTrigger(bj_MAX_PLAYER_SLOTS, whichEvent)
endfunction
function CreateNativeEvent takes nothing returns integer
local integer eventId = eventIndex
call RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId)
set eventIndex = eventIndex + 1
return eventId
endfunction
function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
call RegisterNativeEventTrigger(whichIndex, whichEvent)
return TriggerAddCondition(GetIndexNativeEventTrigger(whichIndex, whichEvent), Condition(func))
endfunction
function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
return RegisterIndexNativeEvent(bj_MAX_PLAYER_SLOTS, whichEvent, func)
endfunction
function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
call TriggerRemoveCondition(GetNativeEventTrigger(whichEvent), handler)
endfunction
endlibrary
/*****************************************************************************
*
* RegisterPlayerEvent v1.0.2.2
* by Bannar
*
* Register version of TriggerRegisterPlayerEvent.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
* Functions:
*
* function GetAnyPlayerEventTrigger takes playerevent whichEvent returns trigger
* Retrieves trigger handle for playerevent whichEvent.
*
* function GetPlayerEventTrigger takes player whichPlayer, playerevent whichEvent returns trigger
* Retrieves trigger handle for playerevent whichEvent specific to player whichPlayer.
*
* function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns nothing
* Registers generic playerevent whichEvent adding code func as callback.
*
* function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code func returns nothing
* Registers playerevent whichEvent for player whichPlayer adding code func as callback.
*
*****************************************************************************/
library RegisterPlayerEvent requires RegisterNativeEvent
function GetAnyPlayerEventTrigger takes playerevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
function GetPlayerEventTrigger takes player whichPlayer, playerevent whichEvent returns trigger
return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction
function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns nothing
local integer eventId = GetHandleId(whichEvent)
local integer index = 0
local trigger t = null
if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
set t = GetNativeEventTrigger(eventId)
loop
call TriggerRegisterPlayerEvent(t, Player(index), whichEvent)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
set t = null
endif
call RegisterNativeEvent(eventId, func)
endfunction
function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code func returns nothing
local integer playerId = GetPlayerId(whichPlayer)
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEventTrigger(playerId, eventId) then
call TriggerRegisterPlayerEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent)
endif
call RegisterIndexNativeEvent(playerId, eventId, func)
endfunction
endlibrary
/*****************************************************************************
*
* RegisterPlayerUnitEvent v1.0.3.2
* by Bannar
*
* Register version of TriggerRegisterPlayerUnitEvent.
*
* Special thanks to Magtheridon96, Bribe, azlier and BBQ for the original library version.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
* Functions:
*
* function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* Retrieves trigger handle for playerunitevent whichEvent.
*
* function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
* Retrieves trigger handle for playerunitevent whichEvent specific to player whichPlayer.
*
* function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
* Registers generic playerunitevent whichEvent adding code func as callback.
*
* function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
* Registers playerunitevent whichEvent for player whichPlayer adding code func as callback.
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent
function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction
function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
local integer eventId = GetHandleId(whichEvent)
local integer index = 0
local trigger t = null
if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
set t = GetNativeEventTrigger(eventId)
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index), whichEvent, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
set t = null
endif
call RegisterNativeEvent(eventId, func)
endfunction
function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
local integer playerId = GetPlayerId(whichPlayer)
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEventTrigger(playerId, eventId) then
call TriggerRegisterPlayerUnitEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent, null)
endif
call RegisterIndexNativeEvent(playerId, eventId, func)
endfunction
endlibrary
scope Test initializer Init
globals
private framehandle frame
private framehandle frame2
private unit u
private group g
endglobals
private function Test takes nothing returns nothing
local Inventory inv = Inventory.create()/*
*/.setTitle("|cffffcc00Inventory|r") /*
*/.setTitleSize(0.015) /*
*/.setBorderSize(0.029) /*
*/.setButtonSize(0.03) /*
*/.setSlotCount(12) /*
*/.setColumnCount(4) /*
*/.setPosition(0.45, 0.35) /*
*/.setButtonSpaceGap(0.01) /*
*/.setSlotIndicatorModel("UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdx") /*
*/.setSlotEmptyTexture("ui\\widgets\\escmenu\\human\\quest-completed-background.blp") /*
*/.setOpenButtonTexture("ReplaceableTextures/CommandButtons/BTNDustOfAppearance")
call inv.build()
call inv.showEx(Player(0), true)
call BlzFrameSetPoint(inv.openButton, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPRIGHT, 0, 0)
call DestroyTimer(GetExpiredTimer())
endfunction
private function OnClick takes nothing returns nothing
local unit un
call UnfocusFrame(BlzGetTriggerFrame(), GetTriggerPlayer())
if BlzGetTriggerFrame() == frame then
call GroupEnumUnitsSelected(g, Player(0), null)
set u = FirstOfGroup(g)
call UnitAddItemById(u, ChooseRandomItemEx(ITEM_TYPE_PERMANENT, -1))
else
set un = CreateUnit(Player(0), 'Hpal', WorldBounds.centerX, WorldBounds.centerY, 0)
call SelectUnit(un, true)
call PanCameraToTimed(GetUnitX(un), GetUnitY(un), 0)
set un = null
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
set frame = BlzCreateFrame("ScriptDialogButton", GAME_UI, 0, 0)
call BlzFrameSetSize(frame, 0.2, 0.05)
call BlzFrameSetAbsPoint(frame, FRAMEPOINT_CENTER, 0.007, 0.19)
call BlzFrameSetText(frame, "Give Hero Item")
call TriggerAddCondition(t, function OnClick)
call BlzTriggerRegisterFrameEvent(t, frame, FRAMEEVENT_CONTROL_CLICK)
set frame2 = BlzCreateFrame("ScriptDialogButton", GAME_UI, 0, 0)
call BlzFrameSetSize(frame2, 0, 0.05)
call BlzFrameSetPoint(frame2, FRAMEPOINT_BOTTOMLEFT, frame, FRAMEPOINT_TOPLEFT, 0, 0.01)
call BlzFrameSetPoint(frame2, FRAMEPOINT_BOTTOMRIGHT, frame, FRAMEPOINT_TOPRIGHT, 0, 0.01)
call BlzFrameSetText(frame2, "Create Hero")
call BlzTriggerRegisterFrameEvent(t, frame2, FRAMEEVENT_CONTROL_CLICK)
call TimerStart(CreateTimer(), 0, false, function Test)
set u = CreateUnit(Player(0), 'Nalc', WorldBounds.centerX, WorldBounds.centerY, 0)
call SelectUnit(u, true)
call PanCameraToTimed(GetUnitX(u), GetUnitY(u), 0)
call CreateUnit(Player(0), 'nmrk', WorldBounds.centerX - 200, WorldBounds.centerY - 200, 0)
set g = CreateGroup()
endfunction
endscope