No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

console.lua 49KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  1. SpeakTypesSettings = {
  2. none = {},
  3. say = { speakType = MessageModes.Say, color = '#FFFF00' },
  4. whisper = { speakType = MessageModes.Whisper, color = '#FFFF00' },
  5. yell = { speakType = MessageModes.Yell, color = '#FFFF00' },
  6. broadcast = { speakType = MessageModes.GamemasterBroadcast, color = '#F55E5E' },
  7. private = { speakType = MessageModes.PrivateTo, color = '#5FF7F7', private = true },
  8. privateRed = { speakType = MessageModes.GamemasterTo, color = '#F55E5E', private = true },
  9. privatePlayerToPlayer = { speakType = MessageModes.PrivateTo, color = '#9F9DFD', private = true },
  10. privatePlayerToNpc = { speakType = MessageModes.NpcTo, color = '#9F9DFD', private = true, npcChat = true },
  11. privateNpcToPlayer = { speakType = MessageModes.NpcFrom, color = '#5FF7F7', private = true, npcChat = true },
  12. channelYellow = { speakType = MessageModes.Channel, color = '#FFFF00' },
  13. channelWhite = { speakType = MessageModes.ChannelManagement, color = '#FFFFFF' },
  14. channelRed = { speakType = MessageModes.GamemasterChannel, color = '#F55E5E' },
  15. channelOrange = { speakType = MessageModes.ChannelHighlight, color = '#FE6500' },
  16. monsterSay = { speakType = MessageModes.MonsterSay, color = '#FE6500', hideInConsole = true},
  17. monsterYell = { speakType = MessageModes.MonsterYell, color = '#FE6500', hideInConsole = true},
  18. rvrAnswerFrom = { speakType = MessageModes.RVRAnswer, color = '#FE6500' },
  19. rvrAnswerTo = { speakType = MessageModes.RVRAnswer, color = '#FE6500' },
  20. rvrContinue = { speakType = MessageModes.RVRContinue, color = '#FFFF00' },
  21. }
  22. SpeakTypes = {
  23. [MessageModes.Say] = SpeakTypesSettings.say,
  24. [MessageModes.Whisper] = SpeakTypesSettings.whisper,
  25. [MessageModes.Yell] = SpeakTypesSettings.yell,
  26. [MessageModes.GamemasterBroadcast] = SpeakTypesSettings.broadcast,
  27. [MessageModes.PrivateFrom] = SpeakTypesSettings.private,
  28. [MessageModes.GamemasterPrivateFrom] = SpeakTypesSettings.privateRed,
  29. [MessageModes.NpcTo] = SpeakTypesSettings.privatePlayerToNpc,
  30. [MessageModes.NpcFrom] = SpeakTypesSettings.privateNpcToPlayer,
  31. [MessageModes.Channel] = SpeakTypesSettings.channelYellow,
  32. [MessageModes.ChannelManagement] = SpeakTypesSettings.channelWhite,
  33. [MessageModes.GamemasterChannel] = SpeakTypesSettings.channelRed,
  34. [MessageModes.ChannelHighlight] = SpeakTypesSettings.channelOrange,
  35. [MessageModes.MonsterSay] = SpeakTypesSettings.monsterSay,
  36. [MessageModes.MonsterYell] = SpeakTypesSettings.monsterYell,
  37. [MessageModes.RVRChannel] = SpeakTypesSettings.channelWhite,
  38. [MessageModes.RVRContinue] = SpeakTypesSettings.rvrContinue,
  39. [MessageModes.RVRAnswer] = SpeakTypesSettings.rvrAnswerFrom,
  40. [MessageModes.NpcFromStartBlock] = SpeakTypesSettings.privateNpcToPlayer,
  41. -- ignored types
  42. [MessageModes.Spell] = SpeakTypesSettings.none,
  43. [MessageModes.BarkLow] = SpeakTypesSettings.none,
  44. [MessageModes.BarkLoud] = SpeakTypesSettings.none,
  45. }
  46. SayModes = {
  47. [1] = { speakTypeDesc = 'whisper', icon = '/images/game/console/whisper' },
  48. [2] = { speakTypeDesc = 'say', icon = '/images/game/console/say' },
  49. [3] = { speakTypeDesc = 'yell', icon = '/images/game/console/yell' }
  50. }
  51. MAX_HISTORY = 500
  52. MAX_LINES = 100
  53. HELP_CHANNEL = 9
  54. consolePanel = nil
  55. consoleContentPanel = nil
  56. consoleTabBar = nil
  57. consoleTextEdit = nil
  58. channels = nil
  59. channelsWindow = nil
  60. communicationWindow = nil
  61. ownPrivateName = nil
  62. messageHistory = {}
  63. currentMessageIndex = 0
  64. ignoreNpcMessages = false
  65. defaultTab = nil
  66. serverTab = nil
  67. violationsChannelId = nil
  68. violationWindow = nil
  69. violationReportTab = nil
  70. ignoredChannels = {}
  71. filters = {}
  72. local communicationSettings = {
  73. useIgnoreList = true,
  74. useWhiteList = true,
  75. privateMessages = false,
  76. yelling = false,
  77. allowVIPs = false,
  78. ignoredPlayers = {},
  79. whitelistedPlayers = {}
  80. }
  81. function init()
  82. connect(g_game, {
  83. onTalk = onTalk,
  84. onChannelList = onChannelList,
  85. onOpenChannel = onOpenChannel,
  86. onOpenPrivateChannel = onOpenPrivateChannel,
  87. onOpenOwnPrivateChannel = onOpenOwnPrivateChannel,
  88. onCloseChannel = onCloseChannel,
  89. onRuleViolationChannel = onRuleViolationChannel,
  90. onRuleViolationRemove = onRuleViolationRemove,
  91. onRuleViolationCancel = onRuleViolationCancel,
  92. onRuleViolationLock = onRuleViolationLock,
  93. onGameStart = online,
  94. onGameEnd = offline
  95. })
  96. consolePanel = g_ui.loadUI('console', modules.game_interface.getBottomPanel())
  97. consoleTextEdit = consolePanel:getChildById('consoleTextEdit')
  98. consoleContentPanel = consolePanel:getChildById('consoleContentPanel')
  99. consoleTabBar = consolePanel:getChildById('consoleTabBar')
  100. consoleTabBar:setContentWidget(consoleContentPanel)
  101. channels = {}
  102. consolePanel.onKeyPress = function(self, keyCode, keyboardModifiers)
  103. if not (keyboardModifiers == KeyboardCtrlModifier and keyCode == KeyC) then return false end
  104. local tab = consoleTabBar:getCurrentTab()
  105. if not tab then return false end
  106. local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
  107. if not selection then return false end
  108. g_window.setClipboardText(selection)
  109. return true
  110. end
  111. g_keyboard.bindKeyPress('Shift+Up', function() navigateMessageHistory(1) end, consolePanel)
  112. g_keyboard.bindKeyPress('Shift+Down', function() navigateMessageHistory(-1) end, consolePanel)
  113. g_keyboard.bindKeyPress('Tab', function() consoleTabBar:selectNextTab() end, consolePanel)
  114. g_keyboard.bindKeyPress('Shift+Tab', function() consoleTabBar:selectPrevTab() end, consolePanel)
  115. g_keyboard.bindKeyDown('Enter', sendCurrentMessage, consolePanel)
  116. g_keyboard.bindKeyPress('Ctrl+A', function() consoleTextEdit:clearText() end, consolePanel)
  117. -- apply buttom functions after loaded
  118. consoleTabBar:setNavigation(consolePanel:getChildById('prevChannelButton'), consolePanel:getChildById('nextChannelButton'))
  119. consoleTabBar.onTabChange = onTabChange
  120. -- tibia like hotkeys
  121. g_keyboard.bindKeyDown('Ctrl+O', g_game.requestChannels)
  122. g_keyboard.bindKeyDown('Ctrl+E', removeCurrentTab)
  123. g_keyboard.bindKeyDown('Ctrl+H', openHelp)
  124. consoleToggleChat = consolePanel:getChildById('toggleChat')
  125. load()
  126. if g_game.isOnline() then
  127. online()
  128. end
  129. end
  130. function clearSelection(consoleBuffer)
  131. for _,label in pairs(consoleBuffer:getChildren()) do
  132. label:clearSelection()
  133. end
  134. consoleBuffer.selectionText = nil
  135. consoleBuffer.selection = nil
  136. end
  137. function selectAll(consoleBuffer)
  138. clearSelection(consoleBuffer)
  139. if consoleBuffer:getChildCount() > 0 then
  140. local text = {}
  141. for _,label in pairs(consoleBuffer:getChildren()) do
  142. label:selectAll()
  143. table.insert(text, label:getSelection())
  144. end
  145. consoleBuffer.selectionText = table.concat(text, '\n')
  146. consoleBuffer.selection = { first = consoleBuffer:getChildIndex(consoleBuffer:getFirstChild()), last = consoleBuffer:getChildIndex(consoleBuffer:getLastChild()) }
  147. end
  148. end
  149. function toggleChat()
  150. if consoleToggleChat:isChecked() then
  151. disableChat()
  152. else
  153. enableChat()
  154. end
  155. end
  156. function enableChat()
  157. local gameInterface = modules.game_interface
  158. consoleTextEdit:setVisible(true)
  159. consoleTextEdit:setText("")
  160. g_keyboard.unbindKeyUp("Space")
  161. g_keyboard.unbindKeyUp("Enter")
  162. g_keyboard.unbindKeyUp("Escape")
  163. gameInterface.unbindWalkKey("W")
  164. gameInterface.unbindWalkKey("D")
  165. gameInterface.unbindWalkKey("S")
  166. gameInterface.unbindWalkKey("A")
  167. gameInterface.unbindWalkKey("E")
  168. gameInterface.unbindWalkKey("Q")
  169. gameInterface.unbindWalkKey("C")
  170. gameInterface.unbindWalkKey("Z")
  171. consoleToggleChat:setTooltip(tr("Disable chat mode, allow to walk using ASDW"))
  172. end
  173. function disableChat()
  174. local gameInterface = modules.game_interface
  175. consoleTextEdit:setVisible(false)
  176. consoleTextEdit:setText("")
  177. local quickFunc = function()
  178. if consoleToggleChat:isChecked() then
  179. consoleToggleChat:setChecked(false)
  180. end
  181. enableChat()
  182. end
  183. g_keyboard.bindKeyUp("Space", quickFunc)
  184. g_keyboard.bindKeyUp("Enter", quickFunc)
  185. g_keyboard.bindKeyUp("Escape", quickFunc)
  186. gameInterface.bindWalkKey("W", North)
  187. gameInterface.bindWalkKey("D", East)
  188. gameInterface.bindWalkKey("S", South)
  189. gameInterface.bindWalkKey("A", West)
  190. gameInterface.bindWalkKey("E", NorthEast)
  191. gameInterface.bindWalkKey("Q", NorthWest)
  192. gameInterface.bindWalkKey("C", SouthEast)
  193. gameInterface.bindWalkKey("Z", SouthWest)
  194. consoleToggleChat:setTooltip(tr("Enable chat mode"))
  195. end
  196. function terminate()
  197. save()
  198. disconnect(g_game, {
  199. onTalk = onTalk,
  200. onChannelList = onChannelList,
  201. onOpenChannel = onOpenChannel,
  202. onOpenPrivateChannel = onOpenPrivateChannel,
  203. onOpenOwnPrivateChannel = onOpenPrivateChannel,
  204. onCloseChannel = onCloseChannel,
  205. onRuleViolationChannel = onRuleViolationChannel,
  206. onRuleViolationRemove = onRuleViolationRemove,
  207. onRuleViolationCancel = onRuleViolationCancel,
  208. onRuleViolationLock = onRuleViolationLock,
  209. onGameStart = online,
  210. onGameEnd = offline
  211. })
  212. if g_game.isOnline() then clear() end
  213. g_keyboard.unbindKeyDown('Ctrl+O')
  214. g_keyboard.unbindKeyDown('Ctrl+E')
  215. g_keyboard.unbindKeyDown('Ctrl+H')
  216. saveCommunicationSettings()
  217. if channelsWindow then
  218. channelsWindow:destroy()
  219. end
  220. if communicationWindow then
  221. communicationWindow:destroy()
  222. end
  223. if violationWindow then
  224. violationWindow:destroy()
  225. end
  226. consoleTabBar = nil
  227. consoleContentPanel = nil
  228. consoleToggleChat = nil
  229. consoleTextEdit = nil
  230. consolePanel:destroy()
  231. consolePanel = nil
  232. ownPrivateName = nil
  233. Console = nil
  234. end
  235. function save()
  236. local settings = {}
  237. settings.messageHistory = messageHistory
  238. g_settings.setNode('game_console', settings)
  239. end
  240. function load()
  241. local settings = g_settings.getNode('game_console')
  242. if settings then
  243. messageHistory = settings.messageHistory or {}
  244. end
  245. loadCommunicationSettings()
  246. end
  247. function onTabChange(tabBar, tab)
  248. if tab == defaultTab or tab == serverTab then
  249. consolePanel:getChildById('closeChannelButton'):disable()
  250. else
  251. consolePanel:getChildById('closeChannelButton'):enable()
  252. end
  253. end
  254. function clear()
  255. -- save last open channels
  256. local lastChannelsOpen = g_settings.getNode('lastChannelsOpen') or {}
  257. local char = g_game.getCharacterName()
  258. local savedChannels = {}
  259. local set = false
  260. for channelId, channelName in pairs(channels) do
  261. if type(channelId) == 'number' then
  262. savedChannels[channelName] = channelId
  263. set = true
  264. end
  265. end
  266. if set then
  267. lastChannelsOpen[char] = savedChannels
  268. else
  269. lastChannelsOpen[char] = nil
  270. end
  271. g_settings.setNode('lastChannelsOpen', lastChannelsOpen)
  272. -- close channels
  273. for _, channelName in pairs(channels) do
  274. local tab = consoleTabBar:getTab(channelName)
  275. consoleTabBar:removeTab(tab)
  276. end
  277. channels = {}
  278. consoleTabBar:removeTab(defaultTab)
  279. defaultTab = nil
  280. consoleTabBar:removeTab(serverTab)
  281. serverTab = nil
  282. local npcTab = consoleTabBar:getTab('NPCs')
  283. if npcTab then
  284. consoleTabBar:removeTab(npcTab)
  285. npcTab = nil
  286. end
  287. if violationReportTab then
  288. consoleTabBar:removeTab(violationReportTab)
  289. violationReportTab = nil
  290. end
  291. consoleTextEdit:clearText()
  292. if violationWindow then
  293. violationWindow:destroy()
  294. violationWindow = nil
  295. end
  296. if channelsWindow then
  297. channelsWindow:destroy()
  298. channelsWindow = nil
  299. end
  300. end
  301. function clearChannel(consoleTabBar)
  302. consoleTabBar:getCurrentTab().tabPanel:getChildById('consoleBuffer'):destroyChildren()
  303. end
  304. function setTextEditText(text)
  305. consoleTextEdit:setText(text)
  306. consoleTextEdit:setCursorPos(-1)
  307. end
  308. function openHelp()
  309. local helpChannel = 9
  310. if g_game.getClientVersion() <= 810 then
  311. helpChannel = 8
  312. end
  313. g_game.joinChannel(helpChannel)
  314. end
  315. function openPlayerReportRuleViolationWindow()
  316. if violationWindow or violationReportTab then return end
  317. violationWindow = g_ui.loadUI('violationwindow', rootWidget)
  318. violationWindow.onEscape = function()
  319. violationWindow:destroy()
  320. violationWindow = nil
  321. end
  322. violationWindow.onEnter = function()
  323. local text = violationWindow:getChildById('text'):getText()
  324. g_game.talkChannel(MessageModes.RVRChannel, 0, text)
  325. violationReportTab = addTab(tr('Report Rule') .. '...', true)
  326. addTabText(tr('Please wait patiently for a gamemaster to reply') .. '.', SpeakTypesSettings.privateRed, violationReportTab)
  327. addTabText(applyMessagePrefixies(g_game.getCharacterName(), 0, text), SpeakTypesSettings.say, violationReportTab, g_game.getCharacterName())
  328. violationReportTab.locked = true
  329. violationWindow:destroy()
  330. violationWindow = nil
  331. end
  332. end
  333. function addTab(name, focus)
  334. local tab = getTab(name)
  335. if tab then -- is channel already open
  336. if not focus then focus = true end
  337. else
  338. tab = consoleTabBar:addTab(name, nil, processChannelTabMenu)
  339. end
  340. if focus then
  341. consoleTabBar:selectTab(tab)
  342. end
  343. return tab
  344. end
  345. function removeTab(tab)
  346. if type(tab) == 'string' then
  347. tab = consoleTabBar:getTab(tab)
  348. end
  349. if tab == defaultTab or tab == serverTab then
  350. return
  351. end
  352. if tab == violationReportTab then
  353. g_game.cancelRuleViolation()
  354. violationReportTab = nil
  355. elseif tab.violationChatName then
  356. g_game.closeRuleViolation(tab.violationChatName)
  357. elseif tab.channelId then
  358. -- notificate the server that we are leaving the channel
  359. for k, v in pairs(channels) do
  360. if (k == tab.channelId) then channels[k] = nil end
  361. end
  362. g_game.leaveChannel(tab.channelId)
  363. elseif tab:getText() == "NPCs" then
  364. g_game.closeNpcChannel()
  365. end
  366. consoleTabBar:removeTab(tab)
  367. end
  368. function removeCurrentTab()
  369. removeTab(consoleTabBar:getCurrentTab())
  370. end
  371. function getTab(name)
  372. return consoleTabBar:getTab(name)
  373. end
  374. function getChannelTab(channelId)
  375. local channel = channels[channelId]
  376. if channel then
  377. return getTab(channel)
  378. end
  379. return nil
  380. end
  381. function getRuleViolationsTab()
  382. if violationsChannelId then
  383. return getChannelTab(violationsChannelId)
  384. end
  385. return nil
  386. end
  387. function getCurrentTab()
  388. return consoleTabBar:getCurrentTab()
  389. end
  390. function addChannel(name, id)
  391. channels[id] = name
  392. local focus = not table.find(ignoredChannels, id)
  393. local tab = addTab(name, focus)
  394. tab.channelId = id
  395. return tab
  396. end
  397. function addPrivateChannel(receiver)
  398. channels[receiver] = receiver
  399. return addTab(receiver, false)
  400. end
  401. function addPrivateText(text, speaktype, name, isPrivateCommand, creatureName)
  402. local focus = false
  403. if speaktype.npcChat then
  404. name = 'NPCs'
  405. focus = true
  406. end
  407. local privateTab = getTab(name)
  408. if privateTab == nil then
  409. if (modules.client_options.getOption('showPrivateMessagesInConsole') and not focus) or (isPrivateCommand and not privateTab) then
  410. privateTab = defaultTab
  411. else
  412. privateTab = addTab(name, focus)
  413. channels[name] = name
  414. end
  415. privateTab.npcChat = speaktype.npcChat
  416. elseif focus then
  417. consoleTabBar:selectTab(privateTab)
  418. end
  419. addTabText(text, speaktype, privateTab, creatureName)
  420. end
  421. function addText(text, speaktype, tabName, creatureName)
  422. local tab = getTab(tabName)
  423. if tab ~= nil then
  424. addTabText(text, speaktype, tab, creatureName)
  425. end
  426. end
  427. -- Contains letter width for font "verdana-11px-antialised" as console is based on it
  428. local letterWidth = { -- New line (10) and Space (32) have width 1 because they are printed and not replaced with spacer
  429. [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,
  430. [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,
  431. [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,
  432. [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,
  433. [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,
  434. [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,
  435. [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,
  436. [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,
  437. [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,
  438. [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,
  439. [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,
  440. [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,
  441. [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,
  442. [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
  443. }
  444. -- Return information about start, end in the string and the highlighted words
  445. function getHighlightedText(text)
  446. local tmpData = {}
  447. repeat
  448. local tmp = {string.find(text, "{([^}]+)}", tmpData[#tmpData-1])}
  449. for _, v in pairs(tmp) do
  450. table.insert(tmpData, v)
  451. end
  452. until not(string.find(text, "{([^}]+)}", tmpData[#tmpData-1]))
  453. return tmpData
  454. end
  455. function addTabText(text, speaktype, tab, creatureName)
  456. if not tab or tab.locked or not text or #text == 0 then return end
  457. if modules.client_options.getOption('showTimestampsInConsole') then
  458. text = os.date('%H:%M') .. ' ' .. text
  459. end
  460. local panel = consoleTabBar:getTabPanel(tab)
  461. local consoleBuffer = panel:getChildById('consoleBuffer')
  462. local label = g_ui.createWidget('ConsoleLabel', consoleBuffer)
  463. label:setId('consoleLabel' .. consoleBuffer:getChildCount())
  464. label:setText(text)
  465. label:setColor(speaktype.color)
  466. consoleTabBar:blinkTab(tab)
  467. -- Overlay for consoleBuffer which shows highlighted words only
  468. if speaktype.npcChat and (g_game.getCharacterName() ~= creatureName or g_game.getCharacterName() == 'Account Manager') then
  469. local highlightData = getHighlightedText(text)
  470. if #highlightData > 0 then
  471. local labelHighlight = g_ui.createWidget('ConsolePhantomLabel', label)
  472. labelHighlight:fill('parent')
  473. labelHighlight:setId('consoleLabelHighlight' .. consoleBuffer:getChildCount())
  474. labelHighlight:setColor("#1f9ffe")
  475. -- Remove the curly braces
  476. for i = 1, #highlightData / 3 do
  477. local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
  478. text = text:gsub("%{(.-)%}", dataBlock.words, 1)
  479. -- Recalculate positions as braces are removed
  480. highlightData[(i-1)*3+1] = dataBlock._start - ((i-1) * 2)
  481. highlightData[(i-1)*3+2] = dataBlock._end - (1 + (i-1) * 2)
  482. end
  483. label:setText(text)
  484. -- Calculate the positions of the highlighted text and fill with string.char(127) [Width: 1]
  485. local drawText = label:getDrawText()
  486. local tmpText = ""
  487. for i = 1, #highlightData / 3 do
  488. local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
  489. local lastBlockEnd = (highlightData[(i-2)*3+2] or 1)
  490. for letter = lastBlockEnd, dataBlock._start-1 do
  491. local tmpChar = string.byte(drawText:sub(letter, letter))
  492. local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
  493. tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
  494. end
  495. tmpText = tmpText .. dataBlock.words
  496. end
  497. -- Fill the highlight label to the same size as default label
  498. local finalBlockEnd = (highlightData[(#highlightData/3-1)*3+2] or 1)
  499. for letter = finalBlockEnd, drawText:len() do
  500. local tmpChar = string.byte(drawText:sub(letter, letter))
  501. local fillChar = (tmpChar == 10 or tmpChar == 32) and string.char(tmpChar) or string.char(127)
  502. tmpText = tmpText .. string.rep(fillChar, letterWidth[tmpChar])
  503. end
  504. labelHighlight:setText(tmpText)
  505. end
  506. end
  507. label.name = creatureName
  508. consoleBuffer.onMouseRelease = function(self, mousePos, mouseButton)
  509. processMessageMenu(mousePos, mouseButton, nil, nil, nil, tab)
  510. end
  511. label.onMouseRelease = function(self, mousePos, mouseButton)
  512. processMessageMenu(mousePos, mouseButton, creatureName, text, self, tab)
  513. end
  514. label.onMousePress = function(self, mousePos, button)
  515. if button == MouseLeftButton then clearSelection(consoleBuffer) end
  516. end
  517. label.onDragEnter = function(self, mousePos)
  518. clearSelection(consoleBuffer)
  519. return true
  520. end
  521. label.onDragLeave = function(self, droppedWidget, mousePos)
  522. local text = {}
  523. for selectionChild = consoleBuffer.selection.first, consoleBuffer.selection.last do
  524. local label = self:getParent():getChildByIndex(selectionChild)
  525. table.insert(text, label:getSelection())
  526. end
  527. consoleBuffer.selectionText = table.concat(text, '\n')
  528. return true
  529. end
  530. label.onDragMove = function(self, mousePos, mouseMoved)
  531. local parent = self:getParent()
  532. local parentRect = parent:getPaddingRect()
  533. local selfIndex = parent:getChildIndex(self)
  534. local child = parent:getChildByPos(mousePos)
  535. -- find bonding children
  536. if not child then
  537. if mousePos.y < self:getY() then
  538. for index = selfIndex - 1, 1, -1 do
  539. local label = parent:getChildByIndex(index)
  540. if label:getY() + label:getHeight() > parentRect.y then
  541. if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == 1 then
  542. child = label
  543. break
  544. end
  545. else
  546. child = parent:getChildByIndex(index + 1)
  547. break
  548. end
  549. end
  550. elseif mousePos.y > self:getY() + self:getHeight() then
  551. for index = selfIndex + 1, parent:getChildCount(), 1 do
  552. local label = parent:getChildByIndex(index)
  553. if label:getY() < parentRect.y + parentRect.height then
  554. if (mousePos.y >= label:getY() and mousePos.y <= label:getY() + label:getHeight()) or index == parent:getChildCount() then
  555. child = label
  556. break
  557. end
  558. else
  559. child = parent:getChildByIndex(index - 1)
  560. break
  561. end
  562. end
  563. else
  564. child = self
  565. end
  566. end
  567. if not child then return false end
  568. local childIndex = parent:getChildIndex(child)
  569. -- remove old selection
  570. clearSelection(consoleBuffer)
  571. -- update self selection
  572. local textBegin = self:getTextPos(self:getLastClickPosition())
  573. local textPos = self:getTextPos(mousePos)
  574. self:setSelection(textBegin, textPos)
  575. consoleBuffer.selection = { first = math.min(selfIndex, childIndex), last = math.max(selfIndex, childIndex) }
  576. -- update siblings selection
  577. if child ~= self then
  578. for selectionChild = consoleBuffer.selection.first + 1, consoleBuffer.selection.last - 1 do
  579. parent:getChildByIndex(selectionChild):selectAll()
  580. end
  581. local textPos = child:getTextPos(mousePos)
  582. if childIndex > selfIndex then
  583. child:setSelection(0, textPos)
  584. else
  585. child:setSelection(string.len(child:getText()), textPos)
  586. end
  587. end
  588. return true
  589. end
  590. if consoleBuffer:getChildCount() > MAX_LINES then
  591. local child = consoleBuffer:getFirstChild()
  592. clearSelection(consoleBuffer)
  593. child:destroy()
  594. end
  595. end
  596. function removeTabLabelByName(tab, name)
  597. local panel = consoleTabBar:getTabPanel(tab)
  598. local consoleBuffer = panel:getChildById('consoleBuffer')
  599. for _,label in pairs(consoleBuffer:getChildren()) do
  600. if label.name == name then
  601. label:destroy()
  602. end
  603. end
  604. end
  605. function processChannelTabMenu(tab, mousePos, mouseButton)
  606. local menu = g_ui.createWidget('PopupMenu')
  607. menu:setGameMenu(true)
  608. local worldName = g_game.getWorldName()
  609. local characterName = g_game.getCharacterName()
  610. channelName = tab:getText()
  611. if tab ~= defaultTab and tab ~= serverTab then
  612. menu:addOption(tr('Close'), function() removeTab(channelName) end)
  613. --menu:addOption(tr('Show Server Messages'), function() --[[TODO]] end)
  614. menu:addSeparator()
  615. end
  616. if consoleTabBar:getCurrentTab() == tab then
  617. menu:addOption(tr('Clear Messages'), function() clearChannel(consoleTabBar) end)
  618. menu:addOption(tr('Save Messages'), function()
  619. local panel = consoleTabBar:getTabPanel(tab)
  620. local consoleBuffer = panel:getChildById('consoleBuffer')
  621. local lines = {}
  622. for _,label in pairs(consoleBuffer:getChildren()) do
  623. table.insert(lines, label:getText())
  624. end
  625. local filename = worldName .. ' - ' .. characterName .. ' - ' .. channelName .. '.txt'
  626. local filepath = '/' .. filename
  627. -- extra information at the beginning
  628. table.insert(lines, 1, os.date('\nChannel saved at %a %b %d %H:%M:%S %Y'))
  629. if g_resources.fileExists(filepath) then
  630. table.insert(lines, 1, protectedcall(g_resources.readFileContents, filepath) or '')
  631. end
  632. g_resources.writeFileContents(filepath, table.concat(lines, '\n'))
  633. modules.game_textmessage.displayStatusMessage(tr('Channel appended to %s', filename))
  634. end)
  635. end
  636. menu:display(mousePos)
  637. end
  638. function processMessageMenu(mousePos, mouseButton, creatureName, text, label, tab)
  639. if mouseButton == MouseRightButton then
  640. local menu = g_ui.createWidget('PopupMenu')
  641. menu:setGameMenu(true)
  642. if creatureName and #creatureName > 0 then
  643. if creatureName ~= g_game.getCharacterName() then
  644. menu:addOption(tr('Message to ' .. creatureName), function () g_game.openPrivateChannel(creatureName) end)
  645. if not g_game.getLocalPlayer():hasVip(creatureName) then
  646. menu:addOption(tr('Add to VIP list'), function () g_game.addVip(creatureName) end)
  647. end
  648. if modules.game_console.getOwnPrivateTab() then
  649. menu:addSeparator()
  650. menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(creatureName) end)
  651. menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(creatureName) end)
  652. end
  653. if isIgnored(creatureName) then
  654. menu:addOption(tr('Unignore') .. ' ' .. creatureName, function() removeIgnoredPlayer(creatureName) end)
  655. else
  656. menu:addOption(tr('Ignore') .. ' ' .. creatureName, function() addIgnoredPlayer(creatureName) end)
  657. end
  658. menu:addSeparator()
  659. end
  660. if modules.game_ruleviolation.hasWindowAccess() then
  661. menu:addOption(tr('Rule Violation'), function() modules.game_ruleviolation.show(creatureName, text:match('.+%:%s(.+)')) end)
  662. menu:addSeparator()
  663. end
  664. menu:addOption(tr('Copy name'), function () g_window.setClipboardText(creatureName) end)
  665. end
  666. local selection = tab.tabPanel:getChildById('consoleBuffer').selectionText
  667. if selection and #selection > 0 then
  668. menu:addOption(tr('Copy'), function() g_window.setClipboardText(selection) end, '(Ctrl+C)')
  669. end
  670. if text then
  671. menu:addOption(tr('Copy message'), function() g_window.setClipboardText(text) end)
  672. end
  673. menu:addOption(tr('Select all'), function() selectAll(tab.tabPanel:getChildById('consoleBuffer')) end)
  674. if tab.violations and creatureName then
  675. menu:addSeparator()
  676. menu:addOption(tr('Process') .. ' ' .. creatureName, function() processViolation(creatureName, text) end)
  677. menu:addOption(tr('Remove') .. ' ' .. creatureName, function() g_game.closeRuleViolation(creatureName) end)
  678. end
  679. menu:display(mousePos)
  680. end
  681. end
  682. function sendCurrentMessage()
  683. local message = consoleTextEdit:getText()
  684. if #message == 0 then return end
  685. consoleTextEdit:clearText()
  686. -- send message
  687. sendMessage(message)
  688. end
  689. function addFilter(filter)
  690. table.insert(filters, filter)
  691. end
  692. function removeFilter(filter)
  693. table.removevalue(filters, filter)
  694. end
  695. function sendMessage(message, tab)
  696. local tab = tab or getCurrentTab()
  697. if not tab then return end
  698. for k,func in pairs(filters) do
  699. if func(message) then
  700. return true
  701. end
  702. end
  703. -- when talking on server log, the message goes to default channel
  704. local name = tab:getText()
  705. if tab == serverTab or tab == getRuleViolationsTab() then
  706. tab = defaultTab
  707. name = defaultTab:getText()
  708. end
  709. -- handling chat commands
  710. local channel = tab.channelId
  711. local originalMessage = message
  712. local chatCommandSayMode
  713. local chatCommandPrivate
  714. local chatCommandPrivateReady
  715. local chatCommandMessage
  716. -- player used yell command
  717. chatCommandMessage = message:match("^%#[y|Y] (.*)")
  718. if chatCommandMessage ~= nil then
  719. chatCommandSayMode = 'yell'
  720. channel = 0
  721. message = chatCommandMessage
  722. end
  723. -- player used whisper
  724. chatCommandMessage = message:match("^%#[w|W] (.*)")
  725. if chatCommandMessage ~= nil then
  726. chatCommandSayMode = 'whisper'
  727. message = chatCommandMessage
  728. channel = 0
  729. end
  730. -- player say
  731. chatCommandMessage = message:match("^%#[s|S] (.*)")
  732. if chatCommandMessage ~= nil then
  733. chatCommandSayMode = 'say'
  734. message = chatCommandMessage
  735. channel = 0
  736. end
  737. -- player red talk on channel
  738. chatCommandMessage = message:match("^%#[c|C] (.*)")
  739. if chatCommandMessage ~= nil then
  740. chatCommandSayMode = 'channelRed'
  741. message = chatCommandMessage
  742. end
  743. -- player broadcast
  744. chatCommandMessage = message:match("^%#[b|B] (.*)")
  745. if chatCommandMessage ~= nil then
  746. chatCommandSayMode = 'broadcast'
  747. message = chatCommandMessage
  748. channel = 0
  749. end
  750. local findIni, findEnd, chatCommandInitial, chatCommandPrivate, chatCommandEnd, chatCommandMessage = message:find("([%*%@])(.+)([%*%@])(.*)")
  751. if findIni ~= nil and findIni == 1 then -- player used private chat command
  752. if chatCommandInitial == chatCommandEnd then
  753. chatCommandPrivateRepeat = false
  754. if chatCommandInitial == "*" then
  755. setTextEditText('*'.. chatCommandPrivate .. '* ')
  756. end
  757. message = chatCommandMessage:trim()
  758. chatCommandPrivateReady = true
  759. end
  760. end
  761. message = message:gsub("^(%s*)(.*)","%2") -- remove space characters from message init
  762. if #message == 0 then return end
  763. -- add new command to history
  764. currentMessageIndex = 0
  765. if #messageHistory == 0 or messageHistory[#messageHistory] ~= originalMessage then
  766. table.insert(messageHistory, originalMessage)
  767. if #messageHistory > MAX_HISTORY then
  768. table.remove(messageHistory, 1)
  769. end
  770. end
  771. local speaktypedesc
  772. if (channel or tab == defaultTab) and not chatCommandPrivateReady then
  773. if tab == defaultTab then
  774. speaktypedesc = chatCommandSayMode or SayModes[consolePanel:getChildById('sayModeButton').sayMode].speakTypeDesc
  775. if speaktypedesc ~= 'say' then sayModeChange(2) end -- head back to say mode
  776. else
  777. speaktypedesc = chatCommandSayMode or 'channelYellow'
  778. end
  779. g_game.talkChannel(SpeakTypesSettings[speaktypedesc].speakType, channel, message)
  780. return
  781. else
  782. local isPrivateCommand = false
  783. local priv = true
  784. local tabname = name
  785. if chatCommandPrivateReady then
  786. speaktypedesc = 'privatePlayerToPlayer'
  787. name = chatCommandPrivate
  788. isPrivateCommand = true
  789. elseif tab.npcChat then
  790. speaktypedesc = 'privatePlayerToNpc'
  791. elseif tab == violationReportTab then
  792. if violationReportTab.locked then
  793. modules.game_textmessage.displayFailureMessage('Wait for a gamemaster reply.')
  794. return
  795. end
  796. speaktypedesc = 'rvrContinue'
  797. tabname = tr('Report Rule') .. '...'
  798. elseif tab.violationChatName then
  799. speaktypedesc = 'rvrAnswerTo'
  800. name = tab.violationChatName
  801. tabname = tab.violationChatName .. '\'...'
  802. else
  803. speaktypedesc = 'privatePlayerToPlayer'
  804. end
  805. local speaktype = SpeakTypesSettings[speaktypedesc]
  806. local player = g_game.getLocalPlayer()
  807. g_game.talkPrivate(speaktype.speakType, name, message)
  808. message = applyMessagePrefixies(g_game.getCharacterName(), player:getLevel(), message)
  809. addPrivateText(message, speaktype, tabname, isPrivateCommand, g_game.getCharacterName())
  810. end
  811. end
  812. function sayModeChange(sayMode)
  813. local buttom = consolePanel:getChildById('sayModeButton')
  814. if sayMode == nil then
  815. sayMode = buttom.sayMode + 1
  816. end
  817. if sayMode > #SayModes then sayMode = 1 end
  818. buttom:setIcon(SayModes[sayMode].icon)
  819. buttom.sayMode = sayMode
  820. end
  821. function getOwnPrivateTab()
  822. if not ownPrivateName then return end
  823. return getTab(ownPrivateName)
  824. end
  825. function setIgnoreNpcMessages(ignore)
  826. ignoreNpcMessages = ignore
  827. end
  828. function navigateMessageHistory(step)
  829. local numCommands = #messageHistory
  830. if numCommands > 0 then
  831. currentMessageIndex = math.min(math.max(currentMessageIndex + step, 0), numCommands)
  832. if currentMessageIndex > 0 then
  833. local command = messageHistory[numCommands - currentMessageIndex + 1]
  834. setTextEditText(command)
  835. else
  836. consoleTextEdit:clearText()
  837. end
  838. end
  839. end
  840. function applyMessagePrefixies(name, level, message)
  841. if name then
  842. if modules.client_options.getOption('showLevelsInConsole') and level > 0 then
  843. message = name .. ' [' .. level .. ']: ' .. message
  844. else
  845. message = name .. ': ' .. message
  846. end
  847. end
  848. return message
  849. end
  850. function onTalk(name, level, mode, message, channelId, creaturePos)
  851. if mode == MessageModes.GamemasterBroadcast then
  852. modules.game_textmessage.displayBroadcastMessage(name .. ': ' .. message)
  853. return
  854. end
  855. local isNpcMode = (mode == MessageModes.NpcFromStartBlock or mode == MessageModes.NpcFrom)
  856. if ignoreNpcMessages and isNpcMode then return end
  857. speaktype = SpeakTypes[mode]
  858. if not speaktype then
  859. perror('unhandled onTalk message mode ' .. mode .. ': ' .. message)
  860. return
  861. end
  862. local localPlayer = g_game.getLocalPlayer()
  863. if name ~= g_game.getCharacterName()
  864. and isUsingIgnoreList()
  865. and not(isUsingWhiteList()) or (isUsingWhiteList() and not(isWhitelisted(name)) and not(isAllowingVIPs() and localPlayer:hasVip(name))) then
  866. if mode == MessageModes.Yell and isIgnoringYelling() then
  867. return
  868. elseif speaktype.private and isIgnoringPrivate() and not isNpcMode then
  869. return
  870. elseif isIgnored(name) then
  871. return
  872. end
  873. end
  874. if mode == MessageModes.RVRChannel then
  875. channelId = violationsChannelId
  876. end
  877. if (mode == MessageModes.Say or mode == MessageModes.Whisper or mode == MessageModes.Yell or
  878. mode == MessageModes.Spell or mode == MessageModes.MonsterSay or mode == MessageModes.MonsterYell or
  879. mode == MessageModes.NpcFrom or mode == MessageModes.BarkLow or mode == MessageModes.BarkLoud or
  880. mode == MessageModes.NpcFromStartBlock) and creaturePos then
  881. local staticText = StaticText.create()
  882. -- Remove curly braces from screen message
  883. local staticMessage = message
  884. if isNpcMode then
  885. local highlightData = getHighlightedText(staticMessage)
  886. if #highlightData > 0 then
  887. for i = 1, #highlightData / 3 do
  888. local dataBlock = { _start = highlightData[(i-1)*3+1], _end = highlightData[(i-1)*3+2], words = highlightData[(i-1)*3+3] }
  889. staticMessage = staticMessage:gsub("{"..dataBlock.words.."}", dataBlock.words)
  890. end
  891. end
  892. staticText:setColor(speaktype.color)
  893. end
  894. staticText:addMessage(name, mode, staticMessage)
  895. g_map.addThing(staticText, creaturePos, -1)
  896. end
  897. local defaultMessage = mode <= 3 and true or false
  898. if speaktype == SpeakTypesSettings.none then return end
  899. if speaktype.hideInConsole then return end
  900. local composedMessage = applyMessagePrefixies(name, level, message)
  901. if mode == MessageModes.RVRAnswer then
  902. violationReportTab.locked = false
  903. addTabText(composedMessage, speaktype, violationReportTab, name)
  904. elseif mode == MessageModes.RVRContinue then
  905. addText(composedMessage, speaktype, name .. '\'...', name)
  906. elseif speaktype.private then
  907. addPrivateText(composedMessage, speaktype, name, false, name)
  908. if modules.client_options.getOption('showPrivateMessagesOnScreen') and speaktype ~= SpeakTypesSettings.privateNpcToPlayer then
  909. modules.game_textmessage.displayPrivateMessage(name .. ':\n' .. message)
  910. end
  911. else
  912. local channel = tr('Default')
  913. if not defaultMessage then
  914. channel = channels[channelId]
  915. end
  916. if channel then
  917. addText(composedMessage, speaktype, channel, name)
  918. else
  919. -- server sent a message on a channel that is not open
  920. pwarning('message in channel id ' .. channelId .. ' which is unknown, this is a server bug, relogin if you want to see messages in this channel')
  921. end
  922. end
  923. end
  924. function onOpenChannel(channelId, channelName)
  925. addChannel(channelName, channelId)
  926. end
  927. function onOpenPrivateChannel(receiver)
  928. addPrivateChannel(receiver)
  929. end
  930. function onOpenOwnPrivateChannel(channelId, channelName)
  931. local privateTab = getTab(channelName)
  932. if privateTab == nil then
  933. addChannel(channelName, channelId)
  934. end
  935. ownPrivateName = channelName
  936. end
  937. function onCloseChannel(channelId)
  938. local channel = channels[channelId]
  939. if channel then
  940. local tab = getTab(channel)
  941. if tab then
  942. consoleTabBar:removeTab(tab)
  943. end
  944. for k, v in pairs(channels) do
  945. if (k == tab.channelId) then channels[k] = nil end
  946. end
  947. end
  948. end
  949. function processViolation(name, text)
  950. local tabname = name .. '\'...'
  951. local tab = addTab(tabname, true)
  952. channels[tabname] = tabname
  953. tab.violationChatName = name
  954. g_game.openRuleViolation(name)
  955. addTabText(text, SpeakTypesSettings.say, tab, name)
  956. end
  957. function onRuleViolationChannel(channelId)
  958. violationsChannelId = channelId
  959. local tab = addChannel(tr('Rule Violations'), channelId)
  960. tab.violations = true
  961. end
  962. function onRuleViolationRemove(name)
  963. local tab = getRuleViolationsTab()
  964. if not tab then return end
  965. removeTabLabelByName(tab, name)
  966. end
  967. function onRuleViolationCancel(name)
  968. local tab = getTab(name .. '\'...')
  969. if not tab then return end
  970. addTabText(tr('%s has finished the request', name) .. '.', SpeakTypesSettings.privateRed, tab)
  971. tab.locked = true
  972. end
  973. function onRuleViolationLock()
  974. if not violationReportTab then return end
  975. violationReportTab.locked = false
  976. addTabText(tr('Your request has been closed') .. '.', SpeakTypesSettings.privateRed, violationReportTab)
  977. violationReportTab.locked = true
  978. end
  979. function doChannelListSubmit()
  980. local channelListPanel = channelsWindow:getChildById('channelList')
  981. local openPrivateChannelWith = channelsWindow:getChildById('openPrivateChannelWith'):getText()
  982. if openPrivateChannelWith ~= '' then
  983. if openPrivateChannelWith:lower() ~= g_game.getCharacterName():lower() then
  984. g_game.openPrivateChannel(openPrivateChannelWith)
  985. else
  986. modules.game_textmessage.displayFailureMessage('You cannot create a private chat channel with yourself.')
  987. end
  988. else
  989. local selectedChannelLabel = channelListPanel:getFocusedChild()
  990. if not selectedChannelLabel then return end
  991. if selectedChannelLabel.channelId == 0xFFFF then
  992. g_game.openOwnChannel()
  993. else
  994. g_game.joinChannel(selectedChannelLabel.channelId)
  995. end
  996. end
  997. channelsWindow:destroy()
  998. end
  999. function onChannelList(channelList)
  1000. if channelsWindow then channelsWindow:destroy() end
  1001. channelsWindow = g_ui.displayUI('channelswindow')
  1002. local channelListPanel = channelsWindow:getChildById('channelList')
  1003. channelsWindow.onEnter = doChannelListSubmit
  1004. channelsWindow.onDestroy = function() channelsWindow = nil end
  1005. g_keyboard.bindKeyPress('Down', function() channelListPanel:focusNextChild(KeyboardFocusReason) end, channelsWindow)
  1006. g_keyboard.bindKeyPress('Up', function() channelListPanel:focusPreviousChild(KeyboardFocusReason) end, channelsWindow)
  1007. for k,v in pairs(channelList) do
  1008. local channelId = v[1]
  1009. local channelName = v[2]
  1010. if #channelName > 0 then
  1011. local label = g_ui.createWidget('ChannelListLabel', channelListPanel)
  1012. label.channelId = channelId
  1013. label:setText(channelName)
  1014. label:setPhantom(false)
  1015. label.onDoubleClick = doChannelListSubmit
  1016. end
  1017. end
  1018. end
  1019. function loadCommunicationSettings()
  1020. communicationSettings.whitelistedPlayers = {}
  1021. communicationSettings.ignoredPlayers = {}
  1022. local ignoreNode = g_settings.getNode('IgnorePlayers')
  1023. if ignoreNode then
  1024. for i = 1, #ignoreNode do
  1025. table.insert(communicationSettings.ignoredPlayers, ignoreNode[i])
  1026. end
  1027. end
  1028. local whitelistNode = g_settings.getNode('WhitelistedPlayers')
  1029. if whitelistNode then
  1030. for i = 1, #whitelistNode do
  1031. table.insert(communicationSettings.whitelistedPlayers, whitelistNode[i])
  1032. end
  1033. end
  1034. communicationSettings.useIgnoreList = g_settings.getBoolean('UseIgnoreList')
  1035. communicationSettings.useWhiteList = g_settings.getBoolean('UseWhiteList')
  1036. communicationSettings.privateMessages = g_settings.getBoolean('IgnorePrivateMessages')
  1037. communicationSettings.yelling = g_settings.getBoolean('IgnoreYelling')
  1038. communicationSettings.allowVIPs = g_settings.getBoolean('AllowVIPs')
  1039. end
  1040. function saveCommunicationSettings()
  1041. local tmpIgnoreList = {}
  1042. local ignoredPlayers = getIgnoredPlayers()
  1043. for i = 1, #ignoredPlayers do
  1044. table.insert(tmpIgnoreList, ignoredPlayers[i])
  1045. end
  1046. local tmpWhiteList = {}
  1047. local whitelistedPlayers = getWhitelistedPlayers()
  1048. for i = 1, #whitelistedPlayers do
  1049. table.insert(tmpWhiteList, whitelistedPlayers[i])
  1050. end
  1051. g_settings.set('UseIgnoreList', communicationSettings.useIgnoreList)
  1052. g_settings.set('UseWhiteList', communicationSettings.useWhiteList)
  1053. g_settings.set('IgnorePrivateMessages', communicationSettings.privateMessages)
  1054. g_settings.set('IgnoreYelling', communicationSettings.yelling)
  1055. g_settings.setNode('IgnorePlayers', tmpIgnoreList)
  1056. g_settings.setNode('WhitelistedPlayers', tmpWhiteList)
  1057. end
  1058. function getIgnoredPlayers()
  1059. return communicationSettings.ignoredPlayers
  1060. end
  1061. function getWhitelistedPlayers()
  1062. return communicationSettings.whitelistedPlayers
  1063. end
  1064. function isUsingIgnoreList()
  1065. return communicationSettings.useIgnoreList
  1066. end
  1067. function isUsingWhiteList()
  1068. return communicationSettings.useWhiteList
  1069. end
  1070. function isIgnored(name)
  1071. return table.find(communicationSettings.ignoredPlayers, name, true)
  1072. end
  1073. function addIgnoredPlayer(name)
  1074. if isIgnored(name) then return end
  1075. table.insert(communicationSettings.ignoredPlayers, name)
  1076. end
  1077. function removeIgnoredPlayer(name)
  1078. table.removevalue(communicationSettings.ignoredPlayers, name)
  1079. end
  1080. function isWhitelisted(name)
  1081. return table.find(communicationSettings.whitelistedPlayers, name, true)
  1082. end
  1083. function addWhitelistedPlayer(name)
  1084. if isWhitelisted(name) then return end
  1085. table.insert(communicationSettings.whitelistedPlayers, name)
  1086. end
  1087. function removeWhitelistedPlayer(name)
  1088. table.removevalue(communicationSettings.whitelistedPlayers, name)
  1089. end
  1090. function isIgnoringPrivate()
  1091. return communicationSettings.privateMessages
  1092. end
  1093. function isIgnoringYelling()
  1094. return communicationSettings.yelling
  1095. end
  1096. function isAllowingVIPs()
  1097. return communicationSettings.allowVIPs
  1098. end
  1099. function onClickIgnoreButton()
  1100. if communicationWindow then return end
  1101. communicationWindow = g_ui.displayUI('communicationwindow')
  1102. local ignoreListPanel = communicationWindow:getChildById('ignoreList')
  1103. local whiteListPanel = communicationWindow:getChildById('whiteList')
  1104. communicationWindow.onDestroy = function() communicationWindow = nil end
  1105. local useIgnoreListBox = communicationWindow:getChildById('checkboxUseIgnoreList')
  1106. useIgnoreListBox:setChecked(communicationSettings.useIgnoreList)
  1107. local useWhiteListBox = communicationWindow:getChildById('checkboxUseWhiteList')
  1108. useWhiteListBox:setChecked(communicationSettings.useWhiteList)
  1109. local removeIgnoreButton = communicationWindow:getChildById('buttonIgnoreRemove')
  1110. removeIgnoreButton:disable()
  1111. ignoreListPanel.onChildFocusChange = function() removeIgnoreButton:enable() end
  1112. removeIgnoreButton.onClick = function()
  1113. local selection = ignoreListPanel:getFocusedChild()
  1114. if selection then
  1115. ignoreListPanel:removeChild(selection)
  1116. selection:destroy()
  1117. end
  1118. removeIgnoreButton:disable()
  1119. end
  1120. local removeWhitelistButton = communicationWindow:getChildById('buttonWhitelistRemove')
  1121. removeWhitelistButton:disable()
  1122. whiteListPanel.onChildFocusChange = function() removeWhitelistButton:enable() end
  1123. removeWhitelistButton.onClick = function()
  1124. local selection = whiteListPanel:getFocusedChild()
  1125. if selection then
  1126. whiteListPanel:removeChild(selection)
  1127. selection:destroy()
  1128. end
  1129. removeWhitelistButton:disable()
  1130. end
  1131. local newlyIgnoredPlayers = {}
  1132. local addIgnoreName = communicationWindow:getChildById('ignoreNameEdit')
  1133. local addIgnoreButton = communicationWindow:getChildById('buttonIgnoreAdd')
  1134. local addIgnoreFunction = function()
  1135. local newEntry = addIgnoreName:getText()
  1136. if newEntry == '' then return end
  1137. if table.find(getIgnoredPlayers(), newEntry) then return end
  1138. if table.find(newlyIgnoredPlayers, newEntry) then return end
  1139. local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
  1140. label:setText(newEntry)
  1141. table.insert(newlyIgnoredPlayers, newEntry)
  1142. addIgnoreName:setText('')
  1143. end
  1144. addIgnoreButton.onClick = addIgnoreFunction
  1145. local newlyWhitelistedPlayers = {}
  1146. local addWhitelistName = communicationWindow:getChildById('whitelistNameEdit')
  1147. local addWhitelistButton = communicationWindow:getChildById('buttonWhitelistAdd')
  1148. local addWhitelistFunction = function()
  1149. local newEntry = addWhitelistName:getText()
  1150. if newEntry == '' then return end
  1151. if table.find(getWhitelistedPlayers(), newEntry) then return end
  1152. if table.find(newlyWhitelistedPlayers, newEntry) then return end
  1153. local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
  1154. label:setText(newEntry)
  1155. table.insert(newlyWhitelistedPlayers, newEntry)
  1156. addWhitelistName:setText('')
  1157. end
  1158. addWhitelistButton.onClick = addWhitelistFunction
  1159. communicationWindow.onEnter = function()
  1160. if addWhitelistName:isFocused() then
  1161. addWhitelistFunction()
  1162. elseif addIgnoreName:isFocused() then
  1163. addIgnoreFunction()
  1164. end
  1165. end
  1166. local ignorePrivateMessageBox = communicationWindow:getChildById('checkboxIgnorePrivateMessages')
  1167. ignorePrivateMessageBox:setChecked(communicationSettings.privateMessages)
  1168. local ignoreYellingBox = communicationWindow:getChildById('checkboxIgnoreYelling')
  1169. ignoreYellingBox:setChecked(communicationSettings.yelling)
  1170. local allowVIPsBox = communicationWindow:getChildById('checkboxAllowVIPs')
  1171. allowVIPsBox:setChecked(communicationSettings.allowVIPs)
  1172. local saveButton = communicationWindow:recursiveGetChildById('buttonSave')
  1173. saveButton.onClick = function()
  1174. communicationSettings.ignoredPlayers = {}
  1175. for i = 1, ignoreListPanel:getChildCount() do
  1176. addIgnoredPlayer(ignoreListPanel:getChildByIndex(i):getText())
  1177. end
  1178. communicationSettings.whitelistedPlayers = {}
  1179. for i = 1, whiteListPanel:getChildCount() do
  1180. addWhitelistedPlayer(whiteListPanel:getChildByIndex(i):getText())
  1181. end
  1182. communicationSettings.useIgnoreList = useIgnoreListBox:isChecked()
  1183. communicationSettings.useWhiteList = useWhiteListBox:isChecked()
  1184. communicationSettings.yelling = ignoreYellingBox:isChecked()
  1185. communicationSettings.privateMessages = ignorePrivateMessageBox:isChecked()
  1186. communicationSettings.allowVIPs = allowVIPsBox:isChecked()
  1187. communicationWindow:destroy()
  1188. end
  1189. local cancelButton = communicationWindow:recursiveGetChildById('buttonCancel')
  1190. cancelButton.onClick = function()
  1191. communicationWindow:destroy()
  1192. end
  1193. local ignoredPlayers = getIgnoredPlayers()
  1194. for i = 1, #ignoredPlayers do
  1195. local label = g_ui.createWidget('IgnoreListLabel', ignoreListPanel)
  1196. label:setText(ignoredPlayers[i])
  1197. end
  1198. local whitelistedPlayers = getWhitelistedPlayers()
  1199. for i = 1, #whitelistedPlayers do
  1200. local label = g_ui.createWidget('WhiteListLabel', whiteListPanel)
  1201. label:setText(whitelistedPlayers[i])
  1202. end
  1203. end
  1204. function online()
  1205. defaultTab = addTab(tr('Default'), true)
  1206. serverTab = addTab(tr('Server Log'), false)
  1207. if g_game.getClientVersion() < 862 then
  1208. g_keyboard.bindKeyDown('Ctrl+R', openPlayerReportRuleViolationWindow)
  1209. end
  1210. -- open last channels
  1211. local lastChannelsOpen = g_settings.getNode('lastChannelsOpen')
  1212. if lastChannelsOpen then
  1213. local savedChannels = lastChannelsOpen[g_game.getCharacterName()]
  1214. if savedChannels then
  1215. for channelName, channelId in pairs(savedChannels) do
  1216. channelId = tonumber(channelId)
  1217. if channelId ~= -1 and channelId < 100 then
  1218. if not table.find(channels, channelId) then
  1219. g_game.joinChannel(channelId)
  1220. table.insert(ignoredChannels, channelId)
  1221. end
  1222. end
  1223. end
  1224. end
  1225. end
  1226. scheduleEvent(function() ignoredChannels = {} end, 3000)
  1227. end
  1228. function offline()
  1229. if g_game.getClientVersion() < 862 then
  1230. g_keyboard.unbindKeyDown('Ctrl+R')
  1231. end
  1232. clear()
  1233. end