Name | Type | is_array | initial_value |
if Debug then Debug.beginFile 'TotalInitialization' end
--[[ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Total Initialization version 5.3.1
Created by: Bribe
Contributors: Eikonium, HerlySQR, Tasyen, Luashine, Forsakn
Inspiration: Almia, ScorpioT1000, Troll-Brain
Hosted at: https://github.com/BribeFromTheHive/Lua/blob/master/TotalInitialization.lua
Debug library hosted at: https://www.hiveworkshop.com/threads/debug-utils-ingame-console-etc.330758/
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ]]
---Calls the user's initialization function during the map's loading process. The first argument should either be the init function,
---or it should be the string to give the initializer a name (works similarly to a module name/identically to a vJass library name).
---
---To use requirements, call `Require.strict 'LibraryName'` or `Require.optional 'LibraryName'`. Alternatively, the OnInit callback
---function can take the `Require` table as a single parameter: `OnInit(function(import) import.strict 'ThisIsTheSameAsRequire' end)`.
---
-- - `OnInit.global` or just `OnInit` is called after InitGlobals and is the standard point to initialize.
-- - `OnInit.trig` is called after InitCustomTriggers, and is useful for removing hooks that should only apply to GUI events.
-- - `OnInit.map` is the last point in initialization before the loading screen is completed.
-- - `OnInit.final` occurs immediately after the loading screen has disappeared, and the game has started.
---@class OnInit
--
--Simple Initialization without declaring a library name:
---@overload async fun(initCallback: Initializer.Callback)
--
--Advanced initialization with a library name and an optional third argument to signal to Eikonium's DebugUtils that the file has ended.
---@overload async fun(libraryName: string, initCallback: Initializer.Callback, debugLineNum?: integer)
--
--A way to yield your library to allow other libraries in the same initialization sequence to load, then resume once they have loaded.
---@overload async fun(customInitializerName: string)
OnInit = {}
---@alias Initializer.Callback fun(require?: Requirement | {[string]: Requirement}):...?
---@alias Requirement async fun(reqName: string, source?: table): unknown
-- `Require` will yield the calling `OnInit` initialization function until the requirement (referenced as a string) exists. It will check the
-- global API (for example, does 'GlobalRemap' exist) and then check for any named OnInit resources which might use that same string as its name.
--
-- Due to the way Sumneko's syntax highlighter works, the return value will only be linted for defined @class objects (and doesn't work for regular
-- globals like `TimerStart`). I tried to request the functionality here: https://github.com/sumneko/lua-language-server/issues/1792 , however it
-- was closed. Presumably, there are other requests asking for it, but I wouldn't count on it.
--
-- To declare a requirement, use: `Require.strict 'SomeLibrary'` or (if you don't care about the missing linting functionality) `Require 'SomeLibrary'`
--
-- To optionally require something, use any other suffix (such as `.optionally` or `.nonstrict`): `Require.optional 'SomeLibrary'`
--
---@class Require: { [string]: Requirement }
---@overload async fun(reqName: string, source?: table): string
Require = {}
do
local library = {} --You can change this to false if you don't use `Require` nor the `OnInit.library` API.
--CONFIGURABLE LEGACY API FUNCTION:
---@param _ENV table
---@param OnInit any
local function assignLegacyAPI(_ENV, OnInit)
OnGlobalInit = OnInit; OnTrigInit = OnInit.trig; OnMapInit = OnInit.map; OnGameStart = OnInit.final --Global Initialization Lite API
--OnMainInit = OnInit.main; OnLibraryInit = OnInit.library; OnGameInit = OnInit.final --short-lived experimental API
--onGlobalInit = OnInit; onTriggerInit = OnInit.trig; onInitialization = OnInit.map; onGameStart = OnInit.final --original Global Initialization API
--OnTriggerInit = OnInit.trig; OnInitialization = OnInit.map --Forsakn's Ordered Indices API
end
--END CONFIGURABLES
local _G, rawget, insert =
_G, rawget, table.insert
local initFuncQueue = {}
---@param name string
---@param continue? function
local function runInitializers(name, continue)
--print('running:', name, tostring(initFuncQueue[name]))
if initFuncQueue[name] then
for _,func in ipairs(initFuncQueue[name]) do
coroutine.wrap(func)(Require)
end
initFuncQueue[name] = nil
end
if library then
library:resume()
end
if continue then
continue()
end
end
local function initEverything()
---@param hookName string
---@param continue? function
local function hook(hookName, continue)
local hookedFunc = rawget(_G, hookName)
if hookedFunc then
rawset(_G, hookName,
function()
hookedFunc()
runInitializers(hookName, continue)
end
)
else
runInitializers(hookName, continue)
end
end
hook(
'InitGlobals',
function()
hook(
'InitCustomTriggers',
function()
hook('RunInitializationTriggers')
end
)
end
)
hook(
'MarkGameStarted',
function()
if library then
for _,func in ipairs(library.queuedInitializerList) do
func(nil, true) --run errors for missing requirements.
end
for _,func in pairs(library.yieldedModuleMatrix) do
func(true) --run errors for modules that aren't required.
end
end
OnInit = nil
Require = nil
end
)
end
---@param initName string
---@param libraryName string | Initializer.Callback
---@param func? Initializer.Callback
---@param debugLineNum? integer
---@param incDebugLevel? boolean
local function addUserFunc(initName, libraryName, func, debugLineNum, incDebugLevel)
if not func then
---@cast libraryName Initializer.Callback
func = libraryName
else
assert(type(libraryName) == 'string')
if debugLineNum and Debug then
Debug.beginFile(libraryName, incDebugLevel and 3 or 2)
Debug.data.sourceMap[#Debug.data.sourceMap].lastLine = debugLineNum
end
if library then
func = library:create(libraryName, func)
end
end
assert(type(func) == 'function')
--print('adding user func: ' , initName , libraryName, debugLineNum, incDebugLevel)
initFuncQueue[initName] = initFuncQueue[initName] or {}
insert(initFuncQueue[initName], func)
if initName == 'root' or initName == 'module' then
runInitializers(initName)
end
end
---@param name string
local function createInit(name)
---@async
---@param libraryName string --Assign your callback a unique name, allowing other OnInit callbacks can use it as a requirement.
---@param userInitFunc Initializer.Callback --Define a function to be called at the chosen point in the initialization process. It can optionally take the `Require` object as a parameter. Its optional return value(s) are passed to a requiring library via the `Require` object (defaults to `true`).
---@param debugLineNum? integer --If the Debug library is present, you can call Debug.getLine() for this parameter (which should coincide with the last line of your script file). This will neatly tie-in with OnInit's built-in Debug library functionality to define a starting line and an ending line for your module.
---@overload async fun(userInitFunc: Initializer.Callback)
return function(libraryName, userInitFunc, debugLineNum)
addUserFunc(name, libraryName, userInitFunc, debugLineNum)
end
end
OnInit.global = createInit 'InitGlobals' -- Called after InitGlobals, and is the standard point to initialize.
OnInit.trig = createInit 'InitCustomTriggers' -- Called after InitCustomTriggers, and is useful for removing hooks that should only apply to GUI events.
OnInit.map = createInit 'RunInitializationTriggers' -- Called last in the script's loading screen sequence. Runs after the GUI "Map Initialization" events have run.
OnInit.final = createInit 'MarkGameStarted' -- Called immediately after the loading screen has disappeared, and the game has started.
do
---@param self table
---@param libraryNameOrInitFunc function | string
---@param userInitFunc function
---@param debugLineNum number
local function __call(
self,
libraryNameOrInitFunc,
userInitFunc,
debugLineNum
)
if userInitFunc or type(libraryNameOrInitFunc) == 'function' then
addUserFunc(
'InitGlobals', --Calling OnInit directly defaults to OnInit.global (AKA OnGlobalInit)
libraryNameOrInitFunc,
userInitFunc,
debugLineNum,
true
)
elseif library then
library:declare(libraryNameOrInitFunc) --API handler for OnInit "Custom initializer"
else
error(
"Bad OnInit args: "..
tostring(libraryNameOrInitFunc) .. ", " ..
tostring(userInitFunc)
)
end
end
setmetatable(OnInit --[[@as table]], { __call = __call })
end
do --if you don't need the initializers for 'root', 'config' and 'main', you can delete this do...end block.
local gmt = getmetatable(_G) or
getmetatable(setmetatable(_G, {}))
local rawIndex = gmt.__newindex or rawset
local hookMainAndConfig
---@param _G table
---@param key string
---@param fnOrDiscard unknown
function hookMainAndConfig(_G, key, fnOrDiscard)
if key == 'main' or key == 'config' then
---@cast fnOrDiscard function
if key == 'main' then
runInitializers 'root'
end
rawIndex(_G, key, function()
if key == 'config' then
fnOrDiscard()
elseif gmt.__newindex == hookMainAndConfig then
gmt.__newindex = rawIndex --restore the original __newindex if no further hooks on __newindex exist.
end
runInitializers(key)
if key == 'main' then
fnOrDiscard()
end
end)
else
rawIndex(_G, key, fnOrDiscard)
end
end
gmt.__newindex = hookMainAndConfig
OnInit.root = createInit 'root' -- Runs immediately during the Lua root, but is yieldable (allowing requirements) and pcalled.
OnInit.config = createInit 'config' -- Runs when `config` is called. Credit to @Luashine: https://www.hiveworkshop.com/threads/inject-main-config-from-we-trigger-code-like-jasshelper.338201/
OnInit.main = createInit 'main' -- Runs when `main` is called. Idea from @Tasyen: https://www.hiveworkshop.com/threads/global-initialization.317099/post-3374063
end
if library then
library.queuedInitializerList = {}
library.customDeclarationList = {}
library.yieldedModuleMatrix = {}
library.moduleValueMatrix = {}
function library:pack(name, ...)
self.moduleValueMatrix[name] = table.pack(...)
end
function library:resume()
if self.queuedInitializerList[1] then
local continue, tempQueue, forceOptional
::initLibraries::
repeat
continue=false
self.queuedInitializerList, tempQueue =
{}, self.queuedInitializerList
for _,func in ipairs(tempQueue) do
if func(forceOptional) then
continue=true --Something was initialized; therefore further systems might be able to initialize.
else
insert(self.queuedInitializerList, func) --If the queued initializer returns false, that means its requirement wasn't met, so we re-queue it.
end
end
until not continue or not self.queuedInitializerList[1]
if self.customDeclarationList[1] then
self.customDeclarationList, tempQueue =
{}, self.customDeclarationList
for _,func in ipairs(tempQueue) do
func() --unfreeze any custom initializers.
end
elseif not forceOptional then
forceOptional = true
else
return
end
goto initLibraries
end
end
local function declareName(name, initialValue)
assert(type(name) == 'string')
assert(library.moduleValueMatrix[name] == nil)
library.moduleValueMatrix[name] =
initialValue and { true, n = 1 }
end
function library:create(name, userFunc)
assert(type(userFunc) == 'function')
declareName(name, false) --declare itself as a non-loaded library.
return function()
self:pack(name, userFunc(Require)) --pack return values to allow multiple values to be communicated.
if self.moduleValueMatrix[name].n == 0 then
self:pack(name, true) --No values were returned; therefore simply package the value as `true`
end
end
end
---@async
function library:declare(name)
declareName(name, true) --declare itself as a loaded library.
local co = coroutine.running()
insert(
self.customDeclarationList,
function()
coroutine.resume(co)
end
)
coroutine.yield() --yields the calling function until after all currently-queued initializers have run.
end
local processRequirement
---@async
function processRequirement(
optional,
requirement,
explicitSource
)
if type(optional) == 'string' then
optional, requirement, explicitSource =
true, optional, requirement --optional requirement (processed by the __index method)
else
optional = false --strict requirement (processed by the __call method)
end
local source = explicitSource or _G
assert(type(source)=='table')
assert(type(requirement)=='string')
::reindex::
local subSource, subReq =
requirement:match("([\x25w_]+)\x25.(.+)") --Check if user is requiring using "table.property" syntax
if subSource and subReq then
source,
requirement =
processRequirement(subSource, source), --If the container is nil, yield until it is not.
subReq
if type(source)=='table' then
explicitSource = source
goto reindex --check for further nested properties ("table.property.subProperty.anyOthers").
else
return --The source table for the requirement wasn't found, so disregard the rest (this only happens with optional requirements).
end
end
local function loadRequirement(unpack)
local package = rawget(source, requirement) --check if the requirement exists in the host table.
if not package and not explicitSource then
if library.yieldedModuleMatrix[requirement] then
library.yieldedModuleMatrix[requirement]() --load module if it exists
end
package = library.moduleValueMatrix[requirement] --retrieve the return value from the module.
if unpack and type(package)=='table' then
return table.unpack(package, 1, package.n) --using unpack allows any number of values to be returned by the required library.
end
end
return package
end
local co, loaded
local function checkReqs(forceOptional, printErrors)
if not loaded then
loaded = loadRequirement()
loaded = loaded or optional and
(loaded==nil or forceOptional)
if loaded then
if co then coroutine.resume(co) end --resume only if it was yielded in the first place.
return loaded
elseif printErrors then
coroutine.resume(co, true)
end
end
end
if not checkReqs() then --only yield if the requirement doesn't already exist.
co = coroutine.running()
insert(library.queuedInitializerList, checkReqs)
if coroutine.yield() then
error("Missing Requirement: "..requirement) --handle the error within the user's function to get an accurate stack trace via the `try` function.
end
end
return loadRequirement(true)
end
---@type Requirement
function Require.strict(name, explicitSource)
return processRequirement(nil, name, explicitSource)
end
setmetatable(Require --[[@as table]], {
__call = processRequirement,
__index = function()
return processRequirement
end
})
local module = createInit 'module'
--- `OnInit.module` will only call the OnInit function if the module is required by another resource, rather than being called at a pre-
--- specified point in the loading process. It works similarly to Go, in that including modules in your map that are not actually being
--- required will throw an error message.
---@param name string
---@param func Initializer.Callback
---@param debugLineNum? integer
OnInit.module = function(name, func, debugLineNum)
if func then
local userFunc = func
func = function(require)
local co = coroutine.running()
library.yieldedModuleMatrix[name] =
function(failure)
library.yieldedModuleMatrix[name] = nil
coroutine.resume(co, failure)
end
if coroutine.yield() then
error("Module declared but not required: "..name)
end
return userFunc(require)
end
end
module(name, func, debugLineNum)
end
end
if assignLegacyAPI then --This block handles legacy code.
---Allows packaging multiple requirements into one table and queues the initialization for later.
---@deprecated
---@param initList string | table
---@param userFunc function
function OnInit.library(initList, userFunc)
local typeOf = type(initList)
assert(typeOf=='table' or typeOf=='string')
assert(type(userFunc) == 'function')
local function caller(use)
if typeOf=='string' then
use(initList)
else
for _,initName in ipairs(initList) do
use(initName)
end
if initList.optional then
for _,initName in ipairs(initList.optional) do
use.lazily(initName)
end
end
end
end
if initList.name then
OnInit(initList.name, caller)
else
OnInit(caller)
end
end
local legacyTable = {}
assignLegacyAPI(legacyTable, OnInit)
for key,func in pairs(legacyTable) do
rawset(_G, key, func)
end
OnInit.final(function()
for key in pairs(legacyTable) do
rawset(_G, key, nil)
end
end)
end
initEverything()
end
if Debug then Debug.endFile() end
library GridSystem initializer init
globals
private image array gridEffect
private boolean showHide
private boolean waitForClick
private integer gridRed = 200
private integer gridGreen = 200
private integer gridBlue = 200
private integer gridAlpha = 255
private integer gridSize = 8
private integer gridSizeMax = 24
private integer gridSizeMin = 4
endglobals
private function ShowHideGrid takes nothing returns nothing
local integer i = 0
if GetLocalPlayer() == GetTriggerPlayer() then
if showHide then
set showHide = false
loop
exitwhen i >= gridSizeMax * gridSizeMax
call SetImageColor(gridEffect[i],255,255,255,0)
set i = i + 1
endloop
else
set waitForClick = true
endif
endif
endfunction
private function MouseMove takes nothing returns nothing endfunction
local real x = I2R(R2I(BlzGetTriggerPlayerMouseX()) / 128) * 128
local real y = I2R(R2I(BlzGetTriggerPlayerMouseY()) / 128) * 128
local real tx
local real ty
local integer i = 0
local integer ix = 0
local integer iy = 0
if GetLocalPlayer() == GetTriggerPlayer() then
if waitForClick then
set waitForClick = false
set showHide = true
loop
exitwhen i >= gridSize * gridSize
set tx = x + ix * 128 - gridSize / 2 * 128
set ty = y + iy * 128 - gridSize / 2 * 128
call SetImageColor(gridEffect[i],gridRed,gridGreen,gridBlue,gridAlpha)
call SetImagePosition(gridEffect[i],tx,ty,0)
set ix = ix + 1
if ix >= gridSize then
set ix = 0
set iy = iy + 1
endif
set i = i + 1
endloop
endif
endif
endfunction
private function GetHexSignValue takes string sign returns integer
if sign == "a" or sign == "A" then
return 10
endif
if sign == "b" or sign == "B" then
return 11
endif
if sign == "c" or sign == "C" then
return 12
endif
if sign == "d" or sign == "D" then
return 13
endif
if sign == "e" or sign == "E" then
return 14
endif
if sign == "f" or sign == "F" then
return 15
endif
return S2I(sign)
endfunction
private function SetGridProp takes nothing returns nothing
local string s = GetEventPlayerChatString()
local integer i = 0
if SubString(s, 0, 4) == "-gc " and GetLocalPlayer() == GetTriggerPlayer() then
set gridRed = GetHexSignValue(SubString(s, 4, 5)) * 16 + GetHexSignValue(SubString(s, 5, 6))
set gridGreen = GetHexSignValue(SubString(s, 6, 7)) * 16 + GetHexSignValue(SubString(s, 7, 8))
set gridBlue = GetHexSignValue(SubString(s, 8, 9)) * 16 + GetHexSignValue(SubString(s, 9, 10))
if showHide then
loop
exitwhen i >= gridSize * gridSize
call SetImageColor(gridEffect[i],gridRed,gridGreen,gridBlue,gridAlpha)
set i = i + 1
endloop
endif
return
endif
if SubString(s, 0, 4) == "-gs " and GetLocalPlayer() == GetTriggerPlayer() then
set gridSize = S2I(SubString(s, 4, 6))
if gridSize < gridSizeMin then
set gridSize = gridSizeMin
endif
if gridSize > gridSizeMax then
set gridSize = gridSizeMax
endif
set showHide = true
call ShowHideGrid()
endif
endfunction
private function init takes nothing returns nothing
local integer i = 0
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
call TriggerAddAction(t, function ShowHideGrid)
call TriggerAddAction(t2, function MouseMove)
call TriggerAddAction(t3, function SetGridProp)
loop
exitwhen i > 23
call BlzTriggerRegisterPlayerKeyEvent(t, Player(i),OSKEY_G,0,true)
call TriggerRegisterPlayerEvent(t2, Player(i), EVENT_PLAYER_MOUSE_DOWN)
call TriggerRegisterPlayerChatEvent( t3, Player(i), "", false )
set i = i + 1
endloop
set showHide = false
set waitForClick = false
set i = 0
loop
exitwhen i >= gridSizeMax * gridSizeMax
set gridEffect[i] = CreateImage("Gridplane4x4.dds",128,128,0,0,0,0, 1,1,1, 1)
call SetImageRenderAlways( gridEffect[i], true )
call SetImageColor( gridEffect[i], 255, 255, 255, 0)
set i = i + 1
endloop
endfunction
endlibrary
scope MapGrid initializer Init
globals
private constant string ACTIVATOR = "-grid"
private constant string IMAGE_TEXTURE_PATH = "Gridplane2x2.dds"
private constant integer RED = 255
private constant integer GREEN = 0
private constant integer BLUE = 0
private constant integer ALPHA = 255
private real minX
private real minY
private real maxX
private real maxY
private integer gridWidth
private integer gridHeight
private image array gridImages
private integer imageCount = 0
private boolean showHide = false
endglobals
private function Ceil takes real value returns integer
local integer i = R2I(value)
if value > I2R(i) then
return i + 1
endif
return i
endfunction
private function ToggleGrid takes nothing returns nothing
local player trigPlayer = GetTriggerPlayer()
local integer i = 0
if trigPlayer != GetLocalPlayer() then
return
endif
set showHide = not showHide
loop
exitwhen i >= imageCount
call SetImageRenderAlways(gridImages[i], showHide)
set i = i + 1
endloop
endfunction
private function Init takes nothing returns nothing
local trigger t
local integer i = 0
local integer ix
local integer iy
local real tx
local real ty
set minX = GetRectMinX(bj_mapInitialPlayableArea)
set minY = GetRectMinY(bj_mapInitialPlayableArea)
set maxX = GetRectMaxX(bj_mapInitialPlayableArea)
set maxY = GetRectMaxY(bj_mapInitialPlayableArea)
set gridWidth = Ceil((maxX - minX) / 64)
set gridHeight = Ceil((maxY - minY) / 64)
set imageCount = 0
set iy = 0
loop
exitwhen iy >= gridHeight
set ix = 0
loop
exitwhen ix >= gridWidth
set tx = minX + 64. * ix
set ty = minY + 64. * iy
if not IsTerrainPathable(tx, ty, PATHING_TYPE_BUILDABILITY) then
set gridImages[imageCount] = CreateImage(IMAGE_TEXTURE_PATH, 64, 64, 10., tx, ty, 0., 0, 0, 0, 1)
call SetImageRenderAlways(gridImages[imageCount], false)
call SetImageColor(gridImages[imageCount], RED, GREEN, BLUE, ALPHA)
set imageCount = imageCount + 1
endif
set ix = ix + 1
endloop
set iy = iy + 1
endloop
set t = CreateTrigger()
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerChatEvent(t, Player(i), ACTIVATOR, false)
set i = i + 1
endloop
call TriggerAddAction(t, function ToggleGrid)
set t = null
return
endfunction
endscope
OnInit.global("AllPlayerGrid", function(require)
local BUTTON_KEY = OSKEY_G
GridSystem = {}
function GridSystem:init()
self.gridEffect = {}
self.showHide = false
self.waitForClick = false
self.gridRed = 200
self.gridGreen = 200
self.gridBlue = 200
self.gridAlpha = 255
self.gridSize = 8
self.gridSizeMax = 32
self.gridSizeMin = 4
for i = 1, self.gridSizeMax * self.gridSizeMax do
self.gridEffect[i] = CreateImage("Gridplane4x4.dds", 128, 128, 0, 0, 0, 0, 1, 1, 1, 1)
SetImageRenderAlways(self.gridEffect[i], true)
SetImageColor(self.gridEffect[i], 255, 255, 255, 0)
end
local t = CreateTrigger()
local t2 = CreateTrigger()
local t3 = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS do
BlzTriggerRegisterPlayerKeyEvent(t, Player(i), BUTTON_KEY, 0, true)
TriggerRegisterPlayerEvent(t2, Player(i), EVENT_PLAYER_MOUSE_DOWN)
TriggerRegisterPlayerChatEvent(t3, Player(i), "", false)
end
TriggerAddAction(t, function() self:ShowHideGrid() end)
TriggerAddAction(t2, function() self:MouseMove() end)
TriggerAddAction(t3, function() self:SetGridProp() end)
end
function GridSystem:ShowHideGrid()
if GetLocalPlayer() ~= GetTriggerPlayer() then
return
end
if self.showHide then
self.showHide = false
for i, image in ipairs(self.gridEffect) do
SetImageColor(image, 255, 255, 255, 0)
end
else
self.waitForClick = true
end
end
function GridSystem:MouseMove()
local x = math.floor(BlzGetTriggerPlayerMouseX() / 128) * 128
local y = math.floor(BlzGetTriggerPlayerMouseY() / 128) * 128
if GetLocalPlayer() ~= GetTriggerPlayer() or not self.waitForClick then return end
self.waitForClick = false
self.showHide = true
local ix, iy = 0, 0
for i, image in ipairs(self.gridEffect) do
if i > self.gridSize * self.gridSize then break end
local tx = x + ix * 128 - self.gridSize / 2 * 128
local ty = y + iy * 128 - self.gridSize / 2 * 128
SetImageColor(image, self.gridRed, self.gridGreen, self.gridBlue, self.gridAlpha)
SetImagePosition(image, tx, ty, 0)
ix = ix + 1
if ix >= self.gridSize then
ix = 0
iy = iy + 1
end
end
end
function GridSystem:GetHexSignValue(sign)
local hex = { ["a"] = 10, ["b"] = 11, ["c"] = 12, ["d"] = 13, ["e"] = 14, ["f"] = 15 }
return hex[sign:lower()] or tonumber(sign)
end
function GridSystem:SetGridProp()
local s = GetEventPlayerChatString()
if GetLocalPlayer() ~= GetTriggerPlayer() then
return
end
if s:sub(1, 4) == "-gc " then
self.gridRed = self:GetHexSignValue(s:sub(5, 5)) * 16 + self:GetHexSignValue(s:sub(6, 6))
self.gridGreen = self:GetHexSignValue(s:sub(7, 7)) * 16 + self:GetHexSignValue(s:sub(8, 8))
self.gridBlue = self:GetHexSignValue(s:sub(9, 9)) * 16 + self:GetHexSignValue(s:sub(10, 10))
if self.showHide then
for i, image in ipairs(self.gridEffect) do
if i > self.gridSize * self.gridSize then break end
SetImageColor(image, self.gridRed, self.gridGreen, self.gridBlue, self.gridAlpha)
end
end
elseif s:sub(1, 4) == "-gs " then
self.gridSize = tonumber(s:sub(5, 7))
self.gridSize = math.max(self.gridSizeMin, math.min(self.gridSize, self.gridSizeMax))
self.showHide = true
self:ShowHideGrid()
end
end
GridSystem:init()
end)
OnInit.global("MapGrid", function(require)
local ACTIVATOR = "-grid"
local IMAGE_TEXTURE_PATH = "Gridplane2x2.dds"
local RED = 255
local GREEN = 0
local BLUE = 0
local ALPHA = 255
GridSystem = {}
function GridSystem:init()
self.minX = GetRectMinX(bj_mapInitialPlayableArea)
self.minY = GetRectMinY(bj_mapInitialPlayableArea)
self.maxX = GetRectMaxX(bj_mapInitialPlayableArea)
self.maxY = GetRectMaxY(bj_mapInitialPlayableArea)
self.gridWidth = math.ceil((self.maxX - self.minX) / 64)
self.gridHeight = math.ceil((self.maxY - self.minY) / 64)
self.gridEffect = {}
self.showHide = false
local index = 0
for iy = 0, self.gridHeight - 1 do
for ix = 0, self.gridWidth - 1 do
local tx = self.minX + ix * 64
local ty = self.minY + iy * 64
if IsTerrainPathable(tx, ty, PATHING_TYPE_BUILDABILITY) == false then
index = index + 1
self.gridEffect[index] = CreateImage(IMAGE_TEXTURE_PATH, 64, 64, 10, tx, ty, 0, 0, 0, 0, 1)
SetImageRenderAlways(self.gridEffect[index], true)
SetImageRenderAlways(self.gridEffect[index], false)
SetImageColor(self.gridEffect[index], RED, GREEN, BLUE, ALPHA)
end
end
end
local t = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
TriggerRegisterPlayerChatEvent(t, Player(i), ACTIVATOR, false)
end
TriggerAddAction(t, function() self:toggleGrid() end)
-- Useful debug prints
--print(self.gridWidth)
--print(self.gridHeight)
--print(#self.gridEffect)
end
function GridSystem:toggleGrid()
if GetLocalPlayer() ~= GetTriggerPlayer() then return end
self.showHide = not self.showHide
for _, image in ipairs(self.gridEffect) do
SetImageRenderAlways(image, self.showHide)
end
end
GridSystem:init()
end)
OnInit.global("AllClearText", function(require)
local t = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
BlzTriggerRegisterPlayerKeyEvent(t, Player(i), OSKEY_ESCAPE, 0, true)
end
TriggerAddAction(t, function()
if GetTriggerPlayer() == GetLocalPlayer() then
ClearTextMessages()
end
end)
end)