Name | Type | is_array | initial_value |
-- do not edit -->
Hashtable = InitHashtable() ---@type hashtable
frameChatHistory = {} ---@type framehandle
frameMain = {} ---@type framehandle
frameMessagePanel = {} ---@type framehandle
Iterator = 1 ---@type integer
gameTime = 0 ---@type integer
tempPrev = 0 ---@type integer
DURATION_HASH = StringHash("Duration") ---@type integer
FRAME_HASH = StringHash("Frame") ---@type integer
CHAT_SYSTEM_VERSION = "0.1" ---@type string
-- <-- do not edit
-- Chat related
COMMAND_SYNTAX = "-" ---@type string -- syntax that indicates a command, can have any length, just no spacebar
MESSAGE_LENGTH_LIMIT = 128 ---@type integer -- maximum length of a player message
MESSAGE_SIZE_OVERFLOW = "MESSAGE SIZE OVERFLOW [LIMIT: " .. MESSAGE_LENGTH_LIMIT .. "]" ---@type string
MAX_MESSAGES = 1000 ---@type integer -- better not touch this
-- Frame position (scales with resolution)
CHAT_REFPOINT = FRAMEPOINT_BOTTOMLEFT ---@type framepointtype -- from which point of screen the X and Y calculate
CHAT_X = 0.0222 ---@type real
CHAT_Y = 0.2106 ---@type real
-- Text alignment
CHAT_FONT = "Fonts\\BLQ55Web.ttf" ---@type string -- font used by messages (default wc3 chat font is "Fonts\\BLQ55Web.ttf")
FONT_SIZE = 0.012 ---@type real -- font size of messages
MESSAGE_DURATION = 500 ---@type integer -- Message disappears after this duration (in 500 == 5.00 seconds)
-- Chat Player related
systemIcon = nil ---@type string -- icon infront of system message text (if null or "", it will be hidden)-- the color of player name (not sure if null will work, better use "")
playerColor = {
[0] = "|cffff0303",
[1] = "|cff0042ff",
[2] = "|cff1ce6b9",
[3] = "|cff540081",
[4] = "|cfffffc01",
[5] = "|cfffe8a0e",
[6] = "|cff20c000",
[7] = "|cffe55bb0",
[8] = "|cff959697",
[9] = "|cff7ebff1",
[10] = "|cff106246",
[11] = "|cff4e2a04",
[12] = "|cff9B0000",
[13] = "|cff0000C3",
[14] = "|cff00EAFF",
[15] = "|cffBE00FE",
[16] = "|cffEBCD87",
[17] = "|cffF8A48B",
[18] = "|cffBFFF80",
[19] = "|cffDCB9EB",
[20] = "|cff282828",
[21] = "|cffEBF0FF",
[22] = "|cff00781E",
[23] = "|cffA46F33"
} ---@type string -- icon infront of player name (if null or "", it will hidden)
playerIcon = {
[0] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[1] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[2] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[3] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[4] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[5] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[6] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[7] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[8] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[9] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[10] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[11] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[12] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[13] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[14] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[15] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[16] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[17] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[18] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[19] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[20] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[21] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[22] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp",
[23] = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp"
} ---@type string
function err(x)
BJDebugMsg(x)
return x
end
function enum(tbl)
local length = #tbl
for i = 1, length do
local v = tbl[i]
tbl[v] = i
end
return tbl
end
UNKNOWN_MESSAGE_TYPE = "[|cffe6a200Unknown|r]" ---@type string
SYSTEM_MESSAGE_TYPE = "[|cffe6a200System|r]" ---@type string -- system messages are marked with this
ALL_PLAYERS_MESSAGE_TYPE = "[|cff00e6e2Global|r]" ---@type string
ALLIED_PLAYERS_MESSAGE_TYPE = "[|cff003ae6Allies|r]" ---@type string
PRIVATE_PLAYERS_MESSAGE_TYPE = "[|cff01b31cPrivate|r]" ---@type string
MessageTypes = enum {
UNKNOWN = 0, ---@type string
SYSTEM = 1, ---@type string
ALL = 2, ---@type string
ALLIED = 3, ---@type string
PRIVATE = 4 ---@type string
}
-- Store messages
message = {}
messageIterator = 0 ---@type integer
-- Define the Message Object
Message = {}
Message.new = function(messageReceivers, messageType, messageTime, messageSender, messageContent, messageSync)
local self = {}
local receivers = messageReceivers or 0 ---@type integer
local type = messageType or MessageTypes.UNKNOWN ---@type integer
local time = messageTime or 0 ---@type integer
local sender = messageSender or 24 ---@type integer
local content = messageContent or "" ---@type string
local sync = messageSync or 0 ---@type integer
function self.getReceivers()
return receivers
end
function self.getReceiversFormatted()
local pID = 23 -- reverse order to be able to perform substraction check
local checksum = receivers
local list = ""
if checksum == 0 then
return "null"
end
while (pID >= 0 and checksum ~= 0) do
if GetPlayerController(Player(pID)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(pID)) == PLAYER_SLOT_STATE_PLAYING then
if checksum - R2I(1 * Pow(2, pID)) >= 0 then -- check if player is supposed to receive the message
checksum = checksum - R2I(1 * Pow(2, pID))
if list == "" then
list = pID
else
list = list .. ", " .. pID
end
end
end
pID = pID - 1
end
return list
end
function self.setReceivers(messageReceivers)
receivers = messageReceivers
end
function self.getType()
return type
end
function self.getTypeFormatted()
if type == MessageTypes.SYSTEM then
return SYSTEM_MESSAGE_TYPE
elseif type == MessageTypes.ALL then
return ALL_PLAYERS_MESSAGE_TYPE
elseif type == MessageTypes.ALLIED then
return ALLIED_PLAYERS_MESSAGE_TYPE
elseif type == MessageTypes.PRIVATE then
return PRIVATE_PLAYERS_MESSAGE_TYPE
end
return UNKNOWN_MESSAGE_TYPE
end
function self.setType(messageType)
type = messageType
end
function self.getTime()
return time
end
function self.getTimeFormatted()
return convertTime(messageTime)
end
function self.setTime(messageTime)
time = messageTime
end
function self.getSender()
return sender
end
function self.getSenderFormatted()
return playerColor[sender] .. GetPlayerName(Player(sender))
end
function self.setSender(messageSender)
sender = messageSender
end
function self.getContent()
return content
end
function self.setContent(messageContent)
content = messageContent
end
function self.getSync()
return sync
end
function self.setSync(messageSync)
sync = messageSync
end
return self
end
-- Store messages
frameMessage = {}
frameMessageIterator = 0 ---@type integer
-- Define the Message Object
FrameMessage = {}
FrameMessage.new = function(index)
local self = {}
local main = BlzCreateSimpleFrame("Message", frameMessagePanel, index)
BlzFrameSetSize(main, 0.8, FONT_SIZE + 0.005)
local typeContainer = BlzGetFrameByName("Message Type Container", index)
BlzFrameSetSize(typeContainer, 0.045, FONT_SIZE + 0.005)
local type = BlzGetFrameByName("Message Type", index)
BlzFrameSetSize(type, 0.045, FONT_SIZE + 0.005)
BlzFrameSetFont(type, CHAT_FONT, FONT_SIZE, 0)
local timestampContainer = BlzGetFrameByName("Message Timestamp Container", index)
BlzFrameSetSize(timestampContainer, 0.045, FONT_SIZE + 0.005)
local timestamp = BlzGetFrameByName("Message Timestamp", index)
BlzFrameSetSize(timestamp, 0.045, FONT_SIZE + 0.005)
BlzFrameSetFont(timestamp, CHAT_FONT, FONT_SIZE, 0)
local iconContainer = BlzGetFrameByName("Message Icon Container", index)
BlzFrameSetSize(iconContainer, FONT_SIZE + 0.005, FONT_SIZE + 0.005)
local icon = BlzGetFrameByName("Message Icon", index)
local textContainer = BlzGetFrameByName("Message Text Container", index)
BlzFrameSetSize(textContainer, 0.675, FONT_SIZE + 0.005)
local text = BlzGetFrameByName("Message Text", index)
BlzFrameSetSize(text, 0.675, FONT_SIZE + 0.005)
BlzFrameSetFont(text, CHAT_FONT, FONT_SIZE, 0)
BlzFrameSetVisible(main, false)
BlzFrameSetAlpha(main, 0)
self.timer = CreateTimer()
self.inUse = false
self.startY = 0.
self.currentY = 0.
self.targetY = 0.
self.alpha = -1
self.timeSinceStart = 0.
self.asyncVisibility = false
self.previous = 0
function self.getMain()
return main
end
function self.getTypeContainer()
return typeContainer
end
function self.getType()
return type
end
function self.getTimestampContainer()
return timestampContainer
end
function self.getTimestamp()
return timestamp
end
function self.getIconContainer()
return iconContainer
end
function self.getIcon()
return icon
end
function self.getTextContainer()
return textContainer
end
function self.getText()
return text
end
return self
end
---@param t real
---@return real
function easeInOutSine(t)
return -(Cos(bj_PI * t) - 1.) / 2.
end
---@param time integer
---@return string
function convertTime(time)
local Quotient = time
local minutes = math.floor(Quotient / 60)
local seconds = Quotient - math.floor(Quotient / 60) * 60
if StringLength(minutes) < 2 then
minutes = "0" .. minutes
end
if StringLength(seconds) < 2 then
seconds = "0" .. seconds
end
timestamp = "[" .. minutes .. ":" .. seconds .. "]"
return timestamp
end
---@param content string
---@return boolean
function sizeCheck(content)
if StringLength(content) > MESSAGE_LENGTH_LIMIT then
return false
end
return true
end
---@return nothing
function hideMessage()
xpcall(function()
local HandleID = GetHandleId(GetExpiredTimer())
local current = LoadInteger(Hashtable, HandleID, FRAME_HASH)
local _frameMessage = frameMessage[current]
local prev = _frameMessage.previousFrame -- async
local duration = LoadInteger(Hashtable, HandleID, DURATION_HASH) + 1
SaveInteger(Hashtable, HandleID, DURATION_HASH, duration)
if _frameMessage.asyncVisibility then -- following stuff is all async, and only happens if player was meant to see the message
if (prev == 0 or not frameMessage[prev].inUse or frameMessage[prev].currentY >= FONT_SIZE + 0.005) and _frameMessage.alpha < 0 then
BlzFrameSetPoint(_frameMessage.getMain(), FRAMEPOINT_BOTTOMLEFT, frameMessagePanel, FRAMEPOINT_BOTTOMLEFT, 0., 0.)
_frameMessage.alpha = 0
end
if _frameMessage.alpha >= 0 and _frameMessage.alpha < 255 and duration < MESSAGE_DURATION then
_frameMessage.alpha = _frameMessage.alpha + 3
BlzFrameSetAlpha(_frameMessage.getMain(), _frameMessage.alpha)
elseif duration > MESSAGE_DURATION and _frameMessage.alpha > 0 then
_frameMessage.alpha = _frameMessage.alpha - 3
BlzFrameSetAlpha(_frameMessage.getMain(), _frameMessage.alpha)
end
if _frameMessage.targetY > _frameMessage.currentY and _frameMessage.alpha >= 0 then
_frameMessage.timeSinceStart = _frameMessage.timeSinceStart + 1
if _frameMessage.timeSinceStart < 20 then
_frameMessage.currentY = _frameMessage.startY + (_frameMessage.targetY - _frameMessage.startY) * easeInOutSine(_frameMessage.timeSinceStart / 20.)
else
_frameMessage.currentY = _frameMessage.targetY
end
BlzFrameSetPoint(_frameMessage.getMain(), FRAMEPOINT_BOTTOMLEFT, frameMessagePanel, FRAMEPOINT_BOTTOMLEFT, 0., _frameMessage.currentY)
end
end
if duration > MESSAGE_DURATION + 100 then
_frameMessage.inUse = false
_frameMessage.asyncVisibility = false
BlzFrameSetVisible(_frameMessage.getMain(), false)
_frameMessage.currentY = 0.
_frameMessage.alpha = -1
_frameMessage.timeSinceStart = 0
FlushChildHashtable(Hashtable, GetHandleId(GetExpiredTimer()))
PauseTimer(GetExpiredTimer())
end
end, err)
end
-- Generates the message frontend in following shematic: [messageType][timeStamp] :icon: Playername: message
---@param time integer
---@param messagetype string
---@param messageIcon string
---@param content string
---@param receivers integer
---@return nothing
function generateMessage(time, messagetype, messageIcon, content, receivers)
xpcall(function()
local current = 1
local HandleID
local prev = 0
local timestamp = convertTime(time)
while frameMessage[Iterator].inUse do
if Iterator > MAX_MESSAGES then
Iterator = 1
else
Iterator = Iterator + 1
end
end
--BJDebugMsg("Expected Time: " .. time)
--BJDebugMsg("Expected Type: " .. messagetype)
--BJDebugMsg("Expected Icon: " .. (messageIcon or "null"))
--BJDebugMsg("Expected Content: " .. content)
--BJDebugMsg("Expected Receivers: " .. receivers)
-- no reason to do these async, since only frameMessage visiblity matters
local _frameMessage = frameMessage[Iterator]
BlzFrameSetText(_frameMessage.getType(), messagetype)
BlzFrameSetText(_frameMessage.getTimestamp(), timestamp)
BlzFrameSetText(_frameMessage.getText(), content)
if messageIcon ~= "" and messageIcon ~= nil then
BlzFrameSetTexture(_frameMessage.getIcon(), messageIcon, 0, true)
BlzFrameSetVisible(_frameMessage.getIconContainer(), true)
BlzFrameSetPoint(_frameMessage.getTextContainer(), FRAMEPOINT_LEFT, _frameMessage.getIconContainer(), FRAMEPOINT_RIGHT, 0.003, 0.)
else
BlzFrameSetVisible(_frameMessage.getIconContainer(), false)
BlzFrameSetPoint(_frameMessage.getTextContainer(), FRAMEPOINT_LEFT, _frameMessage.getTimestampContainer(), FRAMEPOINT_RIGHT, 0.003, 0.)
end
local pID = 23 -- reverse order to be able to perform substraction check
while pID >= 0 and receivers ~= 0 do
if GetPlayerController(Player(pID)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(pID)) == PLAYER_SLOT_STATE_PLAYING then
if receivers - R2I(1 * Pow(2, pID)) >= 0 then -- check if player is supposed to receive the message
receivers = receivers - R2I(1 * Pow(2, pID)) -- substract value from receiver panel
if GetLocalPlayer() == Player(pID) then
BlzFrameSetVisible(_frameMessage.getMain(), true)
_frameMessage.asyncVisibility = true -- async
_frameMessage.previousFrame = tempPrev -- async
prev = tempPrev -- local async
tempPrev = Iterator -- async
current = Iterator -- local async
while true do
if prev == 0 then break end
if prev == current then
frameMessage[current].previousFrame = 0 -- async
prev = 0 -- local async
elseif frameMessage[prev].inUse and frameMessage[prev].asyncVisibility then
frameMessage[prev].targetY = frameMessage[prev].targetY + FONT_SIZE + 0.005 -- async
frameMessage[prev].startY = frameMessage[prev].currentY -- async
frameMessage[prev].timeSinceStart = 0 -- async
current = prev -- local async
prev = frameMessage[current].previousFrame -- local async
else
prev = 0 -- local async
end
end
end
end
end
pID = pID - 1
end
_frameMessage.inUse = true
HandleID = GetHandleId(_frameMessage.timer)
SaveInteger(Hashtable, HandleID, FRAME_HASH, Iterator)
TimerStart(_frameMessage.timer, 0.01, true, hideMessage)
end, err)
end
---@param messageID integer
---@return nothing
function sendPlayerMessage(messageID)
xpcall(function()
local _message = message[messageID]
local visualMessageType = _message.getTypeFormatted()
local sender = _message.getSenderFormatted()
local content = sender .. "|r: " .. _message.getContent()
local receivers = _message.getReceivers()
local time = _message.getTime()
local icon = playerIcon[_message.getSender()]
generateMessage(time, visualMessageType, icon, content, receivers)
end, err)
end
---@return nothing
function syncPlayerMessage()
xpcall(function()
local pID = S2I(SubString(BlzGetTriggerSyncPrefix(), 12, StringLength(BlzGetTriggerSyncPrefix())))
local Data = BlzGetTriggerSyncData()
local messageID = S2I(SubString(Data, 0, StringLength(Data) - 11))
local messageReceived = S2I(SubString(Data, StringLength(Data) - 1, StringLength(Data)))
local allChatSyncValue
local _message = message[messageID]
-- call BJDebugMsg("Player " + I2S(pID) + " synched")
_message.setSync(_message.getSync() - math.floor(1 * Pow(2, pID)))
-- call BJDebugMsg("New Sync Value: " + I2S(syncValue[messageID]))
_message.setReceivers(_message.getReceivers() + math.floor(messageReceived * Pow(2, pID))) -- geometric sequence to tell which players received the message
-- call BJDebugMsg("New Receivers Value: " + I2S(messageReceivers[messageID]))
if _message.getSync() == 0 then
allChatSyncValue = 0
for pID = 0, 23, 1 do
if GetPlayerController(Player(pID)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(pID)) == PLAYER_SLOT_STATE_PLAYING then
allChatSyncValue = allChatSyncValue + math.floor(1 * Pow(2, pID)) -- calculate expected partial sum of all players
end
end
if _message.getReceivers() == allChatSyncValue then -- compare syncValue partial sum with messageReceivers partial sum
_message.setType(MessageTypes.ALL) -- All Chat
else
_message.setType(MessageTypes.ALLIED) -- Allies Chat
end
sendPlayerMessage(messageID)
end
end, err)
end
---@param sender integer
---@param content string
---@param log string
---@return integer
function processPlayerMessage(sender, content, log)
local messageID
messageID = messageIterator
messageIterator = messageIterator + 1
message[messageID] = Message.new()
local _message = message[messageID]
_message.setTime(gameTime)
_message.setContent(content)
_message.setSender(sender)
_message.setReceivers(0)
_message.setType(MessageTypes.UNKNOWN)
_message.setSync(0)
for pID = 0, 23, 1 do
if GetPlayerController(Player(pID)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(pID)) == PLAYER_SLOT_STATE_PLAYING then
_message.setSync(_message.getSync() + R2I(1 * Pow(2, pID))) -- geometric sequence to tell the current sync status of each player
if GetLocalPlayer() == Player(pID) then
if log ~= "" then
BlzSendSyncData("New Message " .. pID, messageID .. "_RECEIVED_1") -- this way everyone receives a list of players that received the message
else
BlzSendSyncData("New Message " .. pID, messageID .. "_RECEIVED_0") -- this way everyone receives a list of players that received the message
end
end
end
end
return messageID
end
-- This function sends out a message to one player as system message. (receiver is a player ID)
---@param receiver integer
---@param content string
---@return nothing
function sendSystemMessage(receiver, content)
xpcall(function()
local receivers
if GetPlayerController(Player(receiver)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(receiver)) == PLAYER_SLOT_STATE_PLAYING then
receivers = R2I(1 * Pow(2, receiver))
generateMessage(gameTime, SYSTEM_MESSAGE_TYPE, systemIcon, content, receivers)
end
end, err)
end
-- This function sends out a message to multiple player as system message. (receivers is a partial sum)
---@param receivers integer
---@param content string
---@return nothing
function sendSystemMessageMultiple(receivers, content)
xpcall(function()
generateMessage(gameTime, SYSTEM_MESSAGE_TYPE, systemIcon, content, receivers)
end, err)
end
-- This function sends out a message to all players as system message.
---@param content string
---@return nothing
function print(content)
xpcall(function()
local receivers = 0
for pID = 0, 23, 1 do
if GetPlayerController(Player(pID)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(pID)) == PLAYER_SLOT_STATE_PLAYING then
receivers = receivers + R2I(1 * Pow(2, pID)) -- calculate expected partial sum of all players
end
end
generateMessage(gameTime, SYSTEM_MESSAGE_TYPE, systemIcon, content, receivers)
end, err)
end
---@param pID integer
---@param content string
---@return nothing
function commandEvent(pID, content)
xpcall(function()
local i = 1
local argsv = {}
local current = 0
local last = 0
-- Splits the message into a array to read message content as parameter
for i = 1, StringLength(content), 1 do
if SubString(content, i - 1, i) == " " then
argsv[current] = SubString(content, last, i - 1)
last = i
current = current + 1
elseif i == StringLength(content) then
argsv[current] = SubString(content, last, i)
end
i = i + 1
end
if argsv[0] == "caminfo" then
sendSystemMessage(pID, "|cFFFFCC00Current Camera Information|r:")
sendSystemMessage(pID, "|cFFFFCC00" .. "Targ" .. "|r" .. " = " .. "|cff00ffff" .. "( " .. R2SW(GetCameraTargetPositionX(), 0, 0) .. ", " .. R2SW(GetCameraTargetPositionY(), 0, 0) .. ", " .. R2SW(GetCameraTargetPositionZ(), 0, 0) .. " )|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "Dist" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_TARGET_DISTANCE), 0, 0) .. "|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "FarZ" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_FARZ), 0, 0) .. "|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "AoA" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK) * bj_RADTODEG, 0, 2) .. "|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "FoV" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_FIELD_OF_VIEW) * bj_RADTODEG, 0, 2) .. "|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "Roll" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_ROLL) * bj_RADTODEG, 0, 2) .. "|r")
sendSystemMessage(pID, "|cFFFFCC00" .. "Rot" .. "|r" .. " = " .. "|cff00ffff" .. R2SW(GetCameraField(CAMERA_FIELD_ROTATION) * bj_RADTODEG, 0, 2) .. "|r")
elseif argsv[0] == "sysinfo" then
sendSystemMessage(pID, "|cFFFFCC00System Version: " .. "|r" .. "|cff00ffff" .. CHAT_SYSTEM_VERSION .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Command Syntax: " .. "|r" .. "|cff00ffff" .. COMMAND_SYNTAX .. "|r")
sendSystemMessage(pID, "|cFFFFCC00System Messages: " .. "|r" .. "|cff00ffff" .. SYSTEM_MESSAGE_TYPE .. "|r")
sendSystemMessage(pID, "|cFFFFCC00All Player Messages: " .. "|r" .. "|cff00ffff" .. ALL_PLAYERS_MESSAGE_TYPE .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Allied Players Messages: " .. "|r" .. "|cff00ffff" .. ALLIED_PLAYERS_MESSAGE_TYPE .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Message Length Limit: " .. "|r" .. "|cff00ffff" .. MESSAGE_LENGTH_LIMIT .. "|r")
elseif argsv[0] == "message" then
i = S2I(argsv[1])
if message[i] ~= nil then
sendSystemMessage(pID, "|cFFFFCC00Message Sender: " .. "|r" .. "|cff00ffff" .. message[i].getSenderFormatted() .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Message Content: " .. "|r" .. "|cff00ffff" .. message[i].getContent() .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Message Time: " .. "|r" .. "|cff00ffff" .. message[i].getTime() .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Message Receivers: " .. "|r" .. "|cff00ffff" .. message[i].getReceiversFormatted() .. "|r")
sendSystemMessage(pID, "|cFFFFCC00Message Type: " .. "|r" .. "|cff00ffff" .. message[i].getTypeFormatted() .. "|r")
else
sendSystemMessage(pID, "|cFFFFCC00No message with given id found. (Searched ID: " .. i .. ")|r")
end
else
sendSystemMessage(pID, "Couldn't find the command '" .. argsv[0] .. "'")
end
end, err)
end
---@return nothing
function chatAction()
xpcall(function()
local pID = GetPlayerId(GetTriggerPlayer())
local content = GetEventPlayerChatString()
if SubString(content, 0, StringLength(COMMAND_SYNTAX)) == COMMAND_SYNTAX then
-- Command
commandEvent(pID, SubString(content, StringLength(COMMAND_SYNTAX), StringLength(content)))
elseif frameChatHistory ~= nil then
-- Message
-- call print("Log Data: " + BlzFrameGetText(frameChatHistory))
if sizeCheck(content) then
processPlayerMessage(GetPlayerId(GetTriggerPlayer()), content, BlzFrameGetText(frameChatHistory))
else
sendSystemMessage(pID, MESSAGE_SIZE_OVERFLOW)
end
end
if frameChatHistory ~= nil then
BlzFrameSetText(frameChatHistory, "")
end
end, err)
end
---@return nothing
function chatInit()
xpcall(function()
-- Try to load ChatSystem.toc, otherwise don't init system
if BlzLoadTOCFile("UI\\ChatSystem.toc") then
local trig1 = CreateTrigger()
local trig2 = CreateTrigger()
for current = 0, 23, 1 do
TriggerRegisterPlayerChatEvent(trig1, Player(current), "", false)
BlzTriggerRegisterPlayerSyncEvent(trig2, Player(current), "New Message " .. current, false)
end
TriggerAddAction(trig1, chatAction)
TriggerAddAction(trig2, syncPlayerMessage)
trig1 = nil
trig2 = nil
BlzFrameSetVisible(BlzGetOriginFrame(ORIGIN_FRAME_CHAT_MSG, 0), false) -- hides default chat
frameMain = BlzCreateSimpleFrame("Main", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0)
frameMessagePanel = BlzGetFrameByName("Message Panel", 0)
for current = 0, MAX_MESSAGES, 1 do
frameMessage[current] = FrameMessage.new(current)
end
BlzFrameSetAbsPoint(frameMain, FRAMEPOINT_BOTTOM, 0.4, 0.)
BlzFrameSetPoint(frameMessagePanel, CHAT_REFPOINT, frameMain, CHAT_REFPOINT, CHAT_X, CHAT_Y)
print("Successfully loaded Chat System v" .. CHAT_SYSTEM_VERSION)
BlzGetFrameByName("ChatHistoryDisplay", 0)
frameChatHistory = BlzGetFrameByName("ChatHistoryDisplay", 0)
if frameChatHistory == nil then
print("Singleplayer detected, normal chat messages are disabled. (Commands will remain working)")
else
print("Multiplayer detected, normal chat messages and commands will work as intended")
BlzFrameSetText(frameChatHistory, "")
-- hide observer chat radio button cause it cause desyncs
BlzFrameSetVisible(BlzGetFrameByName("ChatObserversRadioButton", 0), false)
BlzFrameSetEnable(BlzGetFrameByName("ChatObserversRadioButton", 0), false)
BlzFrameSetVisible(BlzGetFrameByName("ChatObserversLabel", 0), false)
-- move everyone button where observer chat would normally be
BlzFrameSetPoint(BlzGetFrameByName("ChatEveryoneRadioButton", 0), FRAMEPOINT_TOP, BlzGetFrameByName("ChatAlliesRadioButton", 0), FRAMEPOINT_BOTTOM, 0., -0.002)
end
TimerStart(CreateTimer(), 1.0, true, function()
gameTime = gameTime + 1
BlzFrameSetSize(frameMain, 0.6 * BlzGetLocalClientWidth() / BlzGetLocalClientHeight(), 0.6)
end
)
end
end, err)
end
TimerStart(CreateTimer(), 0., false, chatInit)