mirror of
https://github.com/mehah/otclient
synced 2026-08-15 16:29:06 -04:00
1976 lines
59 KiB
Lua
1976 lines
59 KiB
Lua
SpeakTypesSettings = {
|
|
none = {},
|
|
say = {
|
|
speakType = MessageModes.Say,
|
|
color = '#FFFF00'
|
|
},
|
|
whisper = {
|
|
speakType = MessageModes.Whisper,
|
|
color = '#FFFF00'
|
|
},
|
|
yell = {
|
|
speakType = MessageModes.Yell,
|
|
color = '#FFFF00'
|
|
},
|
|
broadcast = {
|
|
speakType = MessageModes.GamemasterBroadcast,
|
|
color = '#F55E5E'
|
|
},
|
|
private = {
|
|
speakType = MessageModes.PrivateTo,
|
|
color = '#5FF7F7',
|
|
private = true
|
|
},
|
|
privateRed = {
|
|
speakType = MessageModes.GamemasterTo,
|
|
color = '#F55E5E',
|
|
private = true
|
|
},
|
|
privatePlayerToPlayer = {
|
|
speakType = MessageModes.PrivateTo,
|
|
color = '#9F9DFD',
|
|
private = true
|
|
},
|
|
privatePlayerToNpc = {
|
|
speakType = MessageModes.NpcTo,
|
|
color = '#9F9DFD',
|
|
private = true,
|
|
npcChat = true
|
|
},
|
|
privateNpcToPlayer = {
|
|
speakType = MessageModes.NpcFrom,
|
|
color = '#5FF7F7',
|
|
private = true,
|
|
npcChat = true
|
|
},
|
|
channelYellow = {
|
|
speakType = MessageModes.Channel,
|
|
color = '#FFFF00'
|
|
},
|
|
channelWhite = {
|
|
speakType = MessageModes.ChannelManagement,
|
|
color = '#FFFFFF'
|
|
},
|
|
channelRed = {
|
|
speakType = MessageModes.GamemasterChannel,
|
|
color = '#F55E5E'
|
|
},
|
|
channelOrange = {
|
|
speakType = MessageModes.ChannelHighlight,
|
|
color = '#F6A731'
|
|
},
|
|
monsterSay = {
|
|
speakType = MessageModes.MonsterSay,
|
|
color = '#FF9A57',
|
|
hideInConsole = true
|
|
},
|
|
monsterYell = {
|
|
speakType = MessageModes.MonsterYell,
|
|
color = '#FF9A57',
|
|
hideInConsole = true
|
|
},
|
|
rvrAnswerFrom = {
|
|
speakType = MessageModes.RVRAnswer,
|
|
color = '#FE6500'
|
|
},
|
|
rvrAnswerTo = {
|
|
speakType = MessageModes.RVRAnswer,
|
|
color = '#FE6500'
|
|
},
|
|
rvrContinue = {
|
|
speakType = MessageModes.RVRContinue,
|
|
color = '#FFFF00'
|
|
}
|
|
}
|
|
|
|
SpeakTypes = {
|
|
[MessageModes.Say] = SpeakTypesSettings.say,
|
|
[MessageModes.Whisper] = SpeakTypesSettings.whisper,
|
|
[MessageModes.Yell] = SpeakTypesSettings.yell,
|
|
[MessageModes.GamemasterBroadcast] = SpeakTypesSettings.broadcast,
|
|
[MessageModes.PrivateTo] = SpeakTypesSettings.private,
|
|
[MessageModes.PrivateFrom] = SpeakTypesSettings.private,
|
|
[MessageModes.GamemasterPrivateFrom] = SpeakTypesSettings.privateRed,
|
|
[MessageModes.NpcTo] = SpeakTypesSettings.privatePlayerToNpc,
|
|
[MessageModes.NpcFrom] = SpeakTypesSettings.privateNpcToPlayer,
|
|
[MessageModes.Channel] = SpeakTypesSettings.channelYellow,
|
|
[MessageModes.ChannelManagement] = SpeakTypesSettings.channelWhite,
|
|
[MessageModes.GamemasterChannel] = SpeakTypesSettings.channelRed,
|
|
[MessageModes.ChannelHighlight] = SpeakTypesSettings.channelOrange,
|
|
[MessageModes.MonsterSay] = SpeakTypesSettings.monsterSay,
|
|
[MessageModes.MonsterYell] = SpeakTypesSettings.monsterYell,
|
|
[MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
|
|
[MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
|
|
[MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
|
|
[MessageModes.NpcFromStartBlock] = SpeakTypesSettings.privateNpcToPlayer,
|
|
|
|
-- ignored types
|
|
[MessageModes.Spell] = SpeakTypesSettings.none,
|
|
[MessageModes.BarkLow] = SpeakTypesSettings.none,
|
|
[MessageModes.BarkLoud] = SpeakTypesSettings.none,
|
|
[MessageModes.Potion] = SpeakTypesSettings.none
|
|
}
|
|
|
|
SayModes = {
|
|
[1] = {
|
|
speakTypeDesc = 'whisper',
|
|
icon = '/images/game/console/whisper'
|
|
},
|
|
[2] = {
|
|
speakTypeDesc = 'say',
|
|
icon = '/images/game/console/say'
|
|
},
|
|
[3] = {
|
|
speakTypeDesc = 'yell',
|
|
icon = '/images/game/console/yell'
|
|
}
|
|
}
|
|
|
|
ChannelEventFormats = {
|
|
[ChannelEvent.Join] = '%s joined the channel.',
|
|
[ChannelEvent.Leave] = '%s left the channel.',
|
|
[ChannelEvent.Invite] = '%s has been invited to the channel.',
|
|
[ChannelEvent.Exclude] = '%s has been removed from the channel.'
|
|
}
|
|
|
|
MAX_HISTORY = 500
|
|
MAX_LINES = 100
|
|
HELP_CHANNEL = 9
|
|
|
|
consolePanel = nil
|
|
consoleContentPanel = nil
|
|
consoleTabBar = nil
|
|
consoleTextEdit = nil
|
|
consoleToggleChat = nil
|
|
channels = nil
|
|
channelsWindow = nil
|
|
communicationWindow = nil
|
|
ownPrivateName = nil
|
|
messageHistory = {}
|
|
currentMessageIndex = 0
|
|
ignoreNpcMessages = false
|
|
defaultTab = nil
|
|
serverTab = nil
|
|
violationsChannelId = nil
|
|
violationWindow = nil
|
|
violationReportTab = nil
|
|
ignoredChannels = {}
|
|
filters = {}
|
|
|
|
local communicationSettings = {
|
|
useIgnoreList = true,
|
|
useWhiteList = true,
|
|
privateMessages = false,
|
|
yelling = false,
|
|
allowVIPs = false,
|
|
ignoredPlayers = {},
|
|
whitelistedPlayers = {}
|
|
}
|
|
|
|
function init()
|
|
connect(g_game, {
|
|
onTalk = onTalk,
|
|
onChannelList = onChannelList,
|
|
onOpenChannel = onOpenChannel,
|
|
onOpenPrivateChannel = onOpenPrivateChannel,
|
|
onOpenOwnPrivateChannel = onOpenOwnPrivateChannel,
|
|
onCloseChannel = onCloseChannel,
|
|
onRuleViolationChannel = onRuleViolationChannel,
|
|
onRuleViolationRemove = onRuleViolationRemove,
|
|
onRuleViolationCancel = onRuleViolationCancel,
|
|
onRuleViolationLock = onRuleViolationLock,
|
|
onGameStart = online,
|
|
onGameEnd = offline,
|
|
onChannelEvent = onChannelEvent
|
|
})
|
|
|
|
consolePanel = g_ui.loadUI('console', modules.game_interface.getBottomPanel())
|
|
consoleTextEdit = consolePanel:getChildById('consoleTextEdit')
|
|
consoleContentPanel = consolePanel:getChildById('consoleContentPanel')
|
|
consoleTabBar = consolePanel:getChildById('consoleTabBar')
|
|
consoleTabBar:setContentWidget(consoleContentPanel)
|
|
channels = {}
|
|
|
|
consolePanel.onDragEnter = onDragEnter
|
|
consolePanel.onDragLeave = onDragLeave
|
|
consolePanel.onDragMove = onDragMove
|
|
consoleTabBar.onDragEnter = onDragEnter
|
|
consoleTabBar.onDragLeave = onDragLeave
|
|
consoleTabBar.onDragMove = onDragMove
|
|
consolePanel.onKeyPress = function(self, keyCode, keyboardModifiers)
|
|
if not (keyboardModifiers == KeyboardCtrlModifier and keyCode == KeyC) then
|
|
return false
|
|
end
|
|
|
|
local tab = consoleTabBar:getCurrentTab()
|
|
if not tab then
|
|
return false
|
|
end
|
|
|
|
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
|
if not selection then
|
|
return false
|
|
end
|
|
|
|
g_window.setClipboardText(selection)
|
|
return true
|
|
end
|
|
|
|
g_keyboard.bindKeyPress('Shift+Up', function()
|
|
navigateMessageHistory(1)
|
|
end, consolePanel)
|
|
g_keyboard.bindKeyPress('Shift+Down', function()
|
|
navigateMessageHistory(-1)
|
|
end, consolePanel)
|
|
g_keyboard.bindKeyPress('Tab', function()
|
|
consoleTabBar:selectNextTab()
|
|
end, consolePanel)
|
|
g_keyboard.bindKeyPress('Shift+Tab', function()
|
|
consoleTabBar:selectPrevTab()
|
|
end, consolePanel)
|
|
g_keyboard.bindKeyDown('Enter', switchChatOnCall, consolePanel)
|
|
g_keyboard.bindKeyDown('Enter', sendCurrentMessage, consolePanel)
|
|
g_keyboard.bindKeyDown('Escape', disableChatOnCall, consolePanel)
|
|
g_keyboard.bindKeyPress('Ctrl+A', function()
|
|
consoleTextEdit:clearText()
|
|
end, consolePanel)
|
|
|
|
-- apply buttom functions after loaded
|
|
consoleTabBar:setNavigation(consolePanel:getChildById('prevChannelButton'),
|
|
consolePanel:getChildById('nextChannelButton'))
|
|
consoleTabBar.onTabChange = onTabChange
|
|
|
|
-- tibia like hotkeys
|
|
g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels)
|
|
g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab)
|
|
g_keyboard.bindKeyDown('Ctrl+H', openHelp)
|
|
|
|
-- toggle WASD
|
|
consoleToggleChat = consolePanel:getChildById('toggleChat')
|
|
load()
|
|
|
|
if g_game.isOnline() then
|
|
online()
|
|
end
|
|
end
|
|
|
|
function clearSelection(consoleBuffer)
|
|
for _, label in pairs(consoleBuffer:getChildren()) do
|
|
label:clearSelection()
|
|
end
|
|
consoleBuffer.selectionText = nil
|
|
consoleBuffer.selection = nil
|
|
end
|
|
|
|
function selectAll(consoleBuffer)
|
|
clearSelection(consoleBuffer)
|
|
if consoleBuffer:getChildCount() > 0 then
|
|
local text = {}
|
|
for _, label in pairs(consoleBuffer:getChildren()) do
|
|
label:selectAll()
|
|
table.insert(text, label:getSelection())
|
|
end
|
|
consoleBuffer.selectionText = table.concat(text, '\n')
|
|
consoleBuffer.selection = {
|
|
first = consoleBuffer:getChildIndex(consoleBuffer:getFirstChild()),
|
|
last = consoleBuffer:getChildIndex(consoleBuffer:getLastChild())
|
|
}
|
|
end
|
|
end
|
|
|
|
function toggleChat()
|
|
consoleToggleChat:setChecked(not consoleToggleChat:isChecked())
|
|
end
|
|
|
|
-- id of object first and then action
|
|
function updateChatMode()
|
|
switchChat(not consoleToggleChat:isChecked())
|
|
end
|
|
|
|
local function unbindMovingKeys()
|
|
local gameInterface = modules.game_interface
|
|
gameInterface.unbindWalkKey('W')
|
|
gameInterface.unbindWalkKey('D')
|
|
gameInterface.unbindWalkKey('S')
|
|
gameInterface.unbindWalkKey('A')
|
|
|
|
gameInterface.unbindWalkKey('E')
|
|
gameInterface.unbindWalkKey('Q')
|
|
gameInterface.unbindWalkKey('C')
|
|
gameInterface.unbindWalkKey('Z')
|
|
|
|
gameInterface.unbindTurnKey('Ctrl+W')
|
|
gameInterface.unbindTurnKey('Ctrl+D')
|
|
gameInterface.unbindTurnKey('Ctrl+S')
|
|
gameInterface.unbindTurnKey('Ctrl+A')
|
|
end
|
|
|
|
local function bindMovingKeys()
|
|
local gameInterface = modules.game_interface
|
|
gameInterface.bindWalkKey('W', North)
|
|
gameInterface.bindWalkKey('D', East)
|
|
gameInterface.bindWalkKey('S', South)
|
|
gameInterface.bindWalkKey('A', West)
|
|
|
|
gameInterface.bindWalkKey('E', NorthEast)
|
|
gameInterface.bindWalkKey('Q', NorthWest)
|
|
gameInterface.bindWalkKey('C', SouthEast)
|
|
gameInterface.bindWalkKey('Z', SouthWest)
|
|
|
|
gameInterface.bindTurnKey('Ctrl+W', North)
|
|
gameInterface.bindTurnKey('Ctrl+D', East)
|
|
gameInterface.bindTurnKey('Ctrl+S', South)
|
|
gameInterface.bindTurnKey('Ctrl+A', West)
|
|
end
|
|
|
|
function switchChat(enabled)
|
|
-- enabled should be true if we enabling the chat and false if disabling it
|
|
-- consoleToggleChat:setChecked(not consoleToggleChat:isChecked())
|
|
if not (enabled and consoleTextEdit:isVisible()) then
|
|
consoleTextEdit:setVisible(enabled)
|
|
consoleTextEdit:setText('')
|
|
end
|
|
|
|
if enabled then
|
|
unbindMovingKeys()
|
|
consoleToggleChat:setTooltip(tr('Disable chat mode, allow to walk using WASD'))
|
|
else
|
|
bindMovingKeys()
|
|
consoleToggleChat:setTooltip(tr('Enable chat mode'))
|
|
end
|
|
end
|
|
|
|
function switchChatOnCall()
|
|
if not g_game.isOnline() or modules.game_hotkeys.areHotkeysDisabled() then
|
|
return
|
|
end
|
|
|
|
if isChatEnabled() and consoleToggleChat:isChecked() then
|
|
toggleChat()
|
|
else
|
|
local message = consoleTextEdit:getText()
|
|
if message == '' then
|
|
toggleChat()
|
|
end
|
|
end
|
|
end
|
|
|
|
function disableChatOnCall()
|
|
if not g_game.isOnline() or modules.game_hotkeys.areHotkeysDisabled() then
|
|
return
|
|
end
|
|
|
|
if isChatEnabled() and not consoleToggleChat:isChecked() then
|
|
toggleChat()
|
|
end
|
|
end
|
|
|
|
function isChatEnabled()
|
|
return consoleTextEdit:isVisible()
|
|
end
|
|
|
|
function terminate()
|
|
save()
|
|
disconnect(g_game, {
|
|
onTalk = onTalk,
|
|
onChannelList = onChannelList,
|
|
onOpenChannel = onOpenChannel,
|
|
onOpenPrivateChannel = onOpenPrivateChannel,
|
|
onOpenOwnPrivateChannel = onOpenPrivateChannel,
|
|
onCloseChannel = onCloseChannel,
|
|
onRuleViolationChannel = onRuleViolationChannel,
|
|
onRuleViolationRemove = onRuleViolationRemove,
|
|
onRuleViolationCancel = onRuleViolationCancel,
|
|
onRuleViolationLock = onRuleViolationLock,
|
|
onGameStart = online,
|
|
onGameEnd = offline,
|
|
onChannelEvent = onChannelEvent
|
|
})
|
|
|
|
if g_game.isOnline() then
|
|
clear()
|
|
end
|
|
|
|
g_keyboard.unbindKeyDown('Ctrl+O')
|
|
g_keyboard.unbindKeyDown('Ctrl+E')
|
|
g_keyboard.unbindKeyDown('Ctrl+H')
|
|
|
|
saveCommunicationSettings()
|
|
|
|
if channelsWindow then
|
|
channelsWindow:destroy()
|
|
end
|
|
|
|
if communicationWindow then
|
|
communicationWindow:destroy()
|
|
end
|
|
|
|
if violationWindow then
|
|
violationWindow:destroy()
|
|
end
|
|
|
|
consoleTabBar = nil
|
|
consoleContentPanel = nil
|
|
consoleToggleChat = nil
|
|
consoleTextEdit = nil
|
|
|
|
consolePanel:destroy()
|
|
consolePanel = nil
|
|
ownPrivateName = nil
|
|
|
|
Console = nil
|
|
end
|
|
|
|
function save()
|
|
local settings = {}
|
|
settings.messageHistory = messageHistory
|
|
settings.wasdMode = consoleToggleChat:isChecked()
|
|
g_settings.setNode('game_console', settings)
|
|
end
|
|
|
|
function load()
|
|
local settings = g_settings.getNode('game_console')
|
|
if settings then
|
|
messageHistory = settings.messageHistory or {}
|
|
consoleToggleChat:setChecked(settings.wasdMode or false)
|
|
end
|
|
loadCommunicationSettings()
|
|
end
|
|
|
|
function onTabChange(tabBar, tab)
|
|
if tab == defaultTab or tab == serverTab then
|
|
consolePanel:getChildById('closeChannelButton'):disable()
|
|
else
|
|
consolePanel:getChildById('closeChannelButton'):enable()
|
|
end
|
|
end
|
|
|
|
function clear()
|
|
-- save last open channels
|
|
local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') or {}
|
|
local char = g_game.getCharacterName()
|
|
local savedChannels = {}
|
|
local set = false
|
|
for channelId, channelName in pairs(channels) do
|
|
if type(channelId) == 'number' then
|
|
savedChannels[channelName] = channelId
|
|
set = true
|
|
end
|
|
end
|
|
if set then
|
|
lastChannelsOpen[char] = savedChannels
|
|
else
|
|
lastChannelsOpen[char] = nil
|
|
end
|
|
g_settings.setNode('lastChannelsOpen', lastChannelsOpen)
|
|
|
|
-- close channels
|
|
for _, channelName in pairs(channels) do
|
|
local tab = consoleTabBar:getTab(channelName)
|
|
consoleTabBar:removeTab(tab)
|
|
end
|
|
channels = {}
|
|
|
|
consoleTabBar:removeTab(defaultTab)
|
|
defaultTab = nil
|
|
consoleTabBar:removeTab(serverTab)
|
|
serverTab = nil
|
|
|
|
local npcTab = consoleTabBar:getTab('NPCs')
|
|
if npcTab then
|
|
consoleTabBar:removeTab(npcTab)
|
|
npcTab = nil
|
|
end
|
|
|
|
if violationReportTab then
|
|
consoleTabBar:removeTab(violationReportTab)
|
|
violationReportTab = nil
|
|
end
|
|
|
|
consoleTextEdit:clearText()
|
|
|
|
if violationWindow then
|
|
violationWindow:destroy()
|
|
violationWindow = nil
|
|
end
|
|
|
|
if channelsWindow then
|
|
channelsWindow:destroy()
|
|
channelsWindow = nil
|
|
end
|
|
end
|
|
|
|
function clearChannel(consoleTabBar)
|
|
consoleTabBar:getCurrentTab().tabPanel:getChildById('consoleBuffer'):destroyChildren()
|
|
end
|
|
|
|
function setTextEditText(text)
|
|
consoleTextEdit:setText(text)
|
|
consoleTextEdit:setCursorPos(-1)
|
|
end
|
|
|
|
function openHelp()
|
|
local helpChannel = 9
|
|
if g_game.getClientVersion() <= 810 then
|
|
helpChannel = 8
|
|
end
|
|
g_game.joinChannel(helpChannel)
|
|
end
|
|
|
|
function openPlayerReportRuleViolationWindow()
|
|
if violationWindow or violationReportTab then
|
|
return
|
|
end
|
|
violationWindow = g_ui.loadUI('violationwindow', rootWidget)
|
|
violationWindow.onEscape = function()
|
|
violationWindow:destroy()
|
|
violationWindow = nil
|
|
end
|
|
violationWindow.onEnter = function()
|
|
local text = violationWindow:getChildById('text'):getText()
|
|
g_game.talkChannel(MessageModes.RVRChannel, 0, text)
|
|
violationReportTab = addTab(tr('Report Rule') .. '...', true)
|
|
addTabText(tr('Please wait patiently for a gamemaster to reply') .. '.', SpeakTypesSettings.privateRed,
|
|
violationReportTab)
|
|
addTabText(applyMessagePrefixies(g_game.getCharacterName(), 0, text), SpeakTypesSettings.say,
|
|
violationReportTab, g_game.getCharacterName())
|
|
violationReportTab.locked = true
|
|
violationWindow:destroy()
|
|
violationWindow = nil
|
|
end
|
|
end
|
|
|
|
function addTab(name, focus)
|
|
local tab = getTab(name)
|
|
if tab then -- is channel already open
|
|
if not focus then
|
|
focus = true
|
|
end
|
|
else
|
|
tab = consoleTabBar:addTab(name, nil, processChannelTabMenu)
|
|
end
|
|
if focus then
|
|
consoleTabBar:selectTab(tab)
|
|
end
|
|
return tab
|
|
end
|
|
|
|
function removeTab(tab)
|
|
if type(tab) == 'string' then
|
|
tab = consoleTabBar:getTab(tab)
|
|
end
|
|
|
|
if tab == defaultTab or tab == serverTab then
|
|
return
|
|
end
|
|
|
|
if tab == violationReportTab then
|
|
g_game.cancelRuleViolation()
|
|
violationReportTab = nil
|
|
elseif tab.violationChatName then
|
|
g_game.closeRuleViolation(tab.violationChatName)
|
|
elseif tab.channelId then
|
|
-- notificate the server that we are leaving the channel
|
|
for k, v in pairs(channels) do
|
|
if (k == tab.channelId) then
|
|
channels[k] = nil
|
|
end
|
|
end
|
|
g_game.leaveChannel(tab.channelId)
|
|
elseif tab:getText() == 'NPCs' then
|
|
g_game.closeNpcChannel()
|
|
end
|
|
|
|
if getCurrentTab() == tab then
|
|
consoleTabBar:selectTab(defaultTab)
|
|
end
|
|
consoleTabBar:removeTab(tab)
|
|
end
|
|
|
|
function removeCurrentTab()
|
|
removeTab(consoleTabBar:getCurrentTab())
|
|
end
|
|
|
|
function getTab(name)
|
|
return consoleTabBar:getTab(name)
|
|
end
|
|
|
|
function getChannelTab(channelId)
|
|
local channel = channels[channelId]
|
|
if channel then
|
|
return getTab(channel)
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function getRuleViolationsTab()
|
|
if violationsChannelId then
|
|
return getChannelTab(violationsChannelId)
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function getCurrentTab()
|
|
return consoleTabBar:getCurrentTab()
|
|
end
|
|
|
|
function addChannel(name, id)
|
|
channels[id] = name
|
|
local focus = not table.find(ignoredChannels, id)
|
|
local tab = addTab(name, focus)
|
|
tab.channelId = id
|
|
return tab
|
|
end
|
|
|
|
function addPrivateChannel(receiver)
|
|
channels[receiver] = receiver
|
|
return addTab(receiver, true)
|
|
end
|
|
|
|
function addPrivateText(text, speaktype, name, isPrivateCommand, creatureName)
|
|
local focus = false
|
|
if speaktype.npcChat then
|
|
name = 'NPCs'
|
|
focus = true
|
|
end
|
|
|
|
local privateTab = getTab(name)
|
|
if privateTab == nil then
|
|
if (modules.client_options.getOption('showPrivateMessagesInConsole') and not focus) or
|
|
(isPrivateCommand and not privateTab) then
|
|
privateTab = defaultTab
|
|
else
|
|
privateTab = addTab(name, focus)
|
|
channels[name] = name
|
|
end
|
|
privateTab.npcChat = speaktype.npcChat
|
|
elseif focus then
|
|
consoleTabBar:selectTab(privateTab)
|
|
end
|
|
addTabText(text, speaktype, privateTab, creatureName)
|
|
end
|
|
|
|
function addText(text, speaktype, tabName, creatureName)
|
|
local tab = getTab(tabName)
|
|
if tab ~= nil then
|
|
addTabText(text, speaktype, tab, creatureName)
|
|
end
|
|
end
|
|
|
|
-- Contains letter width for font "verdana-11px-antialised" as console is based on it
|
|
local letterWidth = { -- New line (10) and Space (32) have width 1 because they are printed and not replaced with spacer
|
|
[10] = 1,
|
|
[32] = 1,
|
|
[33] = 3,
|
|
[34] = 6,
|
|
[35] = 8,
|
|
[36] = 7,
|
|
[37] = 13,
|
|
[38] = 9,
|
|
[39] = 3,
|
|
[40] = 5,
|
|
[41] = 5,
|
|
[42] = 6,
|
|
[43] = 8,
|
|
[44] = 4,
|
|
[45] = 5,
|
|
[46] = 3,
|
|
[47] = 8,
|
|
[48] = 7,
|
|
[49] = 6,
|
|
[50] = 7,
|
|
[51] = 7,
|
|
[52] = 7,
|
|
[53] = 7,
|
|
[54] = 7,
|
|
[55] = 7,
|
|
[56] = 7,
|
|
[57] = 7,
|
|
[58] = 3,
|
|
[59] = 4,
|
|
[60] = 8,
|
|
[61] = 8,
|
|
[62] = 8,
|
|
[63] = 6,
|
|
[64] = 10,
|
|
[65] = 9,
|
|
[66] = 7,
|
|
[67] = 7,
|
|
[68] = 8,
|
|
[69] = 7,
|
|
[70] = 7,
|
|
[71] = 8,
|
|
[72] = 8,
|
|
[73] = 5,
|
|
[74] = 5,
|
|
[75] = 7,
|
|
[76] = 7,
|
|
[77] = 9,
|
|
[78] = 8,
|
|
[79] = 8,
|
|
[80] = 7,
|
|
[81] = 8,
|
|
[82] = 8,
|
|
[83] = 7,
|
|
[84] = 8,
|
|
[85] = 8,
|
|
[86] = 8,
|
|
[87] = 12,
|
|
[88] = 8,
|
|
[89] = 8,
|
|
[90] = 7,
|
|
[91] = 5,
|
|
[92] = 8,
|
|
[93] = 5,
|
|
[94] = 9,
|
|
[95] = 8,
|
|
[96] = 5,
|
|
[97] = 7,
|
|
[98] = 7,
|
|
[99] = 6,
|
|
[100] = 7,
|
|
[101] = 7,
|
|
[102] = 5,
|
|
[103] = 7,
|
|
[104] = 7,
|
|
[105] = 3,
|
|
[106] = 4,
|
|
[107] = 7,
|
|
[108] = 3,
|
|
[109] = 11,
|
|
[110] = 7,
|
|
[111] = 7,
|
|
[112] = 7,
|
|
[113] = 7,
|
|
[114] = 6,
|
|
[115] = 6,
|
|
[116] = 5,
|
|
[117] = 7,
|
|
[118] = 8,
|
|
[119] = 10,
|
|
[120] = 8,
|
|
[121] = 8,
|
|
[122] = 6,
|
|
[123] = 7,
|
|
[124] = 4,
|
|
[125] = 7,
|
|
[126] = 8,
|
|
[127] = 1,
|
|
[128] = 7,
|
|
[129] = 6,
|
|
[130] = 3,
|
|
[131] = 7,
|
|
[132] = 6,
|
|
[133] = 11,
|
|
[134] = 7,
|
|
[135] = 7,
|
|
[136] = 7,
|
|
[137] = 13,
|
|
[138] = 7,
|
|
[139] = 4,
|
|
[140] = 11,
|
|
[141] = 6,
|
|
[142] = 6,
|
|
[143] = 6,
|
|
[144] = 6,
|
|
[145] = 4,
|
|
[146] = 3,
|
|
[147] = 7,
|
|
[148] = 6,
|
|
[149] = 6,
|
|
[150] = 7,
|
|
[151] = 10,
|
|
[152] = 7,
|
|
[153] = 10,
|
|
[154] = 6,
|
|
[155] = 5,
|
|
[156] = 11,
|
|
[157] = 6,
|
|
[158] = 6,
|
|
[159] = 8,
|
|
[160] = 4,
|
|
[161] = 3,
|
|
[162] = 7,
|
|
[163] = 7,
|
|
[164] = 7,
|
|
[165] = 8,
|
|
[166] = 4,
|
|
[167] = 7,
|
|
[168] = 6,
|
|
[169] = 10,
|
|
[170] = 6,
|
|
[171] = 8,
|
|
[172] = 8,
|
|
[173] = 16,
|
|
[174] = 10,
|
|
[175] = 8,
|
|
[176] = 5,
|
|
[177] = 8,
|
|
[178] = 5,
|
|
[179] = 5,
|
|
[180] = 6,
|
|
[181] = 7,
|
|
[182] = 7,
|
|
[183] = 3,
|
|
[184] = 5,
|
|
[185] = 6,
|
|
[186] = 6,
|
|
[187] = 8,
|
|
[188] = 12,
|
|
[189] = 12,
|
|
[190] = 12,
|
|
[191] = 6,
|
|
[192] = 9,
|
|
[193] = 9,
|
|
[194] = 9,
|
|
[195] = 9,
|
|
[196] = 9,
|
|
[197] = 9,
|
|
[198] = 11,
|
|
[199] = 7,
|
|
[200] = 7,
|
|
[201] = 7,
|
|
[202] = 7,
|
|
[203] = 7,
|
|
[204] = 5,
|
|
[205] = 5,
|
|
[206] = 6,
|
|
[207] = 5,
|
|
[208] = 8,
|
|
[209] = 8,
|
|
[210] = 8,
|
|
[211] = 8,
|
|
[212] = 8,
|
|
[213] = 8,
|
|
[214] = 8,
|
|
[215] = 8,
|
|
[216] = 8,
|
|
[217] = 8,
|
|
[218] = 8,
|
|
[219] = 8,
|
|
[220] = 8,
|
|
[221] = 8,
|
|
[222] = 7,
|
|
[223] = 7,
|
|
[224] = 7,
|
|
[225] = 7,
|
|
[226] = 7,
|
|
[227] = 7,
|
|
[228] = 7,
|
|
[229] = 7,
|
|
[230] = 11,
|
|
[231] = 6,
|
|
[232] = 7,
|
|
[233] = 7,
|
|
[234] = 7,
|
|
[235] = 7,
|
|
[236] = 3,
|
|
[237] = 4,
|
|
[238] = 4,
|
|
[239] = 4,
|
|
[240] = 7,
|
|
[241] = 7,
|
|
[242] = 7,
|
|
[243] = 7,
|
|
[244] = 7,
|
|
[245] = 7,
|
|
[246] = 7,
|
|
[247] = 9,
|
|
[248] = 7,
|
|
[249] = 7,
|
|
[250] = 7,
|
|
[251] = 7,
|
|
[252] = 7,
|
|
[253] = 8,
|
|
[254] = 7,
|
|
[255] = 8
|
|
}
|
|
|
|
-- Return information about start, end in the string and the highlighted words
|
|
function getHighlightedText(text)
|
|
local tmpData = {}
|
|
|
|
repeat
|
|
local tmp = {string.find(text, '{([^}]+)}', tmpData[#tmpData - 1])}
|
|
for _, v in pairs(tmp) do
|
|
table.insert(tmpData, v)
|
|
end
|
|
until not (string.find(text, '{([^}]+)}', tmpData[#tmpData - 1]))
|
|
|
|
return tmpData
|
|
end
|
|
|
|
function addTabText(text, speaktype, tab, creatureName)
|
|
if not tab or tab.locked or not text or #text == 0 then
|
|
return
|
|
end
|
|
|
|
if modules.client_options.getOption('showTimestampsInConsole') then
|
|
text = os.date('%H:%M') .. ' ' .. text
|
|
end
|
|
|
|
local panel = consoleTabBar:getTabPanel(tab)
|
|
local consoleBuffer = panel:getChildById('consoleBuffer')
|
|
local label = g_ui.createWidget('ConsoleLabel', consoleBuffer)
|
|
label:setId('consoleLabel' .. consoleBuffer:getChildCount())
|
|
label:setText(text)
|
|
label:setColor(speaktype.color)
|
|
consoleTabBar:blinkTab(tab)
|
|
|
|
label.highlightInfo = {}
|
|
|
|
-- Overlay for consoleBuffer which shows highlighted words only
|
|
|
|
if speaktype.npcChat and
|
|
(g_game.getCharacterName() ~= creatureName or g_game.getCharacterName() == 'Account Manager') then
|
|
local highlightData = getHighlightedText(text)
|
|
if #highlightData > 0 then
|
|
local labelHighlight = g_ui.createWidget('ConsolePhantomLabel', label)
|
|
labelHighlight:fill('parent')
|
|
|
|
labelHighlight:setId('consoleLabelHighlight' .. consoleBuffer:getChildCount())
|
|
labelHighlight:setColor('#1f9ffe')
|
|
|
|
-- Remove the curly braces
|
|
for i = 1, #highlightData / 3 do
|
|
local dataBlock = {
|
|
_start = highlightData[(i - 1) * 3 + 1],
|
|
_end = highlightData[(i - 1) * 3 + 2],
|
|
words = highlightData[(i - 1) * 3 + 3]
|
|
}
|
|
text = text:gsub('%{(.-)%}', dataBlock.words, 1)
|
|
|
|
-- Recalculate positions as braces are removed
|
|
highlightData[(i - 1) * 3 + 1] = dataBlock._start - ((i - 1) * 2)
|
|
highlightData[(i - 1) * 3 + 2] = dataBlock._end - (1 + (i - 1) * 2)
|
|
end
|
|
label:setText(text)
|
|
|
|
-- Calculate the positions of the highlighted text and fill with string.char(127) [Width: 1]
|
|
local drawText = label:getDrawText()
|
|
local tmpText = ''
|
|
for i = 1, #highlightData / 3 do
|
|
local dataBlock = {
|
|
_start = highlightData[(i - 1) * 3 + 1],
|
|
_end = highlightData[(i - 1) * 3 + 2],
|
|
words = highlightData[(i - 1) * 3 + 3]
|
|
}
|
|
local lastBlockEnd = (highlightData[(i - 2) * 3 + 2] or 1)
|
|
|
|
for i = dataBlock._start, dataBlock._end do
|
|
label.highlightInfo[i] = dataBlock.words
|
|
end
|
|
|
|
for letter = lastBlockEnd, dataBlock._start - 1 do
|
|
local tmpChar = string.byte(drawText:sub(letter, letter))
|
|
local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
|
|
|
|
tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
|
|
end
|
|
tmpText = tmpText .. dataBlock.words
|
|
end
|
|
|
|
-- Fill the highlight label to the same size as default label
|
|
local finalBlockEnd = (highlightData[(#highlightData / 3 - 1) * 3 + 2] or 1)
|
|
for letter = finalBlockEnd, drawText:len() do
|
|
local tmpChar = string.byte(drawText:sub(letter, letter))
|
|
local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
|
|
|
|
tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
|
|
end
|
|
|
|
labelHighlight:setText(tmpText)
|
|
end
|
|
end
|
|
|
|
label.name = creatureName
|
|
consoleBuffer.onMouseRelease = function(self, mousePos, mouseButton)
|
|
processMessageMenu(mousePos, mouseButton, nil, nil, nil, tab)
|
|
end
|
|
label.onMouseRelease = function(self, mousePos, mouseButton)
|
|
if mouseButton == MouseLeftButton then
|
|
local position = label:getTextPos(mousePos)
|
|
if position and label.highlightInfo[position] then
|
|
sendMessage(label.highlightInfo[position], npcTab)
|
|
end
|
|
elseif mouseButton == MouseRightButton then
|
|
processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
|
|
end
|
|
end
|
|
label.onMousePress = function(self, mousePos, button)
|
|
if button == MouseLeftButton then
|
|
clearSelection(consoleBuffer)
|
|
end
|
|
end
|
|
label.onDragEnter = function(self, mousePos)
|
|
clearSelection(consoleBuffer)
|
|
return true
|
|
end
|
|
label.onDragLeave = function(self, droppedWidget, mousePos)
|
|
local text = {}
|
|
for selectionChild = consoleBuffer.selection.first, consoleBuffer.selection.last do
|
|
local label = self:getParent():getChildByIndex(selectionChild)
|
|
table.insert(text, label:getSelection())
|
|
end
|
|
consoleBuffer.selectionText = table.concat(text, '\n')
|
|
return true
|
|
end
|
|
label.onDragMove = function(self, mousePos, mouseMoved)
|
|
local parent = self:getParent()
|
|
local parentRect = parent:getPaddingRect()
|
|
local selfIndex = parent:getChildIndex(self)
|
|
local child = parent:getChildByPos(mousePos)
|
|
|
|
-- find bonding children
|
|
if not child then
|
|
if mousePos.y < self:getY() then
|
|
for index = selfIndex - 1, 1, -1 do
|
|
local label = parent:getChildByIndex(index)
|
|
if label:getY() + label:getHeight() > parentRect.y then
|
|
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == 1 then
|
|
child = label
|
|
break
|
|
end
|
|
else
|
|
child = parent:getChildByIndex(index + 1)
|
|
break
|
|
end
|
|
end
|
|
elseif mousePos.y > self:getY() + self:getHeight() then
|
|
for index = selfIndex + 1, parent:getChildCount(), 1 do
|
|
local label = parent:getChildByIndex(index)
|
|
if label:getY() < parentRect.y + parentRect.height then
|
|
if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index ==
|
|
parent:getChildCount() then
|
|
child = label
|
|
break
|
|
end
|
|
else
|
|
child = parent:getChildByIndex(index - 1)
|
|
break
|
|
end
|
|
end
|
|
else
|
|
child = self
|
|
end
|
|
end
|
|
|
|
if not child then
|
|
return false
|
|
end
|
|
|
|
local childIndex = parent:getChildIndex(child)
|
|
|
|
-- remove old selection
|
|
clearSelection(consoleBuffer)
|
|
|
|
-- update self selection
|
|
local textBegin = self:getTextPos(self:getLastClickPosition())
|
|
local textPos = self:getTextPos(mousePos)
|
|
self:setSelection(textBegin, textPos)
|
|
|
|
consoleBuffer.selection = {
|
|
first = math.min(selfIndex, childIndex),
|
|
last = math.max(selfIndex, childIndex)
|
|
}
|
|
|
|
-- update siblings selection
|
|
if child ~= self then
|
|
for selectionChild = consoleBuffer.selection.first + 1, consoleBuffer.selection.last - 1 do
|
|
parent:getChildByIndex(selectionChild):selectAll()
|
|
end
|
|
|
|
local textPos = child:getTextPos(mousePos)
|
|
if childIndex > selfIndex then
|
|
child:setSelection(0, textPos)
|
|
else
|
|
child:setSelection(string.len(child:getText()), textPos)
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
if consoleBuffer:getChildCount() > MAX_LINES then
|
|
local child = consoleBuffer:getFirstChild()
|
|
clearSelection(consoleBuffer)
|
|
child:destroy()
|
|
end
|
|
end
|
|
|
|
function removeTabLabelByName(tab, name)
|
|
local panel = consoleTabBar:getTabPanel(tab)
|
|
local consoleBuffer = panel:getChildById('consoleBuffer')
|
|
for _, label in pairs(consoleBuffer:getChildren()) do
|
|
if label.name == name then
|
|
label:destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
function processChannelTabMenu(tab, mousePos, mouseButton)
|
|
local menu = g_ui.createWidget('PopupMenu')
|
|
menu:setGameMenu(true)
|
|
|
|
local worldName = g_game.getWorldName()
|
|
local characterName = g_game.getCharacterName()
|
|
channelName = tab:getText()
|
|
if tab ~= defaultTab and tab ~= serverTab then
|
|
menu:addOption(tr('Close'), function()
|
|
removeTab(channelName)
|
|
end)
|
|
-- menu:addOption(tr('Show Server Messages'), function() --[[TODO]] end)
|
|
menu:addSeparator()
|
|
end
|
|
|
|
if consoleTabBar:getCurrentTab() == tab then
|
|
menu:addOption(tr('Clear Messages'), function()
|
|
clearChannel(consoleTabBar)
|
|
end)
|
|
menu:addOption(tr('Save Messages'), function()
|
|
local panel = consoleTabBar:getTabPanel(tab)
|
|
local consoleBuffer = panel:getChildById('consoleBuffer')
|
|
local lines = {}
|
|
for _, label in pairs(consoleBuffer:getChildren()) do
|
|
table.insert(lines, label:getText())
|
|
end
|
|
|
|
local filename = worldName .. ' - ' .. characterName .. ' - ' .. channelName .. '.txt'
|
|
local filepath = '/' .. filename
|
|
|
|
-- extra information at the beginning
|
|
table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y'))
|
|
|
|
if g_resources.fileExists(filepath) then
|
|
table.insert(lines, 1, protectedcall(g_resources.readFileContents, filepath) or '')
|
|
end
|
|
|
|
g_resources.writeFileContents(filepath, table.concat(lines, '\n'))
|
|
modules.game_textmessage.displayStatusMessage(tr('Channel appended to %s', filename))
|
|
end)
|
|
end
|
|
|
|
menu:display(mousePos)
|
|
end
|
|
|
|
function processMessageMenu(mousePos, mouseButton, creatureName, text, label, tab)
|
|
if mouseButton == MouseRightButton then
|
|
local menu = g_ui.createWidget('PopupMenu')
|
|
menu:setGameMenu(true)
|
|
if creatureName and #creatureName > 0 then
|
|
if creatureName ~= g_game.getCharacterName() then
|
|
menu:addOption(tr('Message to ' .. creatureName), function()
|
|
g_game.openPrivateChannel(creatureName)
|
|
end)
|
|
if not g_game.getLocalPlayer():hasVip(creatureName) then
|
|
menu:addOption(tr('Add to VIP list'), function()
|
|
g_game.addVip(creatureName)
|
|
end)
|
|
end
|
|
if modules.game_console.getOwnPrivateTab() then
|
|
menu:addSeparator()
|
|
menu:addOption(tr('Invite to private chat'), function()
|
|
g_game.inviteToOwnChannel(creatureName)
|
|
end)
|
|
menu:addOption(tr('Exclude from private chat'), function()
|
|
g_game.excludeFromOwnChannel(creatureName)
|
|
end)
|
|
end
|
|
if isIgnored(creatureName) then
|
|
menu:addOption(tr('Unignore') .. ' ' .. creatureName, function()
|
|
removeIgnoredPlayer(creatureName)
|
|
end)
|
|
else
|
|
menu:addOption(tr('Ignore') .. ' ' .. creatureName, function()
|
|
addIgnoredPlayer(creatureName)
|
|
end)
|
|
end
|
|
menu:addSeparator()
|
|
end
|
|
if modules.game_ruleviolation.hasWindowAccess() then
|
|
menu:addOption(tr('Rule Violation'), function()
|
|
modules.game_ruleviolation.show(creatureName, text:match('.+%:%s(.+)'))
|
|
end)
|
|
menu:addSeparator()
|
|
end
|
|
|
|
menu:addOption(tr('Copy name'), function()
|
|
g_window.setClipboardText(creatureName)
|
|
end)
|
|
end
|
|
local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
|
|
if selection and #selection > 0 then
|
|
menu:addOption(tr('Copy'), function()
|
|
g_window.setClipboardText(selection)
|
|
end, '(Ctrl+C)')
|
|
end
|
|
if text then
|
|
menu:addOption(tr('Copy message'), function()
|
|
g_window.setClipboardText(text)
|
|
end)
|
|
end
|
|
menu:addOption(tr('Select all'), function()
|
|
selectAll(tab.tabPanel:getChildById('consoleBuffer'))
|
|
end)
|
|
if tab.violations and creatureName then
|
|
menu:addSeparator()
|
|
menu:addOption(tr('Process') .. ' ' .. creatureName, function()
|
|
processViolation(creatureName, text)
|
|
end)
|
|
menu:addOption(tr('Remove') .. ' ' .. creatureName, function()
|
|
g_game.closeRuleViolation(creatureName)
|
|
end)
|
|
end
|
|
menu:display(mousePos)
|
|
end
|
|
end
|
|
|
|
function sendCurrentMessage()
|
|
local message = consoleTextEdit:getText()
|
|
if #message == 0 then
|
|
return
|
|
end
|
|
if not isChatEnabled() then
|
|
return
|
|
end
|
|
consoleTextEdit:clearText()
|
|
|
|
-- send message
|
|
sendMessage(message)
|
|
end
|
|
|
|
function addFilter(filter)
|
|
table.insert(filters, filter)
|
|
end
|
|
|
|
function removeFilter(filter)
|
|
table.removevalue(filters, filter)
|
|
end
|
|
|
|
function sendMessage(message, tab)
|
|
local tab = tab or getCurrentTab()
|
|
if not tab then
|
|
return
|
|
end
|
|
|
|
for k, func in pairs(filters) do
|
|
if func(message) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- when talking on server log, the message goes to default channel
|
|
local name = tab:getText()
|
|
if tab == serverTab or tab == getRuleViolationsTab() then
|
|
tab = defaultTab
|
|
name = defaultTab:getText()
|
|
end
|
|
|
|
-- handling chat commands
|
|
local channel = tab.channelId
|
|
local originalMessage = message
|
|
local chatCommandSayMode
|
|
local chatCommandPrivate
|
|
local chatCommandPrivateReady
|
|
local chatCommandMessage
|
|
|
|
-- player used yell command
|
|
chatCommandMessage = message:match('^%#[y|Y] (.*)')
|
|
if chatCommandMessage ~= nil then
|
|
chatCommandSayMode = 'yell'
|
|
channel = 0
|
|
message = chatCommandMessage
|
|
end
|
|
|
|
-- player used whisper
|
|
chatCommandMessage = message:match('^%#[w|W] (.*)')
|
|
if chatCommandMessage ~= nil then
|
|
chatCommandSayMode = 'whisper'
|
|
message = chatCommandMessage
|
|
channel = 0
|
|
end
|
|
|
|
-- player say
|
|
chatCommandMessage = message:match('^%#[s|S] (.*)')
|
|
if chatCommandMessage ~= nil then
|
|
chatCommandSayMode = 'say'
|
|
message = chatCommandMessage
|
|
channel = 0
|
|
end
|
|
|
|
-- player red talk on channel
|
|
chatCommandMessage = message:match('^%#[c|C] (.*)')
|
|
if chatCommandMessage ~= nil then
|
|
chatCommandSayMode = 'channelRed'
|
|
message = chatCommandMessage
|
|
end
|
|
|
|
-- player broadcast
|
|
chatCommandMessage = message:match('^%#[b|B] (.*)')
|
|
if chatCommandMessage ~= nil then
|
|
chatCommandSayMode = 'broadcast'
|
|
message = chatCommandMessage
|
|
channel = 0
|
|
end
|
|
|
|
local findIni, findEnd, chatCommandInitial, chatCommandPrivate, chatCommandEnd, chatCommandMessage = message:find(
|
|
'([%*%@])(.+)([%*%@])(.*)')
|
|
if findIni ~= nil and findIni == 1 then -- player used private chat command
|
|
if chatCommandInitial == chatCommandEnd then
|
|
chatCommandPrivateRepeat = false
|
|
if chatCommandInitial == '*' then
|
|
setTextEditText('*' .. chatCommandPrivate .. '* ')
|
|
end
|
|
message = chatCommandMessage:trim()
|
|
chatCommandPrivateReady = true
|
|
end
|
|
end
|
|
|
|
message = message:gsub('^(%s*)(.*)', '%2') -- remove space characters from message init
|
|
if #message == 0 then
|
|
return
|
|
end
|
|
|
|
-- add new command to history
|
|
currentMessageIndex = 0
|
|
if #messageHistory == 0 or messageHistory[#messageHistory] ~= originalMessage then
|
|
table.insert(messageHistory, originalMessage)
|
|
if #messageHistory > MAX_HISTORY then
|
|
table.remove(messageHistory, 1)
|
|
end
|
|
end
|
|
|
|
local speaktypedesc
|
|
if (channel or tab == defaultTab) and not chatCommandPrivateReady then
|
|
if tab == defaultTab then
|
|
speaktypedesc = chatCommandSayMode or
|
|
SayModes[consolePanel:getChildById('sayModeButton').sayMode].speakTypeDesc
|
|
if speaktypedesc ~= 'say' then
|
|
sayModeChange(2)
|
|
end -- head back to say mode
|
|
else
|
|
speaktypedesc = chatCommandSayMode or 'channelYellow'
|
|
end
|
|
|
|
g_game.talkChannel(SpeakTypesSettings[speaktypedesc].speakType, channel, message)
|
|
return
|
|
else
|
|
local isPrivateCommand = false
|
|
local priv = true
|
|
local tabname = name
|
|
local dontAdd = false
|
|
if chatCommandPrivateReady then
|
|
speaktypedesc = 'privatePlayerToPlayer'
|
|
name = chatCommandPrivate
|
|
isPrivateCommand = true
|
|
elseif tab.npcChat then
|
|
speaktypedesc = 'privatePlayerToNpc'
|
|
elseif tab == violationReportTab then
|
|
if violationReportTab.locked then
|
|
modules.game_textmessage.displayFailureMessage('Wait for a gamemaster reply.')
|
|
dontAdd = true
|
|
else
|
|
speaktypedesc = 'rvrContinue'
|
|
tabname = tr('Report Rule') .. '...'
|
|
end
|
|
elseif tab.violationChatName then
|
|
speaktypedesc = 'rvrAnswerTo'
|
|
name = tab.violationChatName
|
|
tabname = tab.violationChatName .. '\'...'
|
|
else
|
|
speaktypedesc = 'privatePlayerToPlayer'
|
|
end
|
|
|
|
local speaktype = SpeakTypesSettings[speaktypedesc]
|
|
local player = g_game.getLocalPlayer()
|
|
g_game.talkPrivate(speaktype.speakType, name, message)
|
|
if not dontAdd then
|
|
message = applyMessagePrefixies(g_game.getCharacterName(), player:getLevel(), message)
|
|
addPrivateText(message, speaktype, tabname, isPrivateCommand, g_game.getCharacterName())
|
|
end
|
|
end
|
|
end
|
|
|
|
function sayModeChange(sayMode)
|
|
local buttom = consolePanel:getChildById('sayModeButton')
|
|
if sayMode == nil then
|
|
sayMode = buttom.sayMode + 1
|
|
end
|
|
|
|
if sayMode > #SayModes then
|
|
sayMode = 1
|
|
end
|
|
|
|
buttom:setIcon(SayModes[sayMode].icon)
|
|
buttom.sayMode = sayMode
|
|
end
|
|
|
|
function getOwnPrivateTab()
|
|
if not ownPrivateName then
|
|
return
|
|
end
|
|
return getTab(ownPrivateName)
|
|
end
|
|
|
|
function setIgnoreNpcMessages(ignore)
|
|
ignoreNpcMessages = ignore
|
|
end
|
|
|
|
function navigateMessageHistory(step)
|
|
if not isChatEnabled() then
|
|
return
|
|
end
|
|
local numCommands = #messageHistory
|
|
if numCommands > 0 then
|
|
currentMessageIndex = math.min(math.max(currentMessageIndex + step, 0), numCommands)
|
|
if currentMessageIndex > 0 then
|
|
local command = messageHistory[numCommands - currentMessageIndex + 1]
|
|
setTextEditText(command)
|
|
else
|
|
consoleTextEdit:clearText()
|
|
end
|
|
end
|
|
local player = g_game.getLocalPlayer()
|
|
if player then
|
|
player:lockWalk(200) -- lock walk for 200 ms to avoid walk during release of shift
|
|
end
|
|
end
|
|
|
|
function applyMessagePrefixies(name, level, message)
|
|
if name and #name > 0 then
|
|
if modules.client_options.getOption('showLevelsInConsole') and level > 0 then
|
|
message = name .. ' [' .. level .. ']: ' .. message
|
|
else
|
|
message = name .. ': ' .. message
|
|
end
|
|
end
|
|
return message
|
|
end
|
|
|
|
function onTalk(name, level, mode, message, channelId, creaturePos)
|
|
if mode == MessageModes.GamemasterBroadcast then
|
|
modules.game_textmessage.displayBroadcastMessage(name .. ': ' .. message)
|
|
return
|
|
end
|
|
|
|
local isNpcMode = (mode == MessageModes.NpcFromStartBlock or mode == MessageModes.NpcFrom)
|
|
|
|
if ignoreNpcMessages and isNpcMode then
|
|
return
|
|
end
|
|
|
|
speaktype = SpeakTypes[mode]
|
|
|
|
if not speaktype then
|
|
perror('unhandled onTalk message mode ' .. mode .. ': ' .. message)
|
|
return
|
|
end
|
|
|
|
local localPlayer = g_game.getLocalPlayer()
|
|
if name ~= g_game.getCharacterName() and isUsingIgnoreList() and not (isUsingWhiteList()) or
|
|
(isUsingWhiteList() and not (isWhitelisted(name)) and not (isAllowingVIPs() and localPlayer:hasVip(name))) then
|
|
|
|
if mode == MessageModes.Yell and isIgnoringYelling() then
|
|
return
|
|
elseif speaktype.private and isIgnoringPrivate() and not isNpcMode then
|
|
return
|
|
elseif isIgnored(name) then
|
|
return
|
|
end
|
|
end
|
|
|
|
if mode == MessageModes.RVRChannel then
|
|
channelId = violationsChannelId
|
|
end
|
|
|
|
if (mode == MessageModes.Say or mode == MessageModes.Whisper or mode == MessageModes.Yell or mode ==
|
|
MessageModes.Spell or mode == MessageModes.MonsterSay or mode == MessageModes.MonsterYell or mode ==
|
|
MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud or mode ==
|
|
MessageModes.NpcFromStartBlock) and creaturePos then
|
|
local staticText = StaticText.create()
|
|
-- Remove curly braces from screen message
|
|
local staticMessage = message
|
|
if isNpcMode then
|
|
local highlightData = getHighlightedText(staticMessage)
|
|
if #highlightData > 0 then
|
|
for i = 1, #highlightData / 3 do
|
|
local dataBlock = {
|
|
_start = highlightData[(i - 1) * 3 + 1],
|
|
_end = highlightData[(i - 1) * 3 + 2],
|
|
words = highlightData[(i - 1) * 3 + 3]
|
|
}
|
|
staticMessage = staticMessage:gsub('{' .. dataBlock.words .. '}', dataBlock.words)
|
|
end
|
|
end
|
|
staticText:setColor(speaktype.color)
|
|
end
|
|
|
|
staticText:addMessage(name, mode, staticMessage)
|
|
g_map.addStaticText(staticText, creaturePos)
|
|
end
|
|
|
|
local defaultMessage = mode <= 3 and true or false
|
|
|
|
if speaktype == SpeakTypesSettings.none then
|
|
return
|
|
end
|
|
|
|
if speaktype.hideInConsole then
|
|
return
|
|
end
|
|
|
|
local composedMessage = applyMessagePrefixies(name, level, message)
|
|
|
|
if mode == MessageModes.RVRAnswer then
|
|
violationReportTab.locked = false
|
|
addTabText(composedMessage, speaktype, violationReportTab, name)
|
|
elseif mode == MessageModes.RVRContinue then
|
|
addText(composedMessage, speaktype, name .. '\'...', name)
|
|
elseif speaktype.private then
|
|
addPrivateText(composedMessage, speaktype, name, false, name)
|
|
if modules.client_options.getOption('showPrivateMessagesOnScreen') and speaktype ~=
|
|
SpeakTypesSettings.privateNpcToPlayer then
|
|
modules.game_textmessage.displayPrivateMessage(name .. ':\n' .. message)
|
|
end
|
|
else
|
|
local channel = tr('Default')
|
|
if not defaultMessage then
|
|
channel = channels[channelId]
|
|
end
|
|
|
|
if channel then
|
|
addText(composedMessage, speaktype, channel, name)
|
|
else
|
|
-- server sent a message on a channel that is not open
|
|
pwarning('message in channel id ' .. channelId ..
|
|
' which is unknown, this is a server bug, relogin if you want to see messages in this channel')
|
|
end
|
|
end
|
|
end
|
|
|
|
function onOpenChannel(channelId, channelName)
|
|
addChannel(channelName, channelId)
|
|
end
|
|
|
|
function onOpenPrivateChannel(receiver)
|
|
addPrivateChannel(receiver)
|
|
end
|
|
|
|
function onOpenOwnPrivateChannel(channelId, channelName)
|
|
local privateTab = getTab(channelName)
|
|
if privateTab == nil then
|
|
addChannel(channelName, channelId)
|
|
end
|
|
ownPrivateName = channelName
|
|
end
|
|
|
|
function onCloseChannel(channelId)
|
|
local channel = channels[channelId]
|
|
if channel then
|
|
local tab = getTab(channel)
|
|
if tab then
|
|
consoleTabBar:removeTab(tab)
|
|
end
|
|
for k, v in pairs(channels) do
|
|
if (k == tab.channelId) then
|
|
channels[k] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function processViolation(name, text)
|
|
local tabname = name .. '\'...'
|
|
local tab = addTab(tabname, true)
|
|
channels[tabname] = tabname
|
|
tab.violationChatName = name
|
|
g_game.openRuleViolation(name)
|
|
addTabText(text, SpeakTypesSettings.say, tab, name)
|
|
end
|
|
|
|
function onRuleViolationChannel(channelId)
|
|
violationsChannelId = channelId
|
|
local tab = addChannel(tr('Rule Violations'), channelId)
|
|
tab.violations = true
|
|
end
|
|
|
|
function onRuleViolationRemove(name)
|
|
local tab = getRuleViolationsTab()
|
|
if not tab then
|
|
return
|
|
end
|
|
removeTabLabelByName(tab, name)
|
|
end
|
|
|
|
function onRuleViolationCancel(name)
|
|
local tab = getTab(name .. '\'...')
|
|
if not tab then
|
|
return
|
|
end
|
|
addTabText(tr('%s has finished the request', name) .. '.', SpeakTypesSettings.privateRed, tab)
|
|
tab.locked = true
|
|
end
|
|
|
|
function onRuleViolationLock()
|
|
if not violationReportTab then
|
|
return
|
|
end
|
|
violationReportTab.locked = false
|
|
addTabText(tr('Your request has been closed') .. '.', SpeakTypesSettings.privateRed, violationReportTab)
|
|
violationReportTab.locked = true
|
|
end
|
|
|
|
function doChannelListSubmit()
|
|
local channelListPanel = channelsWindow:getChildById('channelList')
|
|
local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText()
|
|
if openPrivateChannelWith ~= '' then
|
|
if openPrivateChannelWith:lower() ~= g_game.getCharacterName():lower() then
|
|
g_game.openPrivateChannel(openPrivateChannelWith)
|
|
else
|
|
modules.game_textmessage.displayFailureMessage('You cannot create a private chat channel with yourself.')
|
|
end
|
|
else
|
|
local selectedChannelLabel = channelListPanel:getFocusedChild()
|
|
if not selectedChannelLabel then
|
|
return
|
|
end
|
|
if selectedChannelLabel.channelId == 0xFFFF then
|
|
g_game.openOwnChannel()
|
|
else
|
|
g_game.leaveChannel(selectedChannelLabel.channelId)
|
|
g_game.joinChannel(selectedChannelLabel.channelId)
|
|
end
|
|
end
|
|
|
|
channelsWindow:destroy()
|
|
end
|
|
|
|
function onChannelList(channelList)
|
|
if channelsWindow then
|
|
channelsWindow:destroy()
|
|
end
|
|
channelsWindow = g_ui.displayUI('channelswindow')
|
|
local channelListPanel = channelsWindow:getChildById('channelList')
|
|
channelsWindow.onEnter = doChannelListSubmit
|
|
channelsWindow.onDestroy = function()
|
|
channelsWindow = nil
|
|
end
|
|
g_keyboard.bindKeyPress('Down', function()
|
|
channelListPanel:focusNextChild(KeyboardFocusReason)
|
|
end, channelsWindow)
|
|
g_keyboard.bindKeyPress('Up', function()
|
|
channelListPanel:focusPreviousChild(KeyboardFocusReason)
|
|
end, channelsWindow)
|
|
|
|
for k, v in pairs(channelList) do
|
|
local channelId = v[1]
|
|
local channelName = v[2]
|
|
|
|
if #channelName > 0 then
|
|
local label = g_ui.createWidget('ChannelListLabel', channelListPanel)
|
|
label.channelId = channelId
|
|
label:setText(channelName)
|
|
|
|
label:setPhantom(false)
|
|
label.onDoubleClick = doChannelListSubmit
|
|
end
|
|
end
|
|
end
|
|
|
|
function loadCommunicationSettings()
|
|
communicationSettings.whitelistedPlayers = {}
|
|
communicationSettings.ignoredPlayers = {}
|
|
|
|
local ignoreNode = g_settings.getNode('IgnorePlayers')
|
|
if ignoreNode then
|
|
for _, player in pairs(ignoreNode) do
|
|
table.insert(communicationSettings.ignoredPlayers, player)
|
|
end
|
|
end
|
|
|
|
local whitelistNode = g_settings.getNode('WhitelistedPlayers')
|
|
if whitelistNode then
|
|
for _, player in pairs(whitelistNode) do
|
|
table.insert(communicationSettings.whitelistedPlayers, player)
|
|
end
|
|
end
|
|
|
|
communicationSettings.useIgnoreList = g_settings.getBoolean('UseIgnoreList')
|
|
communicationSettings.useWhiteList = g_settings.getBoolean('UseWhiteList')
|
|
communicationSettings.privateMessages = g_settings.getBoolean('IgnorePrivateMessages')
|
|
communicationSettings.yelling = g_settings.getBoolean('IgnoreYelling')
|
|
communicationSettings.allowVIPs = g_settings.getBoolean('AllowVIPs')
|
|
end
|
|
|
|
function saveCommunicationSettings()
|
|
local tmpIgnoreList = {}
|
|
local ignoredPlayers = getIgnoredPlayers()
|
|
for i = 1, #ignoredPlayers do
|
|
table.insert(tmpIgnoreList, ignoredPlayers[i])
|
|
end
|
|
|
|
local tmpWhiteList = {}
|
|
local whitelistedPlayers = getWhitelistedPlayers()
|
|
for i = 1, #whitelistedPlayers do
|
|
table.insert(tmpWhiteList, whitelistedPlayers[i])
|
|
end
|
|
|
|
g_settings.set('UseIgnoreList', communicationSettings.useIgnoreList)
|
|
g_settings.set('UseWhiteList', communicationSettings.useWhiteList)
|
|
g_settings.set('IgnorePrivateMessages', communicationSettings.privateMessages)
|
|
g_settings.set('IgnoreYelling', communicationSettings.yelling)
|
|
g_settings.setNode('IgnorePlayers', tmpIgnoreList)
|
|
g_settings.setNode('WhitelistedPlayers', tmpWhiteList)
|
|
end
|
|
|
|
function getIgnoredPlayers()
|
|
return communicationSettings.ignoredPlayers
|
|
end
|
|
|
|
function getWhitelistedPlayers()
|
|
return communicationSettings.whitelistedPlayers
|
|
end
|
|
|
|
function isUsingIgnoreList()
|
|
return communicationSettings.useIgnoreList
|
|
end
|
|
|
|
function isUsingWhiteList()
|
|
return communicationSettings.useWhiteList
|
|
end
|
|
function isIgnored(name)
|
|
return table.find(communicationSettings.ignoredPlayers, name, true)
|
|
end
|
|
|
|
function addIgnoredPlayer(name)
|
|
if isIgnored(name) then
|
|
return
|
|
end
|
|
table.insert(communicationSettings.ignoredPlayers, name)
|
|
communicationSettings.useIgnoreList = true
|
|
end
|
|
|
|
function removeIgnoredPlayer(name)
|
|
table.removevalue(communicationSettings.ignoredPlayers, name)
|
|
end
|
|
|
|
function isWhitelisted(name)
|
|
return table.find(communicationSettings.whitelistedPlayers, name, true)
|
|
end
|
|
|
|
function addWhitelistedPlayer(name)
|
|
if isWhitelisted(name) then
|
|
return
|
|
end
|
|
table.insert(communicationSettings.whitelistedPlayers, name)
|
|
end
|
|
|
|
function removeWhitelistedPlayer(name)
|
|
table.removevalue(communicationSettings.whitelistedPlayers, name)
|
|
end
|
|
|
|
function isIgnoringPrivate()
|
|
return communicationSettings.privateMessages
|
|
end
|
|
|
|
function isIgnoringYelling()
|
|
return communicationSettings.yelling
|
|
end
|
|
|
|
function isAllowingVIPs()
|
|
return communicationSettings.allowVIPs
|
|
end
|
|
|
|
function onClickIgnoreButton()
|
|
if communicationWindow then
|
|
return
|
|
end
|
|
communicationWindow = g_ui.displayUI('communicationwindow')
|
|
local ignoreListPanel = communicationWindow:getChildById('ignoreList')
|
|
local whiteListPanel = communicationWindow:getChildById('whiteList')
|
|
communicationWindow.onDestroy = function()
|
|
communicationWindow = nil
|
|
end
|
|
|
|
local useIgnoreListBox = communicationWindow:getChildById('checkboxUseIgnoreList')
|
|
useIgnoreListBox:setChecked(communicationSettings.useIgnoreList)
|
|
local useWhiteListBox = communicationWindow:getChildById('checkboxUseWhiteList')
|
|
useWhiteListBox:setChecked(communicationSettings.useWhiteList)
|
|
|
|
local removeIgnoreButton = communicationWindow:getChildById('buttonIgnoreRemove')
|
|
removeIgnoreButton:disable()
|
|
ignoreListPanel.onChildFocusChange = function()
|
|
removeIgnoreButton:enable()
|
|
end
|
|
removeIgnoreButton.onClick = function()
|
|
local selection = ignoreListPanel:getFocusedChild()
|
|
if selection then
|
|
ignoreListPanel:removeChild(selection)
|
|
selection:destroy()
|
|
end
|
|
removeIgnoreButton:disable()
|
|
end
|
|
|
|
local removeWhitelistButton = communicationWindow:getChildById('buttonWhitelistRemove')
|
|
removeWhitelistButton:disable()
|
|
whiteListPanel.onChildFocusChange = function()
|
|
removeWhitelistButton:enable()
|
|
end
|
|
removeWhitelistButton.onClick = function()
|
|
local selection = whiteListPanel:getFocusedChild()
|
|
if selection then
|
|
whiteListPanel:removeChild(selection)
|
|
selection:destroy()
|
|
end
|
|
removeWhitelistButton:disable()
|
|
end
|
|
|
|
local newlyIgnoredPlayers = {}
|
|
local addIgnoreName = communicationWindow:getChildById('ignoreNameEdit')
|
|
local addIgnoreButton = communicationWindow:getChildById('buttonIgnoreAdd')
|
|
local addIgnoreFunction = function()
|
|
local newEntry = addIgnoreName:getText()
|
|
if newEntry == '' then
|
|
return
|
|
end
|
|
if table.find(getIgnoredPlayers(), newEntry) then
|
|
return
|
|
end
|
|
if table.find(newlyIgnoredPlayers, newEntry) then
|
|
return
|
|
end
|
|
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
|
|
label:setText(newEntry)
|
|
table.insert(newlyIgnoredPlayers, newEntry)
|
|
addIgnoreName:setText('')
|
|
end
|
|
addIgnoreButton.onClick = addIgnoreFunction
|
|
|
|
local newlyWhitelistedPlayers = {}
|
|
local addWhitelistName = communicationWindow:getChildById('whitelistNameEdit')
|
|
local addWhitelistButton = communicationWindow:getChildById('buttonWhitelistAdd')
|
|
local addWhitelistFunction = function()
|
|
local newEntry = addWhitelistName:getText()
|
|
if newEntry == '' then
|
|
return
|
|
end
|
|
if table.find(getWhitelistedPlayers(), newEntry) then
|
|
return
|
|
end
|
|
if table.find(newlyWhitelistedPlayers, newEntry) then
|
|
return
|
|
end
|
|
local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
|
|
label:setText(newEntry)
|
|
table.insert(newlyWhitelistedPlayers, newEntry)
|
|
addWhitelistName:setText('')
|
|
end
|
|
addWhitelistButton.onClick = addWhitelistFunction
|
|
|
|
communicationWindow.onEnter = function()
|
|
if addWhitelistName:isFocused() then
|
|
addWhitelistFunction()
|
|
elseif addIgnoreName:isFocused() then
|
|
addIgnoreFunction()
|
|
end
|
|
end
|
|
|
|
local ignorePrivateMessageBox = communicationWindow:getChildById('checkboxIgnorePrivateMessages')
|
|
ignorePrivateMessageBox:setChecked(communicationSettings.privateMessages)
|
|
local ignoreYellingBox = communicationWindow:getChildById('checkboxIgnoreYelling')
|
|
ignoreYellingBox:setChecked(communicationSettings.yelling)
|
|
local allowVIPsBox = communicationWindow:getChildById('checkboxAllowVIPs')
|
|
allowVIPsBox:setChecked(communicationSettings.allowVIPs)
|
|
|
|
local saveButton = communicationWindow:recursiveGetChildById('buttonSave')
|
|
saveButton.onClick = function()
|
|
communicationSettings.ignoredPlayers = {}
|
|
for i = 1, ignoreListPanel:getChildCount() do
|
|
addIgnoredPlayer(ignoreListPanel:getChildByIndex(i):getText())
|
|
end
|
|
|
|
communicationSettings.whitelistedPlayers = {}
|
|
for i = 1, whiteListPanel:getChildCount() do
|
|
addWhitelistedPlayer(whiteListPanel:getChildByIndex(i):getText())
|
|
end
|
|
|
|
communicationSettings.useIgnoreList = useIgnoreListBox:isChecked()
|
|
communicationSettings.useWhiteList = useWhiteListBox:isChecked()
|
|
communicationSettings.yelling = ignoreYellingBox:isChecked()
|
|
communicationSettings.privateMessages = ignorePrivateMessageBox:isChecked()
|
|
communicationSettings.allowVIPs = allowVIPsBox:isChecked()
|
|
communicationWindow:destroy()
|
|
end
|
|
|
|
local cancelButton = communicationWindow:recursiveGetChildById('buttonCancel')
|
|
cancelButton.onClick = function()
|
|
communicationWindow:destroy()
|
|
end
|
|
|
|
local ignoredPlayers = getIgnoredPlayers()
|
|
for i = 1, #ignoredPlayers do
|
|
local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
|
|
label:setText(ignoredPlayers[i])
|
|
end
|
|
|
|
local whitelistedPlayers = getWhitelistedPlayers()
|
|
for i = 1, #whitelistedPlayers do
|
|
local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
|
|
label:setText(whitelistedPlayers[i])
|
|
end
|
|
end
|
|
|
|
function online()
|
|
defaultTab = addTab(tr('Default'), true)
|
|
serverTab = addTab(tr('Server Log'), false)
|
|
|
|
if g_game.getClientVersion() >= 820 then
|
|
local tab = addTab('NPCs', false)
|
|
tab.npcChat = true
|
|
end
|
|
if g_game.getClientVersion() < 862 then
|
|
g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow)
|
|
end
|
|
-- open last channels
|
|
local lastChannelsOpen = g_settings.getNode('lastChannelsOpen')
|
|
if lastChannelsOpen then
|
|
local savedChannels = lastChannelsOpen[g_game.getCharacterName()]
|
|
if savedChannels then
|
|
for channelName, channelId in pairs(savedChannels) do
|
|
channelId = tonumber(channelId)
|
|
if channelId ~= -1 and channelId < 100 then
|
|
if not table.find(channels, channelId) then
|
|
g_game.joinChannel(channelId)
|
|
table.insert(ignoredChannels, channelId)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
scheduleEvent(function()
|
|
ignoredChannels = {}
|
|
end, 3000)
|
|
end
|
|
|
|
function offline()
|
|
if g_game.getClientVersion() < 862 then
|
|
g_keyboard.unbindKeyDown('Ctrl+R')
|
|
end
|
|
clear()
|
|
end
|
|
|
|
function onChannelEvent(channelId, name, type)
|
|
local fmt = ChannelEventFormats[type]
|
|
if not fmt then
|
|
print(('Unknown channel event type (%d).'):format(type))
|
|
return
|
|
end
|
|
|
|
local channel = channels[channelId]
|
|
if channel then
|
|
local tab = getTab(channel)
|
|
if tab then
|
|
addTabText(fmt:format(name), SpeakTypesSettings.channelOrange, tab)
|
|
end
|
|
end
|
|
end
|