Name | Type | is_array | initial_value |
ab | abilcode | No | |
colors | string | Yes | |
exampleMenu | integer | No | |
exampleOptions | integer | Yes | |
GUI_hostSettings | integer | Yes | |
HAS_SPELL | boolean | No | |
Hero | unit | Yes | |
heroMenu | integer | No | |
heroType | unitcode | Yes | |
HOST_trgOnComplete | trigger | No | |
hostBTN | string | No | |
hostDesc | string | No | |
hostPlayer | player | No | |
IsUnitPreplaced | boolean | Yes | |
lastCreatedHostSetting | integer | No | |
musicMenu | integer | No | |
musicMenuOptions | integer | Yes | |
player | player | No | |
SBM_customData | integer | No | |
SBM_event | real | No | |
SBM_GUI_btn | string | No | |
SBM_GUI_forceOpen | boolean | No | |
SBM_GUI_index | integer | No | |
SBM_GUI_label | string | No | |
SBM_GUI_menu | integer | No | |
SBM_GUI_next | abilcode | No | |
SBM_GUI_passives | abilcode | No | |
SBM_GUI_spells | abilcode | No | |
SBM_GUI_text | string | No | |
SBM_GUI_title | string | No | |
SBM_lastCreatedMenu | integer | No | |
SBM_lastCreatedOption | integer | No | |
SBM_menuKey | integer | No | |
SBM_optionKey | integer | No | |
SBM_player | player | No | |
songs | string | Yes | |
tempLoc | location | No | |
timer | timerdialog | No | |
tmr | timer | No | |
u | unit | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No |
/*
1.2c
- Stopped using SetPlayerAbilityAvailable and instead use BlzUnitDisableAbility.
- No longer need to use 12 passive spells for disabled state.Thus also fixing the bug of passive spells potentially being effected.
- No longer needs to store or configure DISBTN icons.
- Removed: Option.getLocalIcon(playerId)
- Removed: Option.disbtn
- Removed: Option.setLocalDisbtn(playerId)
- Removed: Option.getLocalDisbtn(playerId)
- Removed: Option.removeLocalDisbtn(playerId)
- Fixed: Small local effect error in the Hero Selection Plugin
- Changed: Option.btn --> Option.icon and Option.getLocalBtn --> Option.getLocalIcon, etc.
1,2
- Added: function GetCurrentSpellMenuPage takes integer playerId returns integer
- Added: function GetCurrentSpellMenu takes integer playerId returns integer
- Removed: trgUsed from SpellMenu as it wasn't being used any more
- Fixed: Bug where the menu could not be opened inside a condition scope.
- Changed: The active abilities now use different variations of Channel rather than using multiple different types. This makes them all instant cast (thanks Overfrost)
- Changed: Hotkey is now configured in the code rather than inside the object editor
- Fixed: Bug where default icons weren't used when btn or disbtn is set to either null or "".
CHANGE LOG
1.1d
- Added: option.rank for sorting rather than using option.userData
- Added: SortValuation function if one wishes to change sorting function
- Added: GUI Hero Pick System and reintroduced old GUI code.
- Fix: Forgot to pause a timer and use TimerUtils when allocating the timer on menu open/close.
- Fix: Added a filter for bag demo.
- Fix: Null trigger handle inside bag demo.
- Added: Feature for forcing the menu open until a manual close event occurs.
- Added: function GetSpellMenuUnit takes player playerId returns unit - In case anyone wishes to manipulate the dummy.
1.1
* SpellOption
- Changed the dummy unit to completely disapear from the map.
- Removed method operator Cooldown.icon takes nothing returns string
- Added Option.clearCooldown takes playerId
- Replaced .allocate() and .table with Table.create() and Table(this) respectively inside SpellOption.
- Improved the SpellOption documentation
- Added a custom ID to the SpellOption, the idea here is the same as GetUntiUserData so that one can attach other type of indexed data to that option more easily.
- Made SpellOption.trg private and added a callback method: select(player) instead.
- Only instantiates a cooldown manager for each playing player now.
- Added: function OnSpellOptionEvent takes real whichEvent, code c returns nothing
- Reworked TimerManagement so that cooldown ticks only update the spell being affected if watched.
- Reduced the textmacros inside SpellOption to one with a static if to handle a special case
- Added: method onResponse takes code callback returns nothing - changes which callback will fire on option selection
* SpellMenu
- Refactored SpellOptionsMenu almost entierly
- Fixed a bug where menus were being reselected (i think)
- Reduced the amount of levels used from 24 to 1 per spell
- Removed the need to copy any of the disabled abilities
- Removed unnecessary player util usage from initialization
- Added: eject(index) removes and returns the option instead of deallocating it as .remove(index) does
- Removed: createOption(...)
- Changed: lockOption --> lock, unlockOption --> unlock, removeOption --> remove optionBelongs --> contains, etc
- Added: SpellMenu.sort(ascending) which sorts all options based on option.userdata
- Added: SpellMenu.get(index)
- Added: SpellMenu.size()
- Fixed: bug with optional library not being included properly
- Improved documentation
- The menu now optionally closes when escape is pressed.
* General
- Made it possible to replace GUI variables with vJASS variables instead (should one want to remove GUI entierly)
- Now supports TimerUtils and PlayerUtils
- All GUI examples have been depreciated for now
1.01
- Added indexOf to SpellMenu
- Fixed bug with Locking not working properly
- Added BagSystem Plugin
1.00
- Added functionality for locking options at index between 0 to 11
- Window size now takes into account hidden options
- Fixed bug with BlzSetAbilityPositionXY not being set properly on configuration
0.99
- Added clear method to remove all options
- Opening another menu will now fire a close menu event before executing
- Fixed deallocation bug
- Added example of creating a menu based on items
0.98
- Fixed a bug with closeMenu not working
- When a menu closes the selection will return to what it was before
- Added votekick menu as an additional example
- Fixed a bug with the SpellMenu not being deallocated when destroy was called
0.97
- Fixed a bug in which the next button could be hidden due to disabled option at slot 11 covering it.
- Added start and end cooldown event registration.
- Changed how callbacks were registrated for faster setup.
0.95
- Ficed a bug where options weren't deallocated once removed from the menu.
- Added method refresh to spell menu so that the menu can be manually changed in case the properties change independant of player selection
- Now updates the menu for all players currently viewing it whenever an option is selected
- Added real events for option selection, menu open and menu close.
- Player related data is now removed from SpellOptionsMenu upon leaving the game
- showWindow(player, index) is now public so that the window can be changed from outside
- Added GUI plugin for additional support
- Added static if to include/exclude some GUI variables from the library
0.9 Release
Containing the bulk of the system and a Music Menu
*/
library SpellOptionsMenu /*
v.1.2d
Made by: Pinzu
*/ requires /*
*/ SpellOption /* (from triggers)
*/ ArrayList /* https://www.hiveworkshop.com/threads/arraylist.312512/
*/ optional PlayerUtils /* https://www.hiveworkshop.com/threads/playerutils.278559/
*/ optional TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
// ---------------------------------------------------------------------
This allows for the creation and manipulation of spell based option menus. A menu can contain any amount
of options inside them with different local properties. Options can also be locked to positions between
0 and 10, which means that they will be visible at that position across all pages.
// ---------------------------------------------------------------------
Credits:
IcemanBo - For creating the base of the Cooldown Manager.
Sir Moriarty - Pointing out some errors in the code
Pyrogasm - Helpful in figuring out how to make the system
Overfrost - Helpful in the improvement of the system
// ---------------------------------------------------------------------
Notice:
1) When the menu is closed the previous selection is restored.
2) When a menu is destroyed all options held inside are deallocated, sharing options across multiple
menus is possible but considered dangerous and not recommended.
*/
// ---------------------------------------------------------------------------------------- \\
// Configurable Block \\
// ---------------------------------------------------------------------------------------- \\
globals
// **************************************************************************************** \\
// Menu Dummy \\
// **************************************************************************************** \\
// Configure which dummy unit should be used as menu and where the menu is located. It's \\
// unlikely that you would ever need to change the coordinates from (0,0) as it will spawn \\
// on both water and black boundary. \\
// **************************************************************************************** \\
private constant integer MENU_DUMMY = 'n000'
private constant real MENU_SPAWN_X = 0
private constant real MENU_SPAWN_Y = 0
// **************************************************************************************** \\
// Active Spells \\
// **************************************************************************************** \\
// These spells are based on Channel ability. You need to copy one of them to your map and \\
// and make copies of it. The only requirement for it to work is that no spell use the same \\
// order string (Text - Order String - Use/Turn On). \\
// \\
// If you don't like that the spells are instant cast you can simply add a casting duration \\
// to them. Don't forget ot make sure the hotkeys below match those assigned in the editor. \\
// **************************************************************************************** \\
// Spells
private constant integer A_1 = 'A00G'
private constant integer A_2 = 'A00H'
private constant integer A_3 = 'A00I'
private constant integer A_4 = 'A00J'
private constant integer A_5 = 'A00K'
private constant integer A_6 = 'A00L'
private constant integer A_7 = 'A00N'
private constant integer A_8 = 'A00M'
private constant integer A_9 = 'A00P'
private constant integer A_10 = 'A00O'
private constant integer A_11 = 'A00Q'
private constant integer A_12 = 'A00R'
private constant integer A_NEXT = 'A000'
// Hotkeys
private constant string H_1 = "Q"
private constant string H_2 = "W"
private constant string H_3 = "E"
private constant string H_4 = "R"
private constant string H_5 = "A"
private constant string H_6 = "S"
private constant string H_7 = "D"
private constant string H_8 = "F"
private constant string H_9 = "Z"
private constant string H_10 = "X"
private constant string H_11 = "C"
private constant string H_12 = "V"
private constant string HOTKEY_COLOR = "|cffffcc00"
private constant string HOTKEY_PREFIX = "["
private constant string HOTKEY_POSTFIX = "|r]"
// **************************************************************************************** \\
// Cooldown \\
// **************************************************************************************** \\
private constant string COOLDOWN_COLOR = "|c00959697"
private constant string COOLDOWN_LABEL = COOLDOWN_COLOR + "Cooldown: "
// **************************************************************************************** \\
// Next Option (skip this) \\
// **************************************************************************************** \\
// private constant string NEXT_DEFAULT_LABEL = "Next"
// private constant string NEXT_DEFAULT_DESC = "Switches to the next menu page."
// private constant string NEXT_DEFAULT_BTN = "ReplaceableTextures\\CommandButtons\\BTNReplay-Loop.blp"
// private constant string NEXT_DEFAULT_DISBTN = "ReplaceableTextures\\CommandButtonsDisabled\\DISBTNReplay-Loop.blp"
// **************************************************************************************** \\
private constant real DESELECT_CHECK_RATE = 0.1 // How frequent deselection events should be checked for
// Enables the functionality for closing a menu when ESC is pressed
private constant boolean CLOSE_ON_ESC = true
endglobals
/*
You can modify this code if you wish to change the format of cooldown display.
For example if you wish the output to be mm:ss or something similar.
*/
private function FormatTime takes integer seconds returns string
return I2S(seconds)
endfunction
/*
You can modify this part if you wish to change how options are valued during sorting.
*/
private function SortValuation takes SpellOption option returns integer
return option.rank
endfunction
// ---------------------------------------------------------------------------------------- \\
// End Configurable \\
// ---------------------------------------------------------------------------------------- \\
//! novjass
API
------------
/*
Wrapper returning the last triggered menu.
*/
function GetTriggerSpellMenu takes nothing returns SpellMenu
/*
Wrapper returning the player triggering a menu event.
*/
function GetTriggerSpellMenuPlayer takes nothing returns player
/*
Used to register callbacks for Any Spell Menu Events, such as when a menu opens or closes.
*/
function OnSpellMenuEvent takes real whichEvent, code c returns nothing
/*
This will return the menu dummy unit, you should be careful what operations you perform on it.
*/
function GetSpellMenuUnit takes integer playerId returns unit
/*
Returns the current open menu page for the player by matching id
*/
function GetCurrentSpellMenuPage takes integer playerId returns integer
/*
Returns the current open menu for the given player.
*/
function GetCurrentSpellMenu takes integer playerId returns SpellMenu
struct SpellMenu
string name // The menu name
boolean forceOpen // Disables selection while the menu is opened, until a menu.close(player) is fired
/*
Allocates a menu instance with the provided title.
*/
static method create takes string title returns thistype
/*
Deallocates the menu and the options held inside.
*/
method destroy takes nothing returns nothing
/*
Returns the current index position of a option inside the menu, -1 if it doesn't exist.
*/
method indexOf takes SpellOption option returns integer
/*
Inserts an option at the index position, if its outside bounds the option will be appended last.
*/
method add takes integer index, SpellOption option returns nothing
/*
Returns and pushes out a option at the index from the menu.
*/
method eject takes integer index returns SpellOption
/*
Removes the option, destroying it in the process. Dangling references will be created for
any references outside the menu to the removed option.
*/
method remove takes integer index returns nothing
/*
Returns the option at the provided index.
*/
method get takes integer index returns SpellOption
/*
Returns the amount of options held inside the menu.
*/
method size takes nothing returns integer
/*
Clears the menu of options and removing them in the process.
*/
method clear takes nothing returns nothing
/*
Returns true if a option is held inside the menu.
*/
method contains takes SpellOption option returns boolean
/*
Swaps position between two options at the provided indexes.
*/
method swap takes integer indexA, integer indexB returns nothing
/*
This will sort the menu using quicksort in descending or ascending order based on the user data
the option has. If you want to sort anything different from a integer hashing would be required.
*/
method sort takes boolean ascending returns nothing
/*
Wrapper for creating an option and inserting it at the provided position.
*/
method createOption takes integer index, string label, string text, string btn, code callback returns SpellOption
/*
Locks a option to a specific menu position between 0 and 10, meaning that the option will appear
at the same position across all menu pages.
*/
method lock takes SpellOption option, integer position returns nothing
/*
Unlocks a locked option.
*/
method unlock takes SpellOption option returns nothing
/*
Returns true if a option is locked.
*/
method isLocked takes SpellOption option returns boolean
/*
This will set the menu page of the given player, can be used to switch between pages.
If the page is outside is outside of bounds the page will simply be set to the first page.
*/
method showPage takes player p, integer page returns nothing
/*
This will refresh the menu for all players currently viewing it. This can be useful in cases where
the same option is visible to multiple players and must be changed globally. This is due refreshes only
being executed for the player that selected the option.
*/
method refresh takes nothing returns nothing
/*
Opens the menu for the given player.
*/
method open takes player p returns nothing
/*
Closes the menu for the given player.
*/
method close takes player p returns nothing
//! endnovjass
globals
constant integer EVENT_SPELL_MENU_OPEN = 11
constant integer EVENT_SPELL_MENU_CLOSE = 12
private constant integer MAX_PLAYERS = 24 // Highest available playable slot
private trigger trgOpen = null
private trigger trgClose = null
private integer array watched [MAX_PLAYERS][12] // Probably could be replaced
private constant integer HIDDEN = 0
private constant integer DISABLED = 1
private constant integer ENABLED = 2
endglobals
function GetTriggerSpellMenu takes nothing returns SpellMenu
static if SBM_JASS_VARS then
return SBM_menuKey
else
return udg_SBM_menuKey
endif
endfunction
function GetTriggerSpellMenuPlayer takes nothing returns player
static if SBM_JASS_VARS then
return SBM_player
else
return udg_SBM_player
endif
endfunction
function OnSpellMenuEvent takes real whichEvent, code c returns nothing
if whichEvent == EVENT_SPELL_MENU_OPEN then
if trgOpen == null then
set trgOpen = CreateTrigger()
call TriggerRegisterVariableEvent(trgOpen, SBM_event_str, EQUAL, whichEvent)
endif
call TriggerAddCondition(trgOpen, Filter(c))
elseif whichEvent == EVENT_SPELL_MENU_CLOSE then
if trgClose == null then
set trgClose = CreateTrigger()
call TriggerRegisterVariableEvent(trgClose, SBM_event_str, EQUAL, whichEvent)
endif
call TriggerAddCondition(trgClose, Filter(c))
debug else
debug call ErrorSBM("Lib_SpellOptionsMenu:OnSpellMenuEvent", "No such argument exists", "InvalidArgumentException")
endif
endfunction
private function NotifyEvent takes player p, SpellMenu menu, real whichEvent returns nothing
static if SBM_JASS_VARS then
set SBM_player = p
set SBM_menuKey = menu
set SBM_event = 0.
set SBM_event = whichEvent
else
set udg_SBM_player = p
set udg_SBM_menuKey = menu
set udg_SBM_event = 0.
set udg_SBM_event = whichEvent
endif
endfunction
private function WatchSpellOption takes integer playerId, integer index, SpellOption option returns nothing
set watched[playerId][index] = option
endfunction
private function UnwatchSpellOptions takes integer playerId returns nothing
local integer i = 0
loop
exitwhen i == 12
set watched[playerId][i] = 0
set i = i + 1
endloop
endfunction
private function GetOptionIndex takes integer playerId, SpellOption option returns integer
local integer i = 0
loop
exitwhen i == 12
if watched[playerId][i] == option then
return i
endif
set i = i + 1
endloop
return -1
endfunction
/*
Player Manager used to encapsulate player related data
*/
private struct PlayerMenu
Table spellTable // Maps spells to options
SpellMenu currOpen // Current open menu
integer pageIndex // Current viewed page
unit u // Menu dummy
player p // Owner
integer pid // Owner-id
private group selectedUnits // Stored selection before menu was opened
private boolean prevSelectionState // Units selected before the menu opened
private boolean forceOpen // Forces selection if deselection before close was detected
private static IntArrayList usedMenu // List of all current open menus
private static timer refreshTimer // Refresh timer for open menus
private integer array spellState[13]
static method create takes player p returns thistype
local thistype this = .allocate()
set .p = p
set .pid = GetPlayerId(p)
set .u = CreateUnit(p, MENU_DUMMY, MENU_SPAWN_X, MENU_SPAWN_Y, 0)
call SetUnitScale(.u, 0, 0, 0)
call ShowUnit(.u, false)
set .selectedUnits = CreateGroup()
set .spellTable = Table.create()
return this
endmethod
method destroy takes nothing returns nothing
call .spellTable.destroy()
call RemoveUnit(.u)
call DestroyGroup(.selectedUnits)
set .u = null
set .p = null
set .selectedUnits = null
call .deallocate()
endmethod
method close takes nothing returns nothing
local unit enum
local integer i
if usedMenu.contains(this) then
call usedMenu.remove(usedMenu.indexOf(this))
endif
if usedMenu.length == 0 then
call PauseTimer(refreshTimer)
static if LIBRARY_TimerUtils then
call ReleaseTimer(refreshTimer)
else
call DestroyTimer(refreshTimer)
endif
set refreshTimer = null
endif
if IsUnitSelected(.u, .p) then // Restores previous selection
if GetLocalPlayer() == .p then
call ClearSelection()
endif
loop
set enum = FirstOfGroup(.selectedUnits)
exitwhen enum == null
call GroupRemoveUnit(.selectedUnits, enum)
if GetLocalPlayer() == .p then
call SelectUnit(enum, true)
endif
endloop
endif
call ShowUnit(.u, false)
call NotifyEvent(.p, .currOpen, EVENT_SPELL_MENU_CLOSE)
set .currOpen = 0
endmethod
/*
Periodically checks if the menu unit is still open. Triggers a close event if not
*/
private static method onRefresh takes nothing returns nothing
local integer i = usedMenu.length - 1
local thistype this
loop
exitwhen i < 0
set this = usedMenu[i]
if IsUnitSelected(.u, .p) then
set .prevSelectionState = true
else
if .prevSelectionState then
if not .forceOpen then
call .close()
set .prevSelectionState = false
else
if GetLocalPlayer() == .p then
call ClearSelection()
call SelectUnit(.u, true)
endif
endif
endif
endif
set i = i - 1
endloop
endmethod
method open takes SpellMenu menu, boolean forceOpen returns nothing
if usedMenu.length == 0 then
static if LIBRARY_TimerUtils then
set refreshTimer = NewTimer()
else
set refreshTimer = CreateTimer()
endif
call TimerStart(refreshTimer, DESELECT_CHECK_RATE, true, function thistype.onRefresh)
endif
if not usedMenu.contains(this) then
call usedMenu.add(0, this)
endif
if IsUnitSelected(.u, .p) then
if menu != .currOpen then // We close the previous one
call NotifyEvent(.p, .currOpen, EVENT_SPELL_MENU_CLOSE)
endif
else // No previous menu selected, store selected units
call GroupEnumUnitsSelected(.selectedUnits, .p, null)
endif
set .forceOpen = forceOpen
set .currOpen = menu
call ShowUnit(.u, true)
call NotifyEvent(.p, .currOpen, EVENT_SPELL_MENU_OPEN)
endmethod
static method updateForceOpenForMenu takes SpellMenu menu, boolean forceOpen returns nothing
static if LIBRARY_PlayerUtils then
local User p = User.first
loop // only loop through players that are playing
exitwhen p == User.NULL
if thistype(p.id).currOpen == menu then
set thistype(p.id).forceOpen = forceOpen
endif
set p = p.next
endloop
else
local player p
local integer i = 0
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER) and /*
*/ thistype(i).currOpen == menu then
set thistype(p.id).forceOpen = forceOpen
endif
set i = i + 1
endloop
endif
endmethod
method setAbilityUIState takes integer spell, integer index, boolean hidden, boolean disabled returns nothing
if hidden and .spellState[index] != HIDDEN then
call UnitRemoveAbility(.u, spell)
call UnitAddAbility(.u, spell)
call BlzUnitDisableAbility(.u, spell, disabled, hidden)
set .spellState[index] = HIDDEN
elseif disabled and .spellState[index] != DISABLED then
call UnitRemoveAbility(.u, spell)
call UnitAddAbility(.u, spell)
call BlzUnitDisableAbility(.u, spell, disabled, hidden)
set .spellState[index] = DISABLED
elseif .spellState[index] != ENABLED then
call UnitRemoveAbility(.u, spell)
call UnitAddAbility(.u, spell)
call BlzUnitDisableAbility(.u, spell, disabled, hidden)
set .spellState[index] = DISABLED
endif
endmethod
private static method onInit takes nothing returns nothing
set usedMenu = IntArrayList.create()
endmethod
endstruct
function GetSpellMenuUnit takes integer playerId returns unit
return PlayerMenu(playerId + 1).u
endfunction
function GetCurrentSpellMenu takes integer playerId returns SpellMenu
return PlayerMenu(playerId + 1).currOpen
endfunction
function GetCurrentSpellMenuPage takes integer playerId returns integer
return PlayerMenu(playerId + 1).pageIndex
endfunction
// ~~
struct SpellMenu
string name // Menu name
private boolean shouldForceOpen
// Spells
private static integer array active[13] // Active spells
private static string array hotkey[13] // Spell hotkeys based on the spell tooltip defined at start
// Options
private IntArrayList options // The underlying list of data
private SpellOption array lockedOptions[11] // Options that have been locked
//private static trigger trgUsed = CreateTrigger() // Trigger for when a option is used
// Temp
private static IntArrayList visibleOptions
private static SpellOption lockedOption
private static integer spell
private static integer timeRemaining
private static string text
// ---------------------------------------------------------------------
// List Manipulation
// ---------------------------------------------------------------------
method indexOf takes SpellOption option returns integer
return .options.indexOf(option)
endmethod
method add takes integer index, SpellOption option returns nothing
if index < 0 or index > .options.length then
call .options.add(.options.length, option)
else
call .options.add(index, option)
endif
endmethod
method eject takes integer index returns SpellOption
local SpellOption o
if index >= 0 and index < .options.length then
set o = .options[index]
call unlock(o)
call .options.remove(index)
return o
debug else
debug call ErrorSBM("SpellMenu:eject", "Invalid index: " + I2S(index), "IndexOutOfBounds")
endif
return 0
endmethod
method remove takes integer index returns nothing
local SpellOption o = .eject(index)
if o != 0 then
call o.destroy()
endif
endmethod
method get takes integer index returns SpellOption
return .options[index]
endmethod
method size takes nothing returns integer
return .options.length
endmethod
method clear takes nothing returns nothing
local integer i = .options.length - 1
loop
exitwhen i < 0
call .remove(i)
set i = i - 1
endloop
set i = 0
loop // Clear locked options
exitwhen i == 12
set .lockedOptions[i] = 0
set i = i + 1
endloop
endmethod
method contains takes SpellOption option returns boolean
return .options.contains(option)
endmethod
method swap takes integer indexA, integer indexB returns nothing
call .options.swap(indexA, indexB)
endmethod
private static method sortAscending takes nothing returns boolean
return SortValuation(IntArrayList.pivot) > SortValuation(IntArrayList.other )
endmethod
private static method sortDescending takes nothing returns boolean
return SortValuation(IntArrayList.pivot ) < SortValuation(IntArrayList.other)
endmethod
method sort takes boolean ascending returns nothing
if ascending then
call .options.sort(function thistype.sortAscending)
else
call .options.sort(function thistype.sortDescending)
endif
endmethod
// ---------------------------------------------------------------------
// Misc
// ---------------------------------------------------------------------
method createOption takes integer index, string label, string text, string btn, code callback returns SpellOption
local SpellOption o = SpellOption.create(label, text, btn, callback)
call .add(index, o)
return o
endmethod
method lock takes SpellOption option, integer position returns nothing
debug if not .contains(option) then
debug call ErrorSBM("Lib_SpellOptionsMenu:lock", "Option does not belong to this menu", "InvalidArgumentException")
debug return
debug endif
if position < 0 or position >= 11 then
debug call ErrorSBM("Lib_SpellOptionsMenu:lock", "Position needs to be between 0 and 10 (" + I2S(position) + ")", "IndexOutOfBounds")
return
endif
set .lockedOptions[position] = option
endmethod
method unlock takes SpellOption option returns nothing
local integer i = 0
local SpellOption cursor
loop
exitwhen i == 11
set cursor =.lockedOptions[i]
if cursor == option then
set .lockedOptions[i] = 0
return
endif
set i = i + 1
endloop
endmethod
method isLocked takes SpellOption option returns boolean
local integer i = 0
loop
exitwhen i == 11
if .lockedOptions[i] == option then
return true
endif
set i = i + 1
endloop
return false
endmethod
private static method getPages takes integer length returns integer
local integer maxWindow = length/11
if ModuloInteger(length, 11) == 0 and length != 0 then
set maxWindow = maxWindow - 1
endif
return maxWindow
endmethod
private static method applyOptionToSpell takes PlayerMenu pmenu, SpellOption o, integer pos returns nothing
local boolean hidden = true
local boolean disabled = true
set spell = active[pos]
if o != 0 and not o.getLocalHidden(pmenu.pid) then
set text = o.getLocalText(pmenu.pid)
set timeRemaining = o.getCooldown(pmenu.pid)
if timeRemaining > 0 then
set text = text + "|n|n" + COOLDOWN_LABEL + FormatTime(timeRemaining) + "|r"
endif
if o.getLocalEnabled(pmenu.pid) then
set hidden = false
set disabled = false
set pmenu.spellTable[spell] = o // map option to spell-table
else
set disabled = true
set hidden = false
endif
if GetLocalPlayer() == pmenu.p then // Update Displayed Ability
call BlzSetAbilityExtendedTooltip(spell, text, 1)
call BlzSetAbilityTooltip(spell, o.getLocalLabel(pmenu.pid) + " " + hotkey[pos], 1)
call BlzSetAbilityIcon(spell, o.getLocalIcon(pmenu.pid))
endif
endif
call pmenu.setAbilityUIState(spell, pos, hidden, disabled)
endmethod
method showPage takes player p, integer page returns nothing
local PlayerMenu pmenu = PlayerMenu(GetPlayerId(p) + 1)
local integer maxPages
local integer i = 0
local integer j = 0
local SpellOption o
if pmenu.currOpen == 0 then
return
endif
call visibleOptions.clear()
call UnwatchSpellOptions(pmenu.pid)
loop
exitwhen i == .options.length
set o = .options[i]
set lockedOption = lockedOptions[ModuloInteger(j, 11)] // TODO: replace modulo
if lockedOption != 0 and not lockedOption.getLocalHidden(pmenu.pid) then
call visibleOptions.add(j, lockedOption) // add locked option to presenter
if lockedOption != o then
set i = i - 1
endif
set j = j + 1
elseif not o.getLocalHidden(pmenu.pid) and not .isLocked(o) then
call visibleOptions.add(j, o) // add default option to presenter
set j = j + 1
endif
set i = i + 1
endloop
// Adjust current page
set maxPages = getPages(j)
if page > maxPages or page < 0 then
set pmenu.pageIndex = 0
else
set pmenu.pageIndex = page
endif
// Adjust Options
set j = pmenu.pageIndex*11
set i = 0
loop
exitwhen i == 12
if j < visibleOptions.length or (lockedOptions[i] != 0) then
if j < visibleOptions.length then
set o = visibleOptions[j]
set j = j + 1
else
set o = lockedOptions[i]
endif
call applyOptionToSpell(pmenu, o, i)
call WatchSpellOption(pmenu.pid, i, o)
else
call pmenu.setAbilityUIState(active[i], i, true, true)
endif
set i = i + 1
endloop
// If there are more than 12 options in the menu than the last button will always be 'Next'
if visibleOptions.length > 12 then
call pmenu.setAbilityUIState(active[11], 11, true, true)
call pmenu.setAbilityUIState(A_NEXT, 12, false, false)
else
call pmenu.setAbilityUIState(A_NEXT, 12, true, true)
endif
call BlzSetUnitName(pmenu.u, .name + " " + I2S(pmenu.pageIndex + 1) + "/" + I2S(maxPages + 1))
if GetLocalPlayer() == pmenu.p then
call ClearSelection()
call SelectUnit(pmenu.u, true)
endif
endmethod
method refresh takes nothing returns nothing
local PlayerMenu pmenu
static if LIBRARY_PlayerUtils then
local User p = User.first
loop // only loop through players that are playing
exitwhen p == User.NULL
set pmenu = PlayerMenu(p.id + 1)
if pmenu.currOpen == this then
call .showPage(p.handle, pmenu.pageIndex)
endif
set p = p.next
endloop
else
local player p
local integer i = 0
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
set pmenu = PlayerMenu(i + 1)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER) and /*
*/ pmenu.currOpen == this then
call .showPage(p, pmenu.pageIndex)
endif
set i = i + 1
endloop
endif
endmethod
method open takes player p returns nothing
local PlayerMenu pmenu = PlayerMenu(GetPlayerId(p) + 1)
call pmenu.open(this, .forceOpen)
call showPage(p, 0)
endmethod
method close takes player p returns nothing
local PlayerMenu pmenu = PlayerMenu(GetPlayerId(p) + 1)
if IsUnitSelected(pmenu.u, p) and this == pmenu.currOpen then
call pmenu.close()
endif
endmethod
method operator forceOpen= takes boolean flag returns nothing
call PlayerMenu.updateForceOpenForMenu(this, flag)
set shouldForceOpen = flag
endmethod
method operator forceOpen takes nothing returns boolean
return shouldForceOpen
endmethod
static method create takes string title, boolean forceOpen returns thistype // add force open argument
local thistype this = .allocate()
local integer i = 0
loop
exitwhen i == 11
set this.lockedOptions[i] = 0
set i = i + 1
endloop
set this.name = title
set this.forceOpen = forceOpen
set this.options = IntArrayList.create()
static if SBM_GUI_PLUGIN then
set udg_SBM_lastCreatedMenu = this
endif
return this
endmethod
method destroy takes nothing returns nothing
call .clear()
call .options.destroy()
call .deallocate()
endmethod
private static method onOptionSelected takes nothing returns boolean
local PlayerMenu pmenu = PlayerMenu(GetPlayerId(GetTriggerPlayer()) + 1)
local integer spell = GetSpellAbilityId()
local SpellOption o
local thistype this = pmenu.currOpen
if spell == A_NEXT then
call this.showPage(pmenu.p, pmenu.pageIndex + 1) // Open the next window
else
set o = pmenu.spellTable[spell]
if o.cooldown > 0 then
call o.startCooldown(pmenu.pid)
endif
static if SBM_JASS_VARS then
set SBM_menuKey = this
else
set udg_SBM_menuKey = this
endif
call o.select(pmenu.p)
call this.refresh() // Refresh the menu for all players that have it open
endif
return false
endmethod
private static method onOptionChanged takes nothing returns nothing
static if SBM_JASS_VARS then
local integer pid = GetPlayerId(SBM_player)
local integer index = GetOptionIndex(pid, SBM_optionKey)
if index != -1 then
call applyOptionToSpell(PlayerMenu(pid + 1), SBM_optionKey, index)
endif
else
local integer pid = GetPlayerId(udg_SBM_player)
local integer index = GetOptionIndex(pid, udg_SBM_optionKey)
if index != -1 then
call applyOptionToSpell(PlayerMenu(pid + 1), udg_SBM_optionKey, index)
endif
endif
endmethod
private static method onLeave takes nothing returns nothing
call PlayerMenu(GetPlayerId(GetTriggerPlayer()) + 1).destroy()
endmethod
// ---------------------------------------------------------------------
// Setup
// ---------------------------------------------------------------------
private static method setAbilityPos takes integer spell, integer index returns nothing // Not working properly yet...
local integer x = ModuloInteger(index, 4)
local integer y = index/4
call BlzSetAbilityPosX(spell, x)
call BlzSetAbilityPosY(spell, y)
endmethod
static if CLOSE_ON_ESC then
private static method onEscapePressed takes nothing returns nothing
local PlayerMenu pmenu = PlayerMenu(GetPlayerId(GetTriggerPlayer()) + 1)
// we only allow escape close on menus that are not in a force open state
if IsUnitSelected(pmenu.u, pmenu.p) and pmenu.currOpen != 0 and not pmenu.currOpen.forceOpen then
call pmenu.close()
endif
endmethod
endif
private static method onInit takes nothing returns nothing
local player p
local integer i
local trigger trgOnOptionSelection = CreateTrigger()
local trigger trgLeave = CreateTrigger()
local trigger trgEsc
local PlayerMenu pmenu
static if CLOSE_ON_ESC then
set trgEsc = CreateTrigger()
call TriggerAddAction(trgEsc, function thistype.onEscapePressed)
endif
call TriggerAddAction(trgOnOptionSelection, function thistype.onOptionSelected) // On Selection
call TriggerAddAction(trgLeave, function thistype.onLeave) // On Leave
call OnSpellOptionEvent(EVENT_SPELL_OPTION_CHANGE, function thistype.onOptionChanged) // On Cooldown Tick
set active[0] = A_1
set active[1] = A_2
set active[2] = A_3
set active[3] = A_4
set active[4] = A_5
set active[5] = A_6
set active[6] = A_7
set active[7] = A_8
set active[8] = A_9
set active[9] = A_10
set active[10] = A_11
set active[11] = A_12
set active[12] = A_NEXT
set hotkey[0] = H_1
set hotkey[1] = H_2
set hotkey[2] = H_3
set hotkey[3] = H_4
set hotkey[4] = H_5
set hotkey[5] = H_6
set hotkey[6] = H_7
set hotkey[7] = H_8
set hotkey[8] = H_9
set hotkey[9] = H_10
set hotkey[10] = H_11
set hotkey[11] = H_12
set hotkey[12] = H_12
set i = 0
loop
exitwhen i == 12
call setAbilityPos(active[i], i)
set hotkey[i] = HOTKEY_PREFIX + HOTKEY_COLOR + hotkey[i] + HOTKEY_POSTFIX
set i = i + 1
endloop
set i = 0
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerEventLeave(trgLeave, p)
set pmenu = PlayerMenu.create(p)
call TriggerRegisterUnitEvent(trgOnOptionSelection, pmenu.u, EVENT_UNIT_SPELL_FINISH)
static if CLOSE_ON_ESC then
call TriggerRegisterPlayerEventEndCinematic(trgEsc, p)
endif
endif
set i = i + 1
endloop
set trgEsc = null
set visibleOptions = IntArrayList.create()
set trgLeave = null
set trgOnOptionSelection = null
endmethod
endstruct
endlibrary
library SpellOption /*
v.1.1d
Made by: Pinzu
*/ requires /*
*/ Table /* hiveworkshop.com/threads/snippet-new-table.188084/
*/ optional PlayerUtils /* https://www.hiveworkshop.com/threads/playerutils.278559/
*/ optional TimerUtils /* http://www.wc3c.net/showthread.php?t=101322
// ---------------------------------------------------------------------
This allows for the creation and manipulation of SpellOption items. Option properties are
stored inside a table and have both a global and local attribute. This means that you can
display different things for different players using player id for reference.
// ---------------------------------------------------------------------
Credits:
IcemanBo - For creating the base of the Cooldown Manager.
Sir Moriarty - Pointing out some errors in the code
Pyrogasm - Helpful in figuring out how to make the system
Overfrost - Helpful in the improvement of the system
// ---------------------------------------------------------------------
Notice:
1) To prevent green icons when an option is disabled the icon used must have a DISPAS version.
Example: https://www.hiveworkshop.com/threads/btnelectroburst.310351/
2) The Icon paths you use must have two backslashes to work correctly, like so: \\
3) if an option has no btn assigned it will use DEFAULT_BTN.
4) The system does not deallocate local data inside options when a player leaves. This must either
be ignored or handled manually by using the method option.removeLocalChanges(playerId).
*/
// ---------------------------------------------------------------------
// Configurable Block
// ---------------------------------------------------------------------
globals
private constant string DEFAULT_BTN = "ReplaceableTextures\\CommandButtons\\BTNHeal.blp"
/* Remove the comments below to run a textmacro which will override the default GUI variables
with vJASS ones. Example:
udg_SBM_optionKey --> SBM_optionKey
*/
// //! runtextmacro JASS_VARS()
/*
SBM_GUI_PLUGIN is an option to enable additional GUI support variables
that allows global access to the last created menu and last created option.
This is not necessary if you don't plan to create menus using GUI.
- udg_SBM_lastCreatedMenu
- udg_SBM_lastCreatedOption
- udg_SBM_customData
*/
constant boolean SBM_GUI_PLUGIN = true
endglobals
// ---------------------------------------------------------------------
// End configuration
// ---------------------------------------------------------------------
//! novjass
API
------------
// Constants
constant integer EVENT_SPELL_OPTION_SELECTED // Option selection event id
constant integer EVENT_SPELL_OPTION_CD_END // Option cooldown ended event id
// Note: These variables are prefixed with udg_ if the textmacro JASS_VARS never ran.
SpellOption SBM_optionKey // Triggering Option
SpellMenu SBM_menuKey // Trigger Menu
player SBM_player // Triggering Player
real SBM_event // Real Event
/*
Used to register callbacks for Any Spell Option Events, such as when a cooldown ends or an option is selected.
*/
function OnSpellOptionEvent takes real whichEvent, code c returns nothing
/*
Wrapper returning the last triggered option, be that on selection or when a cooldown ends.
*/
function GetTriggerSpellOption takes nothing returns SpellOption
/*
Wrapper returning the relevant player when a option is triggered.
*/
function GetTriggerSpellOptionPlayer takes nothing returns player
struct SpellOption
Global data
---------------
integer userData // This is a custom data you can use to attach references, same as you would using for example SetUnitUserData.
integer rank // Custom data which can be used when sorting options.
string label // Option header
string text // Option description
string icon // Icon path, used when the option is enabled
boolean enabled // Flag for toggling if the option should be active
boolean hidden // Flag for if the option should be displayed
integer cooldown // Cooldown duration when the option is selected
/*
Creates an option with the given attributes. The callback code is executed whenever the option is selected.
It's not requirement as you can use real-event listeners as an alternative.
*/
static method create takes string label, string text, string btn, string disbtn, code callback returns thistype
/*
Used to change the callback that triggers when the option is used, null will remove any previous callback.
*/
method onResponse takes code callback returns nothing
/*
Deallocates all data associated with the option.
*/
method destroy takes nothing returns nothing
/*
Used to trigger a callback when a player uses an option.
*/
method select takes player p returns nothing
Local data //This section will only manipulate local data for individual players
---------------
/*
Changes the option attribute for local player by matching id.
*/
method setLocalLabel takes integer playerId, string s returns nothing
method setLocalText takes integer playerId, string s returns nothing
method setLocalIcon takes integer playerId, string s returns nothing
method setLocalEnabled takes integer playerId, boolean b returns nothing
method setLocalHidden takes integer playerId, boolean b returns nothing
method setLocalCooldown takes integer playerId, integer seconds returns nothing
/*
Returns the current option attribute for local player by matching id.
*/
method getLocalLabel takes integer playerId returns string
method getLocalText takes integer playerId returns string
method getLocalIcon takes integer playerId returns string
method getLocalEnabled takes integer playerId returns boolean
method getLocalHidden takes integer playerId returns boolean
method getLocalCooldown takes integer playerId returns integer
/*
Removes any local option changes, reverting back to normal for local player by matching id
*/
method removeLocalLabel takes integer playerId returns nothing
method removeLocalText takes integer playerId returns nothing
method removeLocalIcon takes integer playerId returns nothing
method removeLocalEnabled takes integer playerId returns nothing
method removeLocalHidden takes integer playerId returns nothing
method removeLocalCooldown takes integer playerId returns nothing
/*
Removes all local changes for matching player, reverting to global option attributes.
Does not effect active cooldown.
*/
method removeLocalChanges takes integer playerId returns nothing
/*
Returns the current icon that is shown for a given player. Depending on state
such as if the option is enabled, disabled or has a cooldown.
*/
method getLocalIcon takes integer playerId returns string
/*
Removes option cooldown for a given player.
*/
method stopCooldown takes integer playerId returns nothing
/*
Starts option cooldown for a given player.
*/
method startCooldown takes integer playerId returns nothing
/*
Clears all active cooldowns from the option.
*/
method stopAllCooldowns takes nothing returns nothing
//! endnovjass
globals
constant integer EVENT_SPELL_OPTION_SELECTED = 1 // Triggered when a option is selected
constant integer EVENT_SPELL_OPTION_CD_END = 2 // Triggered exactly when an option cooldown has ended
constant integer EVENT_SPELL_OPTION_CHANGE = 3 // Triggered every time a second of cooldown has passed if the option is being watched
private constant string SBM_EVENT_GUI = "udg_SBM_event"
private constant string SBM_EVENT_JASS = "SBM_event"
string SBM_event_str = SBM_EVENT_GUI
//! textmacro_once JASS_VARS
integer SBM_optionKey // Triggering option id
player SBM_player // Triggering Player
real SBM_event // Real Event
integer SBM_menuKey // Trigger menu id
constant boolean SBM_JASS_VARS = true
//! endtextmacro
private integer label_index
private integer text_index
private integer icon_index
private integer enabled_index
private integer hidden_index
private integer cooldown_index
private constant integer trigger_index = -1 // Storage index for the callback trigger
private constant integer id_index = -2 // Storage index for the owning menu
private constant integer rank_index = -3 // Storage index for the owning menu
private trigger trgOnAnySelection = null
private trigger trgOnAnyCooldownEnd = null
private trigger trgOnAnyChange = null
private Table delayTable
endglobals
static if DEBUG_MODE then
function ErrorSBM takes string consoleName, string msg, string ErrorSBMType returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 50000, "|cffff0000>> " + consoleName + "|r -> " + msg + " |cffff0000" + ErrorSBMType + "|r")
endfunction
endif
function OnSpellOptionEvent takes real whichEvent, code c returns nothing
if whichEvent == EVENT_SPELL_OPTION_SELECTED then
if trgOnAnySelection == null then
set trgOnAnySelection = CreateTrigger()
call TriggerRegisterVariableEvent(trgOnAnySelection, SBM_event_str, EQUAL, whichEvent)
endif
call TriggerAddCondition(trgOnAnySelection, Filter(c))
elseif whichEvent == EVENT_SPELL_OPTION_CD_END then
if trgOnAnyCooldownEnd == null then
set trgOnAnyCooldownEnd = CreateTrigger()
call TriggerRegisterVariableEvent(trgOnAnyCooldownEnd, "udg_SBM_event", EQUAL, whichEvent)
endif
call TriggerAddCondition(trgOnAnyCooldownEnd, Filter(c))
elseif whichEvent == EVENT_SPELL_OPTION_CHANGE then
if trgOnAnyChange == null then
set trgOnAnyChange = CreateTrigger()
call TriggerRegisterVariableEvent(trgOnAnyChange, SBM_event_str, EQUAL, whichEvent)
endif
call TriggerAddCondition(trgOnAnyChange, Filter(c))
debug else
debug call ErrorSBM("Lib_SpellOption:OnSpellOptionEvent", "No such argument exists", "InvalidArgumentException")
endif
endfunction
function GetTriggerSpellOption takes nothing returns SpellOption
static if SBM_JASS_VARS then
return SBM_optionKey
else
return udg_SBM_optionKey
endif
endfunction
function GetTriggerSpellOptionPlayer takes nothing returns player
static if SBM_JASS_VARS then
return SBM_player
else
return udg_SBM_player
endif
endfunction
private function NotifyEvent takes player p, SpellOption o, real whichEvent returns nothing
static if SBM_JASS_VARS then
set SBM_player = p
set SBM_optionKey = o
set SBM_event = 0.
set SBM_event = whichEvent
else
set udg_SBM_player = p
set udg_SBM_optionKey = o
static if SBM_GUI_PLUGIN then
set udg_SBM_customData = o.userData
endif
set udg_SBM_event = 0.
set udg_SBM_event = whichEvent
endif
endfunction
/*
This manages option cooldown for each player. It will execute OnLocalChange after each tick or when it finishes.
*/
private struct CooldownManager extends array
private static Table table_clocks
private Table table
private static method cleanup takes timer t returns nothing
local integer id = GetHandleId(t)
local SpellOption option = table_clocks[-id]
local thistype this = table_clocks[id]
call this.table.timer.remove(option)
call thistype.table_clocks.remove(id)
call thistype.table_clocks.remove(-id)
call thistype.table_clocks.real.remove(id)
call NotifyEvent(Player(this), option, EVENT_SPELL_OPTION_CHANGE)
call PauseTimer(t)
static if LIBRARY_TimerUtils then
call ReleaseTimer(t)
else
call DestroyTimer(t)
endif
endmethod
private static method onRepeat takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local real remaining = table_clocks.real[id]
local SpellOption option = table_clocks[-id]
local thistype this = table_clocks[id]
if remaining == 0 then
call cleanup(t)
else
set table_clocks.real[id] = remaining - 1.0
endif
call NotifyEvent(Player(this), option, EVENT_SPELL_OPTION_CHANGE)
set t = null
endmethod
static method remaining takes integer pid, SpellOption option returns real
return table_clocks.real[GetHandleId(thistype(pid).table.timer[option])]
endmethod
static method purgeFromOption takes SpellOption option returns nothing
local thistype this
local integer pid = 0
loop
exitwhen pid > bj_MAX_PLAYERS
set this = pid
if .table.timer.has(option) then
call cleanup(.table.timer[option])
endif
set pid = pid + 1
endloop
endmethod
static method stop takes integer playerId, SpellOption option returns nothing
local thistype this = playerId
if .table.timer.has(option) then
call cleanup(.table.timer[option])
endif
endmethod
static method start takes integer pid, SpellOption option, integer duration returns nothing
local thistype this = pid
local integer id
local timer t
if duration < 1 then
return
endif
if not .table.timer.has(option) then
static if LIBRARY_TimerUtils then
set t = NewTimer()
else
set t = CreateTimer()
endif
set .table.timer[option] = t
set id = GetHandleId(t)
set table_clocks[id] = this
set table_clocks[-id] = option
set table_clocks.real[id] = duration
call TimerStart(t, 1, true, function thistype.onRepeat)
set t = null
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local player p
loop
exitwhen i > bj_MAX_PLAYERS
set p = Player(i)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER then
set thistype(i).table = Table.create()
endif
set i = i + 1
endloop
set table_clocks = Table.create()
endmethod
endstruct
struct SpellOption
private method operator trg= takes trigger t returns nothing
set Table(this).trigger[trigger_index] = t
endmethod
private method operator trg takes nothing returns trigger
return Table(this).trigger[trigger_index]
endmethod
method onResponse takes code c returns nothing
if c != null then
if .trg == null then
set .trg = CreateTrigger()
else
call TriggerClearActions(.trg)
endif
call TriggerAddAction(.trg, c)
else
if .trg != null then
call TriggerClearActions(.trg)
call DestroyTrigger(.trg)
endif
endif
endmethod
method operator userData takes nothing returns integer
return Table(this).integer[id_index]
endmethod
method operator userData= takes integer customId returns nothing
set Table(this).integer[id_index] = customId
endmethod
method operator rank takes nothing returns integer
return Table(this).integer[rank_index]
endmethod
method operator rank= takes integer newRank returns nothing
set Table(this).integer[rank_index] = newRank
endmethod
method select takes player p returns nothing
call NotifyEvent(p, this, EVENT_SPELL_OPTION_SELECTED)
if .trg != null then
call TriggerExecute(.trg)
endif
endmethod
method stopCooldown takes integer playerId returns nothing
call CooldownManager.stop(playerId, this)
endmethod
method getCooldown takes integer playerId returns integer
return R2I(CooldownManager.remaining(playerId, this))
endmethod
method stopAllCooldowns takes nothing returns nothing
call CooldownManager.purgeFromOption(this)
endmethod
//! runtextmacro DEFINE_ACCESS("label_index", "label", "Label", "string", "false")
//! runtextmacro DEFINE_ACCESS("text_index", "text", "Text", "string", "false")
//! runtextmacro DEFINE_ACCESS("icon_index", "icon", "Icon", "string", "false")
//! runtextmacro DEFINE_ACCESS("enabled_index", "enabled", "Enabled", "boolean", "true")
//! runtextmacro DEFINE_ACCESS("hidden_index", "hidden", "Hidden", "boolean", "false")
//! runtextmacro DEFINE_ACCESS("cooldown_index", "cooldown", "Cooldown", "integer", "false")
//! textmacro DEFINE_ACCESS takes INDEX, NAME_1, NAME_2, TYPE, EXCEPTION_1
method operator $NAME_1$= takes $TYPE$ E returns nothing
set Table(this).$TYPE$[$INDEX$] = E
endmethod
method operator $NAME_1$ takes nothing returns $TYPE$
return Table(this).$TYPE$[$INDEX$]
endmethod
method setLocal$NAME_2$ takes integer pid, $TYPE$ E returns nothing
set Table(this).$TYPE$[$INDEX$ + pid + 1] = E
endmethod
method removeLocal$NAME_2$ takes integer pid returns nothing
call Table(this).$TYPE$.remove($INDEX$ + pid + 1)
endmethod
method getLocal$NAME_2$ takes integer pid returns $TYPE$
static if $EXCEPTION_1$ then // Special case for getLocalEnabled
if getCooldown(pid) > 0 then
return false
endif
endif
if Table(this).$TYPE$.has($INDEX$ + pid + 1) then
return Table(this).$TYPE$[$INDEX$ + pid + 1]
endif
return Table(this).$TYPE$[$INDEX$]
endmethod
//! endtextmacro
method startCooldown takes integer playerId returns nothing
call CooldownManager.start(playerId, this, .getLocalCooldown(playerId))
endmethod
method removeLocalChanges takes integer playerId returns nothing
call removeLocalLabel(playerId)
call removeLocalText(playerId)
call removeLocalIcon(playerId)
call removeLocalEnabled(playerId)
call removeLocalHidden(playerId)
call removeLocalCooldown(playerId)
endmethod
static method create takes string label, string text, string icon, code callback returns thistype
local thistype this = Table.create()
call this.onResponse(callback)
set this.label = label
set this.text = text
set this.icon = icon
set this.enabled = true
set this.hidden = false
set this.userData = 0
static if SBM_GUI_PLUGIN then
set udg_SBM_lastCreatedOption = this
endif
return this
endmethod
method destroy takes nothing returns nothing
call .onResponse(null)
set .trg = null
set .label = null
set .text = null
set .icon = null
call CooldownManager.purgeFromOption(this)
call Table(this).destroy()
endmethod
private static method onInit takes nothing returns nothing
local integer size = bj_MAX_PLAYERS + 1
set label_index = 0*size
set text_index = 1*size
set icon_index = 2*size
set enabled_index = 3*size
set hidden_index = 4*size
set cooldown_index = 5*size
set delayTable = Table.create()
static if SBM_JASS_VARS then
set SBM_event_str = SBM_EVENT_JASS
endif
endmethod
endstruct
endlibrary
library ArrayList requires optional HashRecyler
/*
Made by: Pinzu
Version: 1.2
https://www.hiveworkshop.com/threads/arraylist.312512/
This is a array list container utilizing a hashtable for storage, making it possible to allocate a virtually unlimited amount of lists.
It contains regular list interface, stack interface, and a few utility methods such as sort, addMatching, removeMatching, copy, swap, etc.
Credits:
Bannar for his ListT library which inspired this.
https://www.hiveworkshop.com/threads/containers-list-t.249011/
Bribe for his Table library which the HashRecyler is based on.
https://www.hiveworkshop.com/threads/snippet-new-table.188084/
Overfrost for suggesting improvements.
*/
// ******************************************************************
// API
// ******************************************************************
//! novjass
struct $NAME$ArrayList extends array
readonly static $TYPE$ pivot // Pivot element during sort or comparison
readonly static $TYPE$ other // Other element during sort
// Allocates the list.
static method create takes nothing returns thistype
// Deallocates the list.
method destroy takes nothing returns nothing
// Removes all elements from the list.
method clear takes nothing returns nothing
// Returns the number of elements in the list.
method operator length takes nothing returns integer
// Returns the element at the specified position.
method operator[] takes integer index returns $TYPE$
// Replaces the element at the specified position in the list with the specified element.
method operator[]= takes integer index, $TYPE$ element returns nothing
// Returns the value at the first position of the list
method first takes nothing returns $TYPE$
// Returns the value at the last position of the list
method last takes nothing returns $TYPE$
// Inserts the specified element at the specified position in the list.
method add takes integer index, $TYPE$ element returns nothing
// Removes the element at the specified position in the the list, returning the value.
method remove takes integer index returns $TYPE$
// Inserts the element to the last position of the list (stack interface).
method push takes $TYPE$ value returns thistype
// Removes the element at the last position of the list, returning the value (stack interface).
method pop takes $TYPE$ value returns $TYPE$
// Returns the index position of the first occurrence of the specified element in the list, or -1 if the list does not contain the element.
method indexOf takes $TYPE$ value returns integer
// Returns true if the index is storing any value (table interface).
method has takes integer index returns boolean
// Returns true if the list contains the specified element.
method contains takes $TYPE$ value returns boolean
// Returns true if the calling list contains all elements in the specified list.
method containsAll takes thistype list returns boolean
//Allocates a new list containing shallow copies of all elements held currently.
method clone takes nothing returns thistype
// Returns true if the list contains no elements.
method isEmpty takes nothing returns boolean
// Swaps position of 2 elements at the specified positions.
method swap takes integer indexA, integer indexB returns nothing
// Returns true if two lists are equal, same length and same structure.
method equals takes thistype list returns boolean
// Sorts the list after the provided condition (c). Note that the comparison must use the variables 'pivot' and 'other'.
// Furthermore, only '>' or '<' are valid operators for the sorting to work. Example:
private function SortUnitsByPlayer takes nothing returns boolean
return GetPlayerId(GetOwningPlayer(UnitArrayList.pivot)) < GetPlayerId(GetOwningPlayer(UnitArrayList.other))
endfunction
method sort takes code c returns nothing
// Reverses the order of all elements inside the list.
method reverse takes nothing returns nothing
// Changes the values of all assigned elements from the start position to the end of the range to the specified new value.
method setRange takes integer start, integer range, $TYPE$ value returns nothing
// Will perform a shallow copy of all elements from the specified source list to the calling list, with the given range. Starting
// from the specified source position, inserting to the specified destination position.
method addRange takes integer destPos, thistype src, integer srcPos, integer range returns thistype
//! endnovjass
// ******************************************************************
// Shared Resources
// ******************************************************************
globals
private constant integer SIZE_INDEX = -2 // Should be less than -1 to not risk collision with anything else
private trigger t = CreateTrigger()
private integer up
private integer down
endglobals
static if not LIBRARY_HashRecyler then
struct HashRecyler extends array
debug readonly static integer counter = 0
readonly static hashtable ht = InitHashtable()
static method operator[] takes integer k returns integer
return LoadInteger(ht, -1, k)
endmethod
static method operator []= takes integer k, integer tb returns nothing
call SaveInteger(ht, -1, k, tb)
endmethod
private static method onInit takes nothing returns nothing
set thistype[0] = 1
endmethod
static method alloc takes nothing returns integer
local integer k = thistype[0]
if (thistype[k] == 0) then
set thistype[0] = k + 1
else
set thistype[0] = thistype[k]
endif
debug set counter = counter + 1
return k
endmethod
static method free takes integer k returns nothing
set thistype[k] = thistype[0]
set thistype[0] = k
call FlushChildHashtable(ht, k)
debug set counter = counter - 1
endmethod
endstruct
endif
// ******************************************************************
// Add any textmacro below of the data types you wish to support.
// ******************************************************************
//! runtextmacro ARRAY_LIST_DEFINE("Int", "integer", "0", "Integer", "SavedInteger")
//! runtextmacro ARRAY_LIST_DEFINE("Real", "real", "0.", "Real", "SavedReal")
//! runtextmacro ARRAY_LIST_DEFINE("Bool", "boolean", "false", "Boolean", "SavedBoolean")
//! runtextmacro ARRAY_LIST_DEFINE("Str", "string", "null", "Str", "SavedString")
//! runtextmacro ARRAY_LIST_DEFINE("Unit", "unit", "null", "UnitHandle", "SavedHandle")
//! runtextmacro ARRAY_LIST_DEFINE("Player", "player", "null", "PlayerHandle", "SavedHandle")
// ******************************************************************
// Array List
// ******************************************************************
//! textmacro_once ARRAY_LIST_DEFINE takes NAME, TYPE, NONE, VAR, HANDLE
struct $NAME$ArrayList extends array
readonly static $TYPE$ pivot // Pivot element during sort or comparison
readonly static $TYPE$ other // Other element during sort
static method create takes nothing returns thistype
return HashRecyler.alloc()
endmethod
method destroy takes nothing returns nothing
call HashRecyler.free(this)
endmethod
private method operator length= takes integer index returns nothing
call SaveInteger(HashRecyler.ht , this, SIZE_INDEX, index)
endmethod
method operator length takes nothing returns integer
return LoadInteger(HashRecyler.ht , this, SIZE_INDEX)
endmethod
method clear takes nothing returns nothing
call FlushChildHashtable(HashRecyler.ht , this)
endmethod
method first takes nothing returns $TYPE$
return Load$VAR$(HashRecyler.ht , this, 0)
endmethod
method last takes nothing returns $TYPE$
return Load$VAR$(HashRecyler.ht , this, .length - 1)
endmethod
// Getter
method operator[] takes integer index returns $TYPE$
debug if index < 0 or index >= .length then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").get:IndexOutOfBounds (" + I2S(index) + ")")
debug return $NONE$
debug endif
return Load$VAR$(HashRecyler.ht , this, index)
endmethod
// Setter
method operator[]= takes integer index, $TYPE$ element returns nothing
debug if index < 0 or index >= .length then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").set:IndexOutOfBounds (" + I2S(index) + ")")
debug return
debug endif
call Save$VAR$(HashRecyler.ht , this, index, element)
endmethod
method add takes integer index, $TYPE$ element returns nothing
local integer i = .length
if index < 0 or index > i then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").add:IndexOutOfBounds (" + I2S(index) + ")")
return
endif
set .length = i + 1
loop
exitwhen i == index
call Save$VAR$(HashRecyler.ht , this, i, Load$VAR$(HashRecyler.ht , this, i - 1))
set i = i - 1
endloop
call Save$VAR$(HashRecyler.ht , this, index, element)
endmethod
method remove takes integer index returns $TYPE$
local integer len = .length - 1
if index < 0 or index > len then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").remove:IndexOutOfBounds (" + I2S(index) + ")")
return $NONE$
endif
set .length = len
set other = Load$VAR$(HashRecyler.ht , this, index)
loop
exitwhen index == len
call Save$VAR$(HashRecyler.ht , this, index, Load$VAR$(HashRecyler.ht , this, index + 1))
set index = index + 1
endloop
call Remove$HANDLE$(HashRecyler.ht , this, len)
return other
endmethod
method push takes $TYPE$ value returns thistype
local integer len = .length
call Save$VAR$(HashRecyler.ht , this, len, value)
set .length = len + 1
return this
endmethod
method pop takes $TYPE$ value returns $TYPE$
local integer len = .length - 1
if len < 0 then
return $NONE$
endif
set .length = len
set other = Load$VAR$(HashRecyler.ht , this, len)
call Remove$HANDLE$(HashRecyler.ht , this, len)
return other
endmethod
method indexOf takes $TYPE$ value returns integer
local integer i = 0
local integer len = .length
loop
exitwhen i == len
if Load$VAR$(HashRecyler.ht , this, i) == value then
return i
endif
set i = i + 1
endloop
return -1
endmethod
method has takes integer index returns boolean
return index >= 0 and index < .length
endmethod
method contains takes $TYPE$ value returns boolean
return .indexOf(value) != -1
endmethod
method containsAll takes thistype list returns boolean
local integer i = 0
local integer n = list.length
local integer j
local integer m = .length
loop
exitwhen i == n
set other = Load$VAR$(HashRecyler.ht , list, i)
set j = 0
loop
if j == m then
return false
endif
exitwhen other == Load$VAR$(HashRecyler.ht , this, j)
set j = j + 1
endloop
set i = i + 1
endloop
return true
endmethod
method isEmpty takes nothing returns boolean
return .length == 0
endmethod
method swap takes integer indexA, integer indexB returns nothing
debug if indexA < 0 or indexA >= .length or indexB < 0 or indexB >= .length then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").swap:IndexOutOfBounds")
debug return
debug endif
set other = Load$VAR$(HashRecyler.ht , this, indexA)
call Save$VAR$(HashRecyler.ht , this, indexA, Load$VAR$(HashRecyler.ht , this, indexB))
call Save$VAR$(HashRecyler.ht , this, indexB, other)
endmethod
method clone takes nothing returns thistype
return create().addRange(0, this, 0, .length)
endmethod
method equals takes thistype list returns boolean
local integer i = .length
if i == list.length then
set i = i - 1
loop
exitwhen i < 0
if Load$VAR$(HashRecyler.ht , this, i) != Load$VAR$(HashRecyler.ht , list, i) then
return false
endif
set i = i - 1
endloop
return true
endif
return false
endmethod
private method setupTrigger takes code c returns nothing
call TriggerClearConditions(t)
call TriggerAddCondition(t, Condition(c))
endmethod
private method quicksort takes integer first, integer last returns nothing
if first < last then
set up = first
set down = last
set pivot = Load$VAR$(HashRecyler.ht , this, first)
loop
loop
set other = Load$VAR$(HashRecyler.ht , this, up)
exitwhen up >= last or TriggerEvaluate(t)
set up = up + 1
endloop
loop
set other = Load$VAR$(HashRecyler.ht , this, down)
exitwhen not TriggerEvaluate(t)
set down = down - 1
endloop
exitwhen up >= down
set other = Load$VAR$(HashRecyler.ht , this, up)
call Save$VAR$(HashRecyler.ht , this, up, Load$VAR$(HashRecyler.ht , this, down))
call Save$VAR$(HashRecyler.ht , this, down, other)
endloop
set other = Load$VAR$(HashRecyler.ht, this, first)
call Save$VAR$(HashRecyler.ht , this, first, Load$VAR$(HashRecyler.ht , this, down))
call Save$VAR$(HashRecyler.ht , this, down, other)
call .quicksort(first, down - 1)
call .quicksort(down + 1, last)
endif
endmethod
method sort takes code c returns nothing
debug if .length > 1400 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "WARNING: $NAME$ArrayList.sort: Attempting to sort " + I2S(.length) + " elements.")
debug endif
call .setupTrigger(c)
call .quicksort(0, .length - 1)
endmethod
method reverse takes nothing returns nothing
set up = 0
set down = .length - 1
loop
exitwhen down <= up
set other = Load$VAR$(HashRecyler.ht , this, up)
call Save$VAR$(HashRecyler.ht , this, up, Load$VAR$(HashRecyler.ht , this, down))
call Save$VAR$(HashRecyler.ht , this, down, other)
set up = up + 1
set down = down - 1
endloop
endmethod
method addRange takes integer destPos, thistype src, integer srcPos, integer range returns thistype
local integer srcSize = src.length
local integer len = .length
local integer i = destPos
if srcPos < 0 or srcPos == srcSize or destPos < 0 or destPos > len then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList.copy:IndexOutOfBounds")
return this
endif
if srcPos + range > srcSize then
set range = srcSize - srcPos
endif
loop
exitwhen i == len
call Save$VAR$(HashRecyler.ht , this, i + range, Load$VAR$(HashRecyler.ht , this, i)) // make room
set i = i + 1
endloop
set i = 0
loop
exitwhen i == range
call Save$VAR$(HashRecyler.ht , this, destPos + i, Load$VAR$(HashRecyler.ht , src, srcPos + i)) // fill room with copies
set i = i + 1
endloop
set .length = len + range
return this
endmethod
method setRange takes integer start, integer range, $TYPE$ value returns nothing
local integer i = start
local integer len = .length
debug if i >= len then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60, "ERROR: $NAME$ArrayList(" + I2S(this) + ").setRange:IndexOutOfBounds (" + I2S(start) + ")")
debug endif
loop
exitwhen i == range or i >= len
call Save$VAR$(HashRecyler.ht , this, i, value)
set i = i + 1
endloop
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 GetHotkey uses Table
private struct H
static Table table
private static method onInit takes nothing returns nothing
set table = Table.create()
endmethod
endstruct
function SaveAbilityHotkey takes integer abilCode, string hotkey returns nothing
set H.table.string[abilCode] = hotkey
endfunction
function GetAbilityHotkey takes integer abilCode returns string
debug if not H.table.has(abilCode) then
debug call BJDebugMsg("[Library_Hotkey] GetAbilityHotkey: No hotkey has been bound to this ability.")
debug endif
return H.table.string[abilCode]
endfunction
endlibrary
library TimerUtilsEx
/*************************************************
*
* TimerUtilsEx
* v2.1.0.3
* 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.
*
* 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.
*
*************************************************/
globals //Calibration
//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
private hashtable ht = InitHashtable()
endglobals
private module Init
static if not USE_HASH then
private static method onInit takes nothing returns nothing
local integer i = QUANTITY
loop
set i = i - 1
set tT[i] = CreateTimer()
exitwhen i == 0
endloop
set tN = QUANTITY
endmethod
endif
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
implement Init
endstruct
// Double free protection
private function ValidTimer takes integer i returns boolean
return LoadBoolean(ht, i, 1)
endfunction
private function Get takes integer id returns integer
debug if not ValidTimer(id) then
debug call BJDebugMsg("[TimerUtils]Error: Tried to get data from invalid timer.")
debug endif
static if USE_HASH then
return LoadInteger(ht, id, 0)
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 BJDebugMsg("[TimerUtils]Error: Tried to attach data to invalid timer.")
debug endif
static if USE_HASH then
call SaveInteger(ht, id, 0, data)
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 BJDebugMsg("[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])
call SaveBoolean(ht, id, 1, true)
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.
call RemoveSavedBoolean(ht, id, 1)
//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.
call RemoveSavedInteger(ht, id, 0)
// 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 BJDebugMsg("[TimerUtils]Error: Tried to release non-active timer!")
endif
//Return Timer Data.
return data
endfunction
endlibrary
// https://www.hiveworkshop.com/threads/playerutils.278559/
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
library HeroPickPlugin uses SpellOptionsMenu, RegisterPlayerEvent
/*
This is a simple Hero Pick system which provides a menu for selecting a hero.
*/
globals
private constant string MENU_TITLE = "Hero Selection"
private constant string RANDOM_HERO_BTN = "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn.blp"
private constant string CONFIRM_BTN = "ReplaceableTextures\\CommandButtons\\BTNSell.blp"
private real x
private real y
private real f
private integer lastPickedHeroType
private trigger trgOnPick = null
private trigger trgOnSelect = null
private integer numHeroes = 0
private unit u
private string s
endglobals
/*
Change to appropriate setup
*/
private function SetupSelectionZone takes nothing returns nothing
set x = GetRectCenterX(gg_rct_HeroSelection)
set y = GetRectCenterY(gg_rct_HeroSelection)
set f = 270
endfunction
// **************************************************
// *** System Code **********************************
// **************************************************
private function GetHeroName takes integer unitTypeId returns string
set u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), unitTypeId, 0, 0, 0)
set s = GetUnitName(u)
call RemoveUnit(u)
set u = null
return s
endfunction
private struct UserData extends array
unit dummy
integer heroId
integer option
SpellMenu menu
method safeDummyRemoval takes nothing returns nothing
if GetLocalPlayer() == GetOwningPlayer(.dummy) then
call ShowUnit(.dummy, false)
endif
call RemoveUnit(.dummy)
endmethod
method clear takes nothing returns nothing
if .dummy != null then
call .safeDummyRemoval()
endif
if .menu != 0 then
call .menu.destroy()
set .menu = 0
endif
set .heroId = -1
set .option = 0
endmethod
// will remove any menus that are left open
private static method onLeave takes nothing returns nothing
local integer pid = GetPlayerId(GetTriggerPlayer())
if UserData(pid).menu != 0 then
call UserData(pid).clear()
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
loop
exitwhen i == bj_MAX_PLAYERS
set UserData(i).heroId = -1
set i = i + 1
endloop
call SetupSelectionZone()
call RegisterAnyPlayerEvent(EVENT_PLAYER_LEAVE, function thistype.onLeave)
endmethod
endstruct
private struct Hero extends array
integer type
string btn
string disbtn
string label
string tooltip
integer optionKey
method setLabel takes string s returns thistype
set .label = s
return this
endmethod
method setType takes integer t returns thistype
set .type = t
call .setLabel(GetHeroName(t))
return this
endmethod
method setTooltip takes string s returns thistype
set .tooltip = s
return this
endmethod
method setBtn takes string s returns thistype
set .btn = s
return this
endmethod
method setDisbtn takes string s returns thistype
set .disbtn = s
return this
endmethod
endstruct
private function SetSelection takes player p, integer heroIndex returns nothing
local integer pid = GetPlayerId(p)
local SpellMenu menu = UserData(pid).menu
local SpellOption o
call UserData(pid).safeDummyRemoval()
//if UserData(pid).dummy != null then
// call RemoveUnit(UserData(pid).dummy) // Will removing a locally hidden unit cause desync?
//endif
set UserData(pid).heroId = heroIndex
set UserData(pid).dummy = CreateUnit(p, Hero(heroIndex).type, x, y, f)
call UnitAddAbility(UserData(pid).dummy, 'Aloc') // locust
if not (GetLocalPlayer() == p) then // Hide it for all except one
call ShowUnit(UserData(pid).dummy, false)
endif
if UserData(pid).option != 0 then
set o = menu.get(menu.indexOf(UserData(pid).option))
call o.setLocalEnabled(pid, true)
endif
set o = Hero(heroIndex).optionKey
call o.setLocalEnabled(pid, false)
set UserData(pid).option = o
if GetLocalPlayer() == p then
call PanCameraToTimed(GetUnitX(UserData(pid).dummy), GetUnitY(UserData(pid).dummy), 0)
endif
// Run callback
set lastPickedHeroType = Hero(heroIndex).type
if trgOnSelect != null then
call TriggerEvaluate(trgOnSelect)
endif
endfunction
private function GetRandomHero takes player p returns integer
local integer rdm
local integer pid = GetPlayerId(p)
if numHeroes > 1 then
loop
set rdm = GetRandomInt(0, numHeroes - 1)
if rdm != UserData(pid).heroId then
return rdm
endif
endloop
endif
return 0
endfunction
private function OnRandomPick takes nothing returns nothing
local player p = GetTriggerPlayer()
call SetSelection(p, GetRandomHero(p))
set p = null
endfunction
private function OnHeroPick takes nothing returns nothing
local SpellOption o = GetTriggerSpellOption()
call SetSelection(GetTriggerPlayer(), o.userData)
endfunction
private function OnConfirm takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
call UserData(pid).menu.close(p)
set lastPickedHeroType = Hero(UserData(pid).heroId).type
call UserData(pid).clear()
// Run callback
if trgOnPick != null then
call TriggerEvaluate(trgOnPick)
endif
set p = null
endfunction
private function AddMenuOptions takes SpellMenu menu returns nothing
local integer i = 0
local Hero h
local SpellOption o
loop
exitwhen i >= numHeroes
set h = Hero(i)
set o = menu.createOption(i, h.label, h.tooltip, h.btn, function OnHeroPick)
set h.optionKey = o
set o.userData = i
set i = i + 1
endloop
set o = menu.createOption(3, "Random Hero", "Selects a random hero.", RANDOM_HERO_BTN, function OnRandomPick)
call menu.lock(o, 3)
set o = menu.createOption(7, "Confirm Hero", " ", CONFIRM_BTN, function OnConfirm)
call menu.lock(o, 7)
endfunction
// **************************************************
// *** Public Interface *****************************
// **************************************************
function AddPickableHero takes integer unitTypeId, string btn, string disbtn, string description returns nothing
call Hero(numHeroes).setType(unitTypeId).setTooltip(description).setBtn(btn).setDisbtn(disbtn)
set numHeroes = numHeroes + 1
endfunction
function OpenHeroPickMenu takes player p returns nothing
local integer pid = GetPlayerId(p)
if UserData(pid).menu == 0 then
set UserData(pid).menu = SpellMenu.create(MENU_TITLE, true)
call AddMenuOptions(UserData(pid).menu)
endif
call SetSelection(p, GetRandomHero(p))
call UserData(pid).menu.open(p)
endfunction
function OpenHeroPickMenuAll takes nothing returns nothing
local integer i = 0
local player p
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER) then
call OpenHeroPickMenu(p)
endif
set i = i + 1
endloop
set p = null
endfunction
function GetPickedHeroDummy takes player p returns unit
return UserData(GetPlayerId(p)).dummy
endfunction
function GetPickedHeroType takes nothing returns integer
return lastPickedHeroType
endfunction
function OnHeroPickEvent takes code c returns nothing
if trgOnPick == null then
set trgOnPick = CreateTrigger()
endif
call TriggerAddCondition(trgOnPick, Condition(c))
endfunction
function OnHeroPickChangeEvent takes code c returns nothing
if trgOnSelect == null then
set trgOnSelect = CreateTrigger()
endif
call TriggerAddCondition(trgOnSelect, Condition(c))
endfunction
endlibrary
scope HeroPick initializer Init
private function OnRepick takes nothing returns nothing
call OpenHeroPickMenu(GetTriggerPlayer())
endfunction
private function OnHeroPick takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer unitTypeId = GetPickedHeroType()
local unit u = CreateUnit(p, unitTypeId, 0, 0, 0)
if GetLocalPlayer() == p then
call PanCameraToTimed(GetUnitX(u), GetUnitY(u), 0)
call SelectUnit(u, true)
endif
set p = null
set u = null
endfunction
private function OnHeroChange takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit u = GetPickedHeroDummy(p)
local string path = ""
local effect eff
if GetLocalPlayer() == GetOwningPlayer(u) then
set path = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl"
endif
set eff = AddSpecialEffectTargetUnitBJ( "origin", u, path)
call DestroyEffect(eff)
set eff = null
set u = null
set p = null
endfunction
/*
Opens the pick menu at start
*/
private function StartHeroPick takes nothing returns nothing
local timer t = GetExpiredTimer()
call PauseTimer(t)
call ReleaseTimer(t)
set t = null
call OpenHeroPickMenuAll()
endfunction
private function Init takes nothing returns nothing
local timer t = NewTimer()
call TimerStart(t, 0.1, false, function StartHeroPick)
set t = null
// Chat event
call Command.register("-repick", function OnRepick)
// Callback registration
call OnHeroPickEvent(function OnHeroPick)
call OnHeroPickChangeEvent(function OnHeroChange)
// Paladin
call AddPickableHero('Hpal',/*
*/"ReplaceableTextures\\CommandButtons\\BTNHeroPaladin.blp",/*
*/"ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHeroPaladin.blp",/*
*/"Warrior Hero, exceptional at defense and augmenting nearby friendly troops. Can learn Holy Light, Divine Shield, Devotion Aura and Resurrection. |n|n|cffffcc00Attacks land units.|r")
// Blood Mage
call AddPickableHero('Hblm',/*
*/"ReplaceableTextures\\CommandButtons\\BTNHeroBloodElfPrince.blp",/*
*/"ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHeroBloodElfPrince.blp", /*
*/"Mystical Hero, adept at controlling magic and ranged assaults. Can learn Flame Strike, Banish, Siphon Mana and Phoenix. |n|n|cffffcc00Attacks land and air units.|r")
// Archmage
call AddPickableHero('Hamg',/*
*/"ReplaceableTextures\\CommandButtons\\BTNHeroArchMage.blp",/*
*/"ReplaceableTextures\\CommandButtonsDisabled\\DISBTNHeroArchMage.blp",/*
*/"Mystical Hero, adept at ranged assaults. Can learn Blizzard, Summon Water Elemental, Brilliance Aura and Mass Teleport. |n|n|cffffcc00Attacks land and air units.|r")
endfunction
endscope
scope AnyEventRegistrationExample initializer Init
// This will fire when a cooldown ends. Note that we cannot retrieve which menu the option belongs to.
// However, such information could be stored using option.userData = whichMenu if necessary.
//
private function CDEnded takes nothing returns nothing
local SpellOption option = GetTriggerSpellOption()
local player user = GetTriggerSpellOptionPlayer()
call BJDebugMsg(GetPlayerName(user) + " option cooldown ended " + I2S(option) + ".")
endfunction
// Option Selected event. Can be used in cases where you didn't register a callback
// It was mostly implemented for potential GUI action.
//
private function Selected takes nothing returns nothing
local SpellOption option = GetTriggerSpellOption()
local player user = GetTriggerSpellOptionPlayer()
local SpellMenu menu = GetTriggerSpellMenu()
call BJDebugMsg(GetPlayerName(user) + " selected option '" + option.label + "' (" + I2S(option) + ") belonging to '" + menu.name + "' (" + I2S(menu) + ")" )
endfunction
// This will fire whenever a option cooldown ticks, its mostly meant to be used internally by the system.
//
private function OnChange takes nothing returns nothing
local SpellOption option = GetTriggerSpellOption()
local player user = GetTriggerSpellOptionPlayer()
endfunction
// Triggers whenever a menu is opened, yes, it's pretty redundant.
//
private function OnOpen takes nothing returns nothing
local SpellMenu menu = GetTriggerSpellMenu()
local player user = GetTriggerSpellMenuPlayer()
call BJDebugMsg(GetPlayerName(user) + " opened menu: " + menu.name + " (" + I2S(menu) + ")")
endfunction
// Triggers whenever a menu is closed.
//
private function OnClose takes nothing returns nothing
local SpellMenu menu = GetTriggerSpellMenu()
local player user = GetTriggerSpellMenuPlayer()
call BJDebugMsg(GetPlayerName(user) + " closed menu: " + menu.name + " (" + I2S(menu) + ")")
endfunction
private function Init takes nothing returns nothing
// Option events
call OnSpellOptionEvent(EVENT_SPELL_OPTION_SELECTED, function Selected)
call OnSpellOptionEvent(EVENT_SPELL_OPTION_CD_END, function CDEnded)
call OnSpellOptionEvent(EVENT_SPELL_OPTION_CHANGE, function OnChange)
// Menu events
call OnSpellMenuEvent(EVENT_SPELL_MENU_OPEN, function OnOpen)
call OnSpellMenuEvent(EVENT_SPELL_MENU_CLOSE, function OnClose)
endfunction
endscope
scope SortExample initializer Init
/*
This is a demo of how to sort options inside a menu. It uses a quicksort to sort in either
ascending or descending order. Haven't tested more than 400, but i believe at least dubble that should be fine.
*/
globals
private code sortAscending
private code sortDescending
private constant string MENU_NAME = "Sort Menu"
private constant integer NUM_OPTIONS = 100
endglobals
private function SortDescending takes nothing returns nothing
local SpellMenu menu = GetTriggerSpellMenu()
local integer i = 0
local SpellOption o
loop
exitwhen i == menu.size()
set o = menu.get(i)
call o.onResponse(sortAscending) // We change callback so that the second selection will reverse the order
set o.text = "Press any option to sort the menu in ascending order."
set i = i + 1
endloop
call menu.sort(false) // Descending order
endfunction
private function SortAscending takes nothing returns nothing
local SpellMenu menu = GetTriggerSpellMenu()
local integer i = 0
local SpellOption o
loop
exitwhen i == menu.size()
set o = menu.get(i)
call o.onResponse(sortDescending) // We change callback so that the second selection will reverse the order
set o.text = "Press any option to sort the menu in descending order."
set i = i + 1
endloop
call menu.sort(true) // Ascending order
endfunction
private function CreateMenu takes nothing returns nothing
local SpellMenu menu = SpellMenu.create(MENU_NAME, false)
local integer i = 0
local SpellOption o
local integer rdm
loop
exitwhen i == NUM_OPTIONS
set rdm = GetRandomInt(0, 100)
set o = menu.createOption(i, "Random value: " + I2S(rdm), "Press any option to sort the menu in ascending order." , "ReplaceableTextures\\CommandButtons\\BTNBanish.blp", sortAscending)
// Sorting is based on the value stored inside rank
set o.rank = rdm
set i = i + 1
endloop
call menu.open(GetTriggerPlayer())
endfunction
/*
Remove the menu when the user is done with it
*/
private function OnClose takes nothing returns nothing
local SpellMenu menu = GetTriggerSpellMenu()
if menu.name == MENU_NAME then
call menu.destroy()
endif
endfunction
private function Init takes nothing returns nothing
set sortAscending = function SortAscending
set sortDescending = function SortDescending
call Command.register("-sort", function CreateMenu)
call DisplayTimedTextToForce(GetPlayersAll(), 60.00, "Type \"-sort\" to open the menu.")
call OnSpellMenuEvent(EVENT_SPELL_MENU_CLOSE, function OnClose)
endfunction
endscope
scope MusicMenuExample initializer Init
globals
private SpellMenu songMenu
private SpellOption o
private SpellOption volumeUp
private SpellOption volumeDown
private SpellOption openSongMenu
private SpellOption startStop
private string array songs
private real array length
private integer array playerVolume
private boolean array playerMusicOn
endglobals
private function OpenMenu takes nothing returns nothing
call songMenu.open(GetTriggerPlayer())
endfunction
private function SecondSelection takes nothing returns nothing
call BJDebugMsg("Second callback!")
endfunction
private function MusicSelected takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
set o = GetTriggerSpellOption()
if GetLocalPlayer() == p then
call PlayMusic(songs[o.userData])
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 10, "Now playing " + songs[o.userData] + ".")
endif
// Modify player music status
set playerMusicOn[pid] = true
// Modify start-stop button to represent changes.
call startStop.setLocalLabel(pid, "Pause")
call startStop.setLocalText(pid, "Stops playing music.")
call startStop.setLocalIcon(pid, "ReplaceableTextures\\CommandButtons\\BTNReplay-Pause.blp")
// We can change callback after creation like this:
// call o.onResponse(function SecondSelection)
endfunction
private function StartStop takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
set o = GetTriggerSpellOption()
if playerMusicOn[pid] then
if p == GetLocalPlayer() then
call DisplayTimedTextToPlayer(p,0,0, 10, "Music paused.")
call StopMusicBJ(false)
endif
// Modify option properties for a local player by id
call o.setLocalLabel(pid, "Play")
call o.setLocalText(pid, "Resume playing music.")
call o.setLocalIcon(pid, "ReplaceableTextures\\CommandButtons\\BTNReplay-Play.blp")
set playerMusicOn[pid] = false
else
if p == GetLocalPlayer() then
call DisplayTimedTextToPlayer(p,0,0, 10, "Music resumed.")
call ResumeMusicBJ()
endif
// Modify option properties for a local player by id
call o.setLocalLabel(pid, "Pause")
call o.setLocalText(pid, "Stops playing music.")
call o.setLocalIcon(pid, "ReplaceableTextures\\CommandButtons\\BTNReplay-Pause.blp")
set playerMusicOn[pid] = true
endif
endfunction
private function VolumeUp takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
if playerVolume[pid] == 0 then // enable button if at min
call volumeDown.setLocalEnabled(pid, true)
endif
set playerVolume[pid] = playerVolume[pid] + 10
if playerVolume[pid] > 100 then
set playerVolume[pid] = 100
endif
if playerVolume[pid] == 100 then // disable button if at max
call volumeUp.setLocalEnabled(pid, false)
endif
if p == GetLocalPlayer() then
call DisplayTimedTextToPlayer(p,0,0, 10, "Volume increased to " + I2S(playerVolume[pid]) + "%.")
call SetMusicVolumeBJ(playerVolume[pid])
endif
set p = null
endfunction
private function VolumeDown takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
if playerVolume[pid] == 100 then // enable button if at max
call volumeUp.setLocalEnabled(pid, true)
endif
set playerVolume[pid] = playerVolume[pid] - 10
if playerVolume[pid] < 0 then
set playerVolume[pid] = 0
endif
if playerVolume[pid] == 0 then // disable button if at min
call volumeDown.setLocalEnabled(pid, false)
endif
if p == GetLocalPlayer() then
call DisplayTimedTextToPlayer(p,0,0, 10, "Volume decreased to " + I2S(playerVolume[pid]) + "%.")
call SetMusicVolumeBJ(playerVolume[pid])
endif
set p = null
endfunction
private function Init takes nothing returns nothing
local integer i
local integer j
local player p
set songs[0] = gg_snd_ArthasTheme
set length[0] = 123
set songs[1] = gg_snd_War3XMainScreen
set songs[2] = gg_snd_BloodElfTheme
set songs[3] = gg_snd_Comradeship
set songs[4] = gg_snd_Credits
set songs[5] = gg_snd_DarkAgents
set songs[6] = gg_snd_DarkVictory
set songs[7] = gg_snd_Doom
set songs[8] = gg_snd_HeroicVictory
set songs[9] = gg_snd_Human1
set songs[10] = gg_snd_Human2
set songs[11] = gg_snd_Human3
set songs[12] = gg_snd_HumanDefeat
set songs[13] = gg_snd_HumanVictory
set songs[14] = gg_snd_HumanX1
set songs[15] = gg_snd_IllidansTheme
set songs[16] = gg_snd_LichKingTheme
set songs[17] = gg_snd_Mainscreen
set songs[18] = gg_snd_NagaTheme
set songs[19] = gg_snd_NightElf1
set songs[20] = gg_snd_NightElf2
set songs[21] = gg_snd_NightElf3
set songs[22] = gg_snd_NightElfDefeat
set songs[23] = gg_snd_NightElfVictory
set songs[24] = gg_snd_NightElfX1
set songs[25] = gg_snd_Orc1
set songs[26] = gg_snd_Orc2
set songs[27] = gg_snd_Orc3
set songs[28] = gg_snd_OrcDefeat
set songs[29] = gg_snd_OrcTheme
set songs[30] = gg_snd_OrcVictory
set songs[31] = gg_snd_OrcX1
set songs[32] = gg_snd_PursuitTheme
set songs[33] = gg_snd_SadMystery
set songs[34] = gg_snd_Tension
set songs[35] = gg_snd_TragicConfrontation
set songs[36] = gg_snd_Undead1
set songs[37] = gg_snd_Undead2
set songs[38] = gg_snd_Undead3
set songs[39] = gg_snd_UndeadDefeat
set songs[40] = gg_snd_UndeadVictory
set songs[41] = gg_snd_UndeadX1
set songs[42] = gg_snd_War2IntroMusic
set songMenu = SpellMenu.create("Music Menu", false)
set i = 0
loop
exitwhen songs[i] == null
set o = SpellOption.create("Play " + I2S(i + 1), "Track: " + songs[i], "ReplaceableTextures\\CommandButtons\\BTNBanish.blp", function MusicSelected)
// If you pass an invalid index it will be added at the last position.
call songMenu.add(-1, o)
// This is how you would add global cooldown to an option
set o.cooldown = 15
// If we want to change Player(0) cooldown but maintain 15 second for the other players we could do this
call o.setLocalCooldown(0, 20)
// Similarly we could change other attributes such as label, text, btn, hidden, enabled and disabled...
// Finally we can store custom ids as references to other data, in this case the option needs to be bound to a particular song
// To achieve this we will store the index, i inside the option which we will later use to play the correct song.
set o.userData = i
// Note that id doesn't have any local method wrappers (if you have a need for this do poke me and I'll consider changing it).
set i = i + 1
endloop
set startStop = SpellOption.create("Play", "Resumes player music.", "ReplaceableTextures\\CommandButtons\\BTNReplay-Play.blp", function StartStop)
call songMenu.add(0, startStop)
call songMenu.lock(startStop, 0) // We lock this option to index 0, it will be transfered to all pages of the menu
set volumeUp = SpellOption.create("Increase Volume", "Increases the volume by 10%.", "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedUp.blp", function VolumeUp)
call songMenu.add(3, volumeUp)
set volumeUp.enabled = false
call songMenu.lock(volumeUp, 3)
set volumeDown = SpellOption.create("Decrease Volume", "Decreases the volume by 10%.", "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedDown.blp", function VolumeDown)
call songMenu.add(7, volumeDown)
call songMenu.lock(volumeDown, 7)
// Open Menu on command
call Command.register("-music", function OpenMenu)
call DisplayTimedTextToForce(GetPlayersAll(), 60.00, "Type \"-music\" to open the menu." )
call StopMusicBJ(false) // Stop music at start
set i = 0
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER) then
set j = GetPlayerId(p)
set playerVolume[j] = 100
set playerMusicOn[j] = false
endif
set i = i + 1
endloop
endfunction
endscope
library CommandUtils uses Table
/*
===============================================================================================
Command Utilities version 1.3.
Latest version containing API and Manual can be found here:
hiveworkshop.com/threads/command-utilities.307554/
===============================================================================================
This libary provides a struct for each player, which stores information generated each time a
player enters a chat command. It's purpose is to make the creation of commands faster and easier
to manage by providing a few additional API functions geared towards that end.
Credits:
- Made by Pinzu
Requirements
- Table by Bribe
hiveworkshop.com/threads/snippet-new-table.188084/
Configuration
- Simply copy Bribe's Table and this library into your map
- Modify the configurables to your preference in the global block. You can add multiple command
prefixes if you scroll down to the onInit method inside Command struct.
===============================================================================================
*/
globals
private constant string FILTER_PREFIX = ""
private constant integer MAX_WORDS = 300
private constant boolean ACK_PLAYER_NAME = true
public real chat_event
public constant real RESET_CHAT_EVENT = 0
public constant real ON_CHAT_EVENT = 1
public constant real ON_CMD_BLOCKED = 2
private Table playerchat
private Table playerIds
endglobals
function GetPlayerChat takes player p returns PChat
return playerchat[GetPlayerId(p)]
endfunction
function GetLastUpdatedChat takes nothing returns PChat
return PChat.last
endfunction
function GetLastCommand takes nothing returns Command
return Command.last
endfunction
private function isDigit takes string c returns boolean
return c == "0" or c == "1" or c == "2" or c == "3" or c == "4" or c == "5" or /*
*/ c == "6" or c == "7" or c == "8" or c == "9"
endfunction
function StrIsReal takes string s returns boolean
local integer i = 0
local integer dots = 0
local string char
loop
exitwhen i == StringLength(s)
set char = SubString(s, i, i + 1)
if char == "." then
set dots = dots + 1
if dots > 1 then
return false
endif
elseif not isDigit(char) then
return false
endif
set i = i + 1
endloop
return true
endfunction
function StrIsInt takes string s returns boolean
local integer i = 0
local string char
loop
exitwhen i == StringLength(s)
set char = SubString(s, i, i + 1)
if not isDigit(char) and not (i == 0 and char == "-") then
return false
endif
set i = i + 1
endloop
return true
endfunction
function StrIsBoolean takes string s returns boolean
set s = StringCase(s, false)
return s == "true" or s == "false"
endfunction
function S2B takes string s returns boolean
set s = StringCase(s, false)
if s == "true" then
return true
endif
return false
endfunction
function StrContainsDigit takes string s returns boolean
local integer length = StringLength(s)
local integer i = 0
local string c
set i = 0
loop
exitwhen i == length
set c = SubString(s, i, i + 1)
if isDigit(c) then
return true
endif
set i = i + 1
endloop
return false
endfunction
function StrToPlayer takes string s returns player player
local player p = playerIds.player[StringHash(s)]
local integer i = 0
if p != null then
return p
endif
if ACK_PLAYER_NAME then
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
if s == GetPlayerName(p) then
return p
endif
set i = i + 1
endloop
endif
return null
endfunction
function SavePlayerId takes string identifier, player p returns nothing
set playerIds.player[StringHash(identifier)] = p
endfunction
function RemovePlayerId takes string identifier returns nothing
call playerIds.player.remove(StringHash(identifier))
endfunction
private function IsPlaying takes player p returns boolean
return GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER
endfunction
struct PChat
static thistype last = 0
readonly player user
readonly integer userId
readonly string str
readonly string substr
readonly integer length
readonly string array word[MAX_WORDS]
readonly integer array wordStart[MAX_WORDS]
readonly integer array wordEnd[MAX_WORDS]
readonly integer wordCount
method update takes string chatstring returns nothing
local integer i = 0
local string char = ""
local string prev = ""
loop
exitwhen i == .wordCount
set .word[i] = null
set .wordStart[i] = 0
set .wordEnd[i] = 0
set i = i + 1
endloop
set .length = StringLength(chatstring)
set .str = chatstring
set .wordCount = 0
set .wordStart[0] = 0
set i = 0
loop
exitwhen i > .length
set char = SubString(chatstring, i, i + 1)
if char != " " then
set .word[.wordCount] = .word[.wordCount] + char
elseif prev != " " then
set .wordEnd[.wordCount] = i
set .wordCount = .wordCount + 1
set .wordStart[.wordCount] = i + 1
endif
set prev = char
set i = i + 1
endloop
set .substr = SubString(.str, .wordStart[1], .length)
set .wordEnd[.wordCount] = i - 1
set .wordCount = .wordCount + 1
set thistype.last = this
endmethod
static method create takes player p, integer pid returns thistype
local thistype this = .allocate()
set this.user = p
set this.userId = pid
return this
endmethod
method destroy takes nothing returns nothing
set .user = null
call .deallocate()
endmethod
method wordLength takes integer index returns integer
return .wordEnd[index] - .wordStart[index]
endmethod
method wordLower takes integer index returns string
return StringCase(.word[index], false)
endmethod
method wordUpper takes integer index returns string
return StringCase(.word[index], true)
endmethod
endstruct
struct Command
static thistype last
readonly static thistype head = 0
readonly static thistype tail = 0
readonly thistype next
readonly thistype prev
readonly string argument
public string tooltip
private boolean enabled
private Table trgTable
private Table disabledPlayers
private integer trgSize
private static Table commandTable
private static trigger onChatTrigger
private static method create takes string cmd returns thistype
local thistype this = .allocate()
set this.trgSize = 0
set this.trgTable = Table.create()
set this.disabledPlayers = Table.create()
set this.argument = cmd
set this.enabled = true
set thistype.commandTable[StringHash(cmd)] = this
if head == 0 then
set head = this
set tail = this
else
set this.prev = tail
set tail.next = this
set tail = this
endif
return this
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local trigger t
loop
exitwhen i == .trgSize
set t = .trgTable.trigger[i]
call DestroyTrigger(t)
set i = i + 1
endloop
set t = null
if this == head and this == tail then
set head = 0
set tail = 0
elseif this == head then
set head.next.prev = 0
set head = head.next
elseif this == tail then
set tail.prev.next = 0
set tail = tail.prev
else
set this.prev.next = this.next
set this.next.prev = this.prev
endif
call thistype.commandTable.remove(StringHash(this.argument))
call this.trgTable.destroy()
call this.disabledPlayers.destroy()
call this.deallocate()
endmethod
method addTrigger takes trigger t returns nothing
set .trgTable.trigger[.trgSize] = t
set .trgSize = .trgSize + 1
endmethod
method removeTrigger takes integer index returns boolean
local trigger t
if index < 0 or index >= .trgSize then
return false
endif
set t = .trgTable.trigger[index]
set .trgSize = .trgSize - 1
loop
exitwhen index == .trgSize
set .trgTable.trigger[index] = .trgTable.trigger[index + 1]
endloop
call .trgTable.trigger.remove(index)
call DestroyTrigger(t)
set t = null
return true
endmethod
static method find takes string cmd returns thistype
return thistype.commandTable[StringHash(cmd)]
endmethod
static method exists takes string cmd returns boolean
return thistype.find(cmd) != 0
endmethod
static method register takes string cmd, code c returns thistype
local trigger t = CreateTrigger()
local thistype command = thistype.commandTable[StringHash(cmd)]
if command == 0 then
set command = Command.create(cmd)
endif
call TriggerAddAction(t, c)
call command.addTrigger(t)
set t = null
return command
endmethod
static method registerForPlayer takes string cmd, code c, player whichplayer returns thistype
local thistype command = thistype.register(cmd, c)
local integer i = 0
local player p
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
if IsPlaying(p) and p != whichplayer then
set command.disabledPlayers.boolean[GetPlayerId(p)] = true
endif
set i = i + 1
endloop
return command
endmethod
static method deregister takes string cmd returns boolean
local thistype command = thistype.commandTable[StringHash(cmd)]
if command == 0 then
return false
endif
call command.destroy()
return true
endmethod
static method enableAll takes nothing returns nothing
call EnableTrigger(thistype.onChatTrigger)
endmethod
static method disableAll takes nothing returns nothing
call DisableTrigger(thistype.onChatTrigger)
endmethod
static method enablePlayer takes string cmd, player p returns nothing
call thistype.find(cmd).disabledPlayers.remove(GetPlayerId(p))
endmethod
static method disablePlayer takes string cmd, player p returns nothing
if not IsPlaying(p) then
return
endif
set thistype.find(cmd).disabledPlayers.boolean[GetPlayerId(p)] = true
endmethod
private method isDisabledForPlayer takes player p returns boolean
return .disabledPlayers.boolean.has(GetPlayerId(p))
endmethod
static method isEnabledForPlayer takes string cmd, player p returns boolean
return not thistype.find(cmd).isDisabledForPlayer(p)
endmethod
private method exec takes player p returns nothing
local integer i = 0
loop
exitwhen i == .trgSize
call TriggerExecute(.trgTable.trigger[i])
set i = i + 1
endloop
endmethod
static method enable takes string cmd returns nothing
set thistype.find(cmd).enabled = true
endmethod
static method disable takes string cmd returns nothing
set thistype.find(cmd).enabled = false
endmethod
private static method onChatEvent takes nothing returns nothing
local player p = GetTriggerPlayer()
local boolean blocked = false
call GetPlayerChat(p).update(GetEventPlayerChatString())
set Command.last = Command.find(PChat.last.word[0])
if Command.last != 0 then
if Command.last.isDisabledForPlayer(p) and not Command.last.enabled then
set blocked = true
else
call Command.last.exec(p)
endif
endif
//! runtextmacro CHAT_EVENT_MACRO("chat_event")
//! textmacro_once CHAT_EVENT_MACRO takes VAR
if blocked then
set $VAR$ = RESET_CHAT_EVENT
set $VAR$ = ON_CMD_BLOCKED
else
set $VAR$ = RESET_CHAT_EVENT
set $VAR$ = ON_CHAT_EVENT
endif
//! endtextmacro
set p = null
endmethod
private static method onLeave takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local PChat chat = playerchat[pid]
local thistype cmd
call playerchat.remove(pid)
call chat.destroy()
set cmd = thistype.head
loop
exitwhen cmd == 0
call cmd.disabledPlayers.remove(pid)
set cmd = cmd.next
endloop
set p = null
endmethod
private static method onInit takes nothing returns nothing
local player p
local integer i = 0
local trigger trgLeave = CreateTrigger()
set thistype.commandTable = Table.create()
set thistype.onChatTrigger = CreateTrigger()
set thistype.last = 0
set playerIds = Table.create()
set playerchat = Table.create()
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
set playerIds.player[StringHash(I2S(i + 1))] = p
if IsPlaying(p) then
call TriggerRegisterPlayerChatEvent(thistype.onChatTrigger, p, FILTER_PREFIX, false)
call TriggerRegisterPlayerEventLeave(trgLeave, p)
set playerchat[i] = PChat.create(p, i)
endif
set i = i + 1
endloop
call TriggerAddAction(thistype.onChatTrigger, function thistype.onChatEvent)
call TriggerAddAction(trgLeave, function thistype.onLeave)
set trgLeave = null
set p = null
endmethod
endstruct
endlibrary
library Votekick uses SpellOptionsMenu
/*
This is a votekick system that can be implemented as is with a few changes of the variables in the globals:
1) DEBUG should be set to false
2) MIN_VOTES should be set to 2 or 3 and is the minimum number of voters needed.
*/
globals
private constant string KICK_BTN = "ReplaceableTextures\\CommandButtons\\BTNHire.blp"
private constant integer MAX_PLAYERS = 24
private constant string MENU_TITLE = "Kick Menu"
private constant real VOTE_TIME = 45.
private constant real MSG_DURATION = 15.
// The minimum required vote ratio to kick
private constant real VOTE_REQ = 0.8
// Reduced vote ratio requirement per playing player, the more players the less required votes is the idea here.
private constant real DEC_PER_PLAYER = 0.01
// Must be changed!
private constant integer MIN_VOTES = 0 // Should be 2 or higher
private constant boolean DEBUG = true // Should be false
private string array colors
endglobals
/*
You can modify the player colors below
*/
private function SetupPlayerColors takes nothing returns nothing
set colors[0] = "|c00FF0000"
set colors[1] = "|cff0042ff"
set colors[2] = "|cff00ffff"
set colors[3] = "|cff660066"
set colors[4] = "|cffffff00"
set colors[5] = "|cffff8000"
set colors[6] = "|cff00ff00"
set colors[7] = "|cffff66cc"
set colors[8] = "|cff999999"
set colors[9] = "|cff6699cc"
set colors[10] = "|cff006633"
set colors[11] = "|cff4a2a04"
set colors[12] = "|cff9b0000"
set colors[13] = "|cff0000c3"
set colors[14] = "|cff00eaff"
set colors[15] = "|cffbe00fe"
set colors[16] = "|cffebcd87|r"
set colors[17] = "|cfff8a48b"
set colors[18] = "|cffbfff80"
set colors[19] = "|cffdcb9eb"
set colors[20] = "|cff282828"
set colors[21] = "|cffebf0ff"
set colors[22] = "|cff00781e"
set colors[23] = "|cffa46f33"
endfunction
private struct Votekick
private static Table table
private static player targetPlayer = null
private static integer yes
private static integer no
private static integer required
private static boolean array hasVoted
private static timer t
private SpellMenu menu
private SpellOption array options[MAX_PLAYERS]
method getSelectedPlayer takes SpellOption selectedOption returns player
local SpellOption o
local integer i = 0
loop
exitwhen i == MAX_PLAYERS
set o = .options[i]
if o == selectedOption then
return Player(i)
endif
set i = i + 1
endloop
return null
endmethod
method destroy takes nothing returns nothing
call thistype.table.remove(.menu)
call .menu.destroy()
call .deallocate()
endmethod
private static method countPlayers takes nothing returns integer
local player p
local integer i = 0
local integer count = 0
loop
exitwhen i == MAX_PLAYERS
set p = Player(i)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER then
set count = count + 1
endif
set i = i + 1
endloop
set p = null
return count
endmethod
private static method getVotesNeeded takes nothing returns integer
local integer votes = R2I(countPlayers()*(VOTE_REQ - DEC_PER_PLAYER*.countPlayers()))
if votes < MIN_VOTES then
return MIN_VOTES
endif
return votes
endmethod
private static method onTimerExpires takes nothing returns nothing
local integer pid = GetPlayerId(.targetPlayer)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,MSG_DURATION, "A votekick against " + colors[pid] + GetPlayerName(.targetPlayer) + "|r has expired.")
call PauseTimer(.t)
call DestroyTimer(.t)
set .t = null
set .targetPlayer = null
endmethod
private static method voteYes takes player p returns nothing
local integer pid = GetPlayerId(p)
set .yes = .yes + 1
set .hasVoted[GetPlayerId(p)] = true
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,MSG_DURATION, colors[pid] + GetPlayerName(p) + "|r voted yes (" + I2S(.yes) + "/" + I2S(.required) + ").")
if .yes >= .required then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,MSG_DURATION, colors[GetPlayerId(.targetPlayer)] + GetPlayerName(.targetPlayer) + "|r was kicked.")
call CustomDefeatBJ(.targetPlayer, "You have been kicked!" )
call PauseTimer(.t)
call DestroyTimer(.t)
set .t = null
set .targetPlayer = null
endif
endmethod
private static method onYes takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
if thistype.targetPlayer != null and not thistype.hasVoted[pid] then
call thistype.voteYes(p)
endif
set p = null
endmethod
private static method onNo takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
if thistype.targetPlayer != null and not thistype.hasVoted[pid] then
set thistype.no = thistype.no + 1
set thistype.hasVoted[pid] = true
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,MSG_DURATION, colors[pid] + GetPlayerName(p) + "|r voted no.")
endif
set p = null
endmethod
private static method onSelection takes nothing returns nothing
local player p = GetTriggerPlayer()
local SpellMenu m = GetTriggerSpellMenu()
local thistype this = thistype.table[m]
local player selectedPlayer = .getSelectedPlayer(GetTriggerSpellOption())
local integer i
call m.close(p)
if thistype.targetPlayer != null then
if GetLocalPlayer() == p then
call DisplayTimedTextToPlayer(p,0,0,MSG_DURATION, "A votekick is already in session...")
endif
else
set thistype.yes = 0
set thistype.no = 0
set i = 0
loop
exitwhen i == MAX_PLAYERS
set thistype.hasVoted[i] = false
set i = i + 1
endloop
set thistype.required = thistype.getVotesNeeded()
set thistype.targetPlayer = selectedPlayer
set thistype.t = CreateTimer()
call TimerStart(thistype.t, VOTE_TIME, false, function thistype.onTimerExpires)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,VOTE_TIME, "A votekick session against " + colors[GetPlayerId(selectedPlayer)] + GetPlayerName(selectedPlayer) + "|r has started. Type '-yes' or '-no' to vote.")
call thistype.voteYes(p)
endif
set p = null
set selectedPlayer = null
endmethod
private static method onClose takes nothing returns nothing
local SpellMenu m = GetTriggerSpellMenu()
local thistype this
if m.name == MENU_TITLE then
set this = thistype.table[m]
call this.destroy()
endif
endmethod
private static method onMenuOpen takes nothing returns nothing
local player instigator = GetTriggerPlayer()
local thistype this
local player p
local integer i
if thistype.countPlayers() <= thistype.getVotesNeeded() then
call DisplayTimedTextToPlayer(instigator,0,0,MSG_DURATION, "Not enough players to instigate a votekick.")
set instigator = null
return
endif
set this = .allocate()
set this.menu = SpellMenu.create(MENU_TITLE, false)
set thistype.table[this.menu] = this
set i = 0
loop
exitwhen i == MAX_PLAYERS
set p = Player(i)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER and /*
*/ instigator != p) or DEBUG then
set this.options[i] = menu.createOption(i, "Kick Player " + I2S(i + 1), "Starts a votekick against " + colors[i] +GetPlayerName(p) + "|r.", KICK_BTN, function thistype.onSelection)
endif
set i = i + 1
endloop
call menu.open(instigator)
set instigator = null
set p = null
endmethod
private static method onInit takes nothing returns nothing
local trigger trgClose = CreateTrigger()
call TriggerRegisterVariableEvent(trgClose, "udg_SBM_event", EQUAL, EVENT_SPELL_MENU_CLOSE)
call TriggerAddAction(trgClose, function thistype.onClose)
set thistype.table = Table.create()
call Command.register("-votekick", function thistype.onMenuOpen)
call Command.register("-yes", function thistype.onYes)
call Command.register("-no", function thistype.onNo)
call SetupPlayerColors()
call DisplayTimedTextToForce(GetPlayersAll(), 60.00, "Type \"-votekick\" to kick a player." )
endmethod
endstruct
endlibrary
//TESH.scrollpos=160
//TESH.alwaysfold=0
library OrderIds //v1.0 hiveworkshop.com/threads/orders-repo.290882/
globals
constant integer ORDER_wandillusion=852274
constant integer ORDER_absorb=852529
constant integer ORDER_acidbomb=852662
constant integer ORDER_acolyteharvest=852185
constant integer ORDER_AImove=851988
constant integer ORDER_ambush=852131
constant integer ORDER_ancestralspirit=852490
constant integer ORDER_ancestralspirittarget=852491
constant integer ORDER_animatedead=852217
constant integer ORDER_antimagicshell=852186
constant integer ORDER_attack=851983
constant integer ORDER_attackground=851984
constant integer ORDER_attackonce=851985
constant integer ORDER_attributemodskill=852576
constant integer ORDER_auraunholy=852215
constant integer ORDER_auravampiric=852216
constant integer ORDER_autodispel=852132
constant integer ORDER_autodispeloff=852134
constant integer ORDER_autodispelon=852133
constant integer ORDER_autoentangle=852505
constant integer ORDER_autoentangleinstant=852506
constant integer ORDER_autoharvestgold=852021
constant integer ORDER_autoharvestlumber=852022
constant integer ORDER_avatar=852086
constant integer ORDER_avengerform=852531
constant integer ORDER_awaken=852466
constant integer ORDER_banish=852486
constant integer ORDER_barkskin=852135
constant integer ORDER_barkskinoff=852137
constant integer ORDER_barkskinon=852136
constant integer ORDER_battleroar=852099
constant integer ORDER_battlestations=852099
constant integer ORDER_bearform=852138
constant integer ORDER_berserk=852100
constant integer ORDER_blackarrow=852577
constant integer ORDER_blackarrowoff=852579
constant integer ORDER_blackarrowon=852578
constant integer ORDER_blight=852187
constant integer ORDER_blink=852525
constant integer ORDER_blizzard=852089
constant integer ORDER_bloodlust=852101
constant integer ORDER_bloodlustoff=852103
constant integer ORDER_bloodluston=852102
constant integer ORDER_board=852043
constant integer ORDER_breathoffire=852580
constant integer ORDER_breathoffrost=852560
constant integer ORDER_build=851994
constant integer ORDER_burrow=852533
constant integer ORDER_cannibalize=852188
constant integer ORDER_carrionscarabs=852551
constant integer ORDER_carrionscarabsinstant=852554
constant integer ORDER_carrionscarabsoff=852553
constant integer ORDER_carrionscarabson=852552
constant integer ORDER_carrionswarm=852218
constant integer ORDER_chainlightning=852119
constant integer ORDER_channel=852600
constant integer ORDER_charm=852581
constant integer ORDER_chemicalrage=852663
constant integer ORDER_cloudoffog=852473
constant integer ORDER_clusterrockets=852652
constant integer ORDER_coldarrows=852244
constant integer ORDER_coldarrowstarg=852243
constant integer ORDER_controlmagic=852474
constant integer ORDER_corporealform=852493
constant integer ORDER_corrosivebreath=852140
constant integer ORDER_coupleinstant=852508
constant integer ORDER_coupletarget=852507
constant integer ORDER_creepanimatedead=852246
constant integer ORDER_creepdevour=852247
constant integer ORDER_creepheal=852248
constant integer ORDER_creephealoff=852250
constant integer ORDER_creephealon=852249
constant integer ORDER_creepthunderbolt=852252
constant integer ORDER_creepthunderclap=852253
constant integer ORDER_cripple=852189
constant integer ORDER_curse=852190
constant integer ORDER_curseoff=852192
constant integer ORDER_curseon=852191
constant integer ORDER_cyclone=852144
constant integer ORDER_darkconversion=852228
constant integer ORDER_darkportal=852229
constant integer ORDER_darkritual=852219
constant integer ORDER_darksummoning=852220
constant integer ORDER_deathanddecay=852221
constant integer ORDER_deathcoil=852222
constant integer ORDER_deathpact=852223
constant integer ORDER_decouple=852509
constant integer ORDER_defend=852055
constant integer ORDER_detectaoe=852015
constant integer ORDER_detonate=852145
constant integer ORDER_devour=852104
constant integer ORDER_devourmagic=852536
constant integer ORDER_disassociate=852240
constant integer ORDER_disenchant=852495
constant integer ORDER_dismount=852470
constant integer ORDER_dispel=852057
constant integer ORDER_divineshield=852090
constant integer ORDER_doom=852583
constant integer ORDER_drain=852487
constant integer ORDER_dreadlordinferno=852224
constant integer ORDER_dropitem=852001
constant integer ORDER_drunkenhaze=852585
constant integer ORDER_earthquake=852121
constant integer ORDER_eattree=852146
constant integer ORDER_elementalfury=852586
constant integer ORDER_ensnare=852106
constant integer ORDER_ensnareoff=852108
constant integer ORDER_ensnareon=852107
constant integer ORDER_entangle=852147
constant integer ORDER_entangleinstant=852148
constant integer ORDER_entanglingroots=852171
constant integer ORDER_etherealform=852496
constant integer ORDER_evileye=852105
constant integer ORDER_faeriefire=852149
constant integer ORDER_faeriefireoff=852151
constant integer ORDER_faeriefireon=852150
constant integer ORDER_fanofknives=852526
constant integer ORDER_farsight=852122
constant integer ORDER_fingerofdeath=852230
constant integer ORDER_firebolt=852231
constant integer ORDER_flamestrike=852488
constant integer ORDER_flamingarrows=852174
constant integer ORDER_flamingarrowstarg=852173
constant integer ORDER_flamingattack=852540
constant integer ORDER_flamingattacktarg=852539
constant integer ORDER_flare=852060
constant integer ORDER_forceboard=852044
constant integer ORDER_forceofnature=852176
constant integer ORDER_forkedlightning=852586
constant integer ORDER_freezingbreath=852195
constant integer ORDER_frenzy=852561
constant integer ORDER_frenzyoff=852563
constant integer ORDER_frenzyon=852562
constant integer ORDER_frostarmor=852225
constant integer ORDER_frostarmoroff=852459
constant integer ORDER_frostarmoron=852458
constant integer ORDER_frostnova=852226
constant integer ORDER_getitem=851981
constant integer ORDER_gold2lumber=852233
constant integer ORDER_grabtree=852511
constant integer ORDER_harvest=852018
constant integer ORDER_heal=852063
constant integer ORDER_healingspray=852664
constant integer ORDER_healingward=852109
constant integer ORDER_healingwave=852501
constant integer ORDER_healoff=852065
constant integer ORDER_healon=852064
constant integer ORDER_hex=852502
constant integer ORDER_holdposition=851993
constant integer ORDER_holybolt=852092
constant integer ORDER_howlofterror=852588
constant integer ORDER_humanbuild=851995
constant integer ORDER_immolation=852177
constant integer ORDER_impale=852555
constant integer ORDER_incineratearrow=852670
constant integer ORDER_incineratearrowoff=852672
constant integer ORDER_incineratearrowon=852671
constant integer ORDER_inferno=852232
constant integer ORDER_innerfire=852066
constant integer ORDER_innerfireoff=852068
constant integer ORDER_innerfireon=852067
constant integer ORDER_instant=852200
constant integer ORDER_invisibility=852069
constant integer ORDER_lavamonster=852667
constant integer ORDER_lightningshield=852110
constant integer ORDER_load=852046
constant integer ORDER_loadarcher = 852142
constant integer ORDER_loadcorpse=852050
constant integer ORDER_loadcorpseinstant=852053
constant integer ORDER_locustswarm=852556
constant integer ORDER_lumber2gold=852234
constant integer ORDER_magicdefense=852478
constant integer ORDER_magicleash=852480
constant integer ORDER_magicundefense=852479
constant integer ORDER_manaburn=852179
constant integer ORDER_manaflareoff=852513
constant integer ORDER_manaflareon=852512
constant integer ORDER_manashieldoff=852590
constant integer ORDER_manashieldon=852589
constant integer ORDER_massteleport=852093
constant integer ORDER_mechanicalcritter=852564
constant integer ORDER_metamorphosis=852180
constant integer ORDER_militia=852072
constant integer ORDER_militiaconvert=852071
constant integer ORDER_militiaoff=852073
constant integer ORDER_militiaunconvert=852651
constant integer ORDER_mindrot=852565
constant integer ORDER_mirrorimage=852123
constant integer ORDER_monsoon=852591
constant integer ORDER_mount=852469
constant integer ORDER_mounthippogryph=852143
constant integer ORDER_move=851986
constant integer ORDER_nagabuild=852467
constant integer ORDER_neutraldetectaoe=852023
constant integer ORDER_neutralinteract=852566
constant integer ORDER_neutralspell=852630
constant integer ORDER_nightelfbuild=851997
constant integer ORDER_orcbuild=851996
constant integer ORDER_parasite=852601
constant integer ORDER_parasiteoff=852603
constant integer ORDER_parasiteon=852602
constant integer ORDER_patrol=851990
constant integer ORDER_phaseshift=852514
constant integer ORDER_phaseshiftinstant=852517
constant integer ORDER_phaseshiftoff=852516
constant integer ORDER_phaseshifton=852515
constant integer ORDER_phoenixfire=852481
constant integer ORDER_phoenixmorph=852482
constant integer ORDER_poisonarrows=852255
constant integer ORDER_poisonarrowstarg=852254
constant integer ORDER_polymorph=852074
constant integer ORDER_possession=852196
constant integer ORDER_preservation=852568
constant integer ORDER_purge=852111
constant integer ORDER_rainofchaos=852237
constant integer ORDER_rainoffire=852238
constant integer ORDER_raisedead=852197
constant integer ORDER_raisedeadoff=852199
constant integer ORDER_raisedeadon=852198
constant integer ORDER_ravenform=852155
constant integer ORDER_recharge=852157
constant integer ORDER_rechargeoff=852159
constant integer ORDER_rechargeon=852158
constant integer ORDER_rejuvination=852160
constant integer ORDER_renew=852161
constant integer ORDER_renewoff=852163
constant integer ORDER_renewon=852162
constant integer ORDER_repair=852024
constant integer ORDER_repairoff=852026
constant integer ORDER_repairon=852025
constant integer ORDER_replenish=852542
constant integer ORDER_replenishlife=852545
constant integer ORDER_replenishlifeoff=852547
constant integer ORDER_replenishlifeon=852546
constant integer ORDER_replenishmana=852548
constant integer ORDER_replenishmanaoff=852550
constant integer ORDER_replenishmanaon=852549
constant integer ORDER_replenishoff=852544
constant integer ORDER_replenishon=852543
constant integer ORDER_request_hero=852239
constant integer ORDER_requestsacrifice=852201
constant integer ORDER_restoration=852202
constant integer ORDER_restorationoff=852204
constant integer ORDER_restorationon=852203
constant integer ORDER_resumebuild=851999
constant integer ORDER_resumeharvesting=852017
constant integer ORDER_resurrection=852094
constant integer ORDER_returnresources=852020
constant integer ORDER_revenge=852241
constant integer ORDER_revive=852039
constant integer ORDER_roar=852164
constant integer ORDER_robogoblin=852656
constant integer ORDER_root=852165
constant integer ORDER_sacrifice=852205
constant integer ORDER_sanctuary=852569
constant integer ORDER_scout=852181
constant integer ORDER_selfdestruct=852040
constant integer ORDER_selfdestructoff=852042
constant integer ORDER_selfdestructon=852041
constant integer ORDER_sentinel=852182
constant integer ORDER_setrally=851980
constant integer ORDER_shadowsight=852570
constant integer ORDER_shadowstrike=852527
constant integer ORDER_shockwave=852125
constant integer ORDER_silence=852592
constant integer ORDER_sleep=852227
constant integer ORDER_slow=852075
constant integer ORDER_slowoff=852077
constant integer ORDER_slowon=852076
constant integer ORDER_smart=851971
constant integer ORDER_soulburn=852668
constant integer ORDER_soulpreservation=852242
constant integer ORDER_spellshield=852571
constant integer ORDER_spellshieldaoe=852572
constant integer ORDER_spellsteal=852483
constant integer ORDER_spellstealoff=852485
constant integer ORDER_spellstealon=852484
constant integer ORDER_spies=852235
constant integer ORDER_spiritlink=852499
constant integer ORDER_spiritofvengeance=852528
constant integer ORDER_spirittroll=852573
constant integer ORDER_spiritwolf=852126
constant integer ORDER_stampede=852593
constant integer ORDER_standdown=852113
constant integer ORDER_starfall=852183
constant integer ORDER_stasistrap=852114
constant integer ORDER_steal=852574
constant integer ORDER_stomp=852127
constant integer ORDER_stoneform=852206
constant integer ORDER_stop=851972
constant integer ORDER_submerge=852604
constant integer ORDER_summonfactory=852658
constant integer ORDER_summongrizzly=852594
constant integer ORDER_summonphoenix=852489
constant integer ORDER_summonquillbeast=852595
constant integer ORDER_summonwareagle=852596
constant integer ORDER_tankdroppilot=852079
constant integer ORDER_tankloadpilot=852080
constant integer ORDER_tankpilot=852081
constant integer ORDER_taunt=852520
constant integer ORDER_thunderbolt=852095
constant integer ORDER_thunderclap=852096
constant integer ORDER_tornado=852597
constant integer ORDER_townbelloff=852083
constant integer ORDER_townbellon=852082
constant integer ORDER_tranquility=852184
constant integer ORDER_transmute=852665
constant integer ORDER_unavatar=852087
constant integer ORDER_unavengerform=852532
constant integer ORDER_unbearform=852139
constant integer ORDER_unburrow=852534
constant integer ORDER_uncoldarrows=852245
constant integer ORDER_uncorporealform=852494
constant integer ORDER_undeadbuild=851998
constant integer ORDER_undefend=852056
constant integer ORDER_undivineshield=852091
constant integer ORDER_unetherealform=852497
constant integer ORDER_unflamingarrows=852175
constant integer ORDER_unflamingattack=852541
constant integer ORDER_unholyfrenzy=852209
constant integer ORDER_unimmolation=852178
constant integer ORDER_unload=852047
constant integer ORDER_unloadall=852048
constant integer ORDER_unloadallcorpses=852054
constant integer ORDER_unloadallinstant=852049
constant integer ORDER_unpoisonarrows=852256
constant integer ORDER_unravenform=852156
constant integer ORDER_unrobogoblin=852657
constant integer ORDER_unroot=852166
constant integer ORDER_unstableconcoction=852500
constant integer ORDER_unstoneform=852207
constant integer ORDER_unsubmerge=852605
constant integer ORDER_unsummon=852210
constant integer ORDER_unwindwalk=852130
constant integer ORDER_vengeance=852521
constant integer ORDER_vengeanceinstant=852524
constant integer ORDER_vengeanceoff=852523
constant integer ORDER_vengeanceon=852522
constant integer ORDER_volcano=852669
constant integer ORDER_voodoo=852503
constant integer ORDER_ward=852504
constant integer ORDER_waterelemental=852097
constant integer ORDER_wateryminion=852598
constant integer ORDER_web=852211
constant integer ORDER_weboff=852213
constant integer ORDER_webon=852212
constant integer ORDER_whirlwind=852128
constant integer ORDER_windwalk=852129
constant integer ORDER_wispharvest=852214
constant integer ORDER_scrollofspeed=852285
constant integer ORDER_cancel=851976
constant integer ORDER_moveslot1=852002
constant integer ORDER_moveslot2=852003
constant integer ORDER_moveslot3=852004
constant integer ORDER_moveslot4=852005
constant integer ORDER_moveslot5=852006
constant integer ORDER_moveslot6=852007
constant integer ORDER_useslot1=852008
constant integer ORDER_useslot2=852009
constant integer ORDER_useslot3=852010
constant integer ORDER_useslot4=852011
constant integer ORDER_useslot5=852012
constant integer ORDER_useslot6=852013
constant integer ORDER_skillmenu=852000
constant integer ORDER_stunned=851973
constant integer ORDER_instant1=851991 //patrol sub-order
constant integer ORDER_instant2=851987 //?
constant integer ORDER_instant3=851975 //?
constant integer ORDER_instant4=852019 //?
endglobals
endlibrary
library OrderType /* v0.1 hiveworkshop.com/threads/ordertype.291223/
Can be used to get destinguish "no target" orders.
Other types are not really supported (yet?).
*/ requires /*
*/ OrderIds /* hiveworkshop.com/threads/orders-repo.290882/
related:
OrderTypes: hiveworkshop.com/threads/snippet-order-types.169593/
^This "OrderTypes" library can be used for getting UNIT_TARGET, POINT_TARGET, and UNIT_POINT_TARGET.
*/
// ========== API ==========
//! novjass
struct OrderType
constant integer INSTANT // Real instant orders.
constant integer QUEUE // Not instant orders, but they will
// queue orders like move/attack/smart after finished.
// All spell orders, though, like channeling will
// be interrupted, and won't continue.
// example orders: bearform/metamorphosis
// Getters
static method operator[] takes integer orderId returns integer
static method GetType takes integer orderId returns integer
// Example
if OrderType[GetSpellAbilityId()] == OrderType.INSTANT then
// innstant order
endif
//! endnovjass
// ========== END API ==========
globals
private constant integer OFFSET = 851900
endglobals
struct OrderType extends array
// used
public static constant integer INSTANT = 1
public static constant integer QUEUE = 2
// not used
private static constant integer UNIT_TARGET = 3
private static constant integer POINT_TARGET = 4
private static constant integer UNIT_POINT_TARGET = 5
private static integer array Data
public static method operator[] takes integer orderId returns integer
return Data[orderId - OFFSET]
endmethod
public static method GetType takes integer orderId returns integer
return Data[orderId - OFFSET]
endmethod
private static method onInit takes nothing returns nothing
if (GetExpiredTimer() == null) then
call TimerStart(CreateTimer(), 0, false, function thistype.onInit)
return
endif
/*
==== no target - instant ====
*/
set Data[ORDER_berserk - OFFSET] = INSTANT
set Data[ORDER_defend - OFFSET] = INSTANT
set Data[ORDER_undefend - OFFSET] = INSTANT
set Data[ORDER_divineshield - OFFSET] = INSTANT
set Data[ORDER_undivineshield - OFFSET] = INSTANT
set Data[ORDER_windwalk - OFFSET] = INSTANT
set Data[ORDER_unwindwalk - OFFSET] = INSTANT
set Data[ORDER_manashieldon - OFFSET] = INSTANT
set Data[ORDER_manashieldoff - OFFSET] = INSTANT
set Data[ORDER_autodispel - OFFSET] = INSTANT
set Data[ORDER_autodispeloff - OFFSET] = INSTANT
set Data[ORDER_immolation - OFFSET] = INSTANT
set Data[ORDER_unimmolation - OFFSET] = INSTANT
set Data[ORDER_barkskinon - OFFSET] = INSTANT
set Data[ORDER_barkskinoff - OFFSET] = INSTANT
set Data[ORDER_blackarrowon - OFFSET] = INSTANT
set Data[ORDER_blackarrowoff - OFFSET] = INSTANT
set Data[ORDER_bloodluston - OFFSET] = INSTANT
set Data[ORDER_bloodlustoff - OFFSET] = INSTANT
set Data[ORDER_carrionscarabsinstant - OFFSET] = INSTANT //?
set Data[ORDER_carrionscarabson - OFFSET] = INSTANT
set Data[ORDER_carrionscarabsoff - OFFSET] = INSTANT
set Data[ORDER_creephealon - OFFSET] = INSTANT
set Data[ORDER_creephealoff - OFFSET] = INSTANT
set Data[ORDER_ensnareon - OFFSET] = INSTANT
set Data[ORDER_ensnareoff - OFFSET] = INSTANT
set Data[ORDER_faeriefireon - OFFSET] = INSTANT
set Data[ORDER_faeriefireoff - OFFSET] = INSTANT
set Data[ORDER_flamingarrows - OFFSET] = INSTANT
set Data[ORDER_unflamingarrows - OFFSET] = INSTANT
set Data[ORDER_flamingattack - OFFSET] = INSTANT
set Data[ORDER_unflamingattack - OFFSET] = INSTANT
set Data[ORDER_frenzyon - OFFSET] = INSTANT
set Data[ORDER_frenzyoff - OFFSET] = INSTANT
set Data[ORDER_frostarmoron - OFFSET] = INSTANT
set Data[ORDER_frostarmoroff - OFFSET] = INSTANT
set Data[ORDER_healoff - OFFSET] = INSTANT
set Data[ORDER_healon - OFFSET] = INSTANT
set Data[ORDER_incineratearrowoff - OFFSET] = INSTANT
set Data[ORDER_incineratearrowon - OFFSET] = INSTANT
set Data[ORDER_innerfireon - OFFSET] = INSTANT
set Data[ORDER_innerfireoff - OFFSET] = INSTANT
set Data[ORDER_instant - OFFSET] = INSTANT //?
set Data[ORDER_manaflareon - OFFSET] = INSTANT
set Data[ORDER_manaflareoff - OFFSET] = INSTANT
set Data[ORDER_parasiteon - OFFSET] = INSTANT
set Data[ORDER_parasiteoff - OFFSET] = INSTANT
set Data[ORDER_phaseshiftinstant - OFFSET] = INSTANT //?
set Data[ORDER_phaseshiftoff - OFFSET] = INSTANT
set Data[ORDER_phaseshifton - OFFSET] = INSTANT
set Data[ORDER_raisedeadon - OFFSET] = INSTANT
set Data[ORDER_raisedeadoff - OFFSET] = INSTANT
set Data[ORDER_rechargeon - OFFSET] = INSTANT
set Data[ORDER_rechargeoff - OFFSET] = INSTANT
set Data[ORDER_renewon - OFFSET] = INSTANT
set Data[ORDER_renewoff - OFFSET] = INSTANT
set Data[ORDER_repairon - OFFSET] = INSTANT
set Data[ORDER_repairoff - OFFSET] = INSTANT
set Data[ORDER_replenishlifeon - OFFSET] = INSTANT
set Data[ORDER_replenishlifeoff - OFFSET] = INSTANT
set Data[ORDER_replenishon - OFFSET] = INSTANT
set Data[ORDER_replenishoff - OFFSET] = INSTANT
set Data[ORDER_restorationon - OFFSET] = INSTANT
set Data[ORDER_restorationoff - OFFSET] = INSTANT
set Data[ORDER_selfdestructon - OFFSET] = INSTANT
set Data[ORDER_selfdestructoff - OFFSET] = INSTANT
set Data[ORDER_slowon - OFFSET] = INSTANT
set Data[ORDER_slowoff - OFFSET] = INSTANT
set Data[ORDER_spellstealon - OFFSET] = INSTANT
set Data[ORDER_spellstealoff - OFFSET] = INSTANT
set Data[ORDER_poisonarrows - OFFSET] = INSTANT
set Data[ORDER_unpoisonarrows - OFFSET] = INSTANT
set Data[ORDER_vengeanceoff - OFFSET] = INSTANT
set Data[ORDER_vengeanceon - OFFSET] = INSTANT
set Data[ORDER_webon - OFFSET] = INSTANT
set Data[ORDER_weboff - OFFSET] = INSTANT
set Data[ORDER_whirlwind - OFFSET] = INSTANT
set Data[ORDER_moveslot1 - OFFSET] = INSTANT
set Data[ORDER_moveslot2 - OFFSET] = INSTANT
set Data[ORDER_moveslot3 - OFFSET] = INSTANT
set Data[ORDER_moveslot4 - OFFSET] = INSTANT
set Data[ORDER_moveslot5 - OFFSET] = INSTANT
set Data[ORDER_moveslot6 - OFFSET] = INSTANT
set Data[ORDER_useslot1 - OFFSET] = INSTANT
set Data[ORDER_useslot2 - OFFSET] = INSTANT
set Data[ORDER_useslot3 - OFFSET] = INSTANT
set Data[ORDER_useslot4 - OFFSET] = INSTANT
set Data[ORDER_useslot5 - OFFSET] = INSTANT
set Data[ORDER_useslot6 - OFFSET] = INSTANT
// ????
set Data[ORDER_instant1 - OFFSET] = INSTANT
set Data[ORDER_instant2 - OFFSET] = INSTANT
set Data[ORDER_instant3 - OFFSET] = INSTANT
set Data[ORDER_instant4 - OFFSET] = INSTANT
/*
==== no target - queue ====
*/
set Data[ORDER_avatar - OFFSET] = QUEUE
set Data[ORDER_unavatar - OFFSET] = QUEUE
set Data[ORDER_battleroar - OFFSET] = QUEUE
set Data[ORDER_bearform - OFFSET] = QUEUE
set Data[ORDER_unbearform - OFFSET] = QUEUE
set Data[ORDER_etherealform - OFFSET] = QUEUE
set Data[ORDER_unetherealform - OFFSET] = QUEUE
set Data[ORDER_metamorphosis - OFFSET] = QUEUE
set Data[ORDER_ravenform - OFFSET] = QUEUE
set Data[ORDER_unravenform - OFFSET] = QUEUE
set Data[ORDER_roar - OFFSET] = QUEUE
set Data[ORDER_robogoblin - OFFSET] = QUEUE
set Data[ORDER_unrobogoblin - OFFSET] = QUEUE
set Data[ORDER_stoneform - OFFSET] = QUEUE
set Data[ORDER_unstoneform - OFFSET] = QUEUE
set Data[ORDER_stomp - OFFSET] = QUEUE
set Data[ORDER_thunderclap - OFFSET] = QUEUE
endmethod
endstruct
endlibrary
library BagPlugin uses SpellOptionsMenu, RegisterPlayerUnitEvent
/*
Made by Pinzu (2019-01-23)
v. 1.1
This is a Plugin library that can be included in a Bag System, it is not meant to be a stand alone library.
You will have to manage allocation, errors and event callbacks yourself using the provided API.
struct BagMenu
unit owner - The unit owning the bag, items will be dropped on this unit
integer size - How many items the bag can fit
static method create takes unit owner, integer limit returns thistype
Creates a bag with the provided owner and size limit.
method destroy takes nothing returns nothing
Deallocates the bag, will permanently remove all items still inside the bag.
method count takes nothing returns integer
Returns the number of items currently held inside the bag
method isFull takes nothing returns boolean
Returns true if the bag has no more room
method countItemType takes integer itemType returns integer
Counts the amount of a certain item type inside the bag
method containsItemType takes integer itemType returns boolean
Returns true if the bag contains the specified item type
method find takes integer itemType returns item
Returns the first item found of matching item type. Listed in descending order.
method indexOf takes item whichItem returns integer
Returns the index of a item inside the bag.
method dropAll takes nothing returns nothing
Drops all items inside the bag.
method contains takes item whichItem returns boolean
Returns true if the bag already contains the given item.
method addItem takes item whichItem returns boolean
Adds a given item to the bag. If the bag is full it will return false, else
the item will be hidden from the map.
method open takes nothing returns nothing
Opens the bag for the owning player.
method close takes player p returns nothing
Closes the bag.
function GetTriggerBagItem takes nothing returns item
Returns the last manipulated bag item.
function GetTriggerBagOwner takes nothing returns unit
Returns the owning unit of the last manipulated bag.
function GetTriggeringBag takes nothing returns BagMenu
Returns the manipulated bag.
function OnBagDrop takes code c returns nothing
Used to register a callback function for when items are dropped from the bag.
function OnBagInventory takes code c returns nothing
Used to register a callback function for when items are requested to be moved to inventory.
*/
globals
// Configurables
private constant string MENU_NAME = "Bag"
private constant string SLOT_DROP_MARK = "ReplaceableTextures\\CommandButtons\\BTNPickUpItem.blp"
private constant string DROP_ITEM_BTN = "ReplaceableTextures\\CommandButtons\\BTNUnload.blp"
private constant string TO_INVENTORY_BTN = "ReplaceableTextures\\CommandButtons\\BTNLoad.blp"
// Callback triggers
private trigger trgDrop = CreateTrigger()
private trigger trgInventory = CreateTrigger()
// Global access variables
item bagItem = null // Triggering bag item
unit bagOwner = null // Triggering bag owner
BagMenu bagMenu = 0
endglobals
function DisablePickupTrigger takes nothing returns nothing
// call EnableAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM) REMOVE THIS from Bannars library (keep as original)
local trigger t = GetNativeEventTrigger(GetHandleId(EVENT_PLAYER_UNIT_PICKUP_ITEM))
call DisableTrigger(t)
set t = null
endfunction
function EnablePickupTrigger takes nothing returns nothing
local trigger t = GetNativeEventTrigger(GetHandleId(EVENT_PLAYER_UNIT_PICKUP_ITEM))
call EnableTrigger(t)
set t = null
endfunction
/****************************************************************************
*
* ExtensionMethods
* by Bannar
*
* General purpose functions that extend native jass interface.
*
*******************************************************************************/
private 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
private function IsUnitInventoryFull takes unit whichUnit returns boolean
return GetUnitItemCount(whichUnit) == UnitInventorySize(whichUnit)
endfunction
private 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
private function IsItemAlive takes item whichItem returns boolean
return GetItemTypeId(whichItem) != 0 and GetWidgetLife(whichItem) > 0.405
endfunction
private function IsItemPickupable takes item whichItem returns boolean
return IsItemAlive(whichItem) and not IsItemOwned(whichItem) and IsItemVisible(whichItem)
endfunction
/*
* END ExtensionMethods
*/
private struct Slot
boolean drop
SpellOption option
item slotItem
static method create takes item whichItem returns thistype
local thistype this = .allocate()
set this.drop = false
set this.option = 0
set this.slotItem = whichItem
return this
endmethod
endstruct
private module FakePickup
private static constant real FK_PICKUP_RANGE = 120
private static constant real FK_INTERVAL = 0.1
private static Table timerToInstance = 0
private static integer counter = 0
private trigger trgOnOrder = null
private item orderItem = null
private real x
private real y
private timer t
method cleanupFakePickup takes nothing returns nothing
if .trgOnOrder == null then
return
endif
set thistype.counter = thistype.counter - 1
if thistype.counter == 0 then
call thistype.timerToInstance.destroy()
set thistype.timerToInstance = 0
endif
call PauseTimer(.t)
call DestroyTimer(.t)
call TriggerClearActions(.trgOnOrder)
call DestroyTrigger(.trgOnOrder)
set .trgOnOrder = null
set .orderItem = null
set .t = null
endmethod
private static method onChangedOrder takes nothing returns nothing
local thistype this = .getUnitBag(GetTriggerUnit())
local item it = GetOrderTargetItem()
if this != 0 then
if this.orderItem != null and it == this.orderItem then
call DisableTrigger(this.trgOnOrder)
call IssuePointOrderById(this.owner, ORDER_move, this.x, this.y)
call EnableTrigger(this.trgOnOrder)
else
call this.cleanupFakePickup()
endif
endif
endmethod
private static method onFakePickupTimer takes nothing returns nothing
local thistype this = thistype.timerToInstance[GetHandleId(GetExpiredTimer())]
local real nx
local real ny
if not (IsItemAlive(this.orderItem) and IsItemPickupable(this.orderItem))then
call this.cleanupFakePickup()
else
set nx = GetItemX(this.orderItem)
set ny = GetItemY(this.orderItem)
if IsUnitInRangeXY(.owner, nx, ny, FK_PICKUP_RANGE) then
if not this.isFull() then
call this.addItem(this.orderItem)
endif
call IssueImmediateOrderById(this.owner, ORDER_stop)
call this.cleanupFakePickup()
elseif nx != this.x or ny != ny then
set this.x = nx
set this.y = ny
call DisableTrigger(this.trgOnOrder)
call IssuePointOrderById(.owner, ORDER_move, nx, ny)
call EnableTrigger(this.trgOnOrder)
endif
endif
set t = null
endmethod
private method startFakePickup takes item whichItem returns nothing
if thistype.timerToInstance == 0 then
set thistype.timerToInstance = Table.create()
endif
set thistype.counter = thistype.counter + 1
set .t = CreateTimer()
call TimerStart(.t, FK_INTERVAL, true, function thistype.onFakePickupTimer)
set thistype.timerToInstance[GetHandleId(.t)] = this
set .orderItem = whichItem
set .x = GetItemX(whichItem)
set .y = GetItemY(whichItem)
call IssuePointOrderById(.owner, ORDER_move, GetItemX(whichItem), GetItemY(whichItem))
set .trgOnOrder = CreateTrigger()
call TriggerRegisterUnitEvent(.trgOnOrder, .owner, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerRegisterUnitEvent(.trgOnOrder, .owner, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(.trgOnOrder, .owner, EVENT_UNIT_ISSUED_ORDER)
call TriggerRegisterUnitEvent(.trgOnOrder, .owner, EVENT_UNIT_DEATH)
call TriggerAddAction(.trgOnOrder, function thistype.onChangedOrder)
endmethod
private static method onTargetOrder takes nothing returns nothing
local item it = GetOrderTargetItem()
local thistype this = .getUnitBag(GetTriggerUnit())
if this != 0 and not this.isFull() and it != null and IsUnitInventoryFull(this.owner) and this.orderItem == null then
call this.startFakePickup(it)
endif
set it = null
endmethod
static method setupFakePickup takes nothing returns nothing
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onTargetOrder)
endmethod
endmodule
struct BagMenu
private IntArrayList slots
private SpellMenu menu
private integer limit
private unit owner
implement FakePickup
private static Table bagMenuMap = 0 // SpellMenu --> BagMenu
private static Table slotOptionMap = 0 // SpellOption --> Slot
private static Table unitToBag
private method removeSlot takes Slot slot returns nothing
call thistype.slotOptionMap.integer.remove(slot.option)
call .menu.remove(.menu.indexOf(slot.option))
call .slots.remove(.slots.indexOf(slot))
set slot.slotItem = null
call slot.destroy()
endmethod
private method dropItem takes item whichItem returns nothing
call SetItemVisible(whichItem, true)
call SetItemPosition(whichItem, GetUnitX(.owner), GetUnitY(.owner))
endmethod
private method setGlobals takes item whichItem returns nothing
set bagMenu = this
set bagItem = whichItem
set bagOwner = this.owner
endmethod
private static method onDropItem takes nothing returns nothing
local SpellMenu usedMenu = GetTriggerSpellMenu()
local thistype this = thistype.bagMenuMap.integer[usedMenu]
local integer i = .slots.length - 1
local Slot slot
loop
exitwhen i < 0
set slot = .slots[i]
if slot.drop then
call .dropItem(slot.slotItem)
// Notify
call .setGlobals(slot.slotItem)
call TriggerEvaluate(trgDrop)
// cleanup
call this.removeSlot(slot)
endif
set i = i - 1
endloop
call this.menu.refresh() // We refresh the menu whenever it changes state
endmethod
private static method onMoveToInventory takes nothing returns nothing
local SpellMenu usedMenu = GetTriggerSpellMenu()
local thistype this = thistype.bagMenuMap.integer[usedMenu]
local integer i = .slots.length - 1
local Slot slot
loop
exitwhen i < 0
set slot = .slots[i]
if slot.drop then
call .dropItem(slot.slotItem)
// Notify
call .setGlobals(slot.slotItem)
call DisablePickupTrigger()
call TriggerEvaluate(trgInventory)
call EnablePickupTrigger()
// cleanup
call this.removeSlot(slot)
endif
set i = i - 1
endloop
endmethod
/*
Create
*/
static method create takes unit owner, integer limit returns thistype
local thistype this = .getUnitBag(owner)
local SpellOption o
if this != 0 then
debug call BJDebugMsg("[BagPlugin_BagMenu_create] Warning: " + GetUnitName(owner) + " already has a bag.")
return this
endif
set this = .allocate()
set thistype.unitToBag[GetHandleId(owner)] = this
set this.slots = IntArrayList.create()
set this.limit = limit
set this.menu = SpellMenu.create(MENU_NAME, false)
set this.owner = owner
if thistype.bagMenuMap == 0 then
set thistype.bagMenuMap = Table.create()
set thistype.slotOptionMap = Table.create()
endif
set thistype.bagMenuMap.integer[this.menu] = this // SpellMenu --> BagMenu
set o = this.menu.createOption(0, "Drop Item", "Drops all selected items", DROP_ITEM_BTN, function thistype.onDropItem)
call this.menu.lock(o, 7)
set o = this.menu.createOption(0, "Move To Inventory", "Moves selected items to inventory.", TO_INVENTORY_BTN, function thistype.onMoveToInventory)
call this.menu.lock(o, 3)
return this
endmethod
/*
Deallocates the bag, will permanently remove all items still inside the bag.
*/
method destroy takes nothing returns nothing
local integer i = .slots.length - 1
local Slot slot
loop
exitwhen i < 0
set slot = .slots[i]
call RemoveItem(slot.slotItem)
call .removeSlot(slot)
set i = i - 1
endloop
call .cleanupFakePickup()
call thistype.unitToBag.remove(GetHandleId(.owner))
set .owner = null
call thistype.bagMenuMap.remove(.menu)
call .menu.destroy()
call .deallocate()
endmethod
/*
Returns the number of items currently held inside the bag
*/
method count takes nothing returns integer
return .slots.length
endmethod
/*
Returns true if the bag has no more room
*/
method isFull takes nothing returns boolean
return .count() >= .limit
endmethod
/*
Counts the amount of a certain item type inside the bag
*/
method countItemType takes integer itemType returns integer
local integer count = 0
local integer i = 0
local Slot slot
loop
exitwhen i == .slots.length
set slot = .slots[i]
if GetItemTypeId(slot.slotItem) == itemType then
set count = count + 1
endif
set i = i + 1
endloop
return count
endmethod
/*
Returns true if the bag contains the specified item type
*/
method containsItemType takes integer itemType returns boolean
return .countItemType(itemType) > 0
endmethod
private method dropRange takes integer last, integer first returns nothing
local integer i = last
local Slot slot
loop
exitwhen i < first
set slot = .slots[i]
call .dropItem(slot.slotItem)
// Notify
call .setGlobals(slot.slotItem)
call TriggerEvaluate(trgDrop)
// cleanup
call this.removeSlot(slot)
set i = i - 1
endloop
endmethod
/*
Changes how many items the bag can fit.
*/
method operator size= takes integer newLimit returns nothing
local integer count = .count()
if newLimit < 0 then
set newLimit = 0
endif
set .limit = newLimit
if newLimit < count then
call .dropRange(count - 1, newLimit)
endif
endmethod
/*
Returns how many items the bag can fit.
*/
method operator size takes nothing returns integer
return .limit
endmethod
/*
Returns the first item found of matching item type. Listed in descending order.
*/
method find takes integer itemType returns item
local Slot slot
local integer i = slots.length - 1
loop
exitwhen i < 0
set slot = slots[i]
if GetItemTypeId(slot.slotItem) == itemType then
return slot.slotItem
endif
set i = i - 1
endloop
return null
endmethod
/*
Returns the index of a item inside the bag.
*/
method indexOf takes item whichItem returns integer
local Slot slot
local integer i = 0
loop
exitwhen i == slots.length
set slot = slots[i]
if slot.slotItem == whichItem then
return i
endif
set i = i + 1
endloop
return -1
endmethod
/*
Drops all items inside the bag.
*/
method dropAll takes nothing returns nothing
call .dropRange(.slots.length - 1, 0)
endmethod
/*
Returns true if the bag already contains the given item.
*/
method contains takes item whichItem returns boolean
return .indexOf(whichItem) != -1
endmethod
private static method onItemSelected takes nothing returns nothing
local thistype this = thistype.bagMenuMap.integer[GetTriggerSpellMenu()]
local SpellOption o = GetTriggerSpellOption()
local Slot slot = thistype.slotOptionMap.integer[o]
if slot.drop then
set slot.drop = false
set o.icon = BlzGetItemIconPath(slot.slotItem)
else
set slot.drop = true
set o.icon = SLOT_DROP_MARK
endif
endmethod
private static method getItemName takes item whichItem returns string
local integer charges = GetItemCharges(whichItem)
if charges > 1 then
return GetItemName(whichItem) + " x" + I2S(charges)
endif
return GetItemName(whichItem)
endmethod
private method hideItem takes item whichItem returns nothing
call SetItemPosition(whichItem, GetUnitX(.owner), GetUnitY(.owner))
call SetItemVisible(whichItem, false)
endmethod
/*
Adds a given item to the bag. If the bag is full it will return false, else
the item will be hidden from the map.
*/
method addItem takes item whichItem returns nothing
local integer index = slots.length
local string icon
local Slot slot
if .contains(whichItem) then
call .hideItem(whichItem) // we hide it again to prevent bugs
debug call BJDebugMsg("[BagPlugin_BagMenu_additem] Warning: " + GetItemName(whichItem) + " is already inside the bag.")
return
endif
if index >= limit then
debug call BJDebugMsg("[BagPlugin_BagMenu_additem] Warning: Bag is full.")
return
endif
call .hideItem(whichItem)
set slot = Slot.create(whichItem)
call .slots.add(index, slot)
set icon = BlzGetItemIconPath(whichItem)
set slot.option = .menu.createOption(index, thistype.getItemName(whichItem), BlzGetItemExtendedTooltip(whichItem), icon, function thistype.onItemSelected)
set thistype.slotOptionMap.integer[slot.option] = slot // SpellOption --> Slot
endmethod
private method resetToggle takes nothing returns nothing
local integer i = 0
local Slot slot
loop
exitwhen i == .slots.length
set slot = .slots[i]
if slot.drop then
set slot.drop = false
set slot.option.icon = BlzGetItemIconPath(slot.slotItem)
endif
set i = i + 1
endloop
endmethod
/*
Opens the bag for the owning player
*/
method open takes nothing returns nothing
call .resetToggle()
call .menu.open(GetOwningPlayer(.owner))
endmethod
/*
Closes the bag
*/
method close takes player p returns nothing
call .menu.close(GetOwningPlayer(.owner))
endmethod
static method getUnitBag takes unit u returns thistype
return .unitToBag[GetHandleId(u)]
endmethod
static method unitHasBag takes unit u returns boolean
return .unitToBag.has(GetHandleId(u))
endmethod
private static method onPickup takes nothing returns nothing
local thistype this = .getUnitBag(GetTriggerUnit())
if this == 0 then
return
endif
if not this.isFull() then
call this.addItem(GetManipulatedItem())
endif
endmethod
private static method onInit takes nothing returns nothing
set .unitToBag = Table.create()
call RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.onPickup)
call .setupFakePickup()
endmethod
endstruct
/*
Returns the bag that the unit is currently using.
*/
function GetUnitBag takes unit u returns BagMenu
return BagMenu.getUnitBag(u)
endfunction
/*
Returns true if the unit is currently using a bag.
*/
function UnitHasBag takes unit u returns boolean
return GetUnitBag(u) != 0
endfunction
/*
Returns the last manipulated bag item
*/
function GetTriggeringBagItem takes nothing returns item
return bagItem
endfunction
/*
Returns the owning unit of the last manipulated bag
*/
function GetTriggeringBagOwner takes nothing returns unit
return bagOwner
endfunction
/*
Returns the manipulated bag
*/
function GetTriggeringBag takes nothing returns BagMenu
return bagMenu
endfunction
/*
Used to register a callback function for when items are dropped from the bag
*/
function OnBagDrop takes code c returns nothing
call TriggerAddCondition(trgDrop, Condition(c))
endfunction
/*
Used to register a callback function for when items are requested to be moved to inventory
*/
function OnBagInventory takes code c returns nothing
call TriggerAddCondition(trgInventory, Condition(c))
endfunction
endlibrary
scope ItemMenu initializer Init
/*
This trigger will give every hero on the map a bag
*/
globals
private constant integer BAG_ABILITY = 'A00D'
private constant integer BAG_LIMIT = 16
private BagMenu array bags
endglobals
/*
Here you can filter which units should be given a bag.
*/
private function GiveBagCondition takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_HERO)
endfunction
private function OnMoveToInventory takes nothing returns nothing
local unit owner = GetTriggeringBagOwner()
local item it = GetTriggeringBagItem()
call BJDebugMsg("Item (" + GetItemName(it) + ") was moved to inventory by " + GetUnitName(owner) + ".")
call UnitAddItem(owner, it)
set owner = null
set it = null
endfunction
private function OnItemDrop takes nothing returns nothing
call BJDebugMsg("Item (" + GetItemName(GetTriggeringBagItem()) + ") was dropped by " + GetUnitName(GetTriggeringBagOwner()) + ".")
endfunction
private function Open takes nothing returns nothing
call bags[GetUnitUserData(GetTriggerUnit())].open()
endfunction
private function OnSpell takes nothing returns boolean
if GetSpellAbilityId() == BAG_ABILITY then
return true
endif
return false
endfunction
private function OnDeindex takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer id = GetUnitUserData(u)
if bags[id] != 0 then
call bags[id].destroy()
set bags[id] = 0
endif
set u = null
endfunction
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local BagMenu bag
if GiveBagCondition(u) then
call UnitAddAbility(u, BAG_ABILITY)
set bags[GetUnitUserData(u)] = BagMenu.create(u, BAG_LIMIT)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
local trigger trgSpell = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trgSpell, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition(trgSpell, Condition(function OnSpell))
call TriggerAddAction(trgSpell, function Open)
set trgSpell = null
// Give bag ability
call OnUnitIndex(function OnIndex)
call OnUnitDeindex(function OnDeindex)
// Register Bag Item Events
call OnBagDrop(function OnItemDrop)
call OnBagInventory(function OnMoveToInventory)
endfunction
endscope
library UnitIndexerGUI //requires GUI Unit Indexer
globals
private trigger index = null
private trigger deindex = null
private trigger init = null
private trigger tempTrig
endglobals
private function DoTheThings takes trigger t, code c, real r returns trigger
if t == null then
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_UnitIndexEvent", EQUAL, r)
endif
call TriggerAddCondition(t, Filter(c))
set tempTrig = t
set t = null
return tempTrig
endfunction
//call RegisterUnitIndexEvent(Filter(function Blah), EVENT_UNIT_INDEXED)
//->
//call OnUnitIndex(function Blah)
function OnUnitIndex takes code c returns nothing
set index = DoTheThings(index, c, 1.)
endfunction
//call RegisterUnitIndexEvent(Filter(function Blah), EVENT_UNIT_DEINDEXED)
//->
//call OnUnitDeindex(function Blah)
function OnUnitDeindex takes code c returns nothing
set deindex = DoTheThings(deindex, c, 2.)
endfunction
private function DestroyInit takes nothing returns boolean
call DestroyTrigger(init) //will still allow consecutive triggerconditions to run.
set init = null
return false
endfunction
//GUI Unit Indexer will initialize after any vJass stuff, so you need to do your
//unit-indexer-requiring stuff after this event instead of a module/struct/library
//initializer.
function OnUnitIndexerInitialized takes code c returns nothing
if init == null then
set init = CreateTrigger()
call TriggerAddCondition(init, Filter(function DestroyInit))
call TriggerRegisterVariableEvent(init, "udg_UnitIndexEvent", EQUAL, 3.00)
endif
call TriggerAddCondition(init, Filter(c))
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function GetUnitById takes integer id returns unit
return udg_UDexUnits[id]
endfunction
function GetIndexedUnit takes nothing returns unit
return udg_UDexUnits[udg_UDex]
endfunction
function GetIndexedUnitId takes nothing returns integer
return udg_UDex
endfunction
function IsUnitIndexed takes unit u returns boolean
return udg_UDexUnits[GetUnitUserData(u)] == u
endfunction
endlibrary
library DoorSystem uses Table, RegisterPlayerUnitEvent, RegisterUnitEvent
globals
private integer DOOR_CONTROLLER = 'n001'
endglobals
struct Door
private SpellMenu tempMenu
destructable dest
private unit controller
private boolean lockedState
private static Table table
private static trigger trgSelection
method setOwner takes player p returns nothing
call SetUnitOwner(.controller, p, true)
endmethod
method getOwner takes nothing returns player
return GetOwningPlayer(.controller)
endmethod
method isBroken takes nothing returns boolean
return false
endmethod
method open takes nothing returns nothing
if not .isBroken() then
call ModifyGateBJ(bj_GATEOPERATION_OPEN, .dest)
endif
endmethod
method close takes nothing returns nothing
if not .isBroken() then
call ModifyGateBJ(bj_GATEOPERATION_CLOSE, .dest)
endif
endmethod
method lock takes nothing returns nothing
set .lockedState = true
endmethod
method unlock takes nothing returns nothing
set .lockedState = false
endmethod
method isLocked takes nothing returns boolean
return .lockedState
endmethod
private static method onOptionSelected takes nothing returns nothing
endmethod
private static method hash takes thistype instance, integer playerId returns integer
return instance*bj_MAX_PLAYER_SLOTS + playerId
endmethod
method addDoorController takes player p returns nothing
set table.boolean[hash(this, GetPlayerId(p))] = true
endmethod
method removeDoorController takes player p returns nothing
call table.boolean.remove(hash(this, GetPlayerId(p)))
endmethod
method hasDoorControl takes player p returns boolean
return table.boolean.has(hash(this, GetPlayerId(p)))
endmethod
method canPlayerOpen takes player p returns boolean
return (not .lockedState or .hasDoorControl(p)) and not .isBroken()
endmethod
method createMenu takes player p returns nothing
if tempMenu == 0 then
set tempMenu = SpellMenu.create("Door Menu", false)
endif
if not isBroken() then
endif
endmethod
private static method onSelection takes nothing returns nothing
local thistype this = table[-GetHandleId(GetTriggerUnit())] // Get door
call BJDebugMsg("Selected: " + GetUnitName(GetTriggerUnit()))
call .open()
endmethod
static method create takes integer doorType, real x, real y, real f, real scale, integer variation returns thistype
local thistype this = .allocate()
set this.dest = CreateDestructable(doorType, x, y, f, scale, variation)
set this.controller = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), DOOR_CONTROLLER, x, y, f)
set this.lockedState = true
call RegisterUnitEvent (this.controller, EVENT_UNIT_SELECTED, function thistype.onSelection)
set table[-GetHandleId(this.controller)] = this // Save door
set this.tempMenu = 0
return this
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local player p
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
if .hasDoorControl(p) then
call .removeDoorController(p)
endif
set i = i + 1
endloop
set p = null
call .deallocate()
endmethod
private static method onInit takes nothing returns nothing
set table = Table.create()
endmethod
endstruct
endlibrary
scope DoorExample initializer Init
globals
private integer DOOR_1 = 'LTg3'
endglobals
private function Init takes nothing returns nothing
local Door d
set d = Door.create(DOOR_1, GetRectCenterX(gg_rct_door01), GetRectCenterY(gg_rct_door01), 0, 1.0, 0)
call d.setOwner(Player(0))
endfunction
endscope
library SpellMenuDialogs uses SpellOptionsMenu
globals
//
// Configuration
constant string SPELL_MENU_DIALOG_NO = "ReplaceableTextures\\CommandButtons\\BTNHire.blp"
constant string SPELL_MENU_DIALOG_YES = "ReplaceableTextures\\CommandButtons\\BTNSell.blp"
//
// These are used to pass which options was selected
integer spellDialogResponse // Selected response
integer spellDialogUsed // Dialog id
constant integer SPELL_DIALOG_YES = 1
constant integer SPELL_DIALOG_NO = 2
//
// Cache
private Table tab = 0
private integer size = 0
endglobals
private function ConfirmResponse takes nothing returns nothing
local SpellOption o = GetTriggerSpellOption()
local SpellMenu m = GetTriggerSpellMenu()
local trigger t = tab.trigger[m]
set spellDialogUsed = m
set spellDialogResponse = o.userData
call TriggerExecute(t)
call m.close(GetTriggerSpellOptionPlayer())
call m.destroy()
call TriggerClearActions(t)
call DestroyTrigger(t)
set size = size - 1
if size == 0 then
call tab.destroy()
set tab = 0
endif
set t = null
endfunction
function CreateConfirmDialog takes string question, player p, code callback, string yesT, string yesD, string noT, string noD returns integer
local SpellMenu menu = SpellMenu.create(question, true)
local trigger t = CreateTrigger()
local SpellOption o
call TriggerAddAction(t, callback)
if tab == 0 then
set tab = Table.create()
endif
set tab.trigger[menu] = t
set size = size + 1
set t = null
set o = menu.createOption(-1, yesT, yesD, SPELL_MENU_DIALOG_YES, function ConfirmResponse)
set o.userData = SPELL_DIALOG_YES
set o = menu.createOption(-1, noT, noD, SPELL_MENU_DIALOG_NO, function ConfirmResponse)
set o.userData = SPELL_DIALOG_NO
call menu.open(p)
return menu
endfunction
endlibrary
library HostSettings initializer Init requires SpellOptionsMenu, SpellMenuDialogs
globals
private constant boolean USE_GUI_VARS = true
private player hostPlayer = Player(0)
private integer hostGracePeriod = 60
private constant string NUM_PREFIX = "["
private constant string NUM_POSTFIX = "]"
private constant string HIGHLIGHT = "|cff00ff00"
private constant string ACCEPT_BTN = SPELL_MENU_DIALOG_YES
Setting lastCreatedHostSetting = 0
Setting lastTriggerHostSetting = 0
integer lastTriggerHostSettingValue = 0
// DEMO CODE
private integer array hostSetting
endglobals
private struct Child
thistype next
integer index
string label
string text
string btn
string disbtn
static method create takes integer index, thistype next, string label, string text, string btn, string disbtn returns thistype
local thistype this = .allocate()
set this.label = label
set this.text = text
set this.btn = btn
set this.disbtn = disbtn
set this.index = index
set this.next = next
return this
endmethod
method destroy takes nothing returns nothing
set .label = null
set .text = null
set .btn = null
set .disbtn = null
call .deallocate()
endmethod
static if DEBUG_MODE then
method toString takes nothing returns string
return "{" + I2S(.index) + ": " + label + "," + text + "," + btn + "}"
endmethod
endif
endstruct
struct Setting
thistype next
private Child curr
private Child head
private string label
static method create takes string label returns thistype
local thistype this = .allocate()
set .curr = 0
set .head = 0
set .next = 0
set .label = label
return this
endmethod
method destroy takes nothing returns nothing
local Child c = .head
local Child cc
set c = head
loop // Find last
set c = c.next
exitwhen c.next == .head
endloop
set c.next = 0
set c = head
loop
exitwhen c == 0
set cc = c.next
//call c.destroy()
set c = cc
endloop
endmethod
method listAlternatives takes nothing returns string
local string s = ""
local Child c = .head
local integer i = 1
if .head == 0 then
return ""
endif
loop
if c == .curr then
set s = s + "- " + HIGHLIGHT + c.text + "|r\n"
else
set s = s + "- " + c.text + "\n"
endif
set c = c.next
set i = i + 1
exitwhen c == .head
endloop
return s
endmethod
// Adds another child option to the setting
method add takes string label, string text, string btn, string disbtn returns thistype
local Child c
if .head == 0 then
set .head = Child.create(0, 0, label, text, btn, disbtn)
set .head.next = .head
set .curr = .head
else
set c = head
loop // Find last
set c = c.next
exitwhen c.next == .head
endloop
set c.next = Child.create(c.index + 1, .head, label, text, btn, disbtn)
endif
return this
endmethod
// Changes to next setting
method onNext takes nothing returns nothing
set .curr = .curr.next
endmethod
// Returns the current selected setting
method value takes nothing returns integer
return .curr.index
endmethod
// Changes current setting and modifies the display accordingly
private static method onSelection takes nothing returns nothing
local SpellOption o = GetTriggerSpellOption()
local thistype this = o.userData
local SpellMenu menu = GetTriggerSpellMenu()
call .onNext()
set o.label = .label
set o.text = .listAlternatives()
set o.btn = .curr.btn
call menu.refresh() // We refresh the menu for all players
call BJDebugMsg("Setting(" + I2S(this) + ") changed to " + I2S(this.value()))
endmethod
// Factory method for converting the current setting to a clickable option
method optionFactory takes nothing returns SpellOption
local SpellOption o = SpellOption.create(.label, listAlternatives(), curr.btn, curr.disbtn, function thistype.onSelection)
set o.userData = this
return o
endmethod
endstruct
//====================================================================================
struct HostConfig extends array
static player host
static string title
readonly static Setting last
readonly static Setting head
readonly static Setting cursor
private static trigger trgDone
private static timer t
private static SpellMenu menu
private static method onInit takes nothing returns nothing
set menu = 0
set head = 0
set last = 0
set t = null
endmethod
static method cleanup takes nothing returns nothing
local Setting s = head
local Setting ss
if menu == 0 then
return
endif
call BJDebugMsg("Cleaning up HostConfig")
loop
exitwhen s == 0
set ss = s.next
//call s.destroy()
set s = ss
endloop
call menu.destroy()
call TriggerClearActions(trgDone)
call DestroyTrigger(trgDone)
set trgDone = null
set menu = 0
endmethod
static method createSetting takes string label returns Setting
set lastCreatedHostSetting = Setting.create(label)
if head == 0 then
set head = lastCreatedHostSetting
set last = head
else
set last.next = lastCreatedHostSetting
set last = lastCreatedHostSetting
endif
return lastCreatedHostSetting
endmethod
static method addOptionToLastCreatedHostSetting takes string text, string btn, string disbtn returns nothing
call lastCreatedHostSetting.add("", text, btn, disbtn)
endmethod
// Iterates all settings and pushes the current value held inside
private static method onFinish takes nothing returns nothing
set lastTriggerHostSetting = head
loop
exitwhen lastTriggerHostSetting == 0
set lastTriggerHostSettingValue = lastTriggerHostSetting.value()
call TriggerExecute(trgDone)
set lastTriggerHostSetting = lastTriggerHostSetting.next
endloop
endmethod
private static method onDialogResponse takes nothing returns nothing
local integer response = spellDialogResponse
if response == SPELL_DIALOG_YES then
call onFinish()
else
call menu.open(GetTriggerPlayer()) // Re-open the host menu
endif
endmethod
private static method onDoneClick takes nothing returns nothing
call CreateConfirmDialog("Confirm", GetTriggerPlayer(), function thistype.onDialogResponse, /*
*/ "Yes", "Confirm host settings.", "No", "Continue host configuration.")
endmethod
static method open takes player whichPlayer returns nothing
local Setting setting = .head
local SpellOption o
local integer hostId = GetPlayerId(.host)
if menu == 0 then
set menu = SpellMenu.create(title, true)
loop
exitwhen setting == 0
set o = setting.optionFactory()
call menu.add(-1,o)
set o.enabled = false
call o.setLocalEnabled(hostId, true)
set setting = setting.next
endloop
set o = SpellOption.create("Done", "Completes the host configuration", ACCEPT_BTN, ACCEPT_BTN, function thistype.onDoneClick)
set o.enabled = false
call o.setLocalEnabled(hostId, true)
call menu.add(-1, o)
call menu.lock(o, 3)
endif
call menu.open(whichPlayer)
endmethod
private static method onTimerExpires takes nothing returns nothing
call PauseTimer(t)
call DestroyTimer(t)
set t = null
call onFinish()
endmethod
static method startSession takes integer maxTime returns nothing
local integer i = 0
local player p
set t = CreateTimer()
call TimerStart(t, maxTime, false, function thistype.onTimerExpires)
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER then
call open(p)
endif
set i = i + 1
endloop
set p = null
endmethod
static method onComplete takes code c returns nothing
local integer i = 0
local player p
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and /*
*/ GetPlayerController(p) == MAP_CONTROL_USER then
call menu.close(p)
endif
set i = i + 1
endloop
set p = null
call cleanup()
endmethod
endstruct
private function OpenHostMenu takes nothing returns nothing
call HostConfig.startSession(60)
endfunction
private function Done takes nothing returns nothing
call BJDebugMsg("DONE")
if hostSetting[0] == lastTriggerHostSetting then
if lastTriggerHostSettingValue == 0 then
call BJDebugMsg("0")
elseif lastTriggerHostSettingValue == 1 then
call BJDebugMsg("1")
else
call BJDebugMsg("2")
endif
elseif lastTriggerHostSetting == hostSetting[1] then
call BJDebugMsg("0")
endif
endfunction
private function Init takes nothing returns nothing
call Command.register("-host", function OpenHostMenu)
set HostConfig.title = "Host Options"
set HostConfig.host = Player(0)
set hostSetting[0] = HostConfig.createSetting("Hero Starting Health")
call HostConfig.addOptionToLastCreatedHostSetting("Heroes start with full health.", "ReplaceableTextures\\CommandButtons\\BTNHealthStone.blp", null)
call HostConfig.addOptionToLastCreatedHostSetting("Heroes start with medium health.", "ReplaceableTextures\\CommandButtons\\BTNPotionGreenSmall.blp", null)
call HostConfig.addOptionToLastCreatedHostSetting("Heroes start with low health.", "ReplaceableTextures\\CommandButtons\\BTNHealingSalve.blp", null)
set hostSetting[1] = HostConfig.createSetting("Hero Starting Mana")
call HostConfig.addOptionToLastCreatedHostSetting("Heroes start with full mana.", "ReplaceableTextures\\CommandButtons\\BTNHealthStone.blp", null)
call HostConfig.onComplete(function Done)
endfunction
endlibrary
library ForceAbilityLib uses Table optional TimerUtils
globals
private constant real MIN_DELAY = 0.02 // This is the minimum acceptable delay
private Table table = 0 // Cache
private integer count = 0 // The number of active instances
endglobals
private function cleanup takes integer pid returns nothing
local unit u = null
local string s = BlzGetUnitIconPath(u)
call TriggerClearActions(table.trigger[pid])
call DestroyTrigger(table.trigger[pid])
call TriggerClearActions(table.trigger[pid - 25])
call TriggerClearActions(table.trigger[pid - 50])
call DestroyTrigger(table.trigger[pid])
call DestroyTrigger(table.trigger[pid - 25])
call DestroyTrigger(table.trigger[pid - 50])
call table.trigger.remove(pid)
call table.trigger.remove(pid - 25)
call table.trigger.remove(pid - 50)
call table.integer.remove(pid)
call table.unit.remove(pid)
set count = count - 1
if count == 0 then
call table.destroy()
set table = 0
endif
endfunction
/*
This is not always cast
*/
private function OnAbilityStart takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer pid = GetPlayerId(GetOwningPlayer(u))
if GetSpellAbilityId() == table.integer[pid] then
call UnitRemoveAbility(u, table.integer[pid])
call PauseUnit(u, true)
call PauseUnit(u, false)
call TriggerExecute(table.trigger[pid])
call cleanup(pid)
endif
set u = null
endfunction
private function DelayedCancel takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tid = GetHandleId(t)
local integer pid = table.integer[tid]
local unit u = table.unit[pid]
call table.integer.remove(tid)
if u != null then
call UnitRemoveAbility(u, table.integer[pid])
call PauseUnit(u, true)
call PauseUnit(u, false)
call cleanup(pid)
set u = null
endif
endfunction
/*
Starts a delay before continuing with the cancel order, to allow the spell to be cast first.
*/
private function OnCancel takes nothing returns nothing
local timer t = CreateTimer()
local integer tid = GetHandleId(t)
set table.integer[tid] = GetPlayerId(GetTriggerPlayer())
call TimerStart(t, 0.02, false, function DelayedCancel)
set t = null
endfunction
/*
Forces the order on the player associated with he expired timer.
*/
private function DelayedForceAction takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tid = GetHandleId(t)
local integer pid = table.integer[tid]
call ForceUIKeyBJ(table.player[tid], table.string[tid])
call table.player.remove(tid)
call table.string.remove(tid)
call table.integer.remove(tid)
call PauseTimer(t)
call DestroyTimer(t)
set t = null
endfunction
/*
This will add an ability to the provided unit and force the owning player to use it after a small delay.
When the dummy ability is cast a callback is triggered. After the ability has been cast or if the order
was canceled the ability is removed.
@Precondition: Unit must be selected by owning player.
*/
function ForceAbility takes unit u, integer abilCode, string hotkey, real delay, code callback returns nothing
local timer t
local integer tid
local player p
local integer pid
local trigger t1
local trigger t2
if delay < MIN_DELAY then
debug call BJDebugMsg("[AbilityOverride] ERROR: " + "Invalid delay argument: " + R2S(delay))
return
endif
if table == 0 then
set table = Table.create()
endif
set p = GetOwningPlayer(u)
set pid = GetPlayerId(p)
if table.integer.has(pid) then
debug call BJDebugMsg("[AbilityOverride] ERROR: " + GetPlayerName(Player(pid)) + " already has a pending ability command.")
set p = null
return
endif
// Cancel
set t1 = CreateTrigger()
set table.trigger[pid - 25] = t1
call TriggerAddAction(t1, function OnCancel)
call TriggerRegisterPlayerEventEndCinematic(t1, p)
call TriggerRegisterPlayerMouseEventBJ(t1, p, bj_MOUSEEVENTTYPE_DOWN)
set t1 = null
// Spell cast
set t2 = CreateTrigger()
set table.trigger[pid - 50] = t2
call TriggerRegisterUnitEvent(t2, u, EVENT_UNIT_SPELL_CAST)
call TriggerAddAction(t2, function OnAbilityStart)
set t2 = null
//
set count = count + 1
set t = CreateTimer()
set tid = GetHandleId(t)
set table.string[tid] = hotkey
set table.player[tid] = p
set table.integer[tid] = pid
set table.integer[pid] = abilCode
set table.trigger[pid] = CreateTrigger()
set table.unit[pid] = u
call TriggerAddAction(table.trigger[pid], callback)
call UnitAddAbility(u, abilCode)
call TimerStart(t, delay, false, function DelayedForceAction)
set t = null
set p = null
endfunction
endlibrary
/*****************************************************************************
*
* RegisterNativeEvent v1.1.1.3
* 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 nothing
* Registers new event handler func for event whichEvent specific to index whichIndex.
*
* function RegisterNativeEvent takes integer whichEvent, code func returns nothing
* Registers new event handler func for specified event whichEvent.
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table
globals
/**
* For use with RegisterGameEvent
*/
constant integer gameevent_VICTORY = 0
constant integer gameevent_END_LEVEL = 1
constant integer gameevent_VARIABLE_LIMIT = 2
constant integer gameevent_STATE_LIMIT = 3
constant integer gameevent_TIMER_EXPIRED = 4
constant integer gameevent_ENTER_REGION = 5
constant integer gameevent_LEAVE_REGION = 6
constant integer gameevent_TRACKABLE_HIT = 7
constant integer gameevent_TRACKABLE_TRACK = 8
constant integer gameevent_SHOW_SKILL = 9
constant integer gameevent_BUILD_SUBMENU = 10
/**
* For use with RegisterPlayerEvent
*/
constant integer playerevent_STATE_LIMIT = 11
constant integer playerevent_ALLIANCE_CHANGED = 12
constant integer playerevent_DEFEAT = 13
constant integer playerevent_VICTORY = 14
constant integer playerevent_LEAVE = 15
constant integer playerevent_CHAT = 16
constant integer playerevent_END_CINEMATIC = 17
/**
* For use with RegisterPlayerUnitEvent
*/
constant integer playerunitevent_ATTACKED = 18
constant integer playerunitevent_RESCUED = 19
constant integer playerunitevent_DEATH = 20
constant integer playerunitevent_DECAY = 21
constant integer playerunitevent_DETECTED = 22
constant integer playerunitevent_HIDDEN = 23
constant integer playerunitevent_SELECTED = 24
constant integer playerunitevent_DESELECTED = 25
constant integer playerunitevent_CONSTRUCT_START = 26
constant integer playerunitevent_CONSTRUCT_CANCEL = 27
constant integer playerunitevent_CONSTRUCT_FINISH = 28
constant integer playerunitevent_UPGRADE_START = 29
constant integer playerunitevent_UPGRADE_CANCEL = 30
constant integer playerunitevent_UPGRADE_FINISH = 31
constant integer playerunitevent_TRAIN_START = 32
constant integer playerunitevent_TRAIN_CANCEL = 33
constant integer playerunitevent_TRAIN_FINISH = 34
constant integer playerunitevent_RESEARCH_START = 35
constant integer playerunitevent_RESEARCH_CANCEL = 36
constant integer playerunitevent_RESEARCH_FINISH = 37
constant integer playerunitevent_ISSUED_ORDER = 38
constant integer playerunitevent_ISSUED_POINT_ORDER = 39
constant integer playerunitevent_ISSUED_TARGET_ORDER = 40
constant integer playerunitevent_ISSUED_UNIT_ORDER = 40 // for compat
constant integer playerunitevent_HERO_LEVEL = 41
constant integer playerunitevent_HERO_SKILL = 42
constant integer playerunitevent_HERO_REVIVABLE = 43
constant integer playerunitevent_HERO_REVIVE_START = 44
constant integer playerunitevent_HERO_REVIVE_CANCEL = 45
constant integer playerunitevent_HERO_REVIVE_FINISH = 46
constant integer playerunitevent_SUMMON = 47
constant integer playerunitevent_DROP_ITEM = 48
constant integer playerunitevent_PICKUP_ITEM = 49
constant integer playerunitevent_USE_ITEM = 50
constant integer playerunitevent_LOADED = 51
/**
* For use with RegisterUnitEvent
*/
constant integer unitevent_DAMAGED = 52
constant integer unitevent_DEATH = 53
constant integer unitevent_DECAY = 54
constant integer unitevent_DETECTED = 55
constant integer unitevent_HIDDEN = 56
constant integer unitevent_SELECTED = 57
constant integer unitevent_DESELECTED = 58
constant integer unitevent_STATE_LIMIT = 59
constant integer unitevent_ACQUIRED_TARGET = 60
constant integer unitevent_TARGET_IN_RANGE = 61
constant integer unitevent_ATTACKED = 62
constant integer unitevent_RESCUED = 63
constant integer unitevent_CONSTRUCT_CANCEL = 64
constant integer unitevent_CONSTRUCT_FINISH = 65
constant integer unitevent_UPGRADE_START = 66
constant integer unitevent_UPGRADE_CANCEL = 67
constant integer unitevent_UPGRADE_FINISH = 68
constant integer unitevent_TRAIN_START = 69
constant integer unitevent_TRAIN_CANCEL = 70
constant integer unitevent_TRAIN_FINISH = 71
constant integer unitevent_RESEARCH_START = 72
constant integer unitevent_RESEARCH_CANCEL = 73
constant integer unitevent_RESEARCH_FINISH = 74
constant integer unitevent_ISSUED_ORDER = 75
constant integer unitevent_ISSUED_POINT_ORDER = 76
constant integer unitevent_ISSUED_TARGET_ORDER = 77
constant integer unitevent_HERO_LEVEL = 78
constant integer unitevent_HERO_SKILL = 79
constant integer unitevent_HERO_REVIVABLE = 80
constant integer unitevent_HERO_REVIVE_START = 81
constant integer unitevent_HERO_REVIVE_CANCEL = 82
constant integer unitevent_HERO_REVIVE_FINISH = 83
constant integer unitevent_SUMMON = 84
constant integer unitevent_DROP_ITEM = 85
constant integer unitevent_PICKUP_ITEM = 86
constant integer unitevent_USE_ITEM = 87
constant integer unitevent_LOADED = 88
/**
* For use with RegisterGameEvent
*/
constant integer gameevent_LOADED = 256
constant integer gameevent_TOURNAMENT_FINISH_SOON = 257
constant integer gameevent_TOURNAMENT_FINISH_NOW = 258
constant integer gameevent_SAVE = 259
/**
* For use with RegisterPlayerEvent
*/
constant integer playerevent_ARROW_LEFT_DOWN = 261
constant integer playerevent_ARROW_LEFT_UP = 262
constant integer playerevent_ARROW_RIGHT_DOWN = 263
constant integer playerevent_ARROW_RIGHT_UP = 264
constant integer playerevent_ARROW_DOWN_DOWN = 265
constant integer playerevent_ARROW_DOWN_UP = 266
constant integer playerevent_ARROW_UP_DOWN = 267
constant integer playerevent_ARROW_UP_UP = 268
constant integer playerevent_MOUSE_DOWN = 269
constant integer playerevent_MOUSE_UP = 270
constant integer playerevent_MOUSE_MOVE = 271
/**
* For use with RegisterPlayerUnitEvent
*/
constant integer playerunitevent_SELL = 272
constant integer playerunitevent_CHANGE_OWNER = 273
constant integer playerunitevent_SELL_ITEM = 274
constant integer playerunitevent_SPELL_CHANNEL = 275
constant integer playerunitevent_SPELL_CAST = 276
constant integer playerunitevent_SPELL_EFFECT = 277
constant integer playerunitevent_SPELL_FINISH = 278
constant integer playerunitevent_SPELL_ENDCAST = 279
constant integer playerunitevent_PAWN_ITEM = 280
/**
* For use with RegisterUnitEvent
*/
constant integer unitevent_SELL = 289
constant integer unitevent_CHANGE_OWNER = 290
constant integer unitevent_SELL_ITEM = 291
constant integer unitevent_SPELL_CHANNEL = 292
constant integer unitevent_SPELL_CAST = 293
constant integer unitevent_SPELL_EFFECT = 294
constant integer unitevent_SPELL_FINISH = 295
constant integer unitevent_SPELL_ENDCAST = 296
constant integer unitevent_PAWN_ITEM = 297
endglobals
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 nothing
call RegisterNativeEventTrigger(whichIndex, whichEvent)
call TriggerAddCondition(GetIndexNativeEventTrigger(whichIndex, whichEvent), Condition(func))
endfunction
function RegisterNativeEvent takes integer whichEvent, code func returns nothing
call RegisterIndexNativeEvent(bj_MAX_PLAYER_SLOTS, whichEvent, 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
function EnableAnyPlayerUnitEvent takes playerunitevent whichEvent returns nothing
local trigger t = GetNativeEventTrigger(GetHandleId(whichEvent))
call EnableTrigger(t)
set t = null
endfunction
function DisableAnyPlayerUnitEvent takes playerunitevent whichEvent returns nothing
local trigger t = GetNativeEventTrigger(GetHandleId(whichEvent))
call DisableTrigger(t)
set t = null
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
/*****************************************************************************
*
* RegisterGameEvent v1.0.0.6
* by Bannar
*
* Register version of TriggerRegisterGameEvent.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
* Functions:
*
* function GetGameEventTrigger takes gameevent whichEvent returns trigger
* Retrieves trigger handle for gameevent whichEvent.
*
* function RegisterGameEvent takes gameevent whichEvent, code func returns nothing
* Registers generic gameevent whichEvent adding code func as callback.
*
*****************************************************************************/
library RegisterGameEvent requires RegisterNativeEvent
function GetGameEventTrigger takes gameevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
function RegisterGameEvent takes gameevent whichEvent, code func returns nothing
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
call TriggerRegisterGameEvent(GetNativeEventTrigger(eventId), whichEvent)
endif
call RegisterNativeEvent(eventId, func)
endfunction
endlibrary
/*****************************************************************************
*
* RegisterUnitEvent v1.0.1.2
* by Bannar
*
* Register version of TriggerRegisterUnitEvent.
*
******************************************************************************
*
* Requirements:
*
* RegisterNativeEvent by Bannar
* hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
* Functions:
*
* function GetUnitEventTrigger takes unitevent whichEvent returns trigger
* Retrieves trigger handle for unitevent whichEvent.
*
* function RegisterUnitEvent takes unit whichUnit, unitevent whichEvent, code func returns nothing
* Registers unitevent whichEvent for unit whichUnit adding code func as callback.
*
*****************************************************************************/
library RegisterUnitEvent requires RegisterNativeEvent
function GetUnitEventTrigger takes unitevent whichEvent returns trigger
return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction
function RegisterUnitEvent takes unit whichUnit, unitevent whichEvent, code func returns nothing
local integer unitId = GetHandleId(whichUnit)
local integer eventId = GetHandleId(whichEvent)
if RegisterNativeEventTrigger(unitId, eventId) then
call TriggerRegisterUnitEvent(GetIndexNativeEventTrigger(unitId, eventId), whichUnit, whichEvent)
endif
call RegisterIndexNativeEvent(unitId, eventId, func)
endfunction
endlibrary