· 6 years ago · Dec 03, 2019, 09:58 PM
1-- pChat object will receive functions
2pChat = pChat or {}
3
4-- Common
5local ADDON_NAME = "pChat"
6local ADDON_VERSION = "9.4.0.2"
7local ADDON_AUTHOR = "Ayantir, DesertDwellers, Baertram (current)"
8local ADDON_WEBSITE = "http://www.esoui.com/downloads/info93-pChat.html"
9
10-- Registering libraries
11-- Needed
12local LAM = LibAddonMenu2
13if not LAM and LibStub then LAM = LibStub("LibAddonMenu-2.0", true) end
14assert(LAM, d(string.format(GetString(PCHAT_LIB_MISSING), "LibAddonMenu-2.0")))
15
16local PCHATLC = LibChat2
17if not PCHATLC and LibStub then PCHATLC = LibStub("libChat-1.0", true) end
18assert(PCHATLC, d(string.format(GetString(PCHAT_LIB_MISSING), "LibChat 2")))
19
20local LMP = LibMediaProvider
21if not LMP and LibStub then LMP = LibStub("LibMediaProvider-1.0", true) end
22assert(LMP, d(string.format(GetString(PCHAT_LIB_MISSING), "LibMediaProvider-1.0")))
23
24local LMM = LibMainMenu
25if not LMM and LibStub then LMM = LibStub("LibMainMenu", true) end
26assert(LMM, d(string.format(GetString(PCHAT_LIB_MISSING), "LibMainMenu")))
27local MENU_CATEGORY_PCHAT = nil
28
29--Optional
30local LCT = LibCustomTitles
31if not LCT and LibStub then LCT = LibStub("LibCustomTitles",true) end
32
33-- Init
34local isAddonLoaded = false -- OnAddonLoaded() done
35local isAddonInitialized = false
36
37-- Default variables to push in SavedVars
38local defaults = {
39 -- LAM handled
40 showGuildNumbers = false,
41 allGuildsSameColour = false,
42 allZonesSameColour = true,
43 allNPCSameColour = true,
44 delzonetags = true,
45 carriageReturn = false,
46 alwaysShowChat = false,
47 augmentHistoryBuffer = true,
48 oneColour = false,
49 showTagInEntry = true,
50 showTimestamp = true,
51 timestampcolorislcol = false,
52 useESOcolors = true,
53 diffforESOcolors = 40,
54 timestampFormat = "HH:m",
55 guildTags = {},
56 officertag = {},
57 switchFor = {},
58 officerSwitchFor = {},
59 formatguild = {},
60 defaultchannel = CHAT_CHANNEL_GUILD_1,
61 soundforincwhisps = SOUNDS.NEW_NOTIFICATION,
62 notifyIMIndex = 1, -- SOUNDS.NONE
63 enablecopy = true,
64 enableChatTabChannel = true,
65 enablepartyswitch = true,
66 enableWhisperTab = false,
67 groupLeader = false,
68 disableBrackets = true,
69 chatMinimizedAtLaunch = false,
70 chatMinimizedInMenus = false,
71 chatMaximizedAfterMenus = false,
72 windowDarkness = 6,
73 chatSyncConfig = true,
74 floodProtect = true,
75 floodGracePeriod = 30,
76 lookingForProtect = false,
77 wantToProtect = false,
78 restoreOnReloadUI = true,
79 restoreOnLogOut = true,
80 restoreOnQuit = false,
81 restoreOnAFK = true,
82 restoreSystem = true,
83 restoreSystemOnly = false,
84 restoreWhisps = true,
85 restoreTextEntryHistoryAtLogOutQuit = false,
86 addChannelAndTargetToHistory = true,
87 timeBeforeRestore = 2,
88 notifyIM = false,
89 nicknames = "",
90 defaultTab = 1,
91 defaultTabName = "",
92 groupNames = 1,
93 geoChannelsFormat = 2,
94 urlHandling = true,
95 -- guildRecruitProtect = false,
96 spamGracePeriod = 5,
97 fonts = "ESO Standard Font",
98 colours =
99 {
100 [2*CHAT_CHANNEL_SAY] = "|cFFFFFF", -- say Left
101 [2*CHAT_CHANNEL_SAY + 1] = "|cFFFFFF", -- say Right
102 [2*CHAT_CHANNEL_YELL] = "|cE974D8", -- yell Left
103 [2*CHAT_CHANNEL_YELL + 1] = "|cFFB5F4", -- yell Right
104 [2*CHAT_CHANNEL_WHISPER] = "|cB27BFF", -- tell in Left
105 [2*CHAT_CHANNEL_WHISPER + 1] = "|cB27BFF", -- tell in Right
106 [2*CHAT_CHANNEL_PARTY] = "|c6EABCA", -- group Left
107 [2*CHAT_CHANNEL_PARTY + 1] = "|cA1DAF7", -- group Right
108 [2*CHAT_CHANNEL_WHISPER_SENT] = "|c7E57B5", -- tell out Left
109 [2*CHAT_CHANNEL_WHISPER_SENT + 1] = "|c7E57B5", -- tell out Right
110 [2*CHAT_CHANNEL_EMOTE] = "|cA5A5A5", -- emote Left
111 [2*CHAT_CHANNEL_EMOTE + 1] = "|cA5A5A5", -- emote Right
112 [2*CHAT_CHANNEL_MONSTER_SAY] = "|c879B7D", -- npc Left
113 [2*CHAT_CHANNEL_MONSTER_SAY + 1] = "|c879B7D", -- npc Right
114 [2*CHAT_CHANNEL_MONSTER_YELL] = "|c879B7D", -- npc yell Left
115 [2*CHAT_CHANNEL_MONSTER_YELL + 1] = "|c879B7D", -- npc yell Right
116 [2*CHAT_CHANNEL_MONSTER_WHISPER] = "|c879B7D", -- npc whisper Left
117 [2*CHAT_CHANNEL_MONSTER_WHISPER + 1] = "|c879B7D", -- npc whisper Right
118 [2*CHAT_CHANNEL_MONSTER_EMOTE] = "|c879B7D", -- npc emote Left
119 [2*CHAT_CHANNEL_MONSTER_EMOTE + 1] = "|c879B7D", -- npc emote Right
120 [2*CHAT_CHANNEL_GUILD_1] = "|c94E193", -- guild Left
121 [2*CHAT_CHANNEL_GUILD_1 + 1] = "|cC3F0C2", -- guild Right
122 [2*CHAT_CHANNEL_GUILD_2] = "|c94E193",
123 [2*CHAT_CHANNEL_GUILD_2 + 1] = "|cC3F0C2",
124 [2*CHAT_CHANNEL_GUILD_3] = "|c94E193",
125 [2*CHAT_CHANNEL_GUILD_3 + 1] = "|cC3F0C2",
126 [2*CHAT_CHANNEL_GUILD_4] = "|c94E193",
127 [2*CHAT_CHANNEL_GUILD_4 + 1] = "|cC3F0C2",
128 [2*CHAT_CHANNEL_GUILD_5] = "|c94E193",
129 [2*CHAT_CHANNEL_GUILD_5 + 1] = "|cC3F0C2",
130 [2*CHAT_CHANNEL_OFFICER_1] = "|cC3F0C2", -- guild officers Left
131 [2*CHAT_CHANNEL_OFFICER_1 + 1] = "|cC3F0C2", -- guild officers Right
132 [2*CHAT_CHANNEL_OFFICER_2] = "|cC3F0C2",
133 [2*CHAT_CHANNEL_OFFICER_2 + 1] = "|cC3F0C2",
134 [2*CHAT_CHANNEL_OFFICER_3] = "|cC3F0C2",
135 [2*CHAT_CHANNEL_OFFICER_3 + 1] = "|cC3F0C2",
136 [2*CHAT_CHANNEL_OFFICER_4] = "|cC3F0C2",
137 [2*CHAT_CHANNEL_OFFICER_4 + 1] = "|cC3F0C2",
138 [2*CHAT_CHANNEL_OFFICER_5] = "|cC3F0C2",
139 [2*CHAT_CHANNEL_OFFICER_5 + 1] = "|cC3F0C2",
140 [2*CHAT_CHANNEL_ZONE] = "|cCEB36F", -- zone Left
141 [2*CHAT_CHANNEL_ZONE + 1] = "|cB0A074", -- zone Right
142 [2*CHAT_CHANNEL_ZONE_LANGUAGE_1] = "|cCEB36F", -- EN zone Left
143 [2*CHAT_CHANNEL_ZONE_LANGUAGE_1 + 1] = "|cB0A074", -- EN zone Right
144 [2*CHAT_CHANNEL_ZONE_LANGUAGE_2] = "|cCEB36F", -- FR zone Left
145 [2*CHAT_CHANNEL_ZONE_LANGUAGE_2 + 1] = "|cB0A074", -- FR zone Right
146 [2*CHAT_CHANNEL_ZONE_LANGUAGE_3] = "|cCEB36F", -- DE zone Left
147 [2*CHAT_CHANNEL_ZONE_LANGUAGE_3 + 1] = "|cB0A074", -- DE zone Right
148 [2*CHAT_CHANNEL_ZONE_LANGUAGE_4] = "|cCEB36F", -- JP zone Left
149 [2*CHAT_CHANNEL_ZONE_LANGUAGE_4 + 1] = "|cB0A074", -- JP zone Right
150 ["timestamp"] = "|c8F8F8F", -- timestamp
151 ["tabwarning"] = "|c76BCC3", -- tab Warning ~ "Azure" (ZOS default)
152 ["groupleader"] = "|cC35582", --
153 ["groupleader1"] = "|c76BCC3", --
154 },
155 -- Not LAM
156 chatConfSync = {},
157}
158
159-- SV
160local db
161local targetToWhisp
162local guild1 = 1
163local guild2 = 2
164local guild3 = 3
165local guild4 = 4
166local guild5 = 5
167local guildName1 = ""
168local guildName2 = ""
169local guildName3 = ""
170local guildName4 = ""
171local guildName5 = ""
172local guildId1 = nil
173local guildId2 = nil
174local guildId3 = nil
175local guildId4 = nil
176local guildId5 = nil
177local guildMaxNum = 0
178
179
180
181-- pChatData will receive variables and objects.
182local pChatData = {
183 cachedMessages = {}, -- This one must be init before OnAddonLoaded because it will receive data before this event.
184}
185
186-- Used for pChat LinkHandling
187local PCHAT_LINK = "p"
188local PCHAT_URL_CHAN = 97
189local PCHAT_CHANNEL_SAY = 98
190local PCHAT_CHANNEL_NONE = 99
191
192-- Init Automated Messages
193local automatedMessagesList = ZO_SortFilterList:Subclass()
194
195-- Backuping AddMessage for internal debug - AVOID DOING A CHAT_SYSTEM:AddMessage() in pChat, it can cause recursive calls
196CHAT_SYSTEM.Zo_AddMessage = CHAT_SYSTEM.AddMessage
197
198--[[
199PCHAT_LINK format : ZO_LinkHandler_CreateLink(message, nil, PCHAT_LINK, data)
200message = message to display, nil (ignored by ZO_LinkHandler_CreateLink), PCHAT_LINK : declaration
201data : strings separated by ":"
2021st arg is chancode like CHAT_CHANNEL_GUILD_1
203]]--
204
205local ChanInfoArray = ZO_ChatSystem_GetChannelInfo()
206
207pChatData.chatCategories = {
208 CHAT_CATEGORY_SAY,
209 CHAT_CATEGORY_YELL,
210 CHAT_CATEGORY_WHISPER_INCOMING,
211 CHAT_CATEGORY_WHISPER_OUTGOING,
212 CHAT_CATEGORY_ZONE,
213 CHAT_CATEGORY_PARTY,
214 CHAT_CATEGORY_EMOTE,
215 CHAT_CATEGORY_SYSTEM,
216 CHAT_CATEGORY_GUILD_1,
217 CHAT_CATEGORY_GUILD_2,
218 CHAT_CATEGORY_GUILD_3,
219 CHAT_CATEGORY_GUILD_4,
220 CHAT_CATEGORY_GUILD_5,
221 CHAT_CATEGORY_OFFICER_1,
222 CHAT_CATEGORY_OFFICER_2,
223 CHAT_CATEGORY_OFFICER_3,
224 CHAT_CATEGORY_OFFICER_4,
225 CHAT_CATEGORY_OFFICER_5,
226 CHAT_CATEGORY_ZONE_ENGLISH,
227 CHAT_CATEGORY_ZONE_FRENCH,
228 CHAT_CATEGORY_ZONE_GERMAN,
229 CHAT_CATEGORY_ZONE_JAPANESE,
230 CHAT_CATEGORY_MONSTER_SAY,
231 CHAT_CATEGORY_MONSTER_YELL,
232 CHAT_CATEGORY_MONSTER_WHISPER,
233 CHAT_CATEGORY_MONSTER_EMOTE,
234}
235
236pChatData.guildCategories = {
237 CHAT_CATEGORY_GUILD_1,
238 CHAT_CATEGORY_GUILD_2,
239 CHAT_CATEGORY_GUILD_3,
240 CHAT_CATEGORY_GUILD_4,
241 CHAT_CATEGORY_GUILD_5,
242 CHAT_CATEGORY_OFFICER_1,
243 CHAT_CATEGORY_OFFICER_2,
244 CHAT_CATEGORY_OFFICER_3,
245 CHAT_CATEGORY_OFFICER_4,
246 CHAT_CATEGORY_OFFICER_5,
247}
248
249pChatData.defaultChannels = {
250 PCHAT_CHANNEL_NONE,
251 CHAT_CHANNEL_ZONE,
252 CHAT_CHANNEL_SAY,
253 CHAT_CHANNEL_GUILD_1,
254 CHAT_CHANNEL_GUILD_2,
255 CHAT_CHANNEL_GUILD_3,
256 CHAT_CHANNEL_GUILD_4,
257 CHAT_CHANNEL_GUILD_5,
258 CHAT_CHANNEL_OFFICER_1,
259 CHAT_CHANNEL_OFFICER_2,
260 CHAT_CHANNEL_OFFICER_3,
261 CHAT_CHANNEL_OFFICER_4,
262 CHAT_CHANNEL_OFFICER_5,
263}
264
265local chatStrings =
266{
267 standard = "%s%s: |r%s%s%s|r", -- standard format: say, yell, group, npc, npc yell, npc whisper, zone
268 esostandart = "%s%s %s: |r%s%s%s|r", -- standard format: say, yell, group, npc, npc yell, npc whisper, zone with tag (except for monsters)
269 esoparty = "%s%s%s: |r%s%s%s|r", -- standard format: party
270 tellIn = "%s%s: |r%s%s%s|r", -- tell in
271 tellOut = "%s-> %s: |r%s%s%s|r", -- tell out
272 emote = "%s%s |r%s%s|r", -- emote
273 guild = "%s%s %s: |r%s%s%s|r", -- guild
274 language = "%s[%s] %s: |r%s%s%s|r", -- language zones
275
276 -- For copy System, only Handle "From part"
277
278 copystandard = "[%s]: ", -- standard format: say, yell, group, npc, npc yell, npc whisper, zone
279 copyesostandard = "[%s] %s: ", -- standard format: say, yell, group, npc, npc yell, npc whisper, zone with tag (except for monsters)
280 copyesoparty = "[%s]%s: ", -- standard format: party
281 copytellIn = "[%s]: ", -- tell in
282 copytellOut = "-> [%s]: ", -- tell out
283 copyemote = "%s ", -- emote
284 copyguild = "[%s] [%s]: ", -- guild
285 copylanguage = "[%s] %s: ", -- language zones
286 copynpc = "%s: ", -- language zones
287}
288
289-- Return true/false if text is a flood
290local function SpamFlood(from, text, chanCode)
291
292 -- 2+ messages identiqual in less than 30 seconds on Character channels = spam
293
294 -- Should not happen
295 if db.LineStrings then
296
297 if db.lineNumber then
298 -- 1st message cannot be a spam
299 if db.lineNumber > 1 then
300
301 local checkSpam = true
302 local previousLine = db.lineNumber - 1
303 local ourMessageTimestamp = GetTimeStamp()
304
305 while checkSpam do
306
307 -- Previous line can be a ChanSystem one
308 if db.LineStrings[previousLine].channel ~= CHAT_CHANNEL_SYSTEM then
309 if (ourMessageTimestamp - db.LineStrings[previousLine].rawTimestamp) < db.floodGracePeriod then
310 -- if our message is sent by our chatter / will be break by "Character" channels and "UserID" Channels
311 if from == db.LineStrings[previousLine].rawFrom then
312 -- if our message is eq of last message
313 if text == db.LineStrings[previousLine].rawText then
314 -- Previous and current must be in zone(s), yell, say, emote (Character Channels except party)
315 -- TODO: Find a characterchannel func
316
317 -- CHAT_CHANNEL_SAY = 0 == nil in lua, will broke the array, so use PCHAT_CHANNEL_SAY
318 local spamChanCode = chanCode
319 if spamChanCode == CHAT_CHANNEL_SAY then
320 spamChanCode = PCHAT_CHANNEL_SAY
321 end
322
323 local spammableChannels = {}
324 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_1] = true
325 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_2] = true
326 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_3] = true
327 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_4] = true
328 spammableChannels[PCHAT_CHANNEL_SAY] = true
329 spammableChannels[CHAT_CHANNEL_YELL] = true
330 spammableChannels[CHAT_CHANNEL_ZONE] = true
331 spammableChannels[CHAT_CHANNEL_EMOTE] = true
332
333 -- spammableChannels[spamChanCode] = return true if our message was sent in a spammable channel
334 -- spammableChannels[db.LineStrings[previousLine].channel] = return true if previous message was sent in a spammable channel
335 if spammableChannels[spamChanCode] and spammableChannels[db.LineStrings[previousLine].channel] then
336 -- Spam
337 --CHAT_SYSTEM:Zo_AddMessage("Spam detected ( " .. text .. " )")
338 return true
339 end
340 end
341 end
342 else
343 -- > 30s, stop analyzis
344 checkSpam = false
345 end
346 end
347
348 if previousLine > 1 then
349 previousLine = previousLine - 1
350 else
351 checkSpam = false
352 end
353
354 end
355
356 end
357 end
358
359 end
360
361 return false
362
363end
364
365-- Return true/false if text is a LFG message
366local function SpamLookingFor(text)
367
368 local spamStrings = {
369 [1] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[mMgG]",
370 [2] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[hH][eE][aA][lL]",
371 [3] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[dD][dD]",
372 [4] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[dD][pP][sS]",
373 [5] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[tT][aA][nN][kK]",
374 [6] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[dD][aA][iI][lL][yY]",
375 [7] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[sS][iI][lL][vV][eE][rR]",
376 [8] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[gG][oO][lL][dD]", -- bypassed by first rule
377 [9] = "[lL][%s.]?[fF][%s.]?[%d]?[%s.]?[dD][uU][nN][gG][eE][oO][nN]",
378 }
379
380 for _, spamString in ipairs(spamStrings) do
381 if string.find(text, spamString) then
382 --CHAT_SYSTEM:Zo_AddMessage("spamLookingFor:" .. text .." ;spamString=" .. spamString)
383 return true
384 end
385 end
386
387 return false
388
389end
390
391-- Return true/false if text is a WTT message
392local function SpamWantTo(text)
393
394 -- "w.T S"
395 if string.find(text, "[wW][%s.]?[tT][%s.]?[bBsStT]") then
396
397 -- Item Handler
398 if string.find(text, "|H(.-):item:(.-)|h(.-)|h") then
399 -- Match
400 --CHAT_SYSTEM:Zo_AddMessage("WT detected ( " .. text .. " )")
401 return true
402 elseif string.find(text, "[Ww][Ww][%s]+[Bb][Ii][Tt][Ee]") then
403 -- Match
404 --CHAT_SYSTEM:Zo_AddMessage("WT WW Bite detected ( " .. text .. " )")
405 return true
406 end
407
408 end
409
410 return false
411
412end
413
414-- Return true/false if text is a Guild recruitment one
415local function SpamGuildRecruit(text, chanCode)
416
417 -- Guild Recruitment message are too complex to only use 1/2 patterns, an heuristic method must be used
418
419 -- 1st is channel. only check geographic channels (character ones)
420 -- 2nd is text len, they're generally long ones
421 -- Then, presence of certain words
422
423 --CHAT_SYSTEM:Zo_AddMessage("GR analizis")
424
425 local spamChanCode = chanCode
426 if spamChanCode == CHAT_CHANNEL_SAY then
427 spamChanCode = PCHAT_CHANNEL_SAY
428 end
429
430 local spammableChannels = {}
431 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_1] = true
432 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_2] = true
433 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_3] = true
434 spammableChannels[CHAT_CHANNEL_ZONE_LANGUAGE_4] = true
435 spammableChannels[PCHAT_CHANNEL_SAY] = true
436 spammableChannels[CHAT_CHANNEL_YELL] = true
437 spammableChannels[CHAT_CHANNEL_ZONE] = true
438 spammableChannels[CHAT_CHANNEL_EMOTE] = true
439
440 local spamStrings = {
441 ["[Ll]ooking [Ff]or ([Nn]ew+) [Mm]embers"] = 5, -- looking for (new) members
442 ["%d%d%d\+"] = 5, -- 398+
443 ["%d%d%d\/500"] = 5, -- 398/500
444 ["gilde"] = 1, -- 398/500
445 ["guild"] = 1, -- 398/500
446 ["[Tt][Ee][Aa][Mm][Ss][Pp][Ee][Aa][Kk]"] = 1,
447 }
448
449 --[[
450
451Polska gildia <OUTLAWS> po stronie DC rekrutuje! Oferujemy triale, eventy pvp, dungeony, hardmody, porady doswiadczonych graczy oraz mila atmosfere. Wymagamy TS-a i mikrofonu. "OUTLAWS gildia dla ludzi chcacych tworzyc gildie, a nie tylko byc w gildii!" W sprawie rekrutacji zloz podanie na www.outlawseso.guildlaunch.com lub napisz w grze.
452Seid gegrüßt liebe Abenteurer. Eine der ältesten aktiven Handelsgilden (seit 30.03.14), Caveat Emptor (deutschsprachig), hat wieder Plätze frei. (490+ Mitglieder). Gildenhändler vorhanden! /w bei Interesse
453Salut. L'esprit d'équipe est quelque chose qui vous parle ? Relever les plus haut défis en PvE comme en PvP et RvR vous tente, mais vous ne voulez pas sacrifier votre IRL pour cela ? Empirium League est construite autours de tous ces principes. /w pour plus d'infos ou sur Empiriumleague.com
454Die Gilde Drachenstern sucht noch Aktive Member ab V1 für gemeinsamen Spaß und Erfolg:) unserer aktueller Raidcontent ist Sanctum/HelRah und AA unsere Raidtage sind Mittwoch/Freitags und Sonntag bei Fragen/Intresse einfach tell/me:)
455Anyone wants to join a BIG ACTIVE TRADE GUILD? Then join Daggerfall Trade Masters 493/500 MEMBERS--5DAYS ACTIVITY--_TEAMSPEAK--CRAGLORN FRONT ROW TRADER (SHELZAKA) Whisper me for invite and start BUYING and SELLING right NOW!
456The Cambridge Alliance is a multi-faction social guild based in the UK. Send me a whisper if you would like to join! www.cambridge-alliance.co.uk
457Rejoignez le Comptoir de Bordeciel, Guilde Internationale de Trade (490+) présente depuis la release. Bénéficiez de nos prices check grâce à un historique de vente et bénéficiez d’estimations réelles. Les taxes sont investies dans le marchand de guilde. Envoyez-moi par mp le code « CDC » pour invitation auto
458Valeureux soldats de l'Alliance, rejoignez l'Ordre des Ombres, combattez pour la gloire de Daguefillante, pour la victoire, et la conquète du trône impérial ! -- Mumble et site -- Guilde PVE-PVP -- 18+ -- MP pour info
459Join Honour. A well established guild with over 10 years gaming experience and almost 500 active members. We run a full week of Undaunted, Trials, Cyrodiil and low level helper nights. With a social and helpful community and great crafting support. Check out our forums www.honourforever.com. /w for invite
460{L'Ordre des Ombres} construite sur l'entraide, la sympathie et bonne ambiance vous invite a rejoindre ses rangs afin de profiter au maximum de TESO. www.ordredesombres.fr Cordialement - Chems
461The new guild Auctionhouse Extended is recruiting players, who want to buy or sell items! (300+ member
462Totalitarnaya Destructivnaya Sekta "Cadwell's Honor" nabiraet otvazhnyh i bezbashennyh rakov, krabov i drugie moreprodukty v svoi tesnye ryady!! PvE, PvP, TS, neobychnyi RP i prochie huliganstva. Nam nuzhny vashi kleshni!! TeamSpeak dlya priema cadwells-honor.ru
463you look for a guild (united trade post / 490+ member) for trade, pve and all other things in eso without obligations? /w me for invitation --- du suchst eine gilde (united trade post / 490+ mitglieder) für handel, pve und alle anderen dinge in eso ohne verpflichtungen. /w me
464[The Warehouse] Trading Guild Looking for Members! /w me for Invite :)
465Russian guild Daggerfall Bandits is looking for new members! We are the biggest and the most active russian community in Covenant. Regular PvE and PvP raids to normal and hard mode content! 490+ members. Whisper me.
466 Bonjour, la Guilde La Flibuste recherche des joueurs francophones. Sans conditions et pour jouer dans la bonne humeur, notre guilde est ouverte à tous. On recherche des joueurs de toutes les classes et vétérang pour compléter nos raids. Pour plus d'infos, c'est ici :) Merci et bon jeu.
467
468 ]]--
469
470 -- Our note. Per default, each message get its heuristic level to 0
471 local guildHeuristics = 0
472
473 -- spammableChannels[db.LineStrings[previousLine].channel] = return true if previous message was sent in a spammable channel
474 if spammableChannels[spamChanCode] then
475
476 local textLen = string.len(text)
477 local text300 = (string.len(text) > 300) -- 50
478 local text250 = (string.len(text) > 250) -- 40
479 local text200 = (string.len(text) > 200) -- 30
480 local text150 = (string.len(text) > 150) -- 20
481 local text100 = (string.len(text) > 100) -- 10
482 local text30 = (string.len(text) > 30) -- 0
483
484 -- 30 chars are needed to make a phrase of guild recruitment. If recruiter spam in SMS, pChat won't handle it.
485 if text30 then
486
487 -- Each message can possibly be a spam, let's wrote our checklist
488 --CHAT_SYSTEM:Zo_AddMessage("GR Len ( " .. textLen .. " )")
489
490 if text300 then
491 guildHeuristics = 50
492 elseif text250 then
493 guildHeuristics = 40
494 elseif text200 then
495 guildHeuristics = 30
496 elseif text150 then
497 guildHeuristics = 20
498 elseif text100 then
499 guildHeuristics = 10
500 end
501
502 -- Still to do
503
504 for spamString, value in ipairs(spamStrings) do
505 if string.find(text, spamString) then
506 --CHAT_SYSTEM:Zo_AddMessage(spamString)
507 guildHeuristics = guildHeuristics + value
508 end
509 end
510
511 if guildHeuristics > 60 then
512 --CHAT_SYSTEM:Zo_AddMessage("GR : true (score=" .. guildHeuristics .. ")")
513 return true
514 end
515
516 end
517
518 end
519
520 --CHAT_SYSTEM:Zo_AddMessage("GR : false (score=" .. guildHeuristics .. ")")
521 return false
522
523end
524
525-- Return true/false if anti spam is enabled for a certain category
526-- Categories must be : Flood, LookingFor, WantTo, GuildRecruit
527local function IsSpamEnabledForCategory(category)
528
529 if category == "Flood" then
530
531 -- Enabled in Options?
532 if db.floodProtect then
533 --CHAT_SYSTEM:Zo_AddMessage("floodProtect enabled")
534 -- AntiSpam is enabled
535 return true
536 end
537
538 --CHAT_SYSTEM:Zo_AddMessage("floodProtect disabled")
539 -- AntiSpam is disabled
540 return false
541
542 -- LFG
543 elseif category == "LookingFor" then
544 -- Enabled in Options?
545 if db.lookingForProtect then
546 -- Enabled in reality?
547 if pChatData.spamLookingForEnabled then
548 --CHAT_SYSTEM:Zo_AddMessage("lookingForProtect enabled")
549 -- AntiSpam is enabled
550 return true
551 else
552
553 --CHAT_SYSTEM:Zo_AddMessage("lookingForProtect is temporary disabled since " .. pChat.spamTempLookingForStopTimestamp)
554
555 -- AntiSpam is disabled .. since -/+ grace time ?
556 if GetTimeStamp() - pChatData.spamTempLookingForStopTimestamp > (db.spamGracePeriod * 60) then
557 --CHAT_SYSTEM:Zo_AddMessage("lookingForProtect enabled again")
558 -- Grace period outdatted -> we need to re-enable it
559 pChatData.spamLookingForEnabled = true
560 return true
561 end
562 end
563 end
564
565 --CHAT_SYSTEM:Zo_AddMessage("lookingForProtect disabled")
566 -- AntiSpam is disabled
567 return false
568
569 -- WTT
570 elseif category == "WantTo" then
571 -- Enabled in Options?
572 if db.wantToProtect then
573 -- Enabled in reality?
574 if pChatData.spamWantToEnabled then
575 --CHAT_SYSTEM:Zo_AddMessage("wantToProtect enabled")
576 -- AntiSpam is enabled
577 return true
578 else
579 -- AntiSpam is disabled .. since -/+ grace time ?
580 if GetTimeStamp() - pChatData.spamTempWantToStopTimestamp > (db.spamGracePeriod * 60) then
581 --CHAT_SYSTEM:Zo_AddMessage("wantToProtect enabled again")
582 -- Grace period outdatted -> we need to re-enable it
583 pChatData.spamWantToEnabled = true
584 return true
585 end
586 end
587 end
588
589 --CHAT_SYSTEM:Zo_AddMessage("wantToProtect disabled")
590 -- AntiSpam is disabled
591 return false
592
593 -- Join my Awesome guild
594 elseif category == "GuildRecruit" then
595 -- Enabled in Options?
596 if db.guildRecruitProtect then
597 -- Enabled in reality?
598 if pChatData.spamGuildRecruitEnabled then
599 -- AntiSpam is enabled
600 return true
601 else
602 -- AntiSpam is disabled .. since -/+ grace time ?
603 if GetTimeStamp() - pChatData.spamTempGuildRecruitStopTimestamp > (db.spamGracePeriod * 60) then
604 -- Grace period outdatted -> we need to re-enable it
605 pChatData.spamGuildRecruitEnabled = true
606 return true
607 end
608 end
609 end
610
611 -- AntiSpam is disabled
612 return false
613
614 end
615
616end
617
618-- Return true is message is a spam depending on MANY parameters
619local function SpamFilter(chanCode, from, text, isCS)
620
621 -- 5 options for spam : Spam (multiple messages) ; LFM/LFG ; WT(T/S/B) ; Guild Recruitment ; Gold Spamming for various websites
622
623 -- ZOS GM are NEVER blocked
624 if isCS then
625 return false
626 end
627
628 -- CHAT_CHANNEL_PARTY is not spamfiltered, party leader get its own antispam tool (= kick)
629 if chanCode == CHAT_CHANNEL_PARTY then
630 return false
631 end
632
633 -- "I" or anyone do not flood
634 if IsSpamEnabledForCategory("Flood") then
635 if SpamFlood(from, text, chanCode) then return true end
636 end
637
638 -- But "I" can have exceptions
639 if zo_strformat(SI_UNIT_NAME, from) == pChatData.localPlayer or from == GetDisplayName() then
640
641 --CHAT_SYSTEM:Zo_AddMessage("I say something ( " .. text .. " )")
642
643 if IsSpamEnabledForCategory("LookingFor") then
644 -- "I" can look for a group
645 if SpamLookingFor(text) then
646
647 --CHAT_SYSTEM:Zo_AddMessage("I say a LF Message ( " .. text .. " )")
648
649 -- If I break myself the rule, disable it few minutes
650 pChatData.spamTempLookingForStopTimestamp = GetTimeStamp()
651 pChatData.spamLookingForEnabled = false
652
653 end
654 end
655
656 if IsSpamEnabledForCategory("WantTo") then
657 -- "I" can be a trader
658 if SpamWantTo(text) then
659
660 --CHAT_SYSTEM:Zo_AddMessage("I say a WT Message ( " .. text .. " )")
661
662 -- If I break myself the rule, disable it few minutes
663 pChatData.spamTempWantToStopTimestamp = GetTimeStamp()
664 pChatData.spamWantToStop = true
665
666 end
667 end
668
669 --[[
670 if IsSpamEnabledForCategory("GuildRecruit") then
671 -- "I" can do some guild recruitment
672 if SpamGuildRecruit(text, chanCode) then
673
674 --CHAT_SYSTEM:Zo_AddMessage("I say a GR Message ( " .. text .. " )")
675
676 -- If I break myself the rule, disable it few minutes
677 pChatData.spamTempGuildRecruitStopTimestamp = GetTimeStamp()
678 pChatData.spamGuildRecruitStop = true
679
680 end
681 end
682 ]]--
683
684 -- My message will be displayed in any case
685 return false
686
687 end
688
689 -- Spam
690 if IsSpamEnabledForCategory("Flood") then
691 if SpamFlood(from, text, chanCode) then return true end
692 end
693
694 -- Looking For
695 if IsSpamEnabledForCategory("LookingFor") then
696 if SpamLookingFor(text) then return true end
697 end
698
699 -- Want To
700 if IsSpamEnabledForCategory("WantTo") then
701 if SpamWantTo(text) then return true end
702 end
703
704 -- Guild Recruit
705 --[[
706 if IsSpamEnabledForCategory("GuildRecruit") then
707 if SpamGuildRecruit(text, chanCode) then return true end
708 end
709 ]]--
710
711 return false
712
713end
714
715-- Turn a ([0,1])^3 RGB colour to "|cABCDEF" form. We could use ZO_ColorDef, but we have so many colors so we don't do it.
716local function ConvertRGBToHex(r, g, b)
717 return string.format("|c%.2x%.2x%.2x", zo_floor(r * 255), zo_floor(g * 255), zo_floor(b * 255))
718end
719
720-- Convert a colour from "|cABCDEF" form to [0,1] RGB form.
721local function ConvertHexToRGBA(colourString)
722 local r=tonumber(string.sub(colourString, 3, 4), 16) or 255
723 local g=tonumber(string.sub(colourString, 5, 6), 16) or 255
724 local b=tonumber(string.sub(colourString, 7, 8), 16) or 255
725 return r/255, g/255, b/255, 1
726end
727
728-- Return a formatted time
729local function CreateTimestamp(timeStr, formatStr)
730 formatStr = formatStr or db.timestampFormat
731
732 -- split up default timestamp
733 local hours, minutes, seconds = timeStr:match("([^%:]+):([^%:]+):([^%:]+)")
734 local hoursNoLead = tonumber(hours) -- hours without leading zero
735 local hours12NoLead = (hoursNoLead - 1)%12 + 1
736 local hours12
737 if (hours12NoLead < 10) then
738 hours12 = "0" .. hours12NoLead
739 else
740 hours12 = hours12NoLead
741 end
742 local pUp = "AM"
743 local pLow = "am"
744 if (hoursNoLead >= 12) then
745 pUp = "PM"
746 pLow = "pm"
747 end
748
749 -- create new one
750 local timestamp = formatStr
751 timestamp = timestamp:gsub("HH", hours)
752 timestamp = timestamp:gsub("H", hoursNoLead)
753 timestamp = timestamp:gsub("hh", hours12)
754 timestamp = timestamp:gsub("h", hours12NoLead)
755 timestamp = timestamp:gsub("m", minutes)
756 timestamp = timestamp:gsub("s", seconds)
757 timestamp = timestamp:gsub("A", pUp)
758 timestamp = timestamp:gsub("a", pLow)
759
760 return timestamp
761
762end
763
764-- Format from name
765local function ConvertName(chanCode, from, isCS, fromDisplayName)
766
767 local function DisplayWithOrWoBrackets(realFrom, displayed, linkType)
768 if not displayed then -- reported. Should not happen, maybe parser error with nicknames.
769 displayed = realFrom
770 end
771 if db.disableBrackets then
772 return ZO_LinkHandler_CreateLinkWithoutBrackets(displayed, nil, linkType, realFrom)
773 else
774 return ZO_LinkHandler_CreateLink(displayed, nil, linkType, realFrom)
775 end
776 end
777
778 -- From can be UserID or Character name depending on wich channel we are
779 local new_from = from
780
781 -- Messages from @Someone (guild / whisps)
782 if IsDecoratedDisplayName(from) then
783
784 -- Guild / Officer chat only
785 if chanCode >= CHAT_CHANNEL_GUILD_1 and chanCode <= CHAT_CHANNEL_OFFICER_5 then
786
787 -- Get guild ID based on channel id
788 local guildId = GetGuildId((chanCode - CHAT_CHANNEL_GUILD_1) % 5 + 1)
789 local guildName = GetGuildName(guildId)
790
791 if pChatData.nicknames[new_from] then -- @UserID Nicknammed
792 db.LineStrings[db.lineNumber].rawFrom = pChatData.nicknames[new_from]
793 new_from = DisplayWithOrWoBrackets(new_from, pChatData.nicknames[new_from], DISPLAY_NAME_LINK_TYPE)
794 elseif db.formatguild[guildName] == 2 then -- Char
795 local _, characterName = GetGuildMemberCharacterInfo(guildId, GetGuildMemberIndexFromDisplayName(guildId, new_from))
796 characterName = zo_strformat(SI_UNIT_NAME, characterName)
797 local nickNamedName
798 if pChatData.nicknames[characterName] then -- Char Nicknammed
799 nickNamedName = pChatData.nicknames[characterName]
800 end
801 db.LineStrings[db.lineNumber].rawFrom = nickNamedName or characterName
802 new_from = DisplayWithOrWoBrackets(characterName, nickNamedName or characterName, CHARACTER_LINK_TYPE)
803 elseif db.formatguild[guildName] == 3 then -- Char@UserID
804 local _, characterName = GetGuildMemberCharacterInfo(guildId, GetGuildMemberIndexFromDisplayName(guildId, new_from))
805 characterName = zo_strformat(SI_UNIT_NAME, characterName)
806 if characterName == "" then characterName = new_from end -- Some buggy rosters
807
808 if pChatData.nicknames[characterName] then -- Char Nicknammed
809 characterName = pChatData.nicknames[characterName]
810 else
811 characterName = characterName .. new_from
812 end
813
814 db.LineStrings[db.lineNumber].rawFrom = characterName
815 new_from = DisplayWithOrWoBrackets(new_from, characterName, DISPLAY_NAME_LINK_TYPE)
816 else
817 db.LineStrings[db.lineNumber].rawFrom = new_from
818 new_from = DisplayWithOrWoBrackets(new_from, new_from, DISPLAY_NAME_LINK_TYPE)
819 end
820
821 else
822 -- Wisps with @ We can't guess characterName for those ones
823
824 if pChatData.nicknames[new_from] then -- @UserID Nicknammed
825 db.LineStrings[db.lineNumber].rawFrom = pChatData.nicknames[new_from]
826 new_from = DisplayWithOrWoBrackets(new_from, pChatData.nicknames[new_from], DISPLAY_NAME_LINK_TYPE)
827 else
828 db.LineStrings[db.lineNumber].rawFrom = new_from
829 new_from = DisplayWithOrWoBrackets(new_from, new_from, DISPLAY_NAME_LINK_TYPE)
830 end
831
832 end
833
834 -- Geo chat, Party, Whisps with characterName
835 else
836
837 new_from = zo_strformat(SI_UNIT_NAME, new_from)
838
839 local nicknamedFrom
840 if pChatData.nicknames[new_from] then -- Character or Account Nicknammed
841 nicknamedFrom = pChatData.nicknames[new_from]
842 elseif pChatData.nicknames[fromDisplayName] then
843 nicknamedFrom = pChatData.nicknames[fromDisplayName]
844 end
845
846 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or new_from
847
848 -- No brackets / UserID for emotes
849 if chanCode == CHAT_CHANNEL_EMOTE then
850 new_from = ZO_LinkHandler_CreateLinkWithoutBrackets(nicknamedFrom or new_from, nil, CHARACTER_LINK_TYPE, from)
851 -- zones / whisps / say / tell. No Handler for NPC
852 elseif not (chanCode == CHAT_CHANNEL_MONSTER_SAY or chanCode == CHAT_CHANNEL_MONSTER_YELL or chanCode == CHAT_CHANNEL_MONSTER_WHISPER or chanCode == CHAT_CHANNEL_MONSTER_EMOTE) then
853
854 if chanCode == CHAT_CHANNEL_PARTY then
855 if db.groupNames == 1 then
856 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or fromDisplayName
857 new_from = DisplayWithOrWoBrackets(fromDisplayName, nicknamedFrom or fromDisplayName, DISPLAY_NAME_LINK_TYPE)
858 elseif db.groupNames == 3 then
859 new_from = new_from .. fromDisplayName
860 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or new_from
861 new_from = DisplayWithOrWoBrackets(from, nicknamedFrom or new_from, CHARACTER_LINK_TYPE)
862 else
863 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or new_from
864 new_from = DisplayWithOrWoBrackets(from, nicknamedFrom or new_from, CHARACTER_LINK_TYPE)
865 end
866 else
867 if db.geoChannelsFormat == 1 then
868 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or fromDisplayName
869 new_from = DisplayWithOrWoBrackets(fromDisplayName, nicknamedFrom or fromDisplayName, DISPLAY_NAME_LINK_TYPE)
870 elseif db.geoChannelsFormat == 3 then
871 new_from = new_from .. fromDisplayName
872 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or new_from
873 new_from = DisplayWithOrWoBrackets(from, nicknamedFrom or new_from, CHARACTER_LINK_TYPE)
874 else
875 db.LineStrings[db.lineNumber].rawFrom = nicknamedFrom or new_from
876 new_from = DisplayWithOrWoBrackets(from, nicknamedFrom or new_from, CHARACTER_LINK_TYPE)
877 end
878 end
879
880 end
881
882 end
883
884 if isCS then -- ZOS icon
885 new_from = "|t16:16:EsoUI/Art/ChatWindow/csIcon.dds|t" .. new_from
886 end
887
888 return new_from
889
890end
891
892local function UndockTextEntry()
893
894 -- Unfinshed
895
896 if not db.chatConfSync[pChatData.localPlayer].TextEntryPoint then
897 db.chatConfSync[pChatData.localPlayer].TextEntryPoint = CENTER
898 db.chatConfSync[pChatData.localPlayer].TextEntryRelPoint = CENTER
899 db.chatConfSync[pChatData.localPlayer].TextEntryX = 0
900 db.chatConfSync[pChatData.localPlayer].TextEntryY = -300
901 db.chatConfSync[pChatData.localPlayer].TextEntryWidth = 200
902 end
903
904 ZO_ChatWindowTextEntry:ClearAnchors()
905 ZO_ChatWindowTextEntry:SetAnchor(db.chatConfSync[pChatData.localPlayer].TextEntryPoint, GuiRoot, db.chatConfSync[pChatData.localPlayer].TextEntryRelPoint, db.chatConfSync[pChatData.localPlayer].TextEntryX, 300)
906 ZO_ChatWindowTextEntry:SetDimensions(400, 27)
907 ZO_ChatWindowTextEntry:SetMovable(false)
908
909 local undockedTexture = WINDOW_MANAGER:CreateControl("UndockedBackground", ZO_ChatWindowTextEntry, CT_TEXTURE)
910 undockedTexture:SetTexture("EsoUI/Art/Performance/StatusMeterMunge.dds")
911 undockedTexture:SetAnchor(CENTER, ZO_ChatWindowTextEntry, CENTER, 0, 0)
912 undockedTexture:SetDimensions(800, 250)
913
914end
915
916local function RedockTextEntry()
917
918 -- Unfinished
919
920 ZO_ChatWindowTextEntry:ClearAnchors()
921 ZO_ChatWindowTextEntry:SetAnchor(BOTTOMLEFT, ZO_ChatWindowMinimize, BOTTOMRIGHT, -6, -13)
922 ZO_ChatWindowTextEntry:SetAnchor(BOTTOMRIGHT, ZO_ChatWindow, BOTTOMRIGHT, -23, -13)
923 ZO_ChatWindowTextEntry:SetMovable(false)
924
925end
926
927
928-- For console
929function pChat.CMD_DEBUG()
930 if pChat.DEBUG ~= 1 then
931 d("pChat Debug : On")
932 pChat.DEBUG = 1
933 else
934 d("pChat Debug : Off")
935 pChat.DEBUG = 0
936 end
937end
938
939-- For console quest time
940function pChat.CMD_DEBUG1()
941 if pChat.DEBUG ~= 2 then
942 d("pChat Debug 2: On")
943 pChat.DEBUG = 2
944 else
945 d("pChat Debug 2: Off")
946 pChat.DEBUG = 0
947 end
948end
949
950function pChat.CMD_DEBUG2()
951 if pChat.DEBUG ~=3 then
952 d("pChat Debug 3 : On")
953 pChat.DEBUG = 3
954 else
955 d("pChat Debug 3 : Off")
956 pChat.DEBUG = 0
957 end
958end
959
960
961-- Also called by bindings
962function pChat_ShowAutoMsg()
963 LMM:ToggleCategory(MENU_CATEGORY_PCHAT)
964end
965
966-- Register Slash commands
967SLASH_COMMANDS["/msg"] = pChat_ShowAutoMsg
968SLASH_COMMANDS["/pchat_debug"] = pChat.CMD_DEBUG
969SLASH_COMMANDS["/pchat_debug1"] = pChat.CMD_DEBUG1
970SLASH_COMMANDS["/pchat_debug2"] = pChat.CMD_DEBUG2
971
972ZO_CreateStringId("PCHAT_AUTOMSG_NAME_DEFAULT_TEXT", GetString(PCHAT_PCHAT_AUTOMSG_NAME_DEFAULT_TEXT))
973ZO_CreateStringId("PCHAT_AUTOMSG_MESSAGE_DEFAULT_TEXT", GetString(PCHAT_PCHAT_AUTOMSG_MESSAGE_DEFAULT_TEXT))
974ZO_CreateStringId("PCHAT_AUTOMSG_MESSAGE_TIP1_TEXT", GetString(PCHAT_PCHAT_AUTOMSG_MESSAGE_TIP1_TEXT))
975ZO_CreateStringId("PCHAT_AUTOMSG_MESSAGE_TIP2_TEXT", GetString(PCHAT_PCHAT_AUTOMSG_MESSAGE_TIP2_TEXT))
976ZO_CreateStringId("PCHAT_AUTOMSG_MESSAGE_TIP3_TEXT", GetString(PCHAT_PCHAT_AUTOMSG_MESSAGE_TIP3_TEXT))
977ZO_CreateStringId("PCHAT_AUTOMSG_NAME_HEADER", GetString(PCHAT_PCHAT_AUTOMSG_NAME_HEADER))
978ZO_CreateStringId("PCHAT_AUTOMSG_MESSAGE_HEADER", GetString(PCHAT_PCHAT_AUTOMSG_MESSAGE_HEADER))
979ZO_CreateStringId("PCHAT_AUTOMSG_ADD_TITLE_HEADER", GetString(PCHAT_PCHAT_AUTOMSG_ADD_TITLE_HEADER))
980ZO_CreateStringId("PCHAT_AUTOMSG_EDIT_TITLE_HEADER", GetString(PCHAT_PCHAT_AUTOMSG_EDIT_TITLE_HEADER))
981ZO_CreateStringId("PCHAT_AUTOMSG_ADD_AUTO_MSG", GetString(PCHAT_PCHAT_AUTOMSG_ADD_AUTO_MSG))
982ZO_CreateStringId("PCHAT_AUTOMSG_EDIT_AUTO_MSG", GetString(PCHAT_PCHAT_AUTOMSG_EDIT_AUTO_MSG))
983ZO_CreateStringId("SI_BINDING_NAME_PCHAT_SHOW_AUTO_MSG", GetString(PCHAT_SI_BINDING_NAME_PCHAT_SHOW_AUTO_MSG))
984ZO_CreateStringId("PCHAT_AUTOMSG_REMOVE_AUTO_MSG", GetString(PCHAT_PCHAT_AUTOMSG_REMOVE_AUTO_MSG))
985
986
987
988
989function automatedMessagesList:New(control)
990
991 ZO_SortFilterList.InitializeSortFilterList(self, control)
992
993 local AutomatedMessagesSorterKeys =
994 {
995 ["name"] = {},
996 ["message"] = {tiebreaker = "name"}
997 }
998
999 self.masterList = {}
1000 ZO_ScrollList_AddDataType(self.list, 1, "pChatXMLAutoMsgRowTemplate", 32, function(control, data) self:SetupEntry(control, data) end)
1001 ZO_ScrollList_EnableHighlight(self.list, "ZO_ThinListHighlight")
1002 self.sortFunction = function(listEntry1, listEntry2) return ZO_TableOrderingFunction(listEntry1.data, listEntry2.data, self.currentSortKey, AutomatedMessagesSorterKeys, self.currentSortOrder) end
1003 --self:SetAlternateRowBackgrounds(true)
1004
1005 return self
1006
1007end
1008
1009-- format ESO text to raw text
1010-- IE : Transforms LinkHandlers into their displayed value
1011local function FormatRawText(text)
1012
1013 -- Strip colors from chat
1014 local newtext = string.gsub(text, "|[cC]%x%x%x%x%x%x", ""):gsub("|r", "")
1015
1016 -- Transforms a LinkHandler into its localized displayed value
1017 -- "|H(.-):(.-)|h(.-)|h" = pattern for Linkhandlers
1018 -- Item : |H1:item:33753:25:1:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0|h|h = [Battaglir] in french -> Link to item 33753, etc
1019 -- Achievement |H1:achievement:33753|h|h etc (not searched a lot, was easy)
1020 -- DisplayName = |H1:display:Ayantir|h[@Ayantir]|h = [@Ayantir] -> link to DisplayName @Ayantir
1021 -- Book = |H1:book:186|h|h = [Climat de guerre] in french -> Link to book 186 .. GetLoreBookTitleFromLink()
1022 -- pChat = |H1:PCHAT_LINK:124:11|h[06:18]|h = [06:18] (here 0 is the line number reference and 11 is the chanCode) - URL handling : if chanCode = 97, it will popup a dialog to open internet browser
1023 -- Character = |H1:character:salhamandhil^Mx|h[salhamandhil]|h = text (is there anything which link Characters into a message ?) (here salhamandhil is with brackets volontary)
1024 -- Need to do quest_items too. |H1:quest_item:4275|h|h
1025
1026 newtext = string.gsub(newtext, "|H(.-):(.-)|h(.-)|h", function (linkStyle, data, text)
1027 -- linkStyle = style (ignored by game, seems to be often 1)
1028 -- data = data saparated by ":"
1029 -- text = text displayed, used for Channels, DisplayName, Character, and some fake itemlinks (used by addons)
1030
1031 -- linktype is : item, achievement, character, channel, book, display, pchatlink
1032 -- DOES NOT HANDLE ADDONS LINKTYPES
1033
1034 -- for all types, only param1 is important
1035 local linkType, param1 = zo_strsplit(':', data)
1036
1037 -- param1 : itemID
1038 -- Need to get
1039 if linkType == ITEM_LINK_TYPE or linkType == COLLECTIBLE_LINK_TYPE then
1040 -- Fakelink and GetItemLinkName
1041 return "[" .. zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLinkName("|H" .. linkStyle ..":" .. data .. "|h|h")) .. "]"
1042 -- param1 : achievementID
1043 elseif linkType == ACHIEVEMENT_LINK_TYPE then
1044 -- zo_strformat to avoid masculine/feminine problems
1045 return "[" .. zo_strformat(GetAchievementInfo(param1)) .. "]"
1046 -- SysMessages Links CharacterNames
1047 elseif linkType == CHARACTER_LINK_TYPE then
1048 return text
1049 elseif linkType == CHANNEL_LINK_TYPE then
1050 return text
1051 elseif linkType == BOOK_LINK_TYPE then
1052 return "[" .. GetLoreBookTitleFromLink(newtext) .. "]"
1053 -- SysMessages Links DysplayNames
1054 elseif linkType == DISPLAY_NAME_LINK_TYPE then
1055 -- No formatting here
1056 return "[@" .. param1 .. "]"
1057 -- Used for Sysmessages
1058 elseif linkType == "quest_item" then
1059 -- No formatting here
1060 return "[" .. zo_strformat(SI_TOOLTIP_ITEM_NAME, GetQuestItemNameFromLink(newtext)) .. "]"
1061 elseif linkType == PCHAT_LINK then
1062 -- No formatting here .. maybe yes ?..
1063 return text
1064 end
1065 end)
1066
1067 return newtext
1068
1069end
1070
1071function automatedMessagesList:SetupEntry(control, data)
1072
1073 control.data = data
1074 control.name = GetControl(control, "Name")
1075 control.message = GetControl(control, "Message")
1076
1077 local messageTrunc = FormatRawText(data.message)
1078 if string.len(messageTrunc) > 53 then
1079 messageTrunc = string.sub(messageTrunc, 1, 53) .. " .."
1080 end
1081
1082 control.name:SetText(data.name)
1083 control.message:SetText(messageTrunc)
1084
1085 ZO_SortFilterList.SetupRow(self, control, data)
1086
1087end
1088
1089function automatedMessagesList:BuildMasterList()
1090 self.masterList = {}
1091 local messages = db.automatedMessages
1092 if messages then
1093 for k, v in ipairs(messages) do
1094 local data = v
1095 table.insert(self.masterList, data)
1096 end
1097 end
1098
1099end
1100
1101function automatedMessagesList:SortScrollList()
1102 local scrollData = ZO_ScrollList_GetDataList(self.list)
1103 table.sort(scrollData, self.sortFunction)
1104end
1105
1106function automatedMessagesList:FilterScrollList()
1107 local scrollData = ZO_ScrollList_GetDataList(self.list)
1108 ZO_ClearNumericallyIndexedTable(scrollData)
1109
1110 for i = 1, #self.masterList do
1111 local data = self.masterList[i]
1112 table.insert(scrollData, ZO_ScrollList_CreateDataEntry(1, data))
1113 end
1114end
1115
1116local function GetDataByNameInSavedAutomatedMessages(name)
1117 local dataList = db.automatedMessages
1118 for index, data in ipairs(dataList) do
1119 if(data.name == name) then
1120 return data, index
1121 end
1122 end
1123end
1124
1125local function GetDataByNameInAutomatedMessages(name)
1126 local dataList = pChatData.automatedMessagesList.list.data
1127 for i = 1, #dataList do
1128 local data = dataList[i].data
1129 if(data.name == name) then
1130 return data, index
1131 end
1132 end
1133end
1134
1135local function SaveAutomatedMessage(name, message, isNew)
1136
1137 if db then
1138
1139 local alreadyFav = false
1140
1141 if isNew then
1142 for k, v in pairs(db.automatedMessages) do
1143 if "!" .. name == v.name then
1144 alreadyFav = true
1145 end
1146 end
1147 end
1148
1149 if not alreadyFav then
1150
1151 pChatXMLAutoMsg:GetNamedChild("Warning"):SetHidden(true)
1152 pChatXMLAutoMsg:GetNamedChild("Warning"):SetText("")
1153
1154 if string.len(name) > 12 then
1155 name = string.sub(name, 1, 12)
1156 end
1157
1158 if string.len(message) > 351 then
1159 message = string.sub(message, 1, 351)
1160 end
1161
1162 local entryList = ZO_ScrollList_GetDataList(pChatData.automatedMessagesList.list)
1163
1164 if isNew then
1165 local data = {name = "!" .. name, message = message}
1166 local entry = ZO_ScrollList_CreateDataEntry(1, data)
1167 table.insert(entryList, entry)
1168 table.insert(db.automatedMessages, {name = "!" .. name, message = message}) -- "data" variable is modified by ZO_ScrollList_CreateDataEntry and will crash eso if saved to savedvars
1169 else
1170
1171 local data = GetDataByNameInAutomatedMessages(name)
1172 local _, index = GetDataByNameInSavedAutomatedMessages(name)
1173
1174 data.message = message
1175 db.automatedMessages[index].message = message
1176 end
1177
1178 ZO_ScrollList_Commit(pChatData.automatedMessagesList.list)
1179
1180 else
1181 pChatXMLAutoMsg:GetNamedChild("Warning"):SetHidden(false)
1182 pChatXMLAutoMsg:GetNamedChild("Warning"):SetText(GetString(PCHAT_SAVMSGERRALREADYEXISTS))
1183 pChatXMLAutoMsg:GetNamedChild("Warning"):SetColor(1, 0, 0)
1184 zo_callLater(function() pChatXMLAutoMsg:GetNamedChild("Warning"):SetHidden(true) end, 5000)
1185 end
1186
1187 end
1188
1189end
1190
1191local function CleanAutomatedMessageListForDB()
1192 -- :RefreshData() adds dataEntry recursively, delete it to avoid overflow in SavedVars
1193 for k, v in ipairs(db.automatedMessages) do
1194 if v.dataEntry then
1195 v.dataEntry = nil
1196 end
1197 end
1198end
1199
1200local function RemoveAutomatedMessage()
1201
1202 local data = ZO_ScrollList_GetData(WINDOW_MANAGER:GetMouseOverControl())
1203 local _, index = GetDataByNameInSavedAutomatedMessages(data.name)
1204 table.remove(db.automatedMessages, index)
1205 pChatData.automatedMessagesList:RefreshData()
1206 CleanAutomatedMessageListForDB()
1207
1208end
1209
1210-- Init Automated messages, build the scene and handle array of automated strings
1211local function InitAutomatedMessages()
1212
1213 -- Create Scene
1214 PCHAT_AUTOMSG_SCENE = ZO_Scene:New("pChatAutomatedMessagesScene", SCENE_MANAGER)
1215
1216 -- Mouse standard position and background
1217 PCHAT_AUTOMSG_SCENE:AddFragmentGroup(FRAGMENT_GROUP.MOUSE_DRIVEN_UI_WINDOW)
1218 PCHAT_AUTOMSG_SCENE:AddFragmentGroup(FRAGMENT_GROUP.FRAME_TARGET_STANDARD_RIGHT_PANEL)
1219
1220 -- Background Right, it will set ZO_RightPanelFootPrint and its stuff.
1221 PCHAT_AUTOMSG_SCENE:AddFragment(RIGHT_BG_FRAGMENT)
1222
1223 -- The title fragment
1224 PCHAT_AUTOMSG_SCENE:AddFragment(TITLE_FRAGMENT)
1225
1226 -- Set Title
1227 ZO_CreateStringId("SI_PCHAT_AUTOMSG_TITLE", ADDON_NAME)
1228 PCHAT_AUTOMSG_TITLE_FRAGMENT = ZO_SetTitleFragment:New(SI_PCHAT_AUTOMSG_TITLE)
1229 PCHAT_AUTOMSG_SCENE:AddFragment(PCHAT_AUTOMSG_TITLE_FRAGMENT)
1230
1231 -- Add the XML to our scene
1232 PCHAT_AUTOMSG_SCENE_WINDOW = ZO_FadeSceneFragment:New(pChatXMLAutoMsg)
1233 PCHAT_AUTOMSG_SCENE:AddFragment(PCHAT_AUTOMSG_SCENE_WINDOW)
1234
1235 -- Register Scenes and the group name
1236 SCENE_MANAGER:AddSceneGroup("pChatSceneGroup", ZO_SceneGroup:New("pChatAutomatedMessagesScene"))
1237
1238 -- Its infos
1239 PCHAT_MAIN_MENU_CATEGORY_DATA =
1240 {
1241 binding = "PCHAT_SHOW_AUTO_MSG",
1242 categoryName = PCHAT_SHOW_AUTO_MSG,
1243 normal = "EsoUI/Art/MainMenu/menuBar_champion_up.dds",
1244 pressed = "EsoUI/Art/MainMenu/menuBar_champion_down.dds",
1245 highlight = "EsoUI/Art/MainMenu/menuBar_champion_over.dds",
1246 }
1247
1248 MENU_CATEGORY_PCHAT = LMM:AddCategory(PCHAT_MAIN_MENU_CATEGORY_DATA)
1249
1250 local iconData = {
1251 {
1252 categoryName = SI_BINDING_NAME_PCHAT_SHOW_AUTO_MSG,
1253 descriptor = "pChatAutomatedMessagesScene",
1254 normal = "EsoUI/Art/MainMenu/menuBar_champion_up.dds",
1255 pressed = "EsoUI/Art/MainMenu/menuBar_champion_down.dds",
1256 highlight = "EsoUI/Art/MainMenu/menuBar_champion_over.dds",
1257 },
1258 }
1259
1260 -- Register the group and add the buttons (we cannot all AddRawScene, only AddSceneGroup, so we emulate both functions).
1261 LMM:AddSceneGroup(MENU_CATEGORY_PCHAT, "pChatSceneGroup", iconData)
1262
1263 pChatData.autoMsgDescriptor = {
1264 alignment = KEYBIND_STRIP_ALIGN_CENTER,
1265 {
1266 name = GetString(PCHAT_AUTOMSG_ADD_AUTO_MSG),
1267 keybind = "UI_SHORTCUT_PRIMARY",
1268 control = self,
1269 callback = function(descriptor) ZO_Dialogs_ShowDialog("PCHAT_AUTOMSG_SAVE_MSG", nil, {mainTextParams = {functionName}}) end,
1270 visible = function(descriptor) return true end
1271 },
1272 {
1273 name = GetString(PCHAT_AUTOMSG_EDIT_AUTO_MSG),
1274 keybind = "UI_SHORTCUT_SECONDARY",
1275 control = self,
1276 callback = function(descriptor) ZO_Dialogs_ShowDialog("PCHAT_AUTOMSG_EDIT_MSG", nil, {mainTextParams = {functionName}}) end,
1277 visible = function(descriptor)
1278 if pChatData.autoMessagesShowKeybind then
1279 return true
1280 else
1281 return false
1282 end
1283 end
1284 },
1285 {
1286 name = GetString(PCHAT_AUTOMSG_REMOVE_AUTO_MSG),
1287 keybind = "UI_SHORTCUT_NEGATIVE",
1288 control = self,
1289 callback = function(descriptor) RemoveAutomatedMessage() end,
1290 visible = function(descriptor)
1291 if pChatData.autoMessagesShowKeybind then
1292 return true
1293 else
1294 return false
1295 end
1296 end
1297 },
1298 }
1299
1300 pChatData.pChatAutomatedMessagesScene = SCENE_MANAGER:GetScene("pChatAutomatedMessagesScene")
1301 pChatData.pChatAutomatedMessagesScene:RegisterCallback("StateChange", function(oldState, newState)
1302 if newState == SCENE_SHOWING then
1303 KEYBIND_STRIP:AddKeybindButtonGroup(pChatData.autoMsgDescriptor)
1304 elseif newState == SCENE_HIDDEN then
1305 if KEYBIND_STRIP:HasKeybindButtonGroup(pChatData.autoMsgDescriptor) then
1306 KEYBIND_STRIP:RemoveKeybindButtonGroup(pChatData.autoMsgDescriptor)
1307 end
1308 end
1309 end)
1310
1311 if not db.automatedMessages then
1312 db.automatedMessages = {}
1313 end
1314
1315 pChatData.automatedMessagesList = automatedMessagesList:New(pChatXMLAutoMsg)
1316 pChatData.automatedMessagesList:RefreshData()
1317 CleanAutomatedMessageListForDB()
1318
1319 pChatData.automatedMessagesList.keybindStripDescriptor = pChatData.autoMsgDescriptor
1320
1321end
1322
1323-- Called by XML
1324function pChat_HoverRowOfAutomatedMessages(control)
1325 pChatData.autoMessagesShowKeybind = true
1326 pChatData.automatedMessagesList:Row_OnMouseEnter(control)
1327end
1328
1329-- Called by XML
1330function pChat_ExitRowOfAutomatedMessages(control)
1331 pChatData.autoMessagesShowKeybind = false
1332 pChatData.automatedMessagesList:Row_OnMouseExit(control)
1333end
1334
1335-- Called by XML
1336function pChat_BuildAutomatedMessagesDialog(control)
1337
1338 local function AddDialogSetup(dialog, data)
1339
1340 local name = GetControl(dialog, "NameEdit")
1341 local message = GetControl(dialog, "MessageEdit")
1342
1343 name:SetText("")
1344 message:SetText("")
1345 name:SetEditEnabled(true)
1346
1347 end
1348
1349 ZO_Dialogs_RegisterCustomDialog("PCHAT_AUTOMSG_SAVE_MSG",
1350 {
1351 customControl = control,
1352 setup = AddDialogSetup,
1353 title =
1354 {
1355 text = PCHAT_AUTOMSG_ADD_TITLE_HEADER,
1356 },
1357 buttons =
1358 {
1359 [1] =
1360 {
1361 control = GetControl(control, "Request"),
1362 text = PCHAT_AUTOMSG_ADD_AUTO_MSG,
1363 callback = function(dialog)
1364 local name = GetControl(dialog, "NameEdit"):GetText()
1365 local message = GetControl(dialog, "MessageEdit"):GetText()
1366 if(name ~= "") and (message ~= "") then
1367 SaveAutomatedMessage(name, message, true)
1368 end
1369 end,
1370 },
1371 [2] =
1372 {
1373 control = GetControl(control, "Cancel"),
1374 text = SI_DIALOG_CANCEL,
1375 }
1376 }
1377 })
1378
1379 local function EditDialogSetup(dialog)
1380 local data = ZO_ScrollList_GetData(WINDOW_MANAGER:GetMouseOverControl())
1381 local name = GetControl(dialog, "NameEdit")
1382 local edit = GetControl(dialog, "MessageEdit")
1383
1384
1385 name:SetText(data.name)
1386 name:SetEditEnabled(false)
1387 edit:SetText(data.message)
1388 edit:TakeFocus()
1389
1390 end
1391
1392 ZO_Dialogs_RegisterCustomDialog("PCHAT_AUTOMSG_EDIT_MSG",
1393 {
1394 customControl = control,
1395 setup = EditDialogSetup,
1396 title =
1397 {
1398 text = PCHAT_AUTOMSG_EDIT_TITLE_HEADER,
1399 },
1400 buttons =
1401 {
1402 [1] =
1403 {
1404 control = GetControl(control, "Request"),
1405 text = PCHAT_AUTOMSG_EDIT_AUTO_MSG,
1406 callback = function(dialog)
1407 local name = GetControl(dialog, "NameEdit"):GetText()
1408 local message = GetControl(dialog, "MessageEdit"):GetText()
1409 if(name ~= "") and (message ~= "") then
1410 SaveAutomatedMessage(name, message, false)
1411 end
1412 end,
1413 },
1414 [2] =
1415 {
1416 control = GetControl(control, "Cancel"),
1417 text = SI_DIALOG_CANCEL,
1418 }
1419 }
1420 })
1421
1422end
1423-- **************************************************************************
1424-- Chat Tab Functions
1425-- **************************************************************************
1426local function getTabNames()
1427 local totalTabs = CHAT_SYSTEM.tabPool.m_Active
1428 if totalTabs ~= nil and #totalTabs >= 1 then
1429 tabNames = {}
1430 for idx, tmpTab in pairs(totalTabs) do
1431 local tabLabel = tmpTab:GetNamedChild("Text")
1432 local tmpTabName = tabLabel:GetText()
1433 if tmpTabName ~= nil and tmpTabName ~= "" then
1434 tabNames[idx] = tmpTabName
1435 end
1436 end
1437 end
1438end
1439
1440local function getTabIdx (tabName)
1441 local tabIdx = 0
1442 local totalTabs = CHAT_SYSTEM.tabPool.m_Active
1443 for i = 1, #totalTabs do
1444 if tabNames[i] == tabName then
1445 tabIdx = i
1446 end
1447 end
1448 return tabIdx
1449end
1450
1451-- Rewrite of a core function
1452function CHAT_SYSTEM.textEntry:AddCommandHistory(text)
1453
1454 local currentChannel = CHAT_SYSTEM.currentChannel
1455 local currentTarget = CHAT_SYSTEM.currentTarget
1456 local rewritedText = text
1457
1458 -- Don't add the switch when chat is restored
1459 if db.addChannelAndTargetToHistory and isAddonInitialized then
1460
1461 local switch = CHAT_SYSTEM.switchLookup[0]
1462
1463 -- It's a message
1464 switch = CHAT_SYSTEM.switchLookup[currentChannel]
1465 -- Below code suspected issue fix under comment - Bug ticket 2253 6/12/2018
1466 --[[
1467 rewritedText = string.format("%s ", switch)
1468 if currentTarget then
1469 rewritedText = string.format("%s%s ", rewritedText, currentTarget)
1470 end
1471 rewritedText = string.format("%s%s", rewritedText, text)
1472 ]]--
1473 -- New code for bug ticket 2253 6/12/2018
1474 if switch ~= nil then
1475 rewritedText = string.format("%s ", switch)
1476 if currentTarget then
1477 rewritedText = string.format("%s%s ", rewritedText, currentTarget)
1478 end
1479 rewritedText = string.format("%s%s", rewritedText, text)
1480 end
1481 end
1482
1483 CHAT_SYSTEM.textEntry.commandHistory:Add(rewritedText)
1484 CHAT_SYSTEM.textEntry.commandHistoryCursor = CHAT_SYSTEM.textEntry.commandHistory:Size() + 1
1485
1486end
1487
1488-- Rewrite of a core function
1489function CHAT_SYSTEM.textEntry:GetText()
1490 local text = self.editControl:GetText()
1491
1492 if text ~= "" then
1493 if string.sub(text,1,1) == "!" then
1494 if string.len(text) <= 12 then
1495
1496 local automatedMessage = true
1497 for k, v in ipairs(db.automatedMessages) do
1498 if v.name == text then
1499 text = db.automatedMessages[k].message
1500 automatedMessage = true
1501 end
1502 end
1503
1504 if automatedMessage then
1505
1506 if string.len(text) < 1 or string.len(text) > 351 then
1507 text = self.editControl:GetText()
1508 end
1509
1510 if self.ignoreTextEntryChangedEvent then return end
1511 self.ignoreTextEntryChangedEvent = true
1512
1513 local spaceStart, spaceEnd = zo_strfind(text, " ", 1, true)
1514
1515 if spaceStart and spaceStart > 1 then
1516 local potentialSwitch = zo_strsub(text, 1, spaceStart - 1)
1517 local switch = CHAT_SYSTEM.switchLookup[potentialSwitch:lower()]
1518
1519 local valid, switchArg, deferredError, spaceStartOverride = CHAT_SYSTEM:ValidateSwitch(switch, text, spaceStart)
1520
1521 if valid then
1522 if(deferredError) then
1523 self.requirementErrorMessage = switch.requirementErrorMessage
1524 if self.requirementErrorMessage then
1525 if type(self.requirementErrorMessage) == "string" then
1526 CHAT_SYSTEM:AddMessage(self.requirementErrorMessage)
1527 elseif type(self.requirementErrorMessage) == "function" then
1528 CHAT_SYSTEM:AddMessage(self.requirementErrorMessage())
1529 end
1530 end
1531 else
1532 self.requirementErrorMessage = nil
1533 end
1534
1535 CHAT_SYSTEM:SetChannel(switch.id, switchArg)
1536 local oldCursorPos = CHAT_SYSTEM.textEntry:GetCursorPosition()
1537
1538 spaceStart = spaceStartOverride or spaceStart
1539 CHAT_SYSTEM.textEntry:SetText(zo_strsub(text, spaceStart + 1))
1540 text = zo_strsub(text, spaceStart + 1)
1541 CHAT_SYSTEM.textEntry:SetCursorPosition(oldCursorPos - spaceStart)
1542 end
1543 end
1544
1545 self.ignoreTextEntryChangedEvent = false
1546
1547 end
1548 end
1549 end
1550 end
1551
1552 return text
1553
1554end
1555
1556-- Change ChatWindow Darkness by modifying its <Center> & <Edge>. Originally defined in virtual object ZO_ChatContainerTemplate in sharedchatsystem.xml
1557local function ChangeChatWindowDarkness(changeSetting)
1558
1559 if dbWindowDarkness == 0 then
1560 ZO_ChatWindowBg:SetCenterTexture("EsoUI/Art/ChatWindow/chat_BG_center.dds")
1561 ZO_ChatWindowBg:SetEdgeTexture("EsoUI/Art/ChatWindow/chat_BG_edge.dds", 256, 256, 32)
1562 else
1563 ZO_ChatWindowBg:SetCenterColor(0, 0, 0, 1)
1564 ZO_ChatWindowBg:SetEdgeColor(0, 0, 0, 1)
1565 if db.windowDarkness == 11 and changeSetting then
1566 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_100.dds")
1567 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_100.dds", 256, 256, 32)
1568 elseif db.windowDarkness == 10 then
1569 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_90.dds")
1570 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_90.dds", 256, 256, 32)
1571 elseif db.windowDarkness == 9 then
1572 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_80.dds")
1573 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_80.dds", 256, 256, 32)
1574 elseif db.windowDarkness == 8 then
1575 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_70.dds")
1576 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_70.dds", 256, 256, 32)
1577 elseif db.windowDarkness == 7 then
1578 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_60.dds")
1579 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_60.dds", 256, 256, 32)
1580 elseif db.windowDarkness == 6 then
1581 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_50.dds")
1582 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_50.dds", 256, 256, 32)
1583 elseif db.windowDarkness == 5 then
1584 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_40.dds")
1585 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_40.dds", 256, 256, 32)
1586 elseif db.windowDarkness == 4 then
1587 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_30.dds")
1588 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_30.dds", 256, 256, 32)
1589 elseif db.windowDarkness == 3 then
1590 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_20.dds")
1591 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_20.dds", 256, 256, 32)
1592 elseif db.windowDarkness == 2 then
1593 ZO_ChatWindowBg:SetCenterTexture("pChat/dds/chat_bg_center_10.dds")
1594 ZO_ChatWindowBg:SetEdgeTexture("pChat/dds/chat_bg_edge_10.dds", 256, 256, 32)
1595 elseif db.windowDarkness == 1 then
1596 ZO_ChatWindowBg:SetCenterColor(0, 0, 0, 0)
1597 ZO_ChatWindowBg:SetEdgeColor(0, 0, 0, 0)
1598 end
1599 end
1600end
1601
1602-- Add IM label on XML Initialization, set anchor and set it hidden
1603function pChat_AddIMLabel(control)
1604
1605 control:SetParent(CHAT_SYSTEM.control)
1606 control:ClearAnchors()
1607 control:SetAnchor(RIGHT, ZO_ChatWindowOptions, LEFT, -5, 32)
1608 CHAT_SYSTEM.IMLabel = control
1609
1610end
1611
1612-- Add IM label on XML Initialization, set anchor and set it hidden. Used for Chat Minibar
1613function pChat_AddIMLabelMin(control)
1614
1615 control:SetParent(CHAT_SYSTEM.control)
1616 control:ClearAnchors()
1617 control:SetAnchor(BOTTOM, CHAT_SYSTEM.minBar.maxButton, TOP, 2, 0)
1618 CHAT_SYSTEM.IMLabelMin = control
1619
1620end
1621
1622-- Add IM close button on XML Initialization, set anchor and set it hidden
1623function pChat_AddIMButton(control)
1624
1625 control:SetParent(CHAT_SYSTEM.control)
1626 control:ClearAnchors()
1627 control:SetAnchor(RIGHT, ZO_ChatWindowOptions, LEFT, 2, 35)
1628 CHAT_SYSTEM.IMbutton = control
1629
1630end
1631
1632-- Hide it
1633local function HideIMTooltip()
1634 ClearTooltip(InformationTooltip)
1635end
1636
1637-- Show IM notification tooltip
1638local function ShowIMTooltip(self, lineNumber)
1639
1640 if db.LineStrings[lineNumber] then
1641
1642 local sender = db.LineStrings[lineNumber].rawFrom
1643 local text = db.LineStrings[lineNumber].rawMessage
1644
1645 if (not IsDecoratedDisplayName(sender)) then
1646 sender = zo_strformat(SI_UNIT_NAME, sender)
1647 end
1648
1649 InitializeTooltip(InformationTooltip, self, BOTTOMLEFT, 0, 0, TOPRIGHT)
1650 InformationTooltip:AddLine(sender, "ZoFontGame", 1, 1, 1, TOPLEFT, MODIFY_TEXT_TYPE_NONE, TEXT_ALIGN_LEFT, true)
1651
1652 local r, g, b = ZO_NORMAL_TEXT:UnpackRGB()
1653 InformationTooltip:AddLine(text, "ZoFontGame", r, g, b, TOPLEFT, MODIFY_TEXT_TYPE_NONE, TEXT_ALIGN_LEFT, true)
1654
1655 end
1656
1657end
1658
1659-- When an incoming Whisper is received
1660local function OnIMReceived(from, lineNumber)
1661
1662 -- Display visual notification
1663 if db.notifyIM then
1664
1665 -- If chat minimized, show the minified button
1666 if (CHAT_SYSTEM:IsMinimized()) then
1667 CHAT_SYSTEM.IMLabelMin:SetHandler("OnMouseEnter", function(self) ShowIMTooltip(self, lineNumber) end)
1668 CHAT_SYSTEM.IMLabelMin:SetHandler("OnMouseExit", HideIMTooltip)
1669 CHAT_SYSTEM.IMLabelMin:SetHidden(false)
1670 else
1671 -- Chat maximized
1672 local _, scrollMax = CHAT_SYSTEM.primaryContainer.scrollbar:GetMinMax()
1673
1674 -- If whispers not show in the tab or we don't scroll at bottom
1675 if ((not IsChatContainerTabCategoryEnabled(1, pChatData.activeTab, CHAT_CATEGORY_WHISPER_INCOMING)) or (IsChatContainerTabCategoryEnabled(1, pChatData.activeTab, CHAT_CATEGORY_WHISPER_INCOMING) and CHAT_SYSTEM.primaryContainer.scrollbar:GetValue() < scrollMax)) then
1676
1677 -- Undecorate (^F / ^M)
1678 if (not IsDecoratedDisplayName(from)) then
1679 from = zo_strformat(SI_UNIT_NAME, from)
1680 end
1681
1682 -- Split if name too long
1683 local displayedFrom = from
1684 if string.len(displayedFrom) > 8 then
1685 displayedFrom = string.sub(from, 1, 7) .. ".."
1686 end
1687
1688 -- Show
1689 CHAT_SYSTEM.IMLabel:SetText(displayedFrom)
1690 CHAT_SYSTEM.IMLabel:SetHidden(false)
1691 CHAT_SYSTEM.IMbutton:SetHidden(false)
1692
1693 -- Add handler
1694 CHAT_SYSTEM.IMLabel:SetHandler("OnMouseEnter", function(self) ShowIMTooltip(self, lineNumber) end)
1695 CHAT_SYSTEM.IMLabel:SetHandler("OnMouseExit", function(self) HideIMTooltip() end)
1696 end
1697 end
1698
1699 end
1700
1701end
1702
1703-- Hide IM notification when click on it. Can be Called by XML
1704function pChat_RemoveIMNotification()
1705 CHAT_SYSTEM.IMLabel:SetHidden(true)
1706 CHAT_SYSTEM.IMLabelMin:SetHidden(true)
1707 CHAT_SYSTEM.IMbutton:SetHidden(true)
1708end
1709
1710-- Will try to display the notified IM. Called by XML
1711function pChat_TryToJumpToIm(isMinimized)
1712
1713 -- Show chat first
1714 if isMinimized then
1715 CHAT_SYSTEM:Maximize()
1716 CHAT_SYSTEM.IMLabelMin:SetHidden(true)
1717 end
1718
1719 -- Tab get IM, scroll
1720 if IsChatContainerTabCategoryEnabled(1, pChatData.activeTab, CHAT_CATEGORY_WHISPER_INCOMING) then
1721 ZO_ChatSystem_ScrollToBottom(CHAT_SYSTEM.control)
1722 pChat_RemoveIMNotification()
1723 else
1724
1725 -- Tab don't have IM's, switch to next
1726 local numTabs = #CHAT_SYSTEM.primaryContainer.windows
1727 local actualTab = pChatData.activeTab + 1
1728 local oldActiveTab = pChatData.activeTab
1729 local PRESSED = 1
1730 local UNPRESSED = 2
1731 local hasSwitched = false
1732 local maxt = 1
1733
1734 while actualTab <= numTabs and (not hasSwitched) do
1735 if IsChatContainerTabCategoryEnabled(1, actualTab, CHAT_CATEGORY_WHISPER_INCOMING) then
1736
1737 CHAT_SYSTEM.primaryContainer:HandleTabClick(CHAT_SYSTEM.primaryContainer.windows[actualTab].tab)
1738
1739 local tabText = GetControl("ZO_ChatWindowTabTemplate" .. actualTab .. "Text")
1740 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
1741 tabText:GetParent().state = PRESSED
1742 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. oldActiveTab .. "Text")
1743 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
1744 oldTabText:GetParent().state = UNPRESSED
1745 ZO_ChatSystem_ScrollToBottom(CHAT_SYSTEM.control)
1746
1747 hasSwitched = true
1748 else
1749 actualTab = actualTab + 1
1750 end
1751 end
1752
1753 actualTab = 1
1754
1755 -- If we were on tab #3 and IM are show on tab #2, need to restart from 1
1756 while actualTab < oldActiveTab and (not hasSwitched) do
1757 if IsChatContainerTabCategoryEnabled(1, actualTab, CHAT_CATEGORY_WHISPER_INCOMING) then
1758
1759 CHAT_SYSTEM.primaryContainer:HandleTabClick(CHAT_SYSTEM.primaryContainer.windows[actualTab].tab)
1760
1761 local tabText = GetControl("ZO_ChatWindowTabTemplate" .. actualTab .. "Text")
1762 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
1763 tabText:GetParent().state = PRESSED
1764 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. oldActiveTab .. "Text")
1765 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
1766 oldTabText:GetParent().state = UNPRESSED
1767 ZO_ChatSystem_ScrollToBottom(CHAT_SYSTEM.control)
1768
1769 hasSwitched = true
1770 else
1771 actualTab = actualTab + 1
1772 end
1773 end
1774
1775 end
1776
1777end
1778
1779-- Rewrite of a core function, if user click on the scroll to bottom button, Hide IM notification
1780-- Todo: Hide IM when user manually scroll to the bottom
1781function ZO_ChatSystem_ScrollToBottom(control)
1782
1783 CHAT_SYSTEM.IMbutton:SetHidden(true)
1784 CHAT_SYSTEM.IMLabel:SetHidden(true)
1785 control.container:ScrollToBottom()
1786
1787end
1788
1789-- Set copied text into text entry, if possible
1790local function CopyToTextEntry(message)
1791
1792 -- Max of inputbox is 351 chars
1793 if string.len(message) < 351 then
1794 if CHAT_SYSTEM.textEntry:GetText() == "" then
1795 CHAT_SYSTEM.textEntry:Open(message)
1796 ZO_ChatWindowTextEntryEditBox:SelectAll()
1797 end
1798 end
1799
1800end
1801
1802-- Copy message (only message)
1803local function CopyMessage(numLine)
1804 -- Args are passed as string trought LinkHandlerSystem
1805 CopyToTextEntry(db.LineStrings[numLine].rawMessage)
1806end
1807
1808--Copy line (including timestamp, from, channel, message, etc)
1809local function CopyLine(numLine)
1810 -- Args are passed as string trought LinkHandlerSystem
1811 CopyToTextEntry(db.LineStrings[numLine].rawLine)
1812end
1813
1814-- Popup a dialog message with text to copy
1815local function ShowCopyDialog(message)
1816
1817 -- Split text, courtesy of LibOrangUtils, modified to handle multibyte characters
1818 local function str_lensplit(text, maxChars)
1819
1820 local ret = {}
1821 local text_len = string.len(text)
1822 local UTFAditionalBytes = 0
1823 local fromWithUTFShift = 0
1824 local doCut = true
1825
1826 if(text_len <= maxChars) then
1827 ret[#ret+1] = text
1828 else
1829
1830 local splittedStart = 0
1831 local splittedEnd = splittedStart + maxChars - 1
1832
1833 while doCut do
1834
1835 if UTFAditionalBytes > 0 then
1836 fromWithUTFShift = UTFAditionalBytes
1837 else
1838 fromWithUTFShift = 0
1839 end
1840
1841 local UTFAditionalBytes = 0
1842
1843 splittedEnd = splittedStart + maxChars - 1
1844
1845 if(splittedEnd >= text_len) then
1846 splittedEnd = text_len
1847 doCut = false
1848 elseif (string.byte(text, splittedEnd, splittedEnd)) > 128 then
1849 UTFAditionalBytes = 1
1850
1851 local lastByte = string.byte(splittedString, -1)
1852 local beforeLastByte = string.byte(splittedString, -2, -2)
1853
1854 if (lastByte < 128) then
1855 --
1856 elseif lastByte >= 128 and lastByte < 192 then
1857
1858 if beforeLastByte >= 192 and beforeLastByte < 224 then
1859 --
1860 elseif beforeLastByte >= 128 and beforeLastByte < 192 then
1861 --
1862 elseif beforeLastByte >= 224 and beforeLastByte < 240 then
1863 UTFAditionalBytes = 1
1864 end
1865
1866 splittedEnd = splittedEnd + UTFAditionalBytes
1867 splittedString = text:sub(splittedStart, splittedEnd)
1868
1869 elseif lastByte >= 192 and lastByte < 224 then
1870 UTFAditionalBytes = 1
1871 splittedEnd = splittedEnd + UTFAditionalBytes
1872 elseif lastByte >= 224 and lastByte < 240 then
1873 UTFAditionalBytes = 2
1874 splittedEnd = splittedEnd + UTFAditionalBytes
1875 end
1876
1877 end
1878
1879 --ret = ret+1
1880 ret[#ret+1] = string.sub(text, splittedStart, splittedEnd)
1881
1882 splittedStart = splittedEnd + 1
1883
1884 end
1885 end
1886
1887 return ret
1888
1889 end
1890
1891 local maxChars = 20000
1892
1893 -- editbox is 20000 chars max
1894 if string.len(message) < maxChars then
1895 pChatCopyDialogTLCTitle:SetText(GetString(PCHAT_COPYXMLTITLE))
1896 pChatCopyDialogTLCLabel:SetText(GetString(PCHAT_COPYXMLLABEL))
1897 pChatCopyDialogTLCNoteEdit:SetText(message)
1898 pChatCopyDialogTLCNoteNext:SetHidden(true)
1899 pChatCopyDialogTLC:SetHidden(false)
1900 pChatCopyDialogTLCNoteEdit:SetEditEnabled(false)
1901 pChatCopyDialogTLCNoteEdit:SelectAll()
1902 else
1903
1904 pChatCopyDialogTLCTitle:SetText(GetString(PCHAT_COPYXMLTITLE))
1905 pChatCopyDialogTLCLabel:SetText(GetString(PCHAT_COPYXMLTOOLONG))
1906
1907 pChatData.messageTableId = 1
1908 pChatData.messageTable = str_lensplit(message, maxChars)
1909 pChatCopyDialogTLCNoteNext:SetText(GetString(PCHAT_COPYXMLNEXT) .. " ( " .. pChatData.messageTableId .. " / " .. #pChatData.messageTable .. " )")
1910 pChatCopyDialogTLCNoteEdit:SetText(pChatData.messageTable[pChatData.messageTableId])
1911 pChatCopyDialogTLCNoteEdit:SetEditEnabled(false)
1912 pChatCopyDialogTLCNoteEdit:SelectAll()
1913
1914 pChatCopyDialogTLC:SetHidden(false)
1915 pChatCopyDialogTLCNoteNext:SetHidden(false)
1916
1917 pChatCopyDialogTLCNoteEdit:TakeFocus()
1918
1919 end
1920
1921end
1922
1923-- Copy discussion
1924-- It will copy all text mark with the same chanCode
1925-- Todo : Whisps by person
1926local function CopyDiscussion(chanNumber, numLine)
1927
1928 -- Args are passed as string trought LinkHandlerSystem
1929 local numChanCode = tonumber(chanNumber)
1930 -- Whispers sent and received together
1931 if numChanCode == CHAT_CHANNEL_WHISPER_SENT then
1932 numChanCode = CHAT_CHANNEL_WHISPER
1933 elseif numChanCode == PCHAT_URL_CHAN then
1934 numChanCode = db.LineStrings[numLine].channel
1935 end
1936
1937 local stringToCopy = ""
1938 for k, data in ipairs(db.LineStrings) do
1939 if numChanCode == CHAT_CHANNEL_WHISPER or numChanCode == CHAT_CHANNEL_WHISPER_SENT then
1940 if data.channel == CHAT_CHANNEL_WHISPER or data.channel == CHAT_CHANNEL_WHISPER_SENT then
1941 if stringToCopy == "" then
1942 stringToCopy = db.LineStrings[k].rawLine
1943 else
1944 stringToCopy = stringToCopy .. "\r\n" .. db.LineStrings[k].rawLine
1945 end
1946 end
1947 elseif data.channel == numChanCode then
1948 if stringToCopy == "" then
1949 stringToCopy = db.LineStrings[k].rawLine
1950 else
1951 stringToCopy = stringToCopy .. "\r\n" .. db.LineStrings[k].rawLine
1952 end
1953 end
1954 end
1955
1956 ShowCopyDialog(stringToCopy)
1957
1958end
1959
1960-- Copy Whole chat (not tab)
1961local function CopyWholeChat()
1962
1963 local stringToCopy = ""
1964 for k, data in ipairs(db.LineStrings) do
1965 if stringToCopy == "" then
1966 stringToCopy = db.LineStrings[k].rawLine
1967 else
1968 stringToCopy = stringToCopy .. "\r\n" .. db.LineStrings[k].rawLine
1969 end
1970 end
1971
1972 ShowCopyDialog(stringToCopy)
1973
1974end
1975
1976-- Show contextualMenu when clicking on a pChatLink
1977local function ShowContextMenuOnHandlers(numLine, chanNumber)
1978
1979 ClearMenu()
1980
1981 if not ZO_Dialogs_IsShowingDialog() then
1982 AddMenuItem(GetString(PCHAT_COPYMESSAGECT), function() CopyMessage(numLine) end)
1983 AddMenuItem(GetString(PCHAT_COPYLINECT), function() CopyLine(numLine) end)
1984 AddMenuItem(GetString(PCHAT_COPYDISCUSSIONCT), function() CopyDiscussion(chanNumber, numLine) end)
1985 AddMenuItem(GetString(PCHAT_ALLCT), CopyWholeChat)
1986 end
1987
1988 ShowMenu()
1989
1990end
1991
1992-- Triggers when right clicking on a LinkHandler
1993local function OnLinkClicked(rawLink, mouseButton, linkText, color, linkType, lineNumber, chanCode)
1994
1995 -- Only executed on LinkType = PCHAT_LINK
1996 if linkType == PCHAT_LINK then
1997
1998 local chanNumber = tonumber(chanCode)
1999 local numLine = tonumber(lineNumber)
2000 -- PCHAT_LINK also handle a linkable channel feature for linkable channels
2001
2002 -- Context Menu
2003 if chanCode and mouseButton == MOUSE_BUTTON_INDEX_LEFT then
2004
2005 -- Only Linkable channel - TODO use .channelLinkable
2006 if chanNumber == CHAT_CHANNEL_SAY
2007 or chanNumber == CHAT_CHANNEL_YELL
2008 or chanNumber == CHAT_CHANNEL_PARTY
2009 or chanNumber == CHAT_CHANNEL_ZONE
2010 or chanNumber == CHAT_CHANNEL_ZONE_LANGUAGE_1
2011 or chanNumber == CHAT_CHANNEL_ZONE_LANGUAGE_2
2012 or chanNumber == CHAT_CHANNEL_ZONE_LANGUAGE_3
2013 or chanNumber == CHAT_CHANNEL_ZONE_LANGUAGE_4
2014 or (chanNumber >= CHAT_CHANNEL_GUILD_1 and chanNumber <= CHAT_CHANNEL_GUILD_5)
2015 or (chanNumber >= CHAT_CHANNEL_OFFICER_1 and chanNumber <= CHAT_CHANNEL_OFFICER_5) then
2016 IgnoreMouseDownEditFocusLoss()
2017 CHAT_SYSTEM:StartTextEntry(nil, chanNumber)
2018 elseif chanNumber == CHAT_CHANNEL_WHISPER then
2019 local target = zo_strformat(SI_UNIT_NAME, db.LineStrings[numLine].rawFrom)
2020 IgnoreMouseDownEditFocusLoss()
2021 CHAT_SYSTEM:StartTextEntry(nil, chanNumber, target)
2022 elseif chanNumber == PCHAT_URL_CHAN then
2023 RequestOpenUnsafeURL(linkText)
2024 end
2025
2026 elseif mouseButton == MOUSE_BUTTON_INDEX_RIGHT then
2027 -- Right clic, copy System
2028 ShowContextMenuOnHandlers(numLine, chanNumber)
2029 end
2030
2031 -- Don't execute LinkHandler code
2032 return true
2033
2034 end
2035
2036end
2037
2038local function CopyToTextEntryText()
2039 if db.enablecopy then
2040 LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_CLICKED_EVENT, OnLinkClicked)
2041 LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_MOUSE_UP_EVENT, OnLinkClicked)
2042 end
2043end
2044
2045-- Called by XML
2046function pChat_ShowCopyDialogNext()
2047
2048 pChatData.messageTableId = pChatData.messageTableId + 1
2049
2050 -- Security
2051 if pChatData.messageTable[pChatData.messageTableId] then
2052
2053 -- Build button
2054 pChatCopyDialogTLCNoteNext:SetText(GetString(PCHAT_COPYXMLNEXT) .. " ( " .. pChatData.messageTableId .. " / " .. #pChatData.messageTable .. " )")
2055 pChatCopyDialogTLCNoteEdit:SetText(pChatData.messageTable[pChatData.messageTableId])
2056 pChatCopyDialogTLCNoteEdit:SetEditEnabled(false)
2057 pChatCopyDialogTLCNoteEdit:SelectAll()
2058
2059 -- Don't show next button if its the last
2060 if not pChatData.messageTable[pChatData.messageTableId + 1] then
2061 pChatCopyDialogTLCNoteNext:SetHidden(true)
2062 end
2063
2064 pChatCopyDialogTLCNoteEdit:TakeFocus()
2065
2066 end
2067
2068end
2069
2070-- Needed to bind Shift+Tab in SetSwitchToNextBinding
2071function KEYBINDING_MANAGER:IsChordingAlwaysEnabled()
2072 return true
2073end
2074
2075local function SetSwitchToNextBinding()
2076
2077 ZO_CreateStringId("SI_BINDING_NAME_PCHAT_SWITCH_TAB", GetString(PCHAT_SWITCHTONEXTTABBINDING))
2078
2079 -- get SwitchTab Keybind params
2080 local layerIndex, categoryIndex, actionIndex = GetActionIndicesFromName("PCHAT_SWITCH_TAB")
2081
2082 --If exists
2083 if layerIndex and categoryIndex and actionIndex then
2084
2085 local key = GetActionBindingInfo(layerIndex, categoryIndex, actionIndex, 1)
2086
2087 if key == KEY_INVALID then
2088 -- Unbind it
2089 if IsProtectedFunction("UnbindAllKeysFromAction") then
2090 CallSecureProtected("UnbindAllKeysFromAction", layerIndex, categoryIndex, actionIndex)
2091 else
2092 UnbindAllKeysFromAction(layerIndex, categoryIndex, actionIndex)
2093 end
2094
2095 -- Set it to its default value
2096 if IsProtectedFunction("BindKeyToAction") then
2097 CallSecureProtected("BindKeyToAction", layerIndex, categoryIndex, actionIndex, 1, KEY_TAB, 0, 0, KEY_SHIFT, 0)
2098 else
2099 BindKeyToAction(layerIndex, categoryIndex, actionIndex, 1, KEY_TAB , 0, 0, KEY_SHIFT, 0)
2100 end
2101 end
2102
2103 end
2104
2105end
2106
2107-- Can be called by Bindings
2108function pChat_SwitchToNextTab()
2109
2110 local hasSwitched
2111
2112 local PRESSED = 1
2113 local UNPRESSED = 2
2114 local numTabs = #CHAT_SYSTEM.primaryContainer.windows
2115
2116 if numTabs > 1 then
2117 for numTab, container in ipairs (CHAT_SYSTEM.primaryContainer.windows) do
2118
2119 if (not hasSwitched) then
2120 if pChatData.activeTab + 1 == numTab then
2121 CHAT_SYSTEM.primaryContainer:HandleTabClick(container.tab)
2122
2123 local tabText = GetControl("ZO_ChatWindowTabTemplate" .. numTab .. "Text")
2124 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
2125 tabText:GetParent().state = PRESSED
2126 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. numTab - 1 .. "Text")
2127 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
2128 oldTabText:GetParent().state = UNPRESSED
2129
2130 hasSwitched = true
2131 end
2132 end
2133
2134 end
2135
2136 if (not hasSwitched) then
2137 CHAT_SYSTEM.primaryContainer:HandleTabClick(CHAT_SYSTEM.primaryContainer.windows[1].tab)
2138 local tabText = GetControl("ZO_ChatWindowTabTemplate1Text")
2139 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
2140 tabText:GetParent().state = PRESSED
2141 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. #CHAT_SYSTEM.primaryContainer.windows .. "Text")
2142 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
2143 oldTabText:GetParent().state = UNPRESSED
2144 end
2145 end
2146
2147end
2148--**** Issue
2149local function SetDefaultTab(tabToSet)
2150
2151 -- Search in all tabs the good name
2152 for numTab in ipairs(CHAT_SYSTEM.primaryContainer.windows) do
2153 -- Not this one, try the next one, if tab is not found (newly added, removed), pChat_SwitchToNextTab() will go back to tab 1
2154 if tonumber(tabToSet) ~= numTab then
2155 pChat_SwitchToNextTab()
2156 else
2157 -- Found it, stop
2158 return
2159 end
2160 end
2161end
2162
2163function pChat_ChangeTab(tabToSet)
2164 if type(tabToSet)~="number" then return end
2165 local container=CHAT_SYSTEM.primaryContainer if not container then return end
2166 if tabToSet<1 or tabToSet>#container.windows then return end
2167 if container.windows[tabToSet].tab==nil then return end
2168 container.tabGroup:SetClickedButton(container.windows[tabToSet].tab)
2169 if CHAT_SYSTEM:IsMinimized() then CHAT_SYSTEM:Maximize() end
2170 local container=CHAT_SYSTEM.primaryContainer
2171 if not container then return end
2172 local tabToSet=container.currentBuffer:GetParent().tab.tabToSet
2173
2174end
2175
2176local function StripLinesFromLineStrings(typeOfExit)
2177
2178 local k = 1
2179 -- First loop is time based. If message is older than our limit, it will be stripped.
2180 while k <= #db.LineStrings do
2181
2182 if db.LineStrings[k] then
2183 local channel = db.LineStrings[k].channel
2184 if channel == CHAT_CHANNEL_SYSTEM and (not db.restoreSystem) then
2185 table.remove(db.LineStrings, k)
2186 db.lineNumber = db.lineNumber - 1
2187 k = k-1
2188 elseif channel ~= CHAT_CHANNEL_SYSTEM and db.restoreSystemOnly then
2189 table.remove(db.LineStrings, k)
2190 db.lineNumber = db.lineNumber - 1
2191 k = k-1
2192 elseif (channel == CHAT_CHANNEL_WHISPER or channel == CHAT_CHANNEL_WHISPER_SENT) and (not db.restoreWhisps) then
2193 table.remove(db.LineStrings, k)
2194 db.lineNumber = db.lineNumber - 1
2195 k = k-1
2196 elseif typeOfExit ~= 1 then
2197 if db.LineStrings[k].rawTimestamp then
2198 if (GetTimeStamp() - db.LineStrings[k].rawTimestamp) > (db.timeBeforeRestore * 60 * 60) then
2199 table.remove(db.LineStrings, k)
2200 db.lineNumber = db.lineNumber - 1
2201 k = k-1
2202 elseif db.LineStrings[k].rawTimestamp > GetTimeStamp() then -- System clock of users computer badly set and msg received meanwhile.
2203 table.remove(db.LineStrings, k)
2204 db.lineNumber = db.lineNumber - 1
2205 k = k-1
2206 end
2207 end
2208 end
2209 end
2210
2211 k = k + 1
2212
2213 end
2214
2215 -- 2nd loop is size based. If dump is too big, just delete old ones
2216 if k > 5000 then
2217 local linesToDelete = k - 5000
2218 for l=1, linesToDelete do
2219
2220 if db.LineStrings[l] then
2221 table.remove(db.LineStrings, l)
2222 db.lineNumber = db.lineNumber - 1
2223 end
2224
2225 end
2226 end
2227
2228end
2229
2230local function SaveChatHistory(typeOf)
2231
2232 db.history = {}
2233
2234 if (db.restoreOnReloadUI == true and typeOf == 1) or (db.restoreOnLogOut == true and typeOf == 2) or (db.restoreOnAFK == true) or (db.restoreOnQuit == true and typeOf == 3) then
2235
2236 if typeOf == 1 then
2237
2238 db.lastWasReloadUI = true
2239 db.lastWasLogOut = false
2240 db.lastWasQuit = false
2241 db.lastWasAFK = false
2242
2243 --Save actual channel
2244 db.history.currentChannel = CHAT_SYSTEM.currentChannel
2245 db.history.currentTarget = CHAT_SYSTEM.currentTarget
2246
2247 elseif typeOf == 2 then
2248 db.lastWasReloadUI = false
2249 db.lastWasLogOut = true
2250 db.lastWasQuit = false
2251 db.lastWasAFK = false
2252 elseif typeOf == 3 then
2253 db.lastWasReloadUI = false
2254 db.lastWasLogOut = false
2255 db.lastWasQuit = true
2256 db.lastWasAFK = false
2257 end
2258
2259 db.history.currentTab = pChatData.activeTab
2260
2261 -- Save Chat History isn't needed, because it's saved in realtime, but we can strip some lines from the array to avoid big dumps
2262 StripLinesFromLineStrings(typeOf)
2263
2264 --Save TextEntry history
2265 db.history.textEntry = {}
2266 if CHAT_SYSTEM.textEntry.commandHistory.entries then
2267 db.history.textEntry.entries = CHAT_SYSTEM.textEntry.commandHistory.entries
2268 db.history.textEntry.numEntries = CHAT_SYSTEM.textEntry.commandHistory.index
2269 else
2270 db.history.textEntry.entries = {}
2271 db.history.textEntry.numEntries = 0
2272 end
2273 else
2274 db.LineStrings = {}
2275 db.lineNumber = 1
2276 end
2277
2278end
2279
2280local function CreateNewChatTabPostHook()
2281
2282 for tabIndex, tabObject in ipairs(CHAT_SYSTEM.primaryContainer.windows) do
2283 if db.augmentHistoryBuffer then
2284 tabObject.buffer:SetMaxHistoryLines(1000) -- 1000 = max of control
2285 end
2286 if db.alwaysShowChat then
2287 tabObject.buffer:SetLineFade(3600, 2)
2288 end
2289 end
2290
2291end
2292
2293local function ShowFadedLines()
2294
2295 local origChatSystemCreateNewChatTab = CHAT_SYSTEM.CreateNewChatTab
2296 CHAT_SYSTEM.CreateNewChatTab = function(self, ...)
2297 origChatSystemCreateNewChatTab(self, ...)
2298 CreateNewChatTabPostHook()
2299 end
2300
2301end
2302
2303local function OnReticleTargetChanged()
2304 if IsUnitPlayer("reticleover") then
2305 targetToWhisp = GetUnitName("reticleover")
2306 end
2307end
2308
2309local function BuildNicknames(lamCall)
2310
2311 local function Explode(div, str)
2312 if (div=='') then return false end
2313 local pos,arr = 0,{}
2314 for st,sp in function() return string.find(str,div,pos,true) end do
2315 table.insert(arr,string.sub(str,pos,st-1))
2316 pos = sp + 1
2317 end
2318 table.insert(arr,string.sub(str,pos))
2319 return arr
2320 end
2321
2322 pChatData.nicknames = {}
2323
2324 if db.nicknames ~= "" then
2325 local lines = Explode("\n", db.nicknames)
2326
2327 for lineIndex=#lines, 1, -1 do
2328 local oldName, newName = string.match(lines[lineIndex], "(@?[%w_-]+) ?= ?([%w- ]+)")
2329 if not (oldName and newName) then
2330 table.remove(lines, lineIndex)
2331 else
2332 pChatData.nicknames[oldName] = newName
2333 end
2334 end
2335
2336 db.nicknames = table.concat(lines, "\n")
2337
2338 if lamCall then
2339 CALLBACK_MANAGER:FireCallbacks("LAM-RefreshPanel", pChat.LAMPanel)
2340 end
2341
2342 end
2343
2344end
2345
2346-- Change font of chat
2347local function ChangeChatFont(change)
2348
2349 local fontSize = GetChatFontSize()
2350
2351 if db.fonts == "ESO Standard Font" or db.fonts == "Univers 57" then
2352 return
2353 else
2354
2355 local fontPath = LMP:Fetch("font", db.fonts)
2356
2357 -- Entry Box
2358 ZoFontEditChat:SetFont(fontPath .. "|".. fontSize .. "|shadow")
2359
2360 -- Chat window
2361 ZoFontChat:SetFont(fontPath .. "|" .. fontSize .. "|soft-shadow-thin")
2362
2363 end
2364
2365end
2366
2367-- Rewrite of a core function
2368function CHAT_SYSTEM:UpdateTextEntryChannel()
2369
2370 local channelData = self.channelData[self.currentChannel]
2371
2372 if channelData then
2373 self.textEntry:SetChannel(channelData, self.currentTarget)
2374
2375 if isAddonLoaded then
2376 if not db.useESOcolors then
2377
2378 local pChatcolor
2379 if db.allGuildsSameColour and (self.currentChannel >= CHAT_CHANNEL_GUILD_1 and self.currentChannel <= CHAT_CHANNEL_GUILD_5) then
2380 pChatcolor = db.colours[2*CHAT_CHANNEL_GUILD_1]
2381 elseif db.allGuildsSameColour and (self.currentChannel >= CHAT_CHANNEL_OFFICER_1 and self.currentChannel <= CHAT_CHANNEL_OFFICER_5) then
2382 pChatcolor = db.colours[2*CHAT_CHANNEL_OFFICER_1]
2383 elseif db.allZonesSameColour and (self.currentChannel >= CHAT_CHANNEL_ZONE_LANGUAGE_1 and self.currentChannel <= CHAT_CHANNEL_ZONE_LANGUAGE_4) then
2384 pChatcolor = db.colours[2*CHAT_CHANNEL_ZONE]
2385 else
2386 pChatcolor = db.colours[2*self.currentChannel]
2387 end
2388
2389 if not pChatcolor then
2390 self.textEntry:SetColor(1, 1, 1, 1)
2391 else
2392 local r, g, b, a = ConvertHexToRGBA(pChatcolor)
2393 self.textEntry:SetColor(r, g, b, a)
2394 end
2395
2396 else
2397 self.textEntry:SetColor(self:GetCategoryColorFromChannel(self.currentChannel))
2398 end
2399 else
2400 self.textEntry:SetColor(self:GetCategoryColorFromChannel(self.currentChannel))
2401 end
2402
2403 end
2404
2405end
2406
2407-- Change guild channel names in entry box
2408local function UpdateCharCorrespondanceTableChannelNames()
2409
2410 -- Each guild
2411 for i = 1, GetNumGuilds() do
2412 if db.showTagInEntry then
2413
2414 -- Get saved string
2415 local tag = db.guildTags[GetGuildName(GetGuildId(i))]
2416
2417 -- No SavedVar
2418 if not tag then
2419 tag = GetGuildName(GetGuildId(i))
2420 -- SavedVar, but no tag
2421 elseif tag == "" then
2422 tag = GetGuildName(GetGuildId(i))
2423 end
2424
2425 -- Get saved string
2426 local officertag = db.officertag[GetGuildName(GetGuildId(i))]
2427
2428 -- No SavedVar
2429 if not officertag then
2430 officertag = tag
2431 -- SavedVar, but no tag
2432 elseif officertag == "" then
2433 officertag = tag
2434 end
2435
2436 -- /g1 is 12 /g5 is 16, /o1=17, etc
2437 ChanInfoArray[CHAT_CHANNEL_GUILD_1 - 1 + i].name = tag
2438 ChanInfoArray[CHAT_CHANNEL_OFFICER_1 - 1 + i].name = officertag
2439 --Activating
2440 ChanInfoArray[CHAT_CHANNEL_GUILD_1 - 1 + i].dynamicName = false
2441 ChanInfoArray[CHAT_CHANNEL_OFFICER_1 - 1 + i].dynamicName = false
2442
2443 else
2444 -- /g1 is 12 /g5 is 16, /o1=17, etc
2445 ChanInfoArray[CHAT_CHANNEL_GUILD_1 - 1 + i].name = GetGuildName(GetGuildId(i))
2446 ChanInfoArray[CHAT_CHANNEL_OFFICER_1 - 1 + i].name = GetGuildName(GetGuildId(i))
2447 --Deactivating
2448 ChanInfoArray[CHAT_CHANNEL_GUILD_1 - 1 + i].dynamicName = true
2449 ChanInfoArray[CHAT_CHANNEL_OFFICER_1 - 1 + i].dynamicName = true
2450 end
2451 end
2452
2453 return
2454
2455end
2456
2457-- Split text with blocs of 100 chars (106 is max for LinkHandle) and add LinkHandle to them
2458-- WARNING : See FormatSysMessage()
2459local function SplitTextForLinkHandler(text, numLine, chanCode)
2460
2461 local newText = ""
2462 local textLen = string.len(text)
2463 local MAX_LEN = 100
2464
2465 -- LinkHandle does not handle text > 106 chars, so we need to split
2466 if textLen > MAX_LEN then
2467
2468 local splittedStart = 1
2469 local splits = 1
2470 local needToSplit = true
2471
2472 while needToSplit do
2473
2474 local splittedString = ""
2475 local UTFAditionalBytes = 0
2476
2477 if textLen > (splits * MAX_LEN) then
2478
2479 local splittedEnd = splittedStart + MAX_LEN
2480 splittedString = text:sub(splittedStart, splittedEnd) -- We can "cut" characters by doing this
2481
2482 local lastByte = string.byte(splittedString, -1)
2483 local beforeLastByte = string.byte(splittedString, -2, -2)
2484
2485 -- Characters can be into 1, 2 or 3 bytes. Lua don't support UTF natively. We only handle 3 bytes chars.
2486 -- http://www.utf8-chartable.de/unicode-utf8-table.pl
2487
2488 if (lastByte < 128) then -- any ansi character (ex : a 97 LATIN SMALL LETTER A) (cut was well made)
2489 --
2490 elseif lastByte >= 128 and lastByte < 192 then -- any non ansi character ends with last byte = 128-191 (cut was well made) or 2nd byte of a 3 Byte character. We take 1 byte more. (cut was incorrect)
2491
2492 if beforeLastByte >= 192 and beforeLastByte < 224 then -- "2 latin characters" ex: 195 169 LATIN SMALL LETTER E WITH ACUTE ; е 208 181 CYRILLIC SMALL LETTER IE
2493 --
2494 elseif beforeLastByte >= 128 and beforeLastByte < 192 then -- "3 Bytes Cyrillic & Japaneese" ex U+3057 し 227 129 151 HIRAGANA LETTER SI
2495 --
2496 elseif beforeLastByte >= 224 and beforeLastByte < 240 then -- 2nd byte of a 3 Byte character. We take 1 byte more. (cut was incorrect)
2497 UTFAditionalBytes = 1
2498 end
2499
2500 splittedEnd = splittedEnd + UTFAditionalBytes
2501 splittedString = text:sub(splittedStart, splittedEnd)
2502
2503 elseif lastByte >= 192 and lastByte < 224 then -- last byte = 1st byte of a 2 Byte character. We take 1 byte more. (cut was incorrect)
2504 UTFAditionalBytes = 1
2505 splittedEnd = splittedEnd + UTFAditionalBytes
2506 splittedString = text:sub(splittedStart, splittedEnd)
2507 elseif lastByte >= 224 and lastByte < 240 then -- last byte = 1st byte of a 3 Byte character. We take 2 byte more. (cut was incorrect)
2508 UTFAditionalBytes = 2
2509 splittedEnd = splittedEnd + UTFAditionalBytes
2510 splittedString = text:sub(splittedStart, splittedEnd)
2511 end
2512
2513 splittedStart = splittedEnd + 1
2514 newText = newText .. string.format("|H1:%s:%s:%s|h%s|h", PCHAT_LINK, numLine, chanCode, splittedString)
2515 splits = splits + 1
2516
2517 else
2518 splittedString = text:sub(splittedStart)
2519 local textSplittedlen = splittedString:len()
2520 if textSplittedlen > 0 then
2521 newText = newText .. string.format("|H1:%s:%s:%s|h%s|h", PCHAT_LINK, numLine, chanCode, splittedString)
2522 end
2523 needToSplit = false
2524 end
2525
2526 end
2527 else
2528 -- When dumping back, the "from" section is sent here. It will add handler to spaces. prevent it to avoid an uneeded increase of the message.
2529 if not (text == " " or text == ": ") then
2530 newText = string.format("|H1:%s:%s:%s|h%s|h", PCHAT_LINK, numLine, chanCode, text)
2531 else
2532 newText = text
2533 end
2534 end
2535
2536 return newText
2537
2538end
2539
2540-- Sub function of addLinkHandlerToString
2541-- WARNING : See FormatSysMessage()
2542-- Get a string without |cXXXXXX and without |t as parameter
2543local function AddLinkHandlerToStringWithoutDDS(textToCheck, numLine, chanCode)
2544
2545 local stillToParse = true
2546 local noColorlen = textToCheck:len()
2547
2548 -- this var seems to get some rework
2549 local startNoColor = 1
2550 local textLinked = ""
2551 local preventLoopsCol = 0
2552 local handledText = ""
2553
2554 while stillToParse do
2555
2556 -- Prevent infinit loops while its still in beta
2557 if preventLoopsCol > 10 then
2558 stillToParse = false
2559 CHAT_SYSTEM:Zo_AddMessage("pChat triggered an infinite LinkHandling loop in its copy system with last message : " .. textToCheck .. " -- pChat")
2560 else
2561 preventLoopsCol = preventLoopsCol + 1
2562 end
2563
2564 noColorlen = textToCheck:len()
2565
2566 local startpos, endpos = string.find(textToCheck, "|H(.-):(.-)|h(.-)|h", 1)
2567 -- LinkHandler not found
2568 if not startpos then
2569 -- If nil, then we won't have new link after startposition = startNoColor , so add ours util the end
2570
2571 -- Some addons use table.insert() and chat convert to a CRLF
2572 -- First, drop the final CRLF if we are at the end of the text
2573 if string.sub(textToCheck, -2) == "\r\n" then
2574 textToCheck = string.sub(textToCheck, 1, -2)
2575 end
2576 -- MultiCRLF is handled in .addLinkHandler()
2577
2578 textLinked = SplitTextForLinkHandler(textToCheck, numLine, chanCode)
2579 handledText = handledText .. textLinked
2580
2581 -- No need to parse after
2582 stillToParse = false
2583
2584 else
2585
2586 -- Link is at the begginning of the string
2587 if startpos == 1 then
2588 -- New text is (only handler because its at the pos 1)
2589 handledText = handledText .. textToCheck:sub(startpos, endpos)
2590
2591 -- Do we need to continue ?
2592 if endpos == noColorlen then
2593 -- We're at the end
2594 stillToParse = false
2595 else
2596 -- Still to parse
2597 startNoColor = endpos
2598 -- textToCheck is next to our string
2599 textToCheck = textToCheck:sub(startNoColor + 1)
2600 end
2601
2602 else
2603
2604 -- We Handle string from startNoColor of the message up to the Handle link
2605 local textToHandle = textToCheck:sub(1, startpos - 1)
2606
2607 -- Add ours
2608 -- Maybe we need a split due to 106 chars restriction
2609 textLinked = SplitTextForLinkHandler(textToHandle, numLine, chanCode)
2610
2611 -- New text is handledText + (textLinked .. LinkHandler)
2612 handledText = handledText .. textLinked
2613 handledText = handledText .. textToCheck:sub(startpos, endpos)
2614
2615 -- Do we need to continue ?
2616 if endpos == noColorlen then
2617 -- We're at the end
2618 stillToParse = false
2619 else
2620 -- Still to parse
2621 startNoColor = endpos
2622 -- textToCheck is next to our string
2623 textToCheck = textToCheck:sub(startNoColor + 1)
2624 end
2625
2626 end
2627 end
2628 end
2629
2630 return handledText
2631
2632end
2633
2634-- Sub function of addLinkHandlerToLine, Handling DDS textures in chat
2635-- WARNING : See FormatSysMessage()
2636-- Get a string without |cXXXXXX as parameter
2637local function AddLinkHandlerToString(textToCheck, numLine, chanCode)
2638
2639 local stillToParseDDS = true
2640 local noDDSlen = textToCheck:len()
2641
2642 -- this var seems to get some rework
2643 local startNoDDS = 1
2644 local textLinked = ""
2645 local preventLoopsDDS = 0
2646 local textTReformated = ""
2647
2648 -- Seems the "|" are truncated from the link when send to chatsystem (they're needed for build link, but the output does not include them)
2649
2650 while stillToParseDDS do
2651
2652 -- Prevent infinit loops while its still in beta
2653 if preventLoopsDDS > 20 then
2654 stillToParseDDS = false
2655 CHAT_SYSTEM:Zo_AddMessage("pChat triggered an infinite DDS loop in its copy system with last message : " .. textToCheck .. " -- pChat")
2656 else
2657 preventLoopsDDS = preventLoopsDDS + 1
2658 end
2659
2660 noDDSlen = textToCheck:len()
2661
2662 local startpos, endpos = string.find(textToCheck, "|t%-?%d+%%?:%-?%d+%%?:.-|t", 1)
2663 -- DDS not found
2664 if startpos == nil then
2665 -- If nil, then we won't have new link after startposition = startNoDDS , so add ours until the end
2666
2667 textLinked = AddLinkHandlerToStringWithoutDDS(textToCheck, numLine, chanCode)
2668
2669 textTReformated = textTReformated .. textLinked
2670
2671 -- No need to parse after
2672 stillToParseDDS = false
2673
2674 else
2675
2676 -- DDS is at the begginning of the string
2677 if startpos == 1 then
2678 -- New text is (only DDS because its at the pos 1)
2679 textTReformated = textTReformated .. textToCheck:sub(startpos, endpos)
2680
2681 -- Do we need to continue ?
2682 if endpos == noDDSlen then
2683 -- We're at the end
2684 stillToParseDDS = false
2685 else
2686 -- Still to parse
2687 startNoDDS = endpos
2688 -- textToCheck is next to our string
2689 textToCheck = textToCheck:sub(startNoDDS + 1)
2690 end
2691
2692 else
2693
2694 -- We Handle string from startNoDDS of the message up to the Handle link
2695 local textToHandle = textToCheck:sub(1, startpos - 1)
2696
2697 -- Add ours
2698 textLinked = AddLinkHandlerToStringWithoutDDS(textToHandle, numLine, chanCode)
2699
2700 -- New text is formattedText + (textLinked .. DDS)
2701 textTReformated = textTReformated .. textLinked
2702
2703 textTReformated = textTReformated .. textToCheck:sub(startpos, endpos)
2704
2705 -- Do we need to continue ?
2706 if endpos == noDDSlen then
2707 -- We're at the end
2708 stillToParseDDS = false
2709 else
2710 -- Still to parse
2711 startNoDDS = endpos
2712 -- textToCheck is next to our string
2713 textToCheck = textToCheck:sub(startNoDDS + 1)
2714 end
2715
2716 end
2717 end
2718 end
2719
2720 return textTReformated
2721
2722end
2723
2724-- Reformat Colored Sysmessages to the correct format
2725-- Bad format = |[cC]XXXXXXblablabla[,|[cC]XXXXXXblablabla,(...)] with facultative |r
2726-- Good format : "|c%x%x%x%x%x%x(.-)|r"
2727-- WARNING : See FormatSysMessage()
2728-- TODO : Handle LinkHandler + Malformatted strings , such as : "|c87B7CC|c87B7CCUpdated: |H0:achievement:68:5252:0|h|h (Artisanat)."
2729local function ReformatSysMessages(text)
2730
2731 local rawSys = text
2732 local startColSys, endColSys
2733 local lastTag, lastR, findC, findR
2734 local count, countR
2735 local firstIsR
2736
2737 rawSys = rawSys:gsub("||([Cc])", "%1") -- | is the escape char for |, so if an user type |c it will be sent as ||c by the game which will lead to an infinite loading screen because xxxxx||xxxxxx is a lua pattern operator and few gsub will broke the code
2738
2739 --Search for Color tags
2740 startColSys, endColSys = string.find(rawSys, "|[cC]%x%x%x%x%x%x", 1)
2741 _, count = string.gsub(rawSys, "|[cC]%x%x%x%x%x%x", "")
2742
2743 -- No color tags in the SysMessage
2744 if startColSys then
2745 -- Found X tag
2746 -- Searching for |r after tag color
2747
2748 -- First destroy tags with nothing inside
2749 rawSys = string.gsub(rawSys, "|[cC]%x%x%x%x%x%x|[rR]", "")
2750
2751 _, countR = string.gsub(rawSys, "|[cC]%x%x%x%x%x%x(.-)|[rR]", "")
2752
2753 -- Start tag found but end tag ~= start tag
2754 if count ~= countR then
2755
2756 -- Add |r before the tag
2757 rawSys = string.gsub(rawSys, "|[cC]%x%x%x%x%x%x", "|r%1")
2758 firstIsR = string.find(rawSys, "|[cC]%x%x%x%x%x%x")
2759
2760 --No |r tag at the start of the text if start was |cXXXXXX
2761 if firstIsR == 3 then
2762 rawSys = string.sub(rawSys, 3)
2763 end
2764
2765 -- Replace
2766 rawSys = string.gsub(rawSys, "|r|r", "|r")
2767 rawSys = string.gsub(rawSys, "|r |r", " |r")
2768
2769 lastTag = string.match(rawSys, "^.*()|[cC]%x%x%x%x%x%x")
2770 lastR = string.match(rawSys, "^.*()|r")
2771
2772 -- |r tag found
2773 if lastR ~= nil then
2774 if lastTag > lastR then
2775 rawSys = rawSys .. "|r"
2776 end
2777 else
2778 -- Got X tags and 0 |r, happens only when we got 1 tag and 0 |r because we added |r to every tags just before
2779 -- So add last "|r"
2780 rawSys = rawSys .. "|r"
2781 end
2782
2783 -- Double check
2784
2785 findC = string.find(rawSys, "|[cC]%x%x%x%x%x%x")
2786 findR = string.find(rawSys, "|[rR]")
2787
2788 while findR ~= nil and findC ~= nil do
2789
2790 if findC then
2791 if findR < findC then
2792 rawSys = string.sub(rawSys, 1, findR - 1) .. string.sub(rawSys, findR + 2)
2793 end
2794
2795 findC = string.find(rawSys, "|[cC]%x%x%x%x%x%x", findR)
2796 findR = string.find(rawSys, "|[rR]", findR + 2)
2797 end
2798
2799 end
2800
2801 end
2802
2803 end
2804 -- Added |u search
2805 startColSys, endColSys = string.find(rawSys, "|u%-?%d+%%?:%-?%d+%%?:.-:|u",1)
2806 -- if found
2807 if startColSys then
2808 rawSys = string.gsub(rawSys,"|u%-?%d+%%?:%-?%d+%%?:.-:|u","")
2809 end
2810
2811 return rawSys
2812
2813end
2814
2815-- Add pChatLinks Handlers on the whole text except LinkHandlers already here
2816-- WARNING : See FormatSysMessage()
2817local function AddLinkHandlerToLine(text, chanCode, numLine)
2818
2819 local rawText = ReformatSysMessages(text) -- FUCK YOU
2820
2821 local start = 1
2822 local rawTextlen = string.len(rawText)
2823 local stillToParseCol = true
2824 local formattedText
2825 local noColorText = ""
2826 local textToCheck = ""
2827
2828 local startColortag = ""
2829
2830 local preventLoops = 0
2831 local colorizedText = true
2832 local newText = ""
2833
2834 while stillToParseCol do
2835
2836 -- Prevent infinite loops while its still in beta
2837 if preventLoops > 10 then
2838 stillToParseCol = false
2839 else
2840 preventLoops = preventLoops + 1
2841 end
2842
2843 -- Handling Colors, search for color tag
2844 local startcol, endcol = string.find(rawText, "|[cC]%x%x%x%x%x%x(.-)|r", start)
2845
2846 -- Not Found
2847 if startcol == nil then
2848 startColortag = ""
2849 textToCheck = string.sub(rawText, start)
2850 stillToParseCol = false
2851 newText = newText .. AddLinkHandlerToString(textToCheck, numLine, chanCode)
2852 else
2853 startColortag = string.sub(rawText, startcol, startcol + 7)
2854 -- pChat format all strings
2855 if start == startcol then
2856 -- textToCheck is only (.-)
2857 textToCheck = string.sub(rawText, (startcol + 8), (endcol - 2))
2858 -- Change our start -> pos of (.-)
2859 start = endcol + 1
2860 newText = newText .. startColortag .. AddLinkHandlerToString(textToCheck, numLine, chanCode) .. "|r"
2861
2862 -- Do we need to continue ?
2863 if endcol == rawTextlen then
2864 -- We're at the end
2865 stillToParseCol = false
2866 end
2867
2868 else
2869 -- We will check colorized text at next loop
2870 textToCheck = string.sub(rawText, start, startcol-1)
2871 start = startcol
2872 -- Tag color found but need to check some strings before
2873 newText = newText .. AddLinkHandlerToString(textToCheck, numLine, chanCode)
2874 end
2875 end
2876
2877 end
2878
2879 return newText
2880
2881end
2882
2883-- Split lines using CRLF for function addLinkHandlerToLine
2884-- WARNING : See FormatSysMessage()
2885local function AddLinkHandler(text, chanCode, numLine)
2886 if not text or text == "" then return end
2887 -- Some Addons output multiple lines into a message
2888 -- Split the entire string with CRLF, cause LinkHandler don't support CRLF
2889
2890 -- Init
2891 local formattedText = ""
2892
2893 -- Recheck setting if copy is disabled for chat dump
2894 if db.enablecopy then
2895
2896 -- No CRLF
2897 -- ESO LUA Messages output \n instead of \r\n
2898 local crtext = string.gsub(text, "\r\n", "\n")
2899 -- Find multilines
2900 local cr = string.find(crtext, "\n")
2901
2902 if not cr then
2903 formattedText = AddLinkHandlerToLine(text, chanCode, numLine)
2904 else
2905 local lines = {zo_strsplit("\n", crtext)}
2906 local first = true
2907 local strippedLine
2908 local nunmRows = 0
2909
2910 for _, line in pairs(lines) do
2911
2912 -- Only if there something to display
2913 if string.len(line) > 0 then
2914
2915 if first then
2916 formattedText = AddLinkHandlerToLine(line, chanCode, numLine)
2917 first = false
2918 else
2919 formattedText = formattedText .. "\n" .. AddLinkHandlerToLine(line, chanCode, numLine)
2920 end
2921
2922 if nunmRows > 10 then
2923 local errorMessage = string.format(GetString(PCHAT_LUAERROR), tostring(text))
2924 CHAT_SYSTEM:Zo_AddMessage(errorMessage)
2925 return
2926 else
2927 nunmRows = nunmRows + 1
2928 end
2929
2930 end
2931
2932 end
2933
2934 end
2935 else
2936 formattedText = text
2937 end
2938
2939 return formattedText
2940
2941end
2942
2943-- Can cause infinite loads (why?)
2944local function RestoreChatMessagesFromHistory(wasReloadUI)
2945
2946 -- Restore Chat
2947 local lastInsertionWas = 0
2948
2949 if db.LineStrings then
2950
2951 local historyIndex = 1
2952 local categories = ZO_ChatSystem_GetEventCategoryMappings()
2953
2954 while historyIndex <= #db.LineStrings do
2955 if db.LineStrings[historyIndex] then
2956 local channelToRestore = db.LineStrings[historyIndex].channel
2957 if channelToRestore == PCHAT_CHANNEL_SAY then channelToRestore = 0 end
2958
2959 if channelToRestore == CHAT_CHANNEL_SYSTEM and not db.restoreSystem then
2960 table.remove(db.LineStrings, historyIndex)
2961 db.lineNumber = db.lineNumber - 1
2962 historyIndex = historyIndex - 1
2963 elseif channelToRestore ~= CHAT_CHANNEL_SYSTEM and db.restoreSystemOnly then
2964 table.remove(db.LineStrings, historyIndex)
2965 db.lineNumber = db.lineNumber - 1
2966 historyIndex = historyIndex - 1
2967 elseif (channelToRestore == CHAT_CHANNEL_WHISPER or channelToRestore == CHAT_CHANNEL_WHISPER_SENT) and not db.restoreWhisps then
2968 table.remove(db.LineStrings, historyIndex)
2969 db.lineNumber = db.lineNumber - 1
2970 historyIndex = historyIndex - 1
2971 else
2972
2973 local category = categories[EVENT_CHAT_MESSAGE_CHANNEL][channelToRestore]
2974
2975 if GetTimeStamp() - db.LineStrings[historyIndex].rawTimestamp < db.timeBeforeRestore * 60 * 60 and db.LineStrings[historyIndex].rawTimestamp < GetTimeStamp() then
2976 lastInsertionWas = math.max(lastInsertionWas, db.LineStrings[historyIndex].rawTimestamp)
2977 for containerIndex=1, #CHAT_SYSTEM.containers do
2978
2979 for tabIndex=1, #CHAT_SYSTEM.containers[containerIndex].windows do
2980 if IsChatContainerTabCategoryEnabled(CHAT_SYSTEM.containers[containerIndex].id, tabIndex, category) then
2981 if not db.chatConfSync[pChatData.localPlayer].tabs[tabIndex].notBefore or db.LineStrings[historyIndex].rawTimestamp > db.chatConfSync[pChatData.localPlayer].tabs[tabIndex].notBefore then
2982 CHAT_SYSTEM.containers[containerIndex]:AddEventMessageToWindow(CHAT_SYSTEM.containers[containerIndex].windows[tabIndex], AddLinkHandler(db.LineStrings[historyIndex].rawValue, channelToRestore, historyIndex), category)
2983 end
2984 end
2985 end
2986
2987 end
2988 else
2989 table.remove(db.LineStrings, historyIndex)
2990 db.lineNumber = db.lineNumber - 1
2991 historyIndex = historyIndex - 1
2992 end
2993
2994 end
2995 end
2996 historyIndex = historyIndex + 1
2997 end
2998
2999
3000 local PRESSED = 1
3001 local UNPRESSED = 2
3002 local numTabs = #CHAT_SYSTEM.primaryContainer.windows
3003
3004 for numTab, container in ipairs (CHAT_SYSTEM.primaryContainer.windows) do
3005 if numTab > 1 then
3006 CHAT_SYSTEM.primaryContainer:HandleTabClick(container.tab)
3007 local tabText = GetControl("ZO_ChatWindowTabTemplate" .. numTab .. "Text")
3008 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
3009 tabText:GetParent().state = PRESSED
3010 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. numTab - 1 .. "Text")
3011 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
3012 oldTabText:GetParent().state = UNPRESSED
3013 end
3014 end
3015
3016 if numTabs > 1 then
3017 CHAT_SYSTEM.primaryContainer:HandleTabClick(CHAT_SYSTEM.primaryContainer.windows[1].tab)
3018 local tabText = GetControl("ZO_ChatWindowTabTemplate1Text")
3019 tabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED))
3020 tabText:GetParent().state = PRESSED
3021 local oldTabText = GetControl("ZO_ChatWindowTabTemplate" .. #CHAT_SYSTEM.primaryContainer.windows .. "Text")
3022 oldTabText:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_CONTRAST))
3023 oldTabText:GetParent().state = UNPRESSED
3024 end
3025
3026 end
3027
3028 -- Restore TextEntry History
3029 if (wasReloadUI or db.restoreTextEntryHistoryAtLogOutQuit) and db.history.textEntry then
3030
3031 if db.history.textEntry.entries then
3032
3033 if lastInsertionWas and ((GetTimeStamp() - lastInsertionWas) < (db.timeBeforeRestore * 60 * 60)) then
3034 for _, text in ipairs(db.history.textEntry.entries) do
3035 CHAT_SYSTEM.textEntry:AddCommandHistory(text)
3036 end
3037
3038 CHAT_SYSTEM.textEntry.commandHistory.index = db.history.textEntry.numEntries
3039 end
3040
3041 end
3042
3043 end
3044
3045end
3046
3047-- Restore History from SavedVars
3048local function RestoreChatHistory()
3049
3050 -- Set default tab at login
3051 SetDefaultTab(db.defaultTab)
3052 -- Restore History
3053 if db.history then
3054
3055 if db.lastWasReloadUI and db.restoreOnReloadUI then
3056
3057 -- RestoreChannel
3058 if db.defaultchannel ~= PCHAT_CHANNEL_NONE then
3059 CHAT_SYSTEM:SetChannel(db.history.currentChannel, db.history.currentTarget)
3060 end
3061
3062 -- restore TextEntry and Chat
3063 RestoreChatMessagesFromHistory(true)
3064
3065 -- Restore tab when ReloadUI
3066 --** blocking for now
3067 --SetDefaultTab(db.history.currentTab)
3068
3069 elseif (db.lastWasLogOut and db.restoreOnLogOut) or (db.lastWasAFK and db.restoreOnAFK) or (db.lastWasQuit and db.restoreOnQuit) then
3070 -- restore TextEntry and Chat
3071 RestoreChatMessagesFromHistory(false)
3072 end
3073
3074 pChatData.messagesHaveBeenRestorated = true
3075
3076 local indexMessages = #pChatData.cachedMessages
3077 if indexMessages > 0 then
3078 for index=1, indexMessages do
3079 CHAT_SYSTEM:AddMessage(pChatData.cachedMessages[index])
3080 end
3081 end
3082
3083 db.lastWasReloadUI = false
3084 db.lastWasLogOut = false
3085 db.lastWasQuit = false
3086 db.lastWasAFK = true
3087 else
3088 pChatData.messagesHaveBeenRestorated = true
3089 end
3090
3091end
3092
3093-- Store line number
3094-- Create an array for the copy functions, spam functions and revert history functions
3095-- WARNING : See FormatSysMessage()
3096local function StorelineNumber(rawTimestamp, rawFrom, text, chanCode, originalFrom)
3097
3098 -- Strip DDS tag from Copy text
3099 local function StripDDStags(text)
3100 return text:gsub("|t(.-)|t", "")
3101 end
3102
3103 local formattedMessage = ""
3104 local rawText = text
3105
3106 -- SysMessages does not have a from
3107 if chanCode ~= CHAT_CHANNEL_SYSTEM then
3108
3109 -- Timestamp cannot be nil anymore with SpamFilter, so use the option itself
3110 if db.showTimestamp then
3111 -- Format for Copy
3112 formattedMessage = "[" .. CreateTimestamp(GetTimeString()) .. "] "
3113 end
3114
3115 -- Strip DDS tags for GM
3116 rawFrom = StripDDStags(rawFrom)
3117
3118 -- Needed for SpamFilter
3119 db.LineStrings[db.lineNumber].rawFrom = originalFrom
3120
3121 -- formattedMessage is only rawFrom for now
3122 formattedMessage = formattedMessage .. rawFrom
3123
3124 if db.carriageReturn then
3125 formattedMessage = formattedMessage .. "\n"
3126 end
3127
3128 end
3129
3130 -- Needed for SpamFilter & Restoration, UNIX timestamp
3131 db.LineStrings[db.lineNumber].rawTimestamp = rawTimestamp
3132
3133 -- Store CopyMessage / Used for SpamFiltering. Due to lua 0 == nil in arrays, set value to 98
3134 if chanCode == CHAT_CHANNEL_SAY then
3135 db.LineStrings[db.lineNumber].channel = PCHAT_CHANNEL_SAY
3136 else
3137 db.LineStrings[db.lineNumber].channel = chanCode
3138 end
3139
3140 -- Store CopyMessage
3141 db.LineStrings[db.lineNumber].rawText = rawText
3142
3143 -- Store CopyMessage
3144 --db.LineStrings[db.lineNumber].rawValue = text
3145
3146 -- Strip DDS tags
3147 rawText = StripDDStags(rawText)
3148
3149 -- Used to translate LinkHandlers
3150 rawText = FormatRawText(rawText)
3151
3152 -- Store CopyMessage
3153 db.LineStrings[db.lineNumber].rawMessage = rawText
3154
3155 -- Store CopyLine
3156 db.LineStrings[db.lineNumber].rawLine = formattedMessage .. rawText
3157
3158 --Increment at each message handled
3159 db.lineNumber = db.lineNumber + 1
3160
3161end
3162
3163-- WARNING : Since AddMessage is bypassed, this function and all its subfunctions DOES NOT MUST CALL d() / Emitmessage() / AddMessage() or it will result an infinite loop and crash the game
3164-- Debug must call CHAT_SYSTEM:Zo_AddMessage() wich is backuped copy of CHAT_SYSTEM.AddMessage
3165local function FormatSysMessage(statusMessage)
3166
3167 -- Display Timestamp if needed
3168 local function ShowTimestamp()
3169
3170 local timestamp = ""
3171
3172 -- Add timestamp
3173 if db.showTimestamp then
3174
3175 -- Timestamp formatted
3176 timestamp = CreateTimestamp(GetTimeString())
3177
3178 local timecol
3179 -- Timestamp color is chanCode so no coloring
3180 if db.timestampcolorislcol then
3181 -- Show Message
3182 timestamp = string.format("[%s] ", timestamp)
3183 else
3184 -- Timestamp color is our setting color
3185 timecol = db.colours.timestamp
3186
3187 -- Show Message
3188 timestamp = string.format("%s[%s] |r", timecol, timestamp)
3189 end
3190 else
3191 timestamp = ""
3192 end
3193
3194 return timestamp
3195
3196 end
3197
3198 -- Only if statusMessage is set
3199 if statusMessage then
3200
3201 -- Only if there something to display
3202 if string.len(statusMessage) > 0 then
3203
3204 local sysMessage
3205
3206 -- Some addons are quicker than pChat
3207 if db then
3208
3209 -- Show Message
3210 statusMessage = ShowTimestamp() .. statusMessage
3211
3212 if not db.lineNumber then
3213 db.lineNumber = 1
3214 end
3215
3216 -- for CopySystem
3217 db.LineStrings[db.lineNumber] = {}
3218
3219 -- Make it Linkable
3220
3221 if db.enablecopy then
3222 sysMessage = AddLinkHandler(statusMessage, CHAT_CHANNEL_SYSTEM, db.lineNumber)
3223 else
3224 sysMessage = statusMessage
3225 end
3226
3227 if not db.LineStrings[db.lineNumber].rawFrom then db.LineStrings[db.lineNumber].rawFrom = "" end
3228 if not db.LineStrings[db.lineNumber].rawMessage then db.LineStrings[db.lineNumber].rawMessage = "" end
3229 if not db.LineStrings[db.lineNumber].rawLine then db.LineStrings[db.lineNumber].rawLine = "" end
3230 if not db.LineStrings[db.lineNumber].rawValue then db.LineStrings[db.lineNumber].rawValue = statusMessage end
3231 if not db.LineStrings[db.lineNumber].rawDisplayed then db.LineStrings[db.lineNumber].rawDisplayed = sysMessage end
3232
3233 -- No From, rawTimestamp is in statusMessage, sent as arg for SpamFiltering even if SysMessages are not filtered
3234 StorelineNumber(GetTimeStamp(), nil, statusMessage, CHAT_CHANNEL_SYSTEM, nil)
3235
3236 end
3237
3238 -- Show Message
3239 return sysMessage
3240
3241 end
3242
3243 end
3244
3245end
3246
3247-- Add a pChat handler for URL's
3248local function AddURLHandling(text)
3249
3250 -- handle complex URLs and do
3251 for pos, url, prot, subd, tld, colon, port, slash, path in text:gmatch("()(([%w_.~!*:@&+$/?%%#-]-)(%w[-.%w]*%.)(%w+)(:?)(%d*)(/?)([%w_.~!*:@&+$/?%#=-]*))") do
3252 if pChatData.protocols[prot:lower()] == (1 - #slash) * #path
3253 and (colon == "" or port ~= "" and port + 0 < 65536)
3254 and (pChatData.tlds[tld:lower()] or tld:find("^%d+$") and subd:find("^%d+%.%d+%.%d+%.$") and math.max(tld, subd:match("^(%d+)%.(%d+)%.(%d+)%.$")) < 256)
3255 and not subd:find("%W%W")
3256 then
3257 local urlHandled = string.format("|H1:%s:%s:%s|h%s|h", PCHAT_LINK, db.lineNumber, PCHAT_URL_CHAN, url)
3258 url = url:gsub("([?+-])", "%%%1") -- don't understand why, 1st arg of gsub must be escaped and 2nd not.
3259 text, count = text:gsub(url, urlHandled)
3260 end
3261 end
3262
3263 return text
3264
3265end
3266
3267local function InitializeURLHandling()
3268
3269 -- cTLD + most used (> 0.1%)
3270 local domains =
3271 [[
3272 .ac.ad.ae.af.ag.ai.al.am.an.ao.aq.ar.as.at.au.aw.ax.az.ba.bb.bd.be.bf.bg.bh.bi.bj.bl.bm.bn.bo.bq
3273 .br.bs.bt.bv.bw.by.bz.ca.cc.cd.cf.cg.ch.ci.ck.cl.cm.cn.co.cr.cu.cv.cw.cx.cy.cz.de.dj.dk.dm.do.dz
3274 .ec.ee.eg.eh.er.es.et.eu.fi.fj.fk.fm.fo.fr.ga.gb.gd.ge.gf.gg.gh.gi.gl.gm.gn.gp.gq.gr.gs.gt.gu.gw
3275 .gy.hk.hm.hn.hr.ht.hu.id.ie.il.im.in.io.iq.ir.is.it.je.jm.jo.jp.ke.kg.kh.ki.km.kn.kp.kr.kw.ky.kz
3276 .la.lb.lc.li.lk.lr.ls.lt.lu.lv.ly.ma.mc.md.me.mf.mg.mh.mk.ml.mm.mn.mo.mp.mq.mr.ms.mt.mu.mv.mw.mx
3277 .my.mz.na.nc.ne.nf.ng.ni.nl.no.np.nr.nu.nz.om.pa.pe.pf.pg.ph.pk.pl.pm.pn.pr.ps.pt.pw.py.qa.re.ro
3278 .rs.ru.rw.sa.sb.sc.sd.se.sg.sh.si.sj.sk.sl.sm.sn.so.sr.ss.st.su.sv.sx.sy.sz.tc.td.tf.tg.th.tj.tk
3279 .tl.tm.tn.to.tp.tr.tt.tv.tw.tz.ua.ug.uk.um.us.uy.uz.va.vc.ve.vg.vi.vn.vu.wf.ws.ye.yt.za.zm.zw
3280 .biz.com.coop.edu.gov.int.mil.mobi.info.net.org.xyz.top.club.pro.asia
3281 ]]
3282
3283 -- wxx.yy.zz
3284 pChatData.tlds = {}
3285 for tld in domains:gmatch('%w+') do
3286 pChatData.tlds[tld] = true
3287 end
3288
3289 -- protos : only http/https
3290 pChatData.protocols = {['http://'] = 0, ['https://'] = 0}
3291
3292end
3293
3294local function GetChannelColors(channel, from)
3295
3296 -- Substract XX to a color (darker)
3297 local function FirstColorFromESOSettings(r, g, b)
3298 -- Scale is from 0-100 so divide per 300 will maximise difference at 0.33 (*2)
3299 r = math.max(r - (db.diffforESOcolors / 300 ),0)
3300 g = math.max(g - (db.diffforESOcolors / 300 ),0)
3301 b = math.max(b - (db.diffforESOcolors / 300 ),0)
3302 return r,g,b
3303 end
3304
3305 -- Add XX to a color (brighter)
3306 local function SecondColorFromESOSettings(r, g, b)
3307 r = math.min(r + (db.diffforESOcolors / 300 ),1)
3308 g = math.min(g + (db.diffforESOcolors / 300 ),1)
3309 b = math.min(b + (db.diffforESOcolors / 300 ),1)
3310 return r,g,b
3311 end
3312
3313 if db.useESOcolors then
3314
3315 -- ESO actual color, return r,g,b
3316 local rESO, gESO, bESO
3317 -- Handle the same-colour options.
3318 if db.allNPCSameColour and (channel == CHAT_CHANNEL_MONSTER_SAY or channel == CHAT_CHANNEL_MONSTER_YELL or channel == CHAT_CHANNEL_MONSTER_WHISPER) then
3319 rESO, gESO, bESO = CHAT_SYSTEM:GetCategoryColorFromChannel(CHAT_CHANNEL_MONSTER_SAY)
3320 elseif db.allGuildsSameColour and (channel >= CHAT_CHANNEL_GUILD_1 and channel <= CHAT_CHANNEL_GUILD_5) then
3321 rESO, gESO, bESO = CHAT_SYSTEM:GetCategoryColorFromChannel(CHAT_CHANNEL_GUILD_1)
3322 elseif db.allGuildsSameColour and (channel >= CHAT_CHANNEL_OFFICER_1 and channel <= CHAT_CHANNEL_OFFICER_5) then
3323 rESO, gESO, bESO = CHAT_SYSTEM:GetCategoryColorFromChannel(CHAT_CHANNEL_OFFICER_1)
3324 elseif db.allZonesSameColour and (channel >= CHAT_CHANNEL_ZONE_LANGUAGE_1 and channel <= CHAT_CHANNEL_ZONE_LANGUAGE_4) then
3325 rESO, gESO, bESO = CHAT_SYSTEM:GetCategoryColorFromChannel(CHAT_CHANNEL_ZONE_LANGUAGE_1)
3326 elseif channel == CHAT_CHANNEL_PARTY and from and db.groupLeader and zo_strformat(SI_UNIT_NAME, from) == GetUnitName(GetGroupLeaderUnitTag()) then
3327 rESO, gESO, bESO = ConvertHexToRGBA(db.colours["groupleader"])
3328 else
3329 rESO, gESO, bESO = CHAT_SYSTEM:GetCategoryColorFromChannel(channel)
3330 end
3331
3332 -- Set right colour to left colour - cause ESO colors are rewrited, if onecolor, no rewriting
3333 if db.oneColour then
3334 lcol = ConvertRGBToHex(rESO, gESO, bESO)
3335 rcol = lcol
3336 else
3337 lcol = ConvertRGBToHex(FirstColorFromESOSettings(rESO,gESO,bESO))
3338 rcol = ConvertRGBToHex(SecondColorFromESOSettings(rESO,gESO,bESO))
3339 end
3340
3341 else
3342 -- pChat Colors
3343 -- Handle the same-colour options.
3344 if db.allNPCSameColour and (channel == CHAT_CHANNEL_MONSTER_SAY or channel == CHAT_CHANNEL_MONSTER_YELL or channel == CHAT_CHANNEL_MONSTER_WHISPER) then
3345 lcol = db.colours[2*CHAT_CHANNEL_MONSTER_SAY]
3346 rcol = db.colours[2*CHAT_CHANNEL_MONSTER_SAY + 1]
3347 elseif db.allGuildsSameColour and (channel >= CHAT_CHANNEL_GUILD_1 and channel <= CHAT_CHANNEL_GUILD_5) then
3348 lcol = db.colours[2*CHAT_CHANNEL_GUILD_1]
3349 rcol = db.colours[2*CHAT_CHANNEL_GUILD_1 + 1]
3350 elseif db.allGuildsSameColour and (channel >= CHAT_CHANNEL_OFFICER_1 and channel <= CHAT_CHANNEL_OFFICER_5) then
3351 lcol = db.colours[2*CHAT_CHANNEL_OFFICER_1]
3352 rcol = db.colours[2*CHAT_CHANNEL_OFFICER_1 + 1]
3353 elseif db.allZonesSameColour and (channel >= CHAT_CHANNEL_ZONE_LANGUAGE_1 and channel <= CHAT_CHANNEL_ZONE_LANGUAGE_4) then
3354 lcol = db.colours[2*CHAT_CHANNEL_ZONE]
3355 rcol = db.colours[2*CHAT_CHANNEL_ZONE + 1]
3356 elseif channel == CHAT_CHANNEL_PARTY and from and db.groupLeader and zo_strformat(SI_UNIT_NAME, from) == GetUnitName(GetGroupLeaderUnitTag()) then
3357 lcol = db.colours["groupleader"]
3358 rcol = db.colours["groupleader1"]
3359 else
3360 lcol = db.colours[2*channel]
3361 rcol = db.colours[2*channel + 1]
3362 end
3363
3364 -- Set right colour to left colour
3365 if db.oneColour then
3366 rcol = lcol
3367 end
3368
3369 end
3370
3371 return lcol, rcol
3372
3373end
3374
3375-- Executed when EVENT_CHAT_MESSAGE_CHANNEL triggers
3376-- Formats the message
3377local function FormatMessage(chanCode, from, text, isCS, fromDisplayName, originalFrom, originalText, DDSBeforeAll, TextBeforeAll, DDSBeforeSender, TextBeforeSender, TextAfterSender, DDSAfterSender, DDSBeforeText, TextBeforeText, TextAfterText, DDSAfterText)
3378
3379 -- Will calculate if this message is a spam
3380 local isSpam = SpamFilter(chanCode, from, text, isCS)
3381
3382 -- A spam, drop everything
3383 if isSpam then return end
3384
3385 local info = ChanInfoArray[chanCode]
3386
3387 -- Init message with other addons stuff
3388 local message = DDSBeforeAll .. TextBeforeAll
3389
3390 -- Init text with other addons stuff. Note : text can also be modified by other addons. Only originalText is the string the game has receive
3391 text = DDSBeforeText .. TextBeforeText .. text .. TextAfterText .. DDSAfterText
3392
3393 if db.disableBrackets then
3394 chatStrings["copystandard"] = "%s: " -- standard format: say, yell, group, npc, npc yell, npc whisper, zone
3395 chatStrings["copyesostandard"] = "%s %s: " -- standard format: say, yell, group, npc, npc yell, npc whisper, zone with tag (except for monsters)
3396 chatStrings["copyesoparty"] = "[%s]%s: " -- standard format: party
3397 chatStrings["copytellIn"] = "%s: " -- tell in
3398 chatStrings["copytellOut"] = "-> %s: " -- tell out
3399 chatStrings["copyguild"] = "[%s] %s: " -- guild
3400 chatStrings["copylanguage"] = "[%s] %s: " -- language zones
3401 else
3402 chatStrings["copystandard"] = "[%s]: " -- standard format: say, yell, group, npc, npc yell, npc whisper, zone
3403 chatStrings["copyesostandard"] = "[%s] %s: " -- standard format: say, yell, group, npc, npc yell, npc whisper, zone with tag (except for monsters)
3404 chatStrings["copyesoparty"] = "[%s]%s: " -- standard format: party
3405 chatStrings["copytellIn"] = "[%s]: " -- tell in
3406 chatStrings["copytellOut"] = "-> [%s]: " -- tell out
3407 chatStrings["copyguild"] = "[%s] [%s]: " -- guild
3408 chatStrings["copylanguage"] = "[%s] %s: " -- language zones
3409 end
3410
3411 -- for CopySystem
3412 db.LineStrings[db.lineNumber] = {}
3413 if not db.LineStrings[db.lineNumber].rawFrom then db.LineStrings[db.lineNumber].rawFrom = from end
3414 if not db.LineStrings[db.lineNumber].rawValue then db.LineStrings[db.lineNumber].rawValue = text end
3415 if not db.LineStrings[db.lineNumber].rawMessage then db.LineStrings[db.lineNumber].rawMessage = text end
3416 if not db.LineStrings[db.lineNumber].rawLine then db.LineStrings[db.lineNumber].rawLine = text end
3417 if not db.LineStrings[db.lineNumber].rawDisplayed then db.LineStrings[db.lineNumber].rawDisplayed = text end
3418
3419 local new_from = ConvertName(chanCode, from, isCS, fromDisplayName)
3420 local displayedFrom = db.LineStrings[db.lineNumber].rawFrom
3421
3422 -- Add other addons stuff related to sender
3423 new_from = DDSBeforeSender .. TextBeforeSender .. new_from .. TextAfterSender .. DDSAfterSender
3424
3425 -- Guild tag
3426 local tag
3427 if (chanCode >= CHAT_CHANNEL_GUILD_1 and chanCode <= CHAT_CHANNEL_GUILD_5) then
3428 local guild_number = chanCode - CHAT_CHANNEL_GUILD_1 + 1
3429 local guild_name = GetGuildName(GetGuildId(guild_number))
3430 tag = db.guildTags[guild_name]
3431 if tag and tag ~= "" then
3432 tag = tag
3433 else
3434 tag = guild_name
3435 end
3436 elseif (chanCode >= CHAT_CHANNEL_OFFICER_1 and chanCode <= CHAT_CHANNEL_OFFICER_5) then
3437 local guild_number = chanCode - CHAT_CHANNEL_OFFICER_1 + 1
3438 local guild_name = GetGuildName(GetGuildId(guild_number))
3439 local officertag = db.officertag[guild_name]
3440 if officertag and officertag ~= "" then
3441 tag = officertag
3442 else
3443 tag = guild_name
3444 end
3445 end
3446
3447 -- Initialise colours
3448 local lcol, rcol = GetChannelColors(chanCode, from)
3449
3450 -- Add timestamp
3451 if db.showTimestamp then
3452
3453 -- Initialise timstamp color
3454 local timecol = db.colours.timestamp
3455
3456 -- Timestamp color is lcol
3457 if db.timestampcolorislcol then
3458 timecol = lcol
3459 else
3460 -- Timestamp color is timestamp color
3461 timecol = db.colours.timestamp
3462 end
3463
3464 -- Message is timestamp for now
3465 -- Add PCHAT_HANDLER for display
3466 local timestamp = ZO_LinkHandler_CreateLink(CreateTimestamp(GetTimeString()), nil, PCHAT_LINK, db.lineNumber .. ":" .. chanCode) .. " "
3467
3468 -- Timestamp color
3469 message = message .. string.format("%s%s|r", timecol, timestamp)
3470 db.LineStrings[db.lineNumber].rawValue = string.format("%s[%s] |r", timecol, CreateTimestamp(GetTimeString()))
3471 else
3472 db.LineStrings[db.lineNumber].rawValue = ""
3473 end
3474
3475 local linkedText = text
3476
3477 -- Add URL Handling
3478 if db.urlHandling then
3479 text = AddURLHandling(text)
3480 end
3481
3482 if db.enablecopy then
3483 linkedText = AddLinkHandler(text, chanCode, db.lineNumber)
3484 end
3485
3486 local carriageReturn = ""
3487 if db.carriageReturn then
3488 carriageReturn = "\n"
3489 end
3490
3491 -- Standard format
3492 if chanCode == CHAT_CHANNEL_SAY or chanCode == CHAT_CHANNEL_YELL or chanCode == CHAT_CHANNEL_PARTY or chanCode == CHAT_CHANNEL_ZONE then
3493 -- Remove zone tags
3494 if db.delzonetags then
3495
3496 -- Used for Copy
3497 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copystandard, db.LineStrings[db.lineNumber].rawFrom)
3498
3499 message = message .. string.format(chatStrings.standard, lcol, new_from, carriageReturn, rcol, linkedText)
3500 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.standard, lcol, new_from, carriageReturn, rcol, text)
3501 -- Keep them
3502 else
3503 -- Init zonetag to keep the channel tag
3504 local zonetag
3505 -- Pattern for party is [Party]
3506 if chanCode == CHAT_CHANNEL_PARTY then
3507 zonetag = GetString(PCHAT_ZONETAGPARTY)
3508
3509 -- Used for Copy
3510 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyesoparty, zonetag, db.LineStrings[db.lineNumber].rawFrom)
3511
3512 -- PartyHandler
3513 zonetag = ZO_LinkHandler_CreateLink(zonetag, nil, CHANNEL_LINK_TYPE, chanCode)
3514
3515 message = message .. string.format(chatStrings.esoparty, lcol, zonetag, new_from, carriageReturn, rcol, linkedText)
3516 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.esoparty, lcol, zonetag, new_from, carriageReturn, rcol, text)
3517 else
3518 -- Pattern for say/yell/zone is "player says:" ..
3519 if chanCode == CHAT_CHANNEL_SAY then zonetag = GetString(PCHAT_ZONETAGSAY)
3520 elseif chanCode == CHAT_CHANNEL_YELL then zonetag = GetString(PCHAT_ZONETAGYELL)
3521 elseif chanCode == CHAT_CHANNEL_ZONE then zonetag = GetString(PCHAT_ZONETAGZONE)
3522 end
3523
3524 -- Used for Copy
3525 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyesostandard, db.LineStrings[db.lineNumber].rawFrom, zonetag)
3526
3527 -- pChat Handler
3528 zonetag = string.format("|H1:p:%s|h%s|h", chanCode, zonetag)
3529
3530 message = message .. string.format(chatStrings.esostandart, lcol, new_from, zonetag, carriageReturn, rcol, linkedText)
3531 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.esostandart, lcol, new_from, zonetag, carriageReturn, rcol, text)
3532 end
3533 end
3534
3535 -- NPC speech
3536 elseif chanCode == CHAT_CHANNEL_MONSTER_SAY or chanCode == CHAT_CHANNEL_MONSTER_YELL or chanCode == CHAT_CHANNEL_MONSTER_WHISPER then
3537
3538 -- Used for Copy
3539 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copynpc, db.LineStrings[db.lineNumber].rawFrom)
3540
3541 message = message .. string.format(chatStrings.standard, lcol, new_from, carriageReturn, rcol, linkedText)
3542 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.standard, lcol, new_from, carriageReturn, rcol, text)
3543
3544 -- Incoming whispers
3545 elseif chanCode == CHAT_CHANNEL_WHISPER then
3546
3547 --PlaySound
3548 --[[
3549 if db.soundforincwhisps then
3550 PlaySound(db.soundforincwhisps)
3551 end
3552 ]]
3553 local notifyImSoundIndex = db.notifyIMIndex
3554 if SOUNDS and PlaySound and notifyImSoundIndex and pChat.sounds then
3555 local soundName = pChat.sounds[notifyImSoundIndex]
3556 if soundName and SOUNDS[soundName] then
3557 PlaySound(soundName)
3558 end
3559 end
3560
3561 -- Used for Copy
3562 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copytellIn, db.LineStrings[db.lineNumber].rawFrom)
3563
3564 message = message .. string.format(chatStrings.tellIn, lcol, new_from, carriageReturn, rcol, linkedText)
3565 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.tellIn, lcol, new_from, carriageReturn, rcol, text)
3566
3567 -- Outgoing whispers
3568 elseif chanCode == CHAT_CHANNEL_WHISPER_SENT then
3569
3570 -- Used for Copy
3571 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copytellOut, db.LineStrings[db.lineNumber].rawFrom)
3572
3573 message = message .. string.format(chatStrings.tellOut, lcol, new_from, carriageReturn, rcol, linkedText)
3574 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.tellOut, lcol, new_from, carriageReturn, rcol, text)
3575
3576 -- Guild chat
3577 elseif chanCode >= CHAT_CHANNEL_GUILD_1 and chanCode <= CHAT_CHANNEL_GUILD_5 then
3578
3579 local gtag = tag
3580 if db.showGuildNumbers then
3581 gtag = (chanCode - CHAT_CHANNEL_GUILD_1 + 1) .. "-" .. tag
3582
3583 -- Used for Copy
3584 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyguild, gtag, db.LineStrings[db.lineNumber].rawFrom)
3585
3586 -- GuildHandler
3587 gtag = ZO_LinkHandler_CreateLink(gtag, nil, CHANNEL_LINK_TYPE, chanCode)
3588 message = message .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, linkedText)
3589 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, text)
3590
3591 else
3592
3593 -- Used for Copy
3594 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyguild, gtag, db.LineStrings[db.lineNumber].rawFrom)
3595
3596 -- GuildHandler
3597 gtag = ZO_LinkHandler_CreateLink(gtag, nil, CHANNEL_LINK_TYPE, chanCode)
3598
3599 message = message .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, linkedText)
3600 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, text)
3601
3602 end
3603
3604 -- Officer chat
3605 elseif chanCode >= CHAT_CHANNEL_OFFICER_1 and chanCode <= CHAT_CHANNEL_OFFICER_5 then
3606
3607 local gtag = tag
3608 if db.showGuildNumbers then
3609 gtag = (chanCode - CHAT_CHANNEL_OFFICER_1 + 1) .. "-" .. tag
3610
3611 -- Used for Copy
3612 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyguild, gtag, db.LineStrings[db.lineNumber].rawFrom)
3613
3614 -- GuildHandler
3615 gtag = ZO_LinkHandler_CreateLink(gtag, nil, CHANNEL_LINK_TYPE, chanCode)
3616
3617 message = message .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, linkedText)
3618 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, text)
3619 else
3620
3621 -- Used for Copy
3622 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyguild, gtag, db.LineStrings[db.lineNumber].rawFrom)
3623
3624 -- GuildHandler
3625 gtag = ZO_LinkHandler_CreateLink(gtag, nil, CHANNEL_LINK_TYPE, chanCode)
3626
3627 message = message .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, linkedText)
3628 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.guild, lcol, gtag, new_from, carriageReturn, rcol, text)
3629 end
3630
3631 -- Player emotes
3632 elseif chanCode == CHAT_CHANNEL_EMOTE then
3633
3634 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyemote, db.LineStrings[db.lineNumber].rawFrom)
3635 message = message .. string.format(chatStrings.emote, lcol, new_from, rcol, linkedText)
3636 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.emote, lcol, new_from, rcol, text)
3637
3638 -- NPC emotes
3639 elseif chanCode == CHAT_CHANNEL_MONSTER_EMOTE then
3640
3641 -- Used for Copy
3642 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copyemote, db.LineStrings[db.lineNumber].rawFrom)
3643
3644 message = message .. string.format(chatStrings.emote, lcol, new_from, rcol, linkedText)
3645 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.emote, lcol, new_from, rcol, text)
3646
3647 -- Language zones
3648 elseif chanCode >= CHAT_CHANNEL_ZONE_LANGUAGE_1 and chanCode <= CHAT_CHANNEL_ZONE_LANGUAGE_4 then
3649 local lang
3650 if chanCode == CHAT_CHANNEL_ZONE_LANGUAGE_1 then lang = "EN"
3651 elseif chanCode == CHAT_CHANNEL_ZONE_LANGUAGE_2 then lang = "FR"
3652 elseif chanCode == CHAT_CHANNEL_ZONE_LANGUAGE_3 then lang = "DE"
3653 elseif chanCode == CHAT_CHANNEL_ZONE_LANGUAGE_4 then lang = "JP"
3654 end
3655
3656 -- Used for Copy
3657 db.LineStrings[db.lineNumber].rawFrom = string.format(chatStrings.copylanguage, lang, db.LineStrings[db.lineNumber].rawFrom)
3658
3659 message = message .. string.format(chatStrings.language, lcol, lang, new_from, carriageReturn, rcol, linkedText)
3660 db.LineStrings[db.lineNumber].rawValue = db.LineStrings[db.lineNumber].rawValue .. string.format(chatStrings.language, lcol, lang, new_from, carriageReturn, rcol, text)
3661
3662 -- Unknown messages - just pass it through, no changes.
3663 else
3664 local notHandled = true
3665 message = text
3666 end
3667
3668 db.LineStrings[db.lineNumber].rawDisplayed = message
3669
3670 -- Only if handled by pChat
3671
3672 if not notHandled then
3673 -- Store message and params into an array for copy system and SpamFiltering
3674 StorelineNumber(GetTimeStamp(), db.LineStrings[db.lineNumber].rawFrom, text, chanCode, originalFrom)
3675 end
3676
3677 -- Needs to be after .storelineNumber()
3678 if chanCode == CHAT_CHANNEL_WHISPER then
3679 OnIMReceived(displayedFrom, db.lineNumber - 1)
3680 end
3681
3682 return message
3683
3684end
3685
3686-- Rewrite of core function
3687function CHAT_SYSTEM:AddMessage(text)
3688
3689 -- Overwrite CHAT_SYSTEM:AddMessage() function to format it
3690 -- Overwrite SharedChatContainer:AddDebugMessage(formattedEventText) in order to display system message in specific tabs
3691 -- CHAT_SYSTEM:Zo_AddMessage() can be used in order to use old function
3692 -- Store the message in pChatData.cachedMessages if this one is sent before CHAT_SYSTEM.primaryContainer goes up (before 1st EVENT_PLAYER_ACTIVATED)
3693
3694 if CHAT_SYSTEM.primaryContainer and pChatData.messagesHaveBeenRestorated then
3695 for k in ipairs(CHAT_SYSTEM.containers) do
3696 CHAT_SYSTEM.containers[k]:OnChatEvent(nil, FormatSysMessage(text), CHAT_CATEGORY_SYSTEM)
3697 end
3698 else
3699 table.insert(pChatData.cachedMessages, text)
3700 end
3701
3702end
3703
3704local function EmitMessage(text)
3705 if CHAT_SYSTEM and CHAT_SYSTEM.primaryContainer and pChatData.messagesHaveBeenRestorated then
3706 if text == "" then
3707 text = "[Empty String]"
3708 end
3709 CHAT_SYSTEM:AddMessage(text)
3710 else
3711 table.insert(pChatData.cachedMessages, text)
3712 end
3713end
3714
3715local function EmitTable(t, indent, tableHistory)
3716 indent = indent or "."
3717 tableHistory = tableHistory or {}
3718
3719 for k, v in pairs(t)
3720 do
3721 local vType = type(v)
3722
3723 EmitMessage(indent.."("..vType.."): "..tostring(k).." = "..tostring(v))
3724
3725 if(vType == "table")
3726 then
3727 if(tableHistory[v])
3728 then
3729 EmitMessage(indent.."Avoiding cycle on table...")
3730 else
3731 tableHistory[v] = true
3732 EmitTable(v, indent.." ", tableHistory)
3733 end
3734 end
3735 end
3736end
3737
3738-- Rewrite of a core function
3739function d(...)
3740 for i = 1, select("#", ...) do
3741 local value = select(i, ...)
3742 if(type(value) == "table")
3743 then
3744 EmitTable(value)
3745 else
3746 EmitMessage(tostring (value))
3747 end
3748 end
3749end
3750
3751-- Rewrite of core function
3752function ZO_TabButton_Text_SetTextColor(self, color)
3753
3754 local r, g, b, a = ConvertHexToRGBA(db.colours.tabwarning)
3755
3756 if(self.allowLabelColorChanges) then
3757 local label = GetControl(self, "Text")
3758 label:SetColor(r, g, b, a)
3759 end
3760
3761end
3762
3763-- Rewrite of (local) core function
3764local function GetOfficerChannelErrorFunction(guildIndex)
3765 return function()
3766 if(GetNumGuilds() < guildIndex) then
3767 return zo_strformat(SI_CANT_GUILD_CHAT_NOT_IN_GUILD, guildIndex)
3768 else
3769 return zo_strformat(SI_CANT_OFFICER_CHAT_NO_PERMISSION, GetGuildName(guildIndex))
3770 end
3771 end
3772end
3773
3774-- Rewrite of (local) core function
3775local function GetGuildChannelErrorFunction(guildIndex)
3776 return function()
3777 if(GetNumGuilds() < guildIndex) then
3778 return zo_strformat(SI_CANT_GUILD_CHAT_NOT_IN_GUILD, guildIndex)
3779 else
3780 return zo_strformat(SI_CANT_GUILD_CHAT_NO_PERMISSION, GetGuildName(guildIndex))
3781 end
3782 end
3783end
3784
3785local FILTERS_PER_ROW = 2
3786
3787-- defines the ordering of the filter categories
3788local CHANNEL_ORDERING_WEIGHT = {
3789 [CHAT_CATEGORY_SAY] = 10,
3790 [CHAT_CATEGORY_YELL] = 20,
3791
3792 [CHAT_CATEGORY_WHISPER_INCOMING] = 30,
3793 [CHAT_CATEGORY_PARTY] = 40,
3794
3795 [CHAT_CATEGORY_EMOTE] = 50,
3796 [CHAT_CATEGORY_MONSTER_SAY] = 60,
3797
3798 [CHAT_CATEGORY_ZONE] = 80,
3799 [CHAT_CATEGORY_ZONE_ENGLISH] = 90,
3800
3801 [CHAT_CATEGORY_ZONE_FRENCH] = 100,
3802 [CHAT_CATEGORY_ZONE_GERMAN] = 110,
3803
3804 [CHAT_CATEGORY_ZONE_JAPANESE] = 120,
3805 [CHAT_CATEGORY_SYSTEM] = 130,
3806}
3807
3808local function FilterComparator(left, right)
3809 local leftPrimaryCategory = left.channels[1]
3810 local rightPrimaryCategory = right.channels[1]
3811
3812 local leftWeight = CHANNEL_ORDERING_WEIGHT[leftPrimaryCategory]
3813 local rightWeight = CHANNEL_ORDERING_WEIGHT[rightPrimaryCategory]
3814
3815 if leftWeight and rightWeight then
3816 return leftWeight < rightWeight
3817 elseif not leftWeight and not rightWeight then
3818 return false
3819 elseif leftWeight then
3820 return true
3821 end
3822
3823 return false
3824end
3825
3826local SKIP_CHANNELS = {
3827 -- [CHAT_CATEGORY_SYSTEM] = true,
3828 [CHAT_CATEGORY_GUILD_1] = true,
3829 [CHAT_CATEGORY_GUILD_2] = true,
3830 [CHAT_CATEGORY_GUILD_3] = true,
3831 [CHAT_CATEGORY_GUILD_4] = true,
3832 [CHAT_CATEGORY_GUILD_5] = true,
3833 [CHAT_CATEGORY_OFFICER_1] = true,
3834 [CHAT_CATEGORY_OFFICER_2] = true,
3835 [CHAT_CATEGORY_OFFICER_3] = true,
3836 [CHAT_CATEGORY_OFFICER_4] = true,
3837 [CHAT_CATEGORY_OFFICER_5] = true,
3838}
3839
3840local FILTER_PAD_X = 90
3841local FILTER_PAD_Y = 0
3842local FILTER_WIDTH = 150
3843local FILTER_HEIGHT = 27
3844local INITIAL_XOFFS = 0
3845local INITIAL_YOFFS = 0
3846
3847-- Rewrite of a core data
3848local COMBINED_CHANNELS = {
3849 [CHAT_CATEGORY_WHISPER_INCOMING] = {parentChannel = CHAT_CATEGORY_WHISPER_INCOMING, name = SI_CHAT_CHANNEL_NAME_WHISPER},
3850 [CHAT_CATEGORY_WHISPER_OUTGOING] = {parentChannel = CHAT_CATEGORY_WHISPER_INCOMING, name = SI_CHAT_CHANNEL_NAME_WHISPER},
3851
3852 [CHAT_CATEGORY_MONSTER_SAY] = {parentChannel = CHAT_CATEGORY_MONSTER_SAY, name = SI_CHAT_CHANNEL_NAME_NPC},
3853 [CHAT_CATEGORY_MONSTER_YELL] = {parentChannel = CHAT_CATEGORY_MONSTER_SAY, name = SI_CHAT_CHANNEL_NAME_NPC},
3854 [CHAT_CATEGORY_MONSTER_WHISPER] = {parentChannel = CHAT_CATEGORY_MONSTER_SAY, name = SI_CHAT_CHANNEL_NAME_NPC},
3855 [CHAT_CATEGORY_MONSTER_EMOTE] = {parentChannel = CHAT_CATEGORY_MONSTER_SAY, name = SI_CHAT_CHANNEL_NAME_NPC},
3856}
3857
3858-- Rewrite of a core function. Nothing is changed except in SKIP_CHANNELS set a above
3859function CHAT_OPTIONS:InitializeFilterButtons(dialogControl)
3860 --generate a table of entry data from the chat category header information
3861 local entryData = {}
3862 local lastEntry = CHAT_CATEGORY_HEADER_COMBAT - 1
3863
3864 for i = CHAT_CATEGORY_HEADER_CHANNELS, lastEntry do
3865 if(SKIP_CHANNELS[i] == nil and GetString("SI_CHATCHANNELCATEGORIES", i) ~= "") then
3866
3867 if(COMBINED_CHANNELS[i] == nil) then
3868 entryData[i] =
3869 {
3870 channels = { i },
3871 name = GetString("SI_CHATCHANNELCATEGORIES", i),
3872 }
3873 else
3874 --create the entry for those with combined channels just once
3875 local parentChannel = COMBINED_CHANNELS[i].parentChannel
3876
3877 if(not entryData[parentChannel]) then
3878 entryData[parentChannel] =
3879 {
3880 channels = { },
3881 name = GetString(COMBINED_CHANNELS[i].name),
3882 }
3883 end
3884
3885 table.insert(entryData[parentChannel].channels, i)
3886 end
3887 end
3888 end
3889
3890 --now generate and anchor buttons
3891 local filterAnchor = ZO_Anchor:New(TOPLEFT, self.filterSection, TOPLEFT, 0, 0)
3892 local count = 0
3893
3894 local sortedEntries = {}
3895 for _, entry in pairs(entryData) do
3896 sortedEntries[#sortedEntries + 1] = entry
3897 end
3898
3899 table.sort(sortedEntries, FilterComparator)
3900
3901 for _, entry in ipairs(sortedEntries) do
3902 local filter, key = self.filterPool:AcquireObject()
3903 filter.key = key
3904
3905 local button = filter:GetNamedChild("Check")
3906 button.channels = entry.channels
3907 table.insert(self.filterButtons, button)
3908
3909 local label = filter:GetNamedChild("Label")
3910 label:SetText(entry.name)
3911
3912 ZO_Anchor_BoxLayout(filterAnchor, filter, count, FILTERS_PER_ROW, FILTER_PAD_X, FILTER_PAD_Y, FILTER_WIDTH, FILTER_HEIGHT, INITIAL_XOFFS, INITIAL_YOFFS)
3913 count = count + 1
3914 end
3915end
3916
3917-- Rewrite of core data
3918-- Added "id" key with raw values here because of partial overwriting
3919local channelInfo =
3920{
3921 [CHAT_CHANNEL_SAY] = {
3922 format = SI_CHAT_MESSAGE_SAY,
3923 name = GetString(SI_CHAT_CHANNEL_NAME_SAY),
3924 playerLinkable = true,
3925 channelLinkable = true,
3926 switches = GetString(SI_CHANNEL_SWITCH_SAY),
3927 id = CHAT_CHANNEL_SAY
3928 },
3929 [CHAT_CHANNEL_YELL] =
3930 {
3931 format = SI_CHAT_MESSAGE_YELL,
3932 name = GetString(SI_CHAT_CHANNEL_NAME_YELL),
3933 playerLinkable = true,
3934 channelLinkable = true, -- Modified
3935 switches = GetString(SI_CHANNEL_SWITCH_YELL),
3936 id = CHAT_CHANNEL_YELL
3937 },
3938 [CHAT_CHANNEL_ZONE] =
3939 {
3940 format = SI_CHAT_MESSAGE_ZONE,
3941 name = GetString(SI_CHAT_CHANNEL_NAME_ZONE),
3942 playerLinkable = true,
3943 channelLinkable = true, -- Modified
3944 switches = GetString(SI_CHANNEL_SWITCH_ZONE),
3945 id = CHAT_CHANNEL_ZONE
3946 },
3947 [CHAT_CHANNEL_ZONE_LANGUAGE_1] =
3948 {
3949 format = SI_CHAT_MESSAGE_ZONE_ENGLISH,
3950 name = GetString(SI_CHAT_CHANNEL_NAME_ZONE_ENGLISH),
3951 playerLinkable = true,
3952 channelLinkable = true, -- Modified
3953 switches = GetString(SI_CHANNEL_SWITCH_ZONE_ENGLISH),
3954 id = CHAT_CHANNEL_ZONE_LANGUAGE_1
3955 },
3956 [CHAT_CHANNEL_ZONE_LANGUAGE_2] =
3957 {
3958 format = SI_CHAT_MESSAGE_ZONE_FRENCH,
3959 name = GetString(SI_CHAT_CHANNEL_NAME_ZONE_FRENCH),
3960 playerLinkable = true,
3961 channelLinkable = true, -- Modified
3962 switches = GetString(SI_CHANNEL_SWITCH_ZONE_FRENCH),
3963 id = CHAT_CHANNEL_ZONE_LANGUAGE_2
3964 },
3965 [CHAT_CHANNEL_ZONE_LANGUAGE_3] =
3966 {
3967 format = SI_CHAT_MESSAGE_ZONE_GERMAN,
3968 name = GetString(SI_CHAT_CHANNEL_NAME_ZONE_GERMAN),
3969 playerLinkable = true,
3970 channelLinkable = true, -- Modified
3971 switches = GetString(SI_CHANNEL_SWITCH_ZONE_GERMAN),
3972 id = CHAT_CHANNEL_ZONE_LANGUAGE_3
3973 },
3974 [CHAT_CHANNEL_ZONE_LANGUAGE_4] =
3975 {
3976 format = SI_CHAT_MESSAGE_ZONE_JAPANESE,
3977 name = GetString(SI_CHAT_CHANNEL_NAME_ZONE_JAPANESE),
3978 playerLinkable = true,
3979 channelLinkable = true, -- Modified
3980 switches = GetString(SI_CHANNEL_SWITCH_ZONE_JAPANESE),
3981 id = CHAT_CHANNEL_ZONE_LANGUAGE_4
3982 },
3983 [CHAT_CHANNEL_PARTY] =
3984 {
3985 format = SI_CHAT_MESSAGE_PARTY,
3986 name = GetString(SI_CHAT_CHANNEL_NAME_PARTY),
3987 playerLinkable = true,
3988 channelLinkable = true,
3989 switches = GetString(SI_CHANNEL_SWITCH_PARTY),
3990 requires = function()
3991 return IsUnitGrouped("player")
3992 end,
3993 deferRequirement = true,
3994 requirementErrorMessage = GetString(SI_GROUP_NOTIFICATION_YOU_ARE_NOT_IN_A_GROUP),
3995 id = CHAT_CHANNEL_PARTY
3996 },
3997 [CHAT_CHANNEL_WHISPER] =
3998 {
3999 format = SI_CHAT_MESSAGE_WHISPER,
4000 name = GetString(SI_CHAT_CHANNEL_NAME_WHISPER),
4001 playerLinkable = true,
4002 channelLinkable = false,
4003 switches = GetString(SI_CHANNEL_SWITCH_WHISPER),
4004 target = true,
4005 saveTarget = CHAT_CHANNEL_WHISPER,
4006 targetSwitches = GetString(SI_CHANNEL_SWITCH_WHISPER_REPLY),
4007 id = CHAT_CHANNEL_WHISPER
4008 },
4009 [CHAT_CHANNEL_WHISPER_SENT] =
4010 {
4011 format = SI_CHAT_MESSAGE_WHISPER_SENT,
4012 playerLinkable = true,
4013 channelLinkable = false,
4014 id = CHAT_CHANNEL_WHISPER_SENT
4015 },
4016 [CHAT_CHANNEL_EMOTE] =
4017 {
4018 format = SI_CHAT_EMOTE,
4019 name = GetString(SI_CHAT_CHANNEL_NAME_EMOTE),
4020 playerLinkable = true,
4021 channelLinkable = false,
4022 switches = GetString(SI_CHANNEL_SWITCH_EMOTE),
4023 id = CHAT_CHANNEL_EMOTE
4024 },
4025 [CHAT_CHANNEL_MONSTER_SAY] =
4026 {
4027 format = SI_CHAT_MONSTER_MESSAGE_SAY,
4028 playerLinkable = false,
4029 channelLinkable = false,
4030 id = CHAT_CHANNEL_MONSTER_SAY
4031 },
4032 [CHAT_CHANNEL_MONSTER_YELL] =
4033 {
4034 format = SI_CHAT_MONSTER_MESSAGE_YELL,
4035 playerLinkable = false,
4036 channelLinkable = false,
4037 id = CHAT_CHANNEL_MONSTER_YELL
4038 },
4039 [CHAT_CHANNEL_MONSTER_WHISPER] =
4040 {
4041 format = SI_CHAT_MONSTER_MESSAGE_WHISPER,
4042 playerLinkable = false,
4043 channelLinkable = false,
4044 id = CHAT_CHANNEL_MONSTER_WHISPER
4045 },
4046 [CHAT_CHANNEL_MONSTER_EMOTE] =
4047 {
4048 format = SI_CHAT_MONSTER_EMOTE,
4049 playerLinkable = false,
4050 channelLinkable = false,
4051 id = CHAT_CHANNEL_MONSTER_EMOTE
4052 },
4053 [CHAT_CHANNEL_SYSTEM] =
4054 {
4055 format = SI_CHAT_MESSAGE_SYSTEM,
4056 playerLinkable = false,
4057 channelLinkable = false,
4058 id = CHAT_CHANNEL_SYSTEM
4059 },
4060 [CHAT_CHANNEL_GUILD_1] =
4061 {
4062 format = SI_CHAT_MESSAGE_GUILD,
4063 dynamicName = true,
4064 playerLinkable = true,
4065 channelLinkable = true,
4066 switches = GetString(SI_CHANNEL_SWITCH_GUILD_1),
4067 requires = CanWriteGuildChannel,
4068 requirementErrorMessage = GetGuildChannelErrorFunction(1),
4069 deferRequirement = true,
4070 id = CHAT_CHANNEL_GUILD_1
4071 },
4072 [CHAT_CHANNEL_GUILD_2] =
4073 {
4074 format = SI_CHAT_MESSAGE_GUILD,
4075 dynamicName = true,
4076 playerLinkable = true,
4077 channelLinkable = true,
4078 switches = GetString(SI_CHANNEL_SWITCH_GUILD_2),
4079 requires = CanWriteGuildChannel,
4080 requirementErrorMessage = GetGuildChannelErrorFunction(2),
4081 deferRequirement = true,
4082 id = CHAT_CHANNEL_GUILD_2
4083 },
4084 [CHAT_CHANNEL_GUILD_3] =
4085 {
4086 format = SI_CHAT_MESSAGE_GUILD,
4087 dynamicName = true,
4088 playerLinkable = true,
4089 channelLinkable = true,
4090 switches = GetString(SI_CHANNEL_SWITCH_GUILD_3),
4091 requires = CanWriteGuildChannel,
4092 requirementErrorMessage = GetGuildChannelErrorFunction(3),
4093 deferRequirement = true,
4094 id = CHAT_CHANNEL_GUILD_3
4095 },
4096 [CHAT_CHANNEL_GUILD_4] =
4097 {
4098 format = SI_CHAT_MESSAGE_GUILD,
4099 dynamicName = true,
4100 playerLinkable = true,
4101 channelLinkable = true,
4102 switches = GetString(SI_CHANNEL_SWITCH_GUILD_4),
4103 requires = CanWriteGuildChannel,
4104 requirementErrorMessage = GetGuildChannelErrorFunction(4),
4105 deferRequirement = true,
4106 id = CHAT_CHANNEL_GUILD_4
4107 },
4108 [CHAT_CHANNEL_GUILD_5] =
4109 {
4110 format = SI_CHAT_MESSAGE_GUILD,
4111 dynamicName = true,
4112 playerLinkable = true,
4113 channelLinkable = true,
4114 switches = GetString(SI_CHANNEL_SWITCH_GUILD_5),
4115 requires = CanWriteGuildChannel,
4116 requirementErrorMessage = GetGuildChannelErrorFunction(5),
4117 deferRequirement = true,
4118 id = CHAT_CHANNEL_GUILD_5
4119 },
4120 [CHAT_CHANNEL_OFFICER_1] =
4121 {
4122 format = SI_CHAT_MESSAGE_GUILD,
4123 dynamicName = true,
4124 playerLinkable = true,
4125 channelLinkable = true,
4126 switches = GetString(SI_CHANNEL_SWITCH_OFFICER_1),
4127 requires = CanWriteGuildChannel,
4128 requirementErrorMessage = GetOfficerChannelErrorFunction(1),
4129 deferRequirement = true,
4130 id = CHAT_CHANNEL_OFFICER_1
4131 },
4132 [CHAT_CHANNEL_OFFICER_2] =
4133 {
4134 format = SI_CHAT_MESSAGE_GUILD,
4135 dynamicName = true,
4136 playerLinkable = true,
4137 channelLinkable = true,
4138 switches = GetString(SI_CHANNEL_SWITCH_OFFICER_2),
4139 requires = CanWriteGuildChannel,
4140 requirementErrorMessage = GetOfficerChannelErrorFunction(2),
4141 deferRequirement = true,
4142 id = CHAT_CHANNEL_OFFICER_2
4143 },
4144 [CHAT_CHANNEL_OFFICER_3] =
4145 {
4146 format = SI_CHAT_MESSAGE_GUILD,
4147 dynamicName = true,
4148 playerLinkable = true,
4149 channelLinkable = true,
4150 switches = GetString(SI_CHANNEL_SWITCH_OFFICER_3),
4151 requires = CanWriteGuildChannel,
4152 requirementErrorMessage = GetOfficerChannelErrorFunction(3),
4153 deferRequirement = true,
4154 id = CHAT_CHANNEL_OFFICER_3
4155 },
4156 [CHAT_CHANNEL_OFFICER_4] =
4157 {
4158 format = SI_CHAT_MESSAGE_GUILD,
4159 dynamicName = true,
4160 playerLinkable = true,
4161 channelLinkable = true,
4162 switches = GetString(SI_CHANNEL_SWITCH_OFFICER_4),
4163 requires = CanWriteGuildChannel,
4164 requirementErrorMessage = GetOfficerChannelErrorFunction(4),
4165 deferRequirement = true,
4166 id = CHAT_CHANNEL_OFFICER_4
4167 },
4168 [CHAT_CHANNEL_OFFICER_5] =
4169 {
4170 format = SI_CHAT_MESSAGE_GUILD,
4171 dynamicName = true,
4172 playerLinkable = true,
4173 channelLinkable = true,
4174 switches = GetString(SI_CHANNEL_SWITCH_OFFICER_5),
4175 requires = CanWriteGuildChannel,
4176 requirementErrorMessage = GetOfficerChannelErrorFunction(5),
4177 deferRequirement = true,
4178 id = CHAT_CHANNEL_OFFICER_5
4179 },
4180}
4181
4182-- Rewrite of core function
4183function ZO_ChatSystem_GetChannelInfo()
4184 return channelInfo
4185end
4186
4187-- Save chat configuration
4188local function SaveChatConfig()
4189
4190 if not pChatData.tabNotBefore then
4191 pChatData.tabNotBefore = {} -- Init here or in SyncChatConfig depending if the "Clear Tab" has been used
4192 end
4193
4194 if isAddonLoaded and CHAT_SYSTEM and CHAT_SYSTEM.primaryContainer then -- Some addons calls SetCVar before
4195
4196 -- Rewrite the whole char tab
4197 db.chatConfSync[pChatData.localPlayer] = {}
4198
4199 -- Save Chat positions
4200 db.chatConfSync[pChatData.localPlayer].relPoint = CHAT_SYSTEM.primaryContainer.settings.relPoint
4201 db.chatConfSync[pChatData.localPlayer].x = CHAT_SYSTEM.primaryContainer.settings.x
4202 db.chatConfSync[pChatData.localPlayer].y = CHAT_SYSTEM.primaryContainer.settings.y
4203 db.chatConfSync[pChatData.localPlayer].height = CHAT_SYSTEM.primaryContainer.settings.height
4204 db.chatConfSync[pChatData.localPlayer].width = CHAT_SYSTEM.primaryContainer.settings.width
4205 db.chatConfSync[pChatData.localPlayer].point = CHAT_SYSTEM.primaryContainer.settings.point
4206
4207 --db.chatConfSync[pChatData.localPlayer].textEntryDocked = true
4208
4209 -- Don't overflow screen, remove 10px.
4210 if CHAT_SYSTEM.primaryContainer.settings.height >= ( CHAT_SYSTEM.maxContainerHeight - 15 ) then
4211 db.chatConfSync[pChatData.localPlayer].height = ( CHAT_SYSTEM.maxContainerHeight - 15 )
4212 else
4213 db.chatConfSync[pChatData.localPlayer].height = CHAT_SYSTEM.primaryContainer.settings.height
4214 end
4215
4216 -- Same
4217 if CHAT_SYSTEM.primaryContainer.settings.width >= ( CHAT_SYSTEM.maxContainerWidth - 15 ) then
4218 db.chatConfSync[pChatData.localPlayer].width = ( CHAT_SYSTEM.maxContainerWidth - 15 )
4219 else
4220 db.chatConfSync[pChatData.localPlayer].width = CHAT_SYSTEM.primaryContainer.settings.width
4221 end
4222
4223 -- Save Colors
4224 db.chatConfSync[pChatData.localPlayer].colors = {}
4225
4226 for _, category in ipairs (pChatData.chatCategories) do
4227 local r, g, b = GetChatCategoryColor(category)
4228 db.chatConfSync[pChatData.localPlayer].colors[category] = { red = r, green = g, blue = b }
4229 end
4230
4231 -- Save Font Size
4232 db.chatConfSync[pChatData.localPlayer].fontSize = GetChatFontSize()
4233
4234 -- Save Tabs
4235 db.chatConfSync[pChatData.localPlayer].tabs = {}
4236
4237 -- GetNumChatContainerTabs(1) don't refresh its number before a ReloadUI
4238 -- for numTab = 1, GetNumChatContainerTabs(1) do
4239 for numTab in ipairs (CHAT_SYSTEM.primaryContainer.windows) do
4240
4241 db.chatConfSync[pChatData.localPlayer].tabs[numTab] = {}
4242
4243 -- Save "Clear Tab" flag
4244 if pChatData.tabNotBefore[numTab] then
4245 db.chatConfSync[pChatData.localPlayer].tabs[numTab].notBefore = pChatData.tabNotBefore[numTab]
4246 end
4247
4248 -- No.. need a ReloadUI local name, isLocked, isInteractable, isCombatLog, areTimestampsEnabled = GetChatContainerTabInfo(1, numTab)
4249 -- IsLocked
4250 if CHAT_SYSTEM.primaryContainer:IsLocked(numTab) then
4251 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isLocked = true
4252 else
4253 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isLocked = false
4254 end
4255
4256 -- IsInteractive
4257 if CHAT_SYSTEM.primaryContainer:IsInteractive(numTab) then
4258 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isInteractable = true
4259 else
4260 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isInteractable = false
4261 end
4262
4263 -- IsCombatLog
4264 if CHAT_SYSTEM.primaryContainer:IsCombatLog(numTab) then
4265 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isCombatLog = true
4266 -- AreTimestampsEnabled
4267 if CHAT_SYSTEM.primaryContainer:AreTimestampsEnabled(numTab) then
4268 db.chatConfSync[pChatData.localPlayer].tabs[numTab].areTimestampsEnabled = true
4269 else
4270 db.chatConfSync[pChatData.localPlayer].tabs[numTab].areTimestampsEnabled = false
4271 end
4272 else
4273 db.chatConfSync[pChatData.localPlayer].tabs[numTab].isCombatLog = false
4274 db.chatConfSync[pChatData.localPlayer].tabs[numTab].areTimestampsEnabled = false
4275 end
4276
4277 -- GetTabName
4278 db.chatConfSync[pChatData.localPlayer].tabs[numTab].name = CHAT_SYSTEM.primaryContainer:GetTabName(numTab)
4279
4280 -- Enabled categories
4281 db.chatConfSync[pChatData.localPlayer].tabs[numTab].enabledCategories = {}
4282
4283 for _, category in ipairs (pChatData.chatCategories) do
4284 local isEnabled = IsChatContainerTabCategoryEnabled(1, numTab, category)
4285 db.chatConfSync[pChatData.localPlayer].tabs[numTab].enabledCategories[category] = isEnabled
4286 end
4287
4288 end
4289
4290 db.chatConfSync.lastChar = db.chatConfSync[pChatData.localPlayer]
4291
4292 end
4293
4294end
4295
4296-- Save Chat Tabs config when user changes it
4297local function SaveTabsCategories()
4298
4299 for numTab in ipairs (CHAT_SYSTEM.primaryContainer.windows) do
4300
4301 for _, category in ipairs (pChatData.guildCategories) do
4302 local isEnabled = IsChatContainerTabCategoryEnabled(1, numTab, category)
4303 if db.chatConfSync[pChatData.localPlayer].tabs[numTab] then
4304 db.chatConfSync[pChatData.localPlayer].tabs[numTab].enabledCategories[category] = isEnabled
4305 else
4306 SaveChatConfig()
4307 end
4308 end
4309
4310 end
4311
4312end
4313
4314-- Function for Minimizing chat at launch
4315local function MinimizeChatAtLaunch()
4316 if db.chatMinimizedAtLaunch then
4317 CHAT_SYSTEM:Minimize()
4318 end
4319end
4320
4321local function MinimizeChatInMenus()
4322
4323 -- RegisterCallback for Maximize/Minimize chat when entering/leaving scenes
4324 -- "hud" is base scene (with "hudui")
4325 local hudScene = SCENE_MANAGER:GetScene("hud")
4326 hudScene:RegisterCallback("StateChange", function(oldState, newState)
4327
4328 if db.chatMinimizedInMenus then
4329 if newState == SCENE_HIDDEN and SCENE_MANAGER:GetNextScene():GetName() ~= "hudui" then
4330 CHAT_SYSTEM:Minimize()
4331 end
4332 end
4333
4334 if db.chatMaximizedAfterMenus then
4335 if newState == SCENE_SHOWING then
4336 CHAT_SYSTEM:Maximize()
4337 end
4338 end
4339
4340 end)
4341
4342end
4343
4344-- Set the chat config from pChat settings
4345local function SyncChatConfig(shouldSync, whichChar)
4346
4347 if shouldSync then
4348 if db.chatConfSync then
4349 if db.chatConfSync[whichChar] then
4350
4351 -- Position and width/height
4352 CHAT_SYSTEM.control:SetAnchor(db.chatConfSync[whichChar].point, GuiRoot, db.chatConfSync[whichChar].relPoint, db.chatConfSync[whichChar].x, db.chatConfSync[whichChar].y)
4353 -- Height / Width
4354 CHAT_SYSTEM.control:SetDimensions(db.chatConfSync[whichChar].width, db.chatConfSync[whichChar].height)
4355
4356 -- Save settings immediatly (to check, maybe call function which do this)
4357 CHAT_SYSTEM.primaryContainer.settings.height = db.chatConfSync[whichChar].height
4358 CHAT_SYSTEM.primaryContainer.settings.point = db.chatConfSync[whichChar].point
4359 CHAT_SYSTEM.primaryContainer.settings.relPoint = db.chatConfSync[whichChar].relPoint
4360 CHAT_SYSTEM.primaryContainer.settings.width = db.chatConfSync[whichChar].width
4361 CHAT_SYSTEM.primaryContainer.settings.x = db.chatConfSync[whichChar].x
4362 CHAT_SYSTEM.primaryContainer.settings.y = db.chatConfSync[whichChar].y
4363
4364 --[[
4365 -- Don't overflow screen, remove 15px.
4366 if db.chatConfSync[whichChar].height >= (CHAT_SYSTEM.maxContainerHeight - 15 ) then
4367 CHAT_SYSTEM.control:SetHeight((CHAT_SYSTEM.maxContainerHeight - 15 ))
4368 d("Overflow height " .. db.chatConfSync[whichChar].height .. " -+- " .. (CHAT_SYSTEM.maxContainerHeight - 15))
4369 d(CHAT_SYSTEM.control:GetHeight())
4370 else
4371 -- Don't set good values ?! SetHeight(674) = GetHeight(524) ? same with Width and resizing is buggy
4372 --CHAT_SYSTEM.control:SetHeight(db.chatConfSync[whichChar].height)
4373 CHAT_SYSTEM.control:SetDimensions(settings.width, settings.height)
4374 d("height " .. db.chatConfSync[whichChar].height .. " -+- " .. CHAT_SYSTEM.control:GetHeight())
4375 end
4376
4377 -- Same
4378 if db.chatConfSync[whichChar].width >= (CHAT_SYSTEM.maxContainerWidth - 15 ) then
4379 CHAT_SYSTEM.control:SetWidth((CHAT_SYSTEM.maxContainerWidth - 15 ))
4380 d("Overflow width " .. db.chatConfSync[whichChar].width .. " -+- " .. (CHAT_SYSTEM.maxContainerWidth - 15))
4381 d(CHAT_SYSTEM.control:GetWidth())
4382 else
4383 CHAT_SYSTEM.control:SetHeight(db.chatConfSync[whichChar].width)
4384 d("width " .. db.chatConfSync[whichChar].width .. " -+- " .. CHAT_SYSTEM.control:GetWidth())
4385 end
4386 ]]--
4387
4388 -- Colors
4389 for _, category in ipairs (pChatData.chatCategories) do
4390 if not db.chatConfSync[whichChar].colors[category] then
4391 local r, g, b = GetChatCategoryColor(category)
4392 db.chatConfSync[whichChar].colors[category] = { red = r, green = g, blue = b }
4393 end
4394 SetChatCategoryColor(category, db.chatConfSync[whichChar].colors[category].red, db.chatConfSync[whichChar].colors[category].green, db.chatConfSync[whichChar].colors[category].blue)
4395 end
4396
4397 -- Font Size
4398 -- Not in Realtime SetChatFontSize(db.chatConfSync[whichChar].fontSize), need to add CHAT_SYSTEM:SetFontSize for Realtimed
4399
4400 -- ?!? Need to go by a local?..
4401 local fontSize = db.chatConfSync[whichChar].fontSize
4402 CHAT_SYSTEM:SetFontSize(fontSize)
4403 SetChatFontSize(db.chatConfSync[whichChar].fontSize)
4404 local chatSyncNumTab = 1
4405
4406 for numTab in ipairs(db.chatConfSync[whichChar].tabs) do
4407
4408 --Create a Tab if nessesary
4409 if (GetNumChatContainerTabs(1) < numTab) then
4410 -- AddChatContainerTab(1, , db.chatConfSync[whichChar].tabs[numTab].isCombatLog) No ! Require a ReloadUI
4411 CHAT_SYSTEM.primaryContainer:AddWindow(db.chatConfSync[whichChar].tabs[numTab].name)
4412 end
4413
4414 if db.chatConfSync[whichChar].tabs[numTab] and db.chatConfSync[whichChar].tabs[numTab].notBefore then
4415
4416 if not pChatData.tabNotBefore then
4417 pChatData.tabNotBefore = {} -- Used for tab restoration, init here.
4418 end
4419
4420 pChatData.tabNotBefore[numTab] = db.chatConfSync[whichChar].tabs[numTab].notBefore
4421
4422 end
4423
4424 -- Set Tab options
4425 -- Not in realtime : SetChatContainerTabInfo(1, numTab, db.chatConfSync[whichChar].tabs[numTab].name, db.chatConfSync[whichChar].tabs[numTab].isLocked, db.chatConfSync[whichChar].tabs[numTab].isInteractable, db.chatConfSync[whichChar].tabs[numTab].areTimestampsEnabled)
4426
4427 CHAT_SYSTEM.primaryContainer:SetTabName(numTab, db.chatConfSync[whichChar].tabs[numTab].name)
4428 CHAT_SYSTEM.primaryContainer:SetLocked(numTab, db.chatConfSync[whichChar].tabs[numTab].isLocked)
4429 CHAT_SYSTEM.primaryContainer:SetInteractivity(numTab, db.chatConfSync[whichChar].tabs[numTab].isInteractable)
4430 CHAT_SYSTEM.primaryContainer:SetTimestampsEnabled(numTab, db.chatConfSync[whichChar].tabs[numTab].areTimestampsEnabled)
4431
4432 -- Set Channel per tab configuration
4433 for _, category in ipairs (pChatData.chatCategories) do
4434 if db.chatConfSync[whichChar].tabs[numTab].enabledCategories[category] == nil then -- Cal be false
4435 db.chatConfSync[whichChar].tabs[numTab].enabledCategories[category] = IsChatContainerTabCategoryEnabled(1, numTab, category)
4436 end
4437 SetChatContainerTabCategoryEnabled(1, numTab, category, db.chatConfSync[whichChar].tabs[numTab].enabledCategories[category])
4438 end
4439
4440 chatSyncNumTab = numTab
4441
4442 end
4443
4444 -- If they're was too many tabs before, drop them
4445 local removeTabs = true
4446 while removeTabs do
4447 -- Too many tabs, deleting one
4448 if GetNumChatContainerTabs(1) > chatSyncNumTab then
4449 -- Not in realtime : RemoveChatContainerTab(1, chatSyncNumTab + 1)
4450 CHAT_SYSTEM.primaryContainer:RemoveWindow(chatSyncNumTab + 1, nil)
4451 else
4452 removeTabs = false
4453 end
4454 end
4455
4456 end
4457 end
4458 end
4459
4460end
4461
4462-- When creating a char, try to import settings
4463local function AutoSyncSettingsForNewPlayer()
4464
4465 -- New chars get automaticaly last char config
4466 if GetIsNewCharacter() then
4467 SyncChatConfig(true, "lastChar")
4468 end
4469
4470end
4471
4472-- Set channel to the default one
4473local function SetToDefaultChannel()
4474 if db.defaultchannel ~= PCHAT_CHANNEL_NONE then
4475 CHAT_SYSTEM:SetChannel(db.defaultchannel)
4476 end
4477end
4478
4479local function SaveGuildIndexes()
4480
4481 pChatData.guildIndexes = {}
4482
4483 for guild = 1, GetNumGuilds() do
4484
4485 -- Guildname
4486 local guildId = GetGuildId(guild)
4487 local guildName = GetGuildName(guildId)
4488
4489 -- Occurs sometimes
4490 if(not guildName or (guildName):len() < 1) then
4491 guildName = "Guild " .. guildId
4492 end
4493
4494 pChatData.guildIndexes[guildName] = guild
4495
4496 end
4497
4498end
4499
4500-- Executed when EVENT_IGNORE_ADDED triggers
4501local function OnIgnoreAdded(displayName)
4502
4503 -- DisplayName is linkable
4504 local displayNameLink = ZO_LinkHandler_CreateDisplayNameLink(displayName)
4505 local statusMessage = zo_strformat(SI_FRIENDS_LIST_IGNORE_ADDED, displayNameLink)
4506
4507 -- Only if statusMessage is set
4508 if statusMessage then
4509 return FormatSysMessage(statusMessage)
4510 end
4511
4512end
4513
4514-- Executed when EVENT_IGNORE_REMOVED triggers
4515local function OnIgnoreRemoved(displayName)
4516
4517 -- DisplayName is linkable
4518 local displayNameLink = ZO_LinkHandler_CreateDisplayNameLink(displayName)
4519 local statusMessage = zo_strformat(SI_FRIENDS_LIST_IGNORE_REMOVED, displayNameLink)
4520
4521 -- Only if statusMessage is set
4522 if statusMessage then
4523 return FormatSysMessage(statusMessage)
4524 end
4525
4526end
4527
4528-- triggers when EVENT_FRIEND_PLAYER_STATUS_CHANGED
4529local function OnFriendPlayerStatusChanged(displayName, characterName, oldStatus, newStatus)
4530
4531 local statusMessage
4532
4533 -- DisplayName is linkable
4534 local displayNameLink = ZO_LinkHandler_CreateDisplayNameLink(displayName)
4535 -- CharacterName is linkable
4536 local characterNameLink = ZO_LinkHandler_CreateCharacterLink(characterName)
4537
4538 local wasOnline = oldStatus ~= PLAYER_STATUS_OFFLINE
4539 local isOnline = newStatus ~= PLAYER_STATUS_OFFLINE
4540
4541 -- Not connected before and Connected now (no messages for Away/Busy)
4542 if not wasOnline and isOnline then
4543 -- Return
4544 statusMessage = zo_strformat(SI_FRIENDS_LIST_FRIEND_CHARACTER_LOGGED_ON, displayNameLink, characterNameLink)
4545 -- Connected before and Offline now
4546 elseif wasOnline and not isOnline then
4547 statusMessage = zo_strformat(SI_FRIENDS_LIST_FRIEND_CHARACTER_LOGGED_OFF, displayNameLink, characterNameLink)
4548 end
4549
4550 -- Only if statusMessage is set
4551 if statusMessage then
4552 return FormatSysMessage(statusMessage)
4553 end
4554
4555end
4556
4557-- Executed when EVENT_GROUP_TYPE_CHANGED triggers
4558local function OnGroupTypeChanged(largeGroup)
4559
4560 if largeGroup then
4561 return FormatSysMessage(GetString(SI_CHAT_ANNOUNCEMENT_IN_LARGE_GROUP))
4562 else
4563 return FormatSysMessage(GetString(SI_CHAT_ANNOUNCEMENT_IN_SMALL_GROUP))
4564 end
4565
4566end
4567
4568local function OnGroupMemberLeft(_, reason, isLocalPlayer, _, _, actionRequiredVote)
4569 if reason == GROUP_LEAVE_REASON_KICKED and isLocalPlayer and actionRequiredVote then
4570 return GetString(SI_GROUP_ELECTION_KICK_PLAYER_PASSED)
4571 end
4572end
4573
4574local function UpdateCharCorrespondanceTableSwitchs()
4575
4576 -- Each guild
4577 for i = 1, GetNumGuilds() do
4578
4579 -- Get saved string
4580 local switch = db.switchFor[GetGuildName(GetGuildId(i))]
4581
4582 if switch and switch ~= "" then
4583 switch = GetString(SI_CHANNEL_SWITCH_GUILD_1 - 1 + i) .. " " .. switch
4584 else
4585 switch = GetString(SI_CHANNEL_SWITCH_GUILD_1 - 1 + i)
4586 end
4587
4588 ChanInfoArray[CHAT_CHANNEL_GUILD_1 - 1 + i].switches = switch
4589
4590 -- Get saved string
4591 local officerSwitch = db.officerSwitchFor[GetGuildName(GetGuildId(i))]
4592
4593 -- No SavedVar
4594 if officerSwitch and officerSwitch ~= "" then
4595 officerSwitch = GetString(SI_CHANNEL_SWITCH_OFFICER_1 - 1 + i) .. " " .. officerSwitch
4596 else
4597 officerSwitch = GetString(SI_CHANNEL_SWITCH_OFFICER_1 - 1 + i)
4598 end
4599
4600 ChanInfoArray[CHAT_CHANNEL_OFFICER_1 - 1 + i].switches = officerSwitch
4601
4602 end
4603
4604end
4605
4606-- *********************************************************************************
4607-- * Section: LAM Outside Functions : used in LAM but function resides outside LAM
4608-- *********************************************************************************
4609-- Character Sync
4610local function SyncCharacterSelectChoices()
4611 -- Sync Character Select
4612 pChatData.chatConfSyncChoices = {}
4613 if db.chatConfSync then
4614 for names, tagada in pairs (db.chatConfSync) do
4615 if names ~= "lastChar" then
4616 table.insert(pChatData.chatConfSyncChoices, names)
4617 end
4618 end
4619 else
4620 table.insert(pChatData.chatConfSyncChoices, pChatData.localPlayer)
4621 end
4622end
4623
4624
4625-- *********************************************************************************
4626-- * Section: Settings Start (LAM)
4627-- *********************************************************************************
4628-- Build LAM Option Table, used when AddonLoads or when a player join/leave a guild
4629local function BuildLAMPanel()
4630
4631 local function UpdateSoundDescription(soundType, newSoundIndex)
4632 --Whisper sound
4633 if soundType == "whisper" then
4634 newSoundIndex = newSoundIndex or db.notifyIMIndex
4635 pChatLAMWhisperSoundSlider.label:SetText(GetString(PCHAT_SOUNDFORINCWHISPS) .. ": " .. tostring(pChat.sounds[newSoundIndex]))
4636 end
4637 end
4638
4639 --LAM 2.0 callback function if the panel was created
4640 local pChatLAMPanelCreated = function(panel)
4641 if panel == pChat.LAMPanel then
4642 UpdateSoundDescription("whisper")
4643 end
4644 end
4645 CALLBACK_MANAGER:RegisterCallback("LAM-PanelControlsCreated", pChatLAMPanelCreated)
4646
4647
4648 -- Used to reset colors to default value, lam need a formatted array
4649 -- LAM Message Settings
4650
4651 local fontsDefined = LMP:List('font')
4652
4653 local function ConvertHexToRGBAPacked(colourString)
4654 local r, g, b, a = ConvertHexToRGBA(colourString)
4655 return {r = r, g = g, b = b, a = a}
4656 end
4657 -- Sync Character Select
4658 pChatData.chatConfSyncChoices = {}
4659 if db.chatConfSync then
4660 for names, tagada in pairs (db.chatConfSync) do
4661 if names ~= "lastChar" then
4662 table.insert(pChatData.chatConfSyncChoices, names)
4663 end
4664 end
4665 else
4666 table.insert(pChatData.chatConfSyncChoices, pChatData.localPlayer)
4667 end
4668
4669 -- CHAT_SYSTEM.primaryContainer.windows doesn't exists yet at OnAddonLoaded. So using the pChat reference.
4670 local arrayTab = {}
4671 if db.chatConfSync and db.chatConfSync[pChatData.localPlayer] and db.chatConfSync[pChatData.localPlayer].tabs then
4672 for numTab, data in pairs (db.chatConfSync[pChatData.localPlayer].tabs) do
4673 table.insert(arrayTab, numTab)
4674 end
4675 else
4676 table.insert(arrayTab, 1)
4677 end
4678
4679 getTabNames()
4680
4681
4682 --Update the available sounds from the game
4683 pChat.sounds = {}
4684 if SOUNDS then
4685 for soundName, _ in pairs(SOUNDS) do
4686 if soundName ~= "NONE" then
4687 table.insert(pChat.sounds, soundName)
4688 end
4689 end
4690 if #pChat.sounds > 0 then
4691 table.sort(pChat.sounds)
4692 table.insert(pChat.sounds, 1, "NONE")
4693 end
4694 end
4695 local optionsData = {}
4696
4697 -- Messages Settings
4698 optionsData[#optionsData + 1] = {
4699 type = "submenu",
4700 name = GetString(PCHAT_OPTIONSH),
4701 controls = {
4702 {-- LAM Option Show Guild Numbers
4703 type = "checkbox",
4704 name = GetString(PCHAT_GUILDNUMBERS),
4705 tooltip = GetString(PCHAT_GUILDNUMBERSTT),
4706 getFunc = function() return db.showGuildNumbers end,
4707 setFunc = function(newValue)
4708 db.showGuildNumbers = newValue
4709 end,
4710 width = "full",
4711 default = defaults.showGuildNumbers,
4712 },
4713 {-- LAM Option Use Same Color for all Guilds
4714 type = "checkbox",
4715 name = GetString(PCHAT_ALLGUILDSSAMECOLOUR),
4716 tooltip = GetString(PCHAT_ALLGUILDSSAMECOLOURTT),
4717 getFunc = function() return db.allGuildsSameColour end,
4718 setFunc = function(newValue) db.allGuildsSameColour = newValue end,
4719 width = "full",
4720 default = defaults.allGuildsSameColour,
4721 },
4722 {-- LAM Option Use same color for all zone chats
4723 type = "checkbox",
4724 name = GetString(PCHAT_ALLZONESSAMECOLOUR),
4725 tooltip = GetString(PCHAT_ALLZONESSAMECOLOURTT),
4726 getFunc = function() return db.allZonesSameColour end,
4727 setFunc = function(newValue) db.allZonesSameColour = newValue end,
4728 width = "full",
4729 default = defaults.allZonesSameColour,
4730 },
4731 {-- LAM Option Use same color for all NPC
4732 type = "checkbox",
4733 name = GetString(PCHAT_ALLNPCSAMECOLOUR),
4734 tooltip = GetString(PCHAT_ALLNPCSAMECOLOURTT),
4735 getFunc = function() return db.allNPCSameColour end,
4736 setFunc = function(newValue) db.allNPCSameColour = newValue end,
4737 width = "full",
4738 default = defaults.allNPCSameColour,
4739 },
4740 {-- LAM Option Remove Zone Tags
4741 type = "checkbox",
4742 name = GetString(PCHAT_DELZONETAGS),
4743 tooltip = GetString(PCHAT_DELZONETAGSTT),
4744 getFunc = function() return db.delzonetags end,
4745 setFunc = function(newValue) db.delzonetags = newValue end,
4746 width = "full",
4747 default = defaults.delzonetags,
4748 },
4749 {-- LAM Option Newline between name and message
4750 type = "checkbox",
4751 name = GetString(PCHAT_CARRIAGERETURN),
4752 tooltip = GetString(PCHAT_CARRIAGERETURNTT),
4753 getFunc = function() return db.carriageReturn end,
4754 setFunc = function(newValue) db.carriageReturn = newValue end,
4755 width = "full",
4756 default = defaults.carriageReturn,
4757 },
4758 {-- LAM Option Use ESO Colors
4759 type = "checkbox",
4760 name = GetString(PCHAT_USEESOCOLORS),
4761 tooltip = GetString(PCHAT_USEESOCOLORSTT),
4762 getFunc = function() return db.useESOcolors end,
4763 setFunc = function(newValue) db.useESOcolors = newValue end,
4764 width = "full",
4765 default = defaults.useESOcolors,
4766 },
4767 {-- LAM Option Difference Between ESO Colors
4768 type = "slider",
4769 name = GetString(PCHAT_DIFFFORESOCOLORS),
4770 tooltip = GetString(PCHAT_DIFFFORESOCOLORSTT),
4771 min = 0,
4772 max = 100,
4773 step = 1,
4774 getFunc = function() return db.diffforESOcolors end,
4775 setFunc = function(newValue) db.diffforESOcolors = newValue end,
4776 width = "full",
4777 default = defaults.diffforESOcolors,
4778 disabled = function() return not db.useESOcolors end,
4779 },
4780 {-- LAM Option Prevent Chat Fading
4781 type = "checkbox",
4782 name = GetString(PCHAT_PREVENTCHATTEXTFADING),
4783 tooltip = GetString(PCHAT_PREVENTCHATTEXTFADINGTT),
4784 getFunc = function() return db.alwaysShowChat end,
4785 setFunc = function(newValue) db.alwaysShowChat = newValue end,
4786 width = "full",
4787 default = defaults.alwaysShowChat,
4788 },
4789 {-- Augment lines of chat
4790 type = "checkbox",
4791 name = GetString(PCHAT_AUGMENTHISTORYBUFFER),
4792 tooltip = GetString(PCHAT_AUGMENTHISTORYBUFFERTT),
4793 getFunc = function() return db.augmentHistoryBuffer end,
4794 setFunc = function(newValue) db.augmentHistoryBuffer = newValue end,
4795 width = "full",
4796 default = defaults.augmentHistoryBuffer,
4797 },
4798 {-- LAM Option Use one color for lines
4799 type = "checkbox",
4800 name = GetString(PCHAT_USEONECOLORFORLINES),
4801 tooltip = GetString(PCHAT_USEONECOLORFORLINESTT),
4802 getFunc = function() return db.oneColour end,
4803 setFunc = function(newValue) db.oneColour = newValue end,
4804 width = "full",
4805 default = defaults.oneColour,
4806 },
4807 {-- LAM Option Guild Tags next to entry box
4808 type = "checkbox",
4809 name = GetString(PCHAT_GUILDTAGSNEXTTOENTRYBOX),
4810 tooltip = GetString(PCHAT_GUILDTAGSNEXTTOENTRYBOXTT),
4811 width = "full",
4812 default = defaults.showTagInEntry,
4813 getFunc = function() return db.showTagInEntry end,
4814 setFunc = function(newValue)
4815 db.showTagInEntry = newValue
4816 UpdateCharCorrespondanceTableChannelNames()
4817 end
4818 },
4819 {-- LAM Option Names Format
4820 type = "dropdown",
4821 name = GetString(PCHAT_GEOCHANNELSFORMAT),
4822 tooltip = GetString(PCHAT_GEOCHANNELSFORMATTT),
4823 choices = {GetString("PCHAT_GROUPNAMESCHOICE", 1), GetString("PCHAT_GROUPNAMESCHOICE", 2), GetString("PCHAT_GROUPNAMESCHOICE", 3)}, -- Same as group.
4824 width = "full",
4825 default = defaults.geoChannelsFormat,
4826 getFunc = function() return GetString("PCHAT_GROUPNAMESCHOICE", db.geoChannelsFormat) end,
4827 setFunc = function(choice)
4828 if choice == GetString("PCHAT_GROUPNAMESCHOICE", 1) then
4829 db.geoChannelsFormat = 1
4830 elseif choice == GetString("PCHAT_GROUPNAMESCHOICE", 2) then
4831 db.geoChannelsFormat = 2
4832 elseif choice == GetString("PCHAT_GROUPNAMESCHOICE", 3) then
4833 db.geoChannelsFormat = 3
4834 else
4835 -- When clicking on LAM default button
4836 db.geoChannelsFormat = defaults.geoChannelsFormat
4837 end
4838
4839 end,
4840 },
4841 {-- Disable Brackets
4842 type = "checkbox",
4843 name = GetString(PCHAT_DISABLEBRACKETS),
4844 tooltip = GetString(PCHAT_DISABLEBRACKETSTT),
4845 getFunc = function() return db.disableBrackets end,
4846 setFunc = function(newValue) db.disableBrackets = newValue end,
4847 width = "full",
4848 default = defaults.disableBrackets,
4849 },
4850 {--Traget Histoyr
4851 type = "checkbox",
4852 name = GetString(PCHAT_ADDCHANNELANDTARGETTOHISTORY),
4853 tooltip = GetString(PCHAT_ADDCHANNELANDTARGETTOHISTORYTT),
4854 getFunc = function() return db.addChannelAndTargetToHistory end,
4855 setFunc = function(newValue) db.addChannelAndTargetToHistory = newValue end,
4856 width = "full",
4857 default = defaults.addChannelAndTargetToHistory,
4858 },
4859 {-- URL is clickable
4860 type = "checkbox",
4861 name = GetString(PCHAT_URLHANDLING),
4862 tooltip = GetString(PCHAT_URLHANDLINGTT),
4863 getFunc = function() return db.urlHandling end,
4864 setFunc = function(newValue) db.urlHandling = newValue end,
4865 width = "full",
4866 default = defaults.urlHandling,
4867 },
4868 {-- Copy Chat
4869 type = "checkbox",
4870 name = GetString(PCHAT_ENABLECOPY),
4871 tooltip = GetString(PCHAT_ENABLECOPYTT),
4872 getFunc = function() return db.enablecopy end,
4873 setFunc = function(newValue) db.enablecopy = newValue end,
4874 width = "full",
4875 default = defaults.enablecopy,
4876 },--
4877 },
4878 } -- Chat Tabs
4879 optionsData[#optionsData + 1] = {
4880 type = "submenu",
4881 name = GetString(PCHAT_CHATTABH),
4882 controls = {
4883 {-- Enable chat channel memory
4884 type = "checkbox",
4885 name = GetString(PCHAT_enableChatTabChannel),
4886 tooltip = GetString(PCHAT_enableChatTabChannelT),
4887 getFunc = function() return db.enableChatTabChannel end,
4888 setFunc = function(newValue) db.enableChatTabChannel = newValue end,
4889 width = "full",
4890 default = defaults.enableChatTabChannel,
4891 },
4892 {-- TODO : optimize
4893 type = "dropdown",
4894 name = GetString(PCHAT_DEFAULTCHANNEL),
4895 tooltip = GetString(PCHAT_DEFAULTCHANNELTT),
4896 --choices = chatTabNames,
4897 choices = {
4898 GetString("PCHAT_DEFAULTCHANNELCHOICE", PCHAT_CHANNEL_NONE),
4899 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_ZONE),
4900 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_SAY),
4901 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_1),
4902 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_2),
4903 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_3),
4904 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_4),
4905 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_5),
4906 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_1),
4907 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_2),
4908 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_3),
4909 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_4),
4910 GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_5)
4911 },
4912 width = "full",
4913 default = defaults.defaultchannel,
4914 getFunc = function() return GetString("PCHAT_DEFAULTCHANNELCHOICE", db.defaultchannel) end,
4915 setFunc = function(choice)
4916 if choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_ZONE) then
4917 db.defaultchannel = CHAT_CHANNEL_ZONE
4918 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_SAY) then
4919 db.defaultchannel = CHAT_CHANNEL_SAY
4920 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_1) then
4921 db.defaultchannel = CHAT_CHANNEL_GUILD_1
4922 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_2) then
4923 db.defaultchannel = CHAT_CHANNEL_GUILD_2
4924 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_3) then
4925 db.defaultchannel = CHAT_CHANNEL_GUILD_3
4926 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_4) then
4927 db.defaultchannel = CHAT_CHANNEL_GUILD_4
4928 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_GUILD_5) then
4929 db.defaultchannel = CHAT_CHANNEL_GUILD_5
4930 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_1) then
4931 db.defaultchannel = CHAT_CHANNEL_OFFICER_1
4932 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_2) then
4933 db.defaultchannel = CHAT_CHANNEL_OFFICER_2
4934 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_3) then
4935 db.defaultchannel = CHAT_CHANNEL_OFFICER_3
4936 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_4) then
4937 db.defaultchannel = CHAT_CHANNEL_OFFICER_4
4938 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", CHAT_CHANNEL_OFFICER_5) then
4939 db.defaultchannel = CHAT_CHANNEL_OFFICER_5
4940 elseif choice == GetString("PCHAT_DEFAULTCHANNELCHOICE", PCHAT_CHANNEL_NONE) then
4941 db.defaultchannel = PCHAT_CHANNEL_NONE
4942 else
4943 -- When user click on LAM reinit button
4944 db.defaultchannel = defaults.defaultchannel
4945 end
4946
4947 end,
4948 },
4949 {-- CHAT_SYSTEM.primaryContainer.windows doesn't exists yet at OnAddonLoaded. So using the pChat reference.
4950 type = "dropdown",
4951 name = GetString(PCHAT_DEFAULTTAB),
4952 tooltip = GetString(PCHAT_DEFAULTTABTT),
4953 choices = tabNames,
4954 width = "full",
4955 getFunc = function() return db.defaultTabName end,
4956 setFunc = function(choice)
4957 db.defaultTabName = choice
4958 --d(choice)
4959 --d(db.defaultTabName)
4960 db.defaultTab = getTabIdx(choice)
4961 --d(db.defaultTab)
4962 end,
4963 },
4964 --[[{-- CHAT_SYSTEM.primaryContainer.windows doesn't exists yet at OnAddonLoaded. So using the pChat reference.
4965 type = "dropdown",
4966 name = GetString(PCHAT_DEFAULTTAB),
4967 tooltip = GetString(PCHAT_DEFAULTTABTT),
4968 choices = arrayTab,
4969 width = "full",
4970 default = defaults.defaultTab,
4971 getFunc = function() return db.defaultTab end,
4972 setFunc = function(choice) db.defaultTab = choice end,
4973 },]]--
4974 --[[{-- Enable whisper redirect
4975 type = "checkbox",
4976 name = GetString(PCHAT_enableWhisperTab),
4977 tooltip = GetString(PCHAT_enableWhisperTabT),
4978 getFunc = function() return db.enableWhisperTab end,
4979 setFunc = function(newValue) db.enableWhisperTab = newValue end,
4980 width = "full",
4981 default = defaults.enableWhisperTab,
4982 },]]--
4983 -- !!!!!need code for specific tab here
4984 },
4985 } -- Group Submenu
4986 optionsData[#optionsData + 1] = {
4987 type = "submenu",
4988 name = GetString(PCHAT_GROUPH),
4989 controls = {
4990 {-- Enable Party Switch
4991 type = "checkbox",
4992 name = GetString(PCHAT_ENABLEPARTYSWITCH),
4993 tooltip = GetString(PCHAT_ENABLEPARTYSWITCHTT),
4994 getFunc = function() return db.enablepartyswitch end,
4995 setFunc = function(newValue) db.enablepartyswitch = newValue end,
4996 width = "full",
4997 default = defaults.enablepartyswitch,
4998 },
4999 {-- Group Leader
5000 type = "checkbox",
5001 name = GetString(PCHAT_GROUPLEADER),
5002 tooltip = GetString(PCHAT_GROUPLEADERTT),
5003 getFunc = function() return db.groupLeader end,
5004 setFunc = function(newValue) db.groupLeader = newValue end,
5005 width = "full",
5006 default = defaults.groupLeader,
5007 },
5008 {-- Group Leader Color
5009 type = "colorpicker",
5010 name = GetString(PCHAT_GROUPLEADERCOLOR),
5011 tooltip = GetString(PCHAT_GROUPLEADERCOLORTT),
5012 getFunc = function() return ConvertHexToRGBA(db.colours["groupleader"]) end,
5013 setFunc = function(r, g, b) db.colours["groupleader"] = ConvertRGBToHex(r, g, b) end,
5014 default = ConvertHexToRGBAPacked(defaults.colours["groupleader"]),
5015 disabled = function() return not db.groupLeader end,
5016 },
5017 {-- Group Leader Coor 2
5018 type = "colorpicker",
5019 name = GetString(PCHAT_GROUPLEADERCOLOR1),
5020 tooltip = GetString(PCHAT_GROUPLEADERCOLOR1TT),
5021 getFunc = function() return ConvertHexToRGBA(db.colours["groupleader1"]) end,
5022 setFunc = function(r, g, b) db.colours["groupleader1"] = ConvertRGBToHex(r, g, b) end,
5023 default = ConvertHexToRGBAPacked(defaults.colours["groupleader1"]),
5024 disabled = function()
5025 if not db.groupLeader then
5026 return true
5027 elseif db.useESOcolors then
5028 return true
5029 else
5030 return false
5031 end
5032 end,
5033 },
5034 {-- Group Names
5035 type = "dropdown",
5036 name = GetString(PCHAT_GROUPNAMES),
5037 tooltip = GetString(PCHAT_GROUPNAMESTT),
5038 choices = {GetString("PCHAT_GROUPNAMESCHOICE", 1), GetString("PCHAT_GROUPNAMESCHOICE", 2), GetString("PCHAT_GROUPNAMESCHOICE", 3)},
5039 width = "full",
5040 default = defaults.groupNames,
5041 getFunc = function() return GetString("PCHAT_GROUPNAMESCHOICE", db.groupNames) end,
5042 setFunc = function(choice)
5043 if choice == GetString("PCHAT_GROUPNAMESCHOICE", 1) then
5044 db.groupNames = 1
5045 elseif choice == GetString("PCHAT_GROUPNAMESCHOICE", 2) then
5046 db.groupNames = 2
5047 elseif choice == GetString("PCHAT_GROUPNAMESCHOICE", 3) then
5048 db.groupNames = 3
5049 else
5050 -- When clicking on LAM default button
5051 db.groupNames = defaults.groupNames
5052 end
5053
5054 end,
5055 },
5056 },
5057 } -- Sync Settings Header
5058 optionsData[#optionsData + 1] = {
5059 type = "submenu",
5060 name = GetString(PCHAT_SYNCH),
5061 controls = {
5062 {-- Sync ON
5063 type = "checkbox",
5064 name = GetString(PCHAT_CHATSYNCCONFIG),
5065 tooltip = GetString(PCHAT_CHATSYNCCONFIGTT),
5066 getFunc = function() return db.chatSyncConfig end,
5067 setFunc = function(newValue) db.chatSyncConfig = newValue end,
5068 width = "full",
5069 default = defaults.chatSyncConfig,
5070 },
5071 {-- Config Import From
5072 type = "dropdown",
5073 name = GetString(PCHAT_CHATSYNCCONFIGIMPORTFROM),
5074 tooltip = GetString(PCHAT_CHATSYNCCONFIGIMPORTFROMTT),
5075 choices = pChatData.chatConfSyncChoices,
5076 width = "full",
5077 getFunc = function() return pChatData.localPlayer end,
5078 setFunc = function(choice)
5079 SyncChatConfig(true, choice)
5080 end,
5081 },
5082 },
5083 } -- Mouse
5084 optionsData[#optionsData + 1] = {
5085 type = "submenu",
5086 name = GetString(PCHAT_APPARENCEMH),
5087 controls = {
5088 {-- New Message Color
5089 type = "colorpicker",
5090 name = GetString(PCHAT_TABWARNING),
5091 tooltip = GetString(PCHAT_TABWARNINGTT),
5092 getFunc = function() return ConvertHexToRGBA(db.colours["tabwarning"]) end,
5093 setFunc = function(r, g, b) db.colours["tabwarning"] = ConvertRGBToHex(r, g, b) end,
5094 default = ConvertHexToRGBAPacked(defaults.colours["tabwarning"]),
5095 },
5096 {-- Chat Window Transparency
5097 type = "slider",
5098 name = GetString(PCHAT_WINDOWDARKNESS),
5099 tooltip = GetString(PCHAT_WINDOWDARKNESSTT),
5100 min = 0,
5101 max = 11,
5102 step = 1,
5103 getFunc = function() return db.windowDarkness end,
5104 setFunc = function(newValue)
5105 db.windowDarkness = newValue
5106 ChangeChatWindowDarkness(true)
5107 CHAT_SYSTEM:Maximize()
5108 end,
5109 width = "full",
5110 default = defaults.windowDarkness,
5111 },
5112 {-- Minimize at luanch
5113 type = "checkbox",
5114 name = GetString(PCHAT_CHATMINIMIZEDATLAUNCH),
5115 tooltip = GetString(PCHAT_CHATMINIMIZEDATLAUNCHTT),
5116 getFunc = function() return db.chatMinimizedAtLaunch end,
5117 setFunc = function(newValue) db.chatMinimizedAtLaunch = newValue end,
5118 width = "full",
5119 default = defaults.chatMinimizedAtLaunch,
5120 },
5121 {-- Minimize Menues
5122 type = "checkbox",
5123 name = GetString(PCHAT_CHATMINIMIZEDINMENUS),
5124 tooltip = GetString(PCHAT_CHATMINIMIZEDINMENUSTT),
5125 getFunc = function() return db.chatMinimizedInMenus end,
5126 setFunc = function(newValue) db.chatMinimizedInMenus = newValue end,
5127 width = "full",
5128 default = defaults.chatMinimizedInMenus,
5129 },
5130 { -- Mximize After Menus
5131 type = "checkbox",
5132 name = GetString(PCHAT_CHATMAXIMIZEDAFTERMENUS),
5133 tooltip = GetString(PCHAT_CHATMAXIMIZEDAFTERMENUSTT),
5134 getFunc = function() return db.chatMaximizedAfterMenus end,
5135 setFunc = function(newValue) db.chatMaximizedAfterMenus = newValue end,
5136 width = "full",
5137 default = defaults.chatMaximizedAfterMenus,
5138 },
5139 { -- Fonts
5140 type = "dropdown",
5141 name = GetString(PCHAT_FONTCHANGE),
5142 tooltip = GetString(PCHAT_FONTCHANGETT),
5143 choices = fontsDefined,
5144 width = "full",
5145 getFunc = function() return db.fonts end,
5146 setFunc = function(choice)
5147 db.fonts = choice
5148 ChangeChatFont(true)
5149 ReloadUI()
5150 end,
5151 default = defaults.fontChange,
5152 warning = "ReloadUI"
5153 },
5154 },
5155 } -- LAM Menu Whispers
5156 optionsData[#optionsData + 1] = {
5157 type = "submenu",
5158 name = GetString(PCHAT_IMH),
5159 controls = {
5160 --[[
5161 {-- LAM Option Whispers: Sound
5162 type = "dropdown",
5163 name = GetString(PCHAT_SOUNDFORINCWHISPS),
5164 tooltip = GetString(PCHAT_SOUNDFORINCWHISPSTT),
5165 choices = {
5166 GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 1),
5167 GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 2),
5168 GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 3),
5169 GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 4),
5170 },
5171 width = "full",
5172 default = defaults.soundforincwhisps, --> SOUNDS.NEW_NOTIFICATION
5173 getFunc = function()
5174 if db.soundforincwhisps == SOUNDS.NONE then
5175 return GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 1)
5176 elseif db.soundforincwhisps == SOUNDS.NEW_NOTIFICATION then
5177 return GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 2)
5178 elseif db.soundforincwhisps == SOUNDS.DEFAULT_CLICK then
5179 return GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 3)
5180 elseif db.soundforincwhisps == SOUNDS.EDIT_CLICK then
5181 return GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 4)
5182 else
5183 return GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 2)
5184 end
5185 end,
5186 setFunc = function(choice)
5187 if choice == GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 1) then
5188 db.soundforincwhisps = SOUNDS.NONE
5189 PlaySound(SOUNDS.NONE)
5190 elseif choice == GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 2) then
5191 db.soundforincwhisps = SOUNDS.NEW_NOTIFICATION
5192 PlaySound(SOUNDS.NEW_NOTIFICATION)
5193 elseif choice == GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 3) then
5194 db.soundforincwhisps = SOUNDS.DEFAULT_CLICK
5195 PlaySound(SOUNDS.DEFAULT_CLICK)
5196 elseif choice == GetString("PCHAT_SOUNDFORINCWHISPSCHOICE", 4) then
5197 db.soundforincwhisps = SOUNDS.EDIT_CLICK
5198 PlaySound(SOUNDS.EDIT_CLICK)
5199 else
5200 -- When clicking on LAM default button
5201 db.soundforincwhisps = defaults.soundforincwhisps
5202 end
5203
5204 end,
5205 },
5206 ]]
5207 {-- -- LAM Option Whisper: Notification by sound slider
5208 type = "slider",
5209 name = GetString(PCHAT_SOUNDFORINCWHISPS),
5210 tooltip = GetString(PCHAT_SOUNDFORINCWHISPSTT),
5211 getFunc = function() return db.notifyIMIndex end,
5212 setFunc = function(newIndexValue)
5213 db.notifyIMIndex = newIndexValue
5214 local soundName = pChat.sounds[newIndexValue]
5215 if newIndexValue ~= 1 then
5216 if soundName and SOUNDS and SOUNDS[soundName] then
5217 PlaySound(SOUNDS[soundName])
5218 end
5219 end
5220 --Update the label to show the sound name
5221 UpdateSoundDescription("whisper", newIndexValue)
5222 end,
5223 width = "full",
5224 step = 1,
5225 min = 1,
5226 max = #pChat.sounds,
5227 default = defaults.notifyIMIndex,
5228 reference = "pChatLAMWhisperSoundSlider",
5229 },
5230
5231 {-- -- LAM Option Whisper: Visual Notification
5232 type = "checkbox",
5233 name = GetString(PCHAT_NOTIFYIM),
5234 tooltip = GetString(PCHAT_NOTIFYIMTT),
5235 getFunc = function() return db.notifyIM end,
5236 setFunc = function(newValue) db.notifyIM = newValue end,
5237 width = "full",
5238 default = defaults.notifyIM,
5239 },
5240 },
5241 }-- LAM Menu Restore Chat
5242 optionsData[#optionsData + 1] = {
5243 type = "submenu",
5244 name = GetString(PCHAT_RESTORECHATH),
5245 controls = {
5246 {-- LAM Option Restore: After ReloadUI
5247 type = "checkbox",
5248 name = GetString(PCHAT_RESTOREONRELOADUI),
5249 tooltip = GetString(PCHAT_RESTOREONRELOADUITT),
5250 getFunc = function() return db.restoreOnReloadUI end,
5251 setFunc = function(newValue) db.restoreOnReloadUI = newValue end,
5252 width = "full",
5253 default = defaults.restoreOnReloadUI,
5254 },
5255 {-- LAM Option Restore: Logout
5256 type = "checkbox",
5257 name = GetString(PCHAT_RESTOREONLOGOUT),
5258 tooltip = GetString(PCHAT_RESTOREONLOGOUTTT),
5259 getFunc = function() return db.restoreOnLogOut end,
5260 setFunc = function(newValue) db.restoreOnLogOut = newValue end,
5261 width = "full",
5262 default = defaults.restoreOnLogOut,
5263 },
5264 {-- LAM Option Restore: Kicked
5265 type = "checkbox",
5266 name = GetString(PCHAT_RESTOREONAFK),
5267 tooltip = GetString(PCHAT_RESTOREONAFKTT),
5268 getFunc = function() return db.restoreOnAFK end,
5269 setFunc = function(newValue) db.restoreOnAFK = newValue end,
5270 width = "full",
5271 default = defaults.restoreOnAFK,
5272 },
5273 {-- LAM Option Restore: Hours
5274 type = "slider",
5275 name = GetString(PCHAT_TIMEBEFORERESTORE),
5276 tooltip = GetString(PCHAT_TIMEBEFORERESTORETT),
5277 min = 1,
5278 max = 24,
5279 step = 1,
5280 getFunc = function() return db.timeBeforeRestore end,
5281 setFunc = function(newValue) db.timeBeforeRestore = newValue end,
5282 width = "full",
5283 default = defaults.timeBeforeRestore,
5284 },
5285 {-- LAM Option Restore: Leave
5286 type = "checkbox",
5287 name = GetString(PCHAT_RESTOREONQUIT),
5288 tooltip = GetString(PCHAT_RESTOREONQUITTT),
5289 getFunc = function() return db.restoreOnQuit end,
5290 setFunc = function(newValue) db.restoreOnQuit = newValue end,
5291 width = "full",
5292 default = defaults.restoreOnQuit,
5293 },
5294 {-- LAM Option Restore: System Messages
5295 type = "checkbox",
5296 name = GetString(PCHAT_RESTORESYSTEM),
5297 tooltip = GetString(PCHAT_RESTORESYSTEMTT),
5298 getFunc = function() return db.restoreSystem end,
5299 setFunc = function(newValue) db.restoreSystem = newValue end,
5300 width = "full",
5301 default = defaults.restoreSystem,
5302 },
5303 {-- LAM Option Restore: System Only Messages
5304 type = "checkbox",
5305 name = GetString(PCHAT_RESTORESYSTEMONLY),
5306 tooltip = GetString(PCHAT_RESTORESYSTEMONLYTT),
5307 getFunc = function() return db.restoreSystemOnly end,
5308 setFunc = function(newValue) db.restoreSystemOnly = newValue end,
5309 width = "full",
5310 default = defaults.restoreSystemOnly,
5311 },
5312 {-- LAM Option Restore: Whispers
5313 type = "checkbox",
5314 name = GetString(PCHAT_RESTOREWHISPS),
5315 tooltip = GetString(PCHAT_RESTOREWHISPSTT),
5316 getFunc = function() return db.restoreWhisps end,
5317 setFunc = function(newValue) db.restoreWhisps = newValue end,
5318 width = "full",
5319 default = defaults.restoreWhisps,
5320 },
5321 {-- LAM Option Restore: Text entry history
5322 type = "checkbox",
5323 name = GetString(PCHAT_RESTORETEXTENTRYHISTORYATLOGOUTQUIT),
5324 tooltip = GetString(PCHAT_RESTORETEXTENTRYHISTORYATLOGOUTQUITTT),
5325 getFunc = function() return db.restoreTextEntryHistoryAtLogOutQuit end,
5326 setFunc = function(newValue) db.restoreTextEntryHistoryAtLogOutQuit = newValue end,
5327 width = "full",
5328 default = defaults.restoreTextEntryHistoryAtLogOutQuit,
5329 },
5330 },
5331 } -- Anti-Spam Timestamp options
5332 optionsData[#optionsData + 1] = {
5333 type = "submenu",
5334 name = GetString(PCHAT_ANTISPAMH),
5335 controls = {
5336 {-- flood protect
5337 type = "checkbox",
5338 name = GetString(PCHAT_FLOODPROTECT),
5339 tooltip = GetString(PCHAT_FLOODPROTECTTT),
5340 getFunc = function() return db.floodProtect end,
5341 setFunc = function(newValue) db.floodProtect = newValue end,
5342 width = "full",
5343 default = defaults.floodProtect,
5344 }, --Anti spam grace period
5345 {
5346 type = "slider",
5347 name = GetString(PCHAT_FLOODGRACEPERIOD),
5348 tooltip = GetString(PCHAT_FLOODGRACEPERIODTT),
5349 min = 0,
5350 max = 180,
5351 step = 1,
5352 getFunc = function() return db.floodGracePeriod end,
5353 setFunc = function(newValue) db.floodGracePeriod = newValue end,
5354 width = "full",
5355 default = defaults.floodGracePeriod,
5356 disabled = function() return not db.floodProtect end,
5357 },
5358 {
5359 type = "checkbox",
5360 name = GetString(PCHAT_LOOKINGFORPROTECT),
5361 tooltip = GetString(PCHAT_LOOKINGFORPROTECTTT),
5362 getFunc = function() return db.lookingForProtect end,
5363 setFunc = function(newValue) db.lookingForProtect = newValue end,
5364 width = "full",
5365 default = defaults.lookingForProtect,
5366 },
5367 {
5368 type = "checkbox",
5369 name = GetString(PCHAT_WANTTOPROTECT),
5370 tooltip = GetString(PCHAT_WANTTOPROTECTTT),
5371 getFunc = function() return db.wantToProtect end,
5372 setFunc = function(newValue) db.wantToProtect = newValue end,
5373 width = "full",
5374 default = defaults.wantToProtect,
5375 },
5376 {
5377 type = "slider",
5378 name = GetString(PCHAT_SPAMGRACEPERIOD),
5379 tooltip = GetString(PCHAT_SPAMGRACEPERIODTT),
5380 min = 0,
5381 max = 10,
5382 step = 1,
5383 getFunc = function() return db.spamGracePeriod end,
5384 setFunc = function(newValue) db.spamGracePeriod = newValue end,
5385 width = "full",
5386 default = defaults.spamGracePeriod,
5387 },
5388 {
5389 type = "editbox",
5390 name = GetString(PCHAT_NICKNAMES),
5391 tooltip = GetString(PCHAT_NICKNAMESTT),
5392 isMultiline = true,
5393 isExtraWide = true,
5394 getFunc = function() return db.nicknames end,
5395 setFunc = function(newValue)
5396 db.nicknames = newValue
5397 BuildNicknames(true) -- Rebuild the control if data is invalid
5398 end,
5399 width = "full",
5400 default = defaults.nicknames,
5401 },
5402 },
5403 } -- Timestamp options
5404 optionsData[#optionsData + 1] = {
5405 type = "submenu",
5406 name = GetString(PCHAT_TIMESTAMPH),
5407 controls = {
5408 {
5409 type = "checkbox",
5410 name = GetString(PCHAT_ENABLETIMESTAMP),
5411 tooltip = GetString(PCHAT_ENABLETIMESTAMPTT),
5412 getFunc = function() return db.showTimestamp end,
5413 setFunc = function(newValue) db.showTimestamp = newValue end,
5414 width = "full",
5415 default = defaults.showTimestamp,
5416 },
5417 {
5418 type = "checkbox",
5419 name = GetString(PCHAT_TIMESTAMPCOLORISLCOL),
5420 tooltip = GetString(PCHAT_TIMESTAMPCOLORISLCOLTT),
5421 getFunc = function() return db.timestampcolorislcol end,
5422 setFunc = function(newValue) db.timestampcolorislcol = newValue end,
5423 width = "full",
5424 default = defaults.timestampcolorislcol,
5425 disabled = function() return not db.showTimestamp end,
5426 },
5427 {
5428 type = "editbox",
5429 name = GetString(PCHAT_TIMESTAMPFORMAT),
5430 tooltip = GetString(PCHAT_TIMESTAMPFORMATTT),
5431 getFunc = function() return db.timestampFormat end,
5432 setFunc = function(newValue) db.timestampFormat = newValue end,
5433 width = "full",
5434 default = defaults.timestampFormat,
5435 disabled = function() return not db.showTimestamp end,
5436 },
5437 {
5438 type = "colorpicker",
5439 name = GetString(PCHAT_TIMESTAMP),
5440 tooltip = GetString(PCHAT_TIMESTAMPTT),
5441 getFunc = function() return ConvertHexToRGBA(db.colours.timestamp) end,
5442 setFunc = function(r, g, b) db.colours.timestamp = ConvertRGBToHex(r, g, b) end,
5443 default = ConvertHexToRGBAPacked(defaults.colours.timestamp),
5444 disabled = function() return not db.showTimestamp end,
5445 },
5446 },
5447 }
5448 -- Addon Menu Other Colors
5449 optionsData[#optionsData + 1] = {
5450 type = "submenu",
5451 name = GetString(PCHAT_CHATCOLORSH),
5452 controls = {
5453 {-- Say players
5454 type = "colorpicker",
5455 name = GetString(PCHAT_SAY),
5456 tooltip = GetString(PCHAT_SAYTT),
5457 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_SAY]) end,
5458 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_SAY] = ConvertRGBToHex(r, g, b) end,
5459 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_SAY]),
5460 disabled = function() return db.useESOcolors end,
5461 },
5462 {--Say Chat Color
5463 type = "colorpicker",
5464 name = GetString(PCHAT_SAYCHAT),
5465 tooltip = GetString(PCHAT_SAYCHATTT),
5466 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_SAY + 1]) end,
5467 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_SAY + 1] = ConvertRGBToHex(r, g, b) end,
5468 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_SAY + 1]),
5469 disabled = function() return db.useESOcolors end,
5470 },
5471 {-- Zone Player
5472 type = "colorpicker",
5473 name = GetString(PCHAT_ZONE),
5474 tooltip = GetString(PCHAT_ZONETT),
5475 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE]) end,
5476 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE] = ConvertRGBToHex(r, g, b) end,
5477 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE]),
5478 disabled = function() return db.useESOcolors end,
5479 },
5480 {
5481 type = "colorpicker",
5482 name = GetString(PCHAT_ZONECHAT),
5483 tooltip = GetString(PCHAT_ZONECHATTT),
5484 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE + 1]) end,
5485 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE + 1] = ConvertRGBToHex(r, g, b) end,
5486 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE + 1]),
5487 disabled = function() return db.useESOcolors end,
5488 },
5489 {-- Yell Player
5490 type = "colorpicker",
5491 name = GetString(PCHAT_YELL),
5492 tooltip = GetString(PCHAT_YELLTT),
5493 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_YELL]) end,
5494 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_YELL] = ConvertRGBToHex(r, g, b) end,
5495 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_YELL]),
5496 disabled = function() return db.useESOcolors end,
5497 },
5498 {--Yell Chat
5499 type = "colorpicker",
5500 name = GetString(PCHAT_YELLCHAT),
5501 tooltip = GetString(PCHAT_YELLCHATTT),
5502 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_YELL + 1]) end,
5503 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_YELL + 1] = ConvertRGBToHex(r, g, b) end,
5504 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_YELL + 1]),
5505 disabled = function() return db.useESOcolors end,
5506 },
5507 {--
5508 type = "colorpicker",
5509 name = GetString(PCHAT_INCOMINGWHISPERS),
5510 tooltip = GetString(PCHAT_INCOMINGWHISPERSTT),
5511 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_WHISPER]) end,
5512 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_WHISPER] = ConvertRGBToHex(r, g, b) end,
5513 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_WHISPER]),
5514 disabled = function() return db.useESOcolors end,
5515 },
5516 {--
5517 type = "colorpicker",
5518 name = GetString(PCHAT_INCOMINGWHISPERSCHAT),
5519 tooltip = GetString(PCHAT_INCOMINGWHISPERSCHATTT),
5520 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_WHISPER + 1]) end,
5521 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_WHISPER + 1] = ConvertRGBToHex(r, g, b) end,
5522 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_WHISPER + 1]),
5523 disabled = function() return db.useESOcolors end,
5524 },
5525 {--
5526 type = "colorpicker",
5527 name = GetString(PCHAT_OUTGOINGWHISPERS),
5528 tooltip = GetString(PCHAT_OUTGOINGWHISPERSTT),
5529 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_WHISPER_SENT]) end,
5530 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_WHISPER_SENT] = ConvertRGBToHex(r, g, b) end,
5531 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_WHISPER_SENT]),
5532 disabled = function() return db.useESOcolors end,
5533 },
5534 {--
5535 type = "colorpicker",
5536 name = GetString(PCHAT_OUTGOINGWHISPERSCHAT),
5537 tooltip = GetString(PCHAT_OUTGOINGWHISPERSCHATTT),
5538 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_WHISPER_SENT + 1]) end,
5539 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_WHISPER_SENT + 1] = ConvertRGBToHex(r, g, b) end,
5540 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_WHISPER_SENT + 1]),
5541 disabled = function() return db.useESOcolors end,
5542 },
5543 {--
5544 type = "colorpicker",
5545 name = GetString(PCHAT_GROUP),
5546 tooltip = GetString(PCHAT_GROUPTT),
5547 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_PARTY]) end,
5548 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_PARTY] = ConvertRGBToHex(r, g, b) end,
5549 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_PARTY]),
5550 disabled = function() return db.useESOcolors end,
5551 },
5552 {--
5553 type = "colorpicker",
5554 name = GetString(PCHAT_GROUPCHAT),
5555 tooltip = GetString(PCHAT_GROUPCHATTT),
5556 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_PARTY + 1]) end,
5557 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_PARTY + 1] = ConvertRGBToHex(r, g, b) end,
5558 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_PARTY + 1]),
5559 disabled = function() return db.useESOcolors end,
5560 },
5561 },
5562 }--Other Colors
5563 optionsData[#optionsData + 1] = {
5564 type = "submenu",
5565 name = GetString(PCHAT_OTHERCOLORSH),
5566 controls = {
5567 {
5568 type = "colorpicker",
5569 name = GetString(PCHAT_EMOTES),
5570 tooltip = GetString(PCHAT_EMOTESTT),
5571 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_EMOTE]) end,
5572 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_EMOTE] = ConvertRGBToHex(r, g, b) end,
5573 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_EMOTE]),
5574 disabled = function() return db.useESOcolors end,
5575 },
5576 {--
5577 type = "colorpicker",
5578 name = GetString(PCHAT_EMOTESCHAT),
5579 tooltip = GetString(PCHAT_EMOTESCHATTT),
5580 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_EMOTE + 1]) end,
5581 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_EMOTE + 1] = ConvertRGBToHex(r, g, b) end,
5582 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_EMOTE + 1]),
5583 disabled = function() return db.useESOcolors end,
5584 },
5585 {--
5586 type = "colorpicker",
5587 name = GetString(PCHAT_NPCSAY),
5588 tooltip = GetString(PCHAT_NPCSAYTT),
5589 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_SAY]) end,
5590 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_SAY] = ConvertRGBToHex(r, g, b) end,
5591 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_SAY]),
5592 disabled = function() return db.useESOcolors end,
5593 },
5594 {--
5595 type = "colorpicker",
5596 name = GetString(PCHAT_NPCSAYCHAT),
5597 tooltip = GetString(PCHAT_NPCSAYCHATTT),
5598 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_SAY + 1]) end,
5599 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_SAY + 1] = ConvertRGBToHex(r, g, b) end,
5600 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_SAY + 1]),
5601 disabled = function() return db.useESOcolors end,
5602 },
5603 {--
5604 type = "colorpicker",
5605 name = GetString(PCHAT_NPCYELL),
5606 tooltip = GetString(PCHAT_NPCYELLTT),
5607 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_YELL]) end,
5608 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_YELL] = ConvertRGBToHex(r, g, b) end,
5609 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_YELL]),
5610 disabled = function()
5611 if db.useESOcolors then
5612 return true
5613 else
5614 return db.allNPCSameColour
5615 end
5616 end,
5617 },
5618 {--
5619 type = "colorpicker",
5620 name = GetString(PCHAT_NPCYELLCHAT),
5621 tooltip = GetString(PCHAT_NPCYELLCHATTT),
5622 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_YELL + 1]) end,
5623 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_YELL + 1] = ConvertRGBToHex(r, g, b) end,
5624 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_YELL + 1]),
5625 disabled = function()
5626 if db.useESOcolors then
5627 return true
5628 else
5629 return db.allNPCSameColour
5630 end
5631 end,
5632 },
5633 {--
5634 type = "colorpicker",
5635 name = GetString(PCHAT_NPCWHISPER),
5636 tooltip = GetString(PCHAT_NPCWHISPERTT),
5637 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_WHISPER]) end,
5638 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_WHISPER] = ConvertRGBToHex(r, g, b) end,
5639 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_WHISPER]),
5640 disabled = function()
5641 if db.useESOcolors then
5642 return true
5643 else
5644 return db.allNPCSameColour
5645 end
5646 end,
5647 },
5648 {--
5649 type = "colorpicker",
5650 name = GetString(PCHAT_NPCWHISPERCHAT),
5651 tooltip = GetString(PCHAT_NPCWHISPERCHATTT),
5652 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_WHISPER + 1]) end,
5653 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_WHISPER + 1] = ConvertRGBToHex(r, g, b) end,
5654 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_WHISPER + 1]),
5655 disabled = function()
5656 if db.useESOcolors then
5657 return true
5658 else
5659 return db.allNPCSameColour
5660 end
5661 end,
5662 },
5663 {--
5664 type = "colorpicker",
5665 name = GetString(PCHAT_NPCEMOTES),
5666 tooltip = GetString(PCHAT_NPCEMOTESTT),
5667 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_EMOTE]) end,
5668 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_EMOTE] = ConvertRGBToHex(r, g, b) end,
5669 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_EMOTE]),
5670 disabled = function()
5671 if db.useESOcolors then
5672 return true
5673 else
5674 return db.allNPCSameColour
5675 end
5676 end,
5677 },
5678 {--
5679 type = "colorpicker",
5680 name = GetString(PCHAT_NPCEMOTESCHAT),
5681 tooltip = GetString(PCHAT_NPCEMOTESCHATTT),
5682 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_MONSTER_EMOTE + 1]) end,
5683 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_MONSTER_EMOTE + 1] = ConvertRGBToHex(r, g, b) end,
5684 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_MONSTER_EMOTE + 1]),
5685 disabled = function()
5686 if db.useESOcolors then
5687 return true
5688 else
5689 return db.allNPCSameColour
5690 end
5691 end,
5692 },
5693 {--
5694 type = "colorpicker",
5695 name = GetString(PCHAT_ENZONE),
5696 tooltip = GetString(PCHAT_ENZONETT),
5697 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1]) end,
5698 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1] = ConvertRGBToHex(r, g, b) end,
5699 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1]),
5700 disabled = function()
5701 if db.useESOcolors then
5702 return true
5703 else
5704 return db.allZonesSameColour
5705 end
5706 end,
5707 },
5708 {--
5709 type = "colorpicker",
5710 name = GetString(PCHAT_ENZONECHAT),
5711 tooltip = GetString(PCHAT_ENZONECHATTT),
5712 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1 + 1]) end,
5713 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1 + 1] = ConvertRGBToHex(r, g, b) end,
5714 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_1 + 1]),
5715 disabled = function()
5716 if db.useESOcolors then
5717 return true
5718 else
5719 return db.allZonesSameColour
5720 end
5721 end,
5722 },
5723 {--
5724 type = "colorpicker",
5725 name = GetString(PCHAT_FRZONE),
5726 tooltip = GetString(PCHAT_FRZONETT),
5727 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2]) end,
5728 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2] = ConvertRGBToHex(r, g, b) end,
5729 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2]),
5730 disabled = function()
5731 if db.useESOcolors then
5732 return true
5733 else
5734 return db.allZonesSameColour
5735 end
5736 end,
5737 },
5738 {--
5739 type = "colorpicker",
5740 name = GetString(PCHAT_FRZONECHAT),
5741 tooltip = GetString(PCHAT_FRZONECHATTT),
5742 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2 + 1]) end,
5743 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2 + 1] = ConvertRGBToHex(r, g, b) end,
5744 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_2 + 1]),
5745 disabled = function()
5746 if db.useESOcolors then
5747 return true
5748 else
5749 return db.allZonesSameColour
5750 end
5751 end,
5752 },
5753 {--
5754 type = "colorpicker",
5755 name = GetString(PCHAT_DEZONE),
5756 tooltip = GetString(PCHAT_DEZONETT),
5757 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3]) end,
5758 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3] = ConvertRGBToHex(r, g, b) end,
5759 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3]),
5760 disabled = function()
5761 if db.useESOcolors then
5762 return true
5763 else
5764 return db.allZonesSameColour
5765 end
5766 end,
5767 },
5768 {--
5769 type = "colorpicker",
5770 name = GetString(PCHAT_DEZONECHAT),
5771 tooltip = GetString(PCHAT_DEZONECHATTT),
5772 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3 + 1]) end,
5773 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3 + 1] = ConvertRGBToHex(r, g, b) end,
5774 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_3 + 1]),
5775 disabled = function()
5776 if db.useESOcolors then
5777 return true
5778 else
5779 return db.allZonesSameColour
5780 end
5781 end,
5782 },
5783 {--
5784 type = "colorpicker",
5785 name = GetString(PCHAT_JPZONE),
5786 tooltip = GetString(PCHAT_JPZONETT),
5787 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4]) end,
5788 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4] = ConvertRGBToHex(r, g, b) end,
5789 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4]),
5790 disabled = function()
5791 if db.useESOcolors then
5792 return true
5793 else
5794 return db.allZonesSameColour
5795 end
5796 end,
5797 },
5798 {--
5799 type = "colorpicker",
5800 name = GetString(PCHAT_JPZONECHAT),
5801 tooltip = GetString(PCHAT_JPZONECHATTT),
5802 getFunc = function() return ConvertHexToRGBA(db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4 + 1]) end,
5803 setFunc = function(r, g, b) db.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4 + 1] = ConvertRGBToHex(r, g, b) end,
5804 default = ConvertHexToRGBAPacked(defaults.colours[2*CHAT_CHANNEL_ZONE_LANGUAGE_4 + 1]),
5805 disabled = function()
5806 if db.useESOcolors then
5807 return true
5808 else
5809 return db.allZonesSameColour
5810 end
5811 end,
5812 },
5813 },
5814 }
5815-- Guilds
5816
5817-- Guild Stuff
5818--
5819 for guild = 1, GetNumGuilds() do
5820
5821 -- Guildname
5822 local guildId = GetGuildId(guild)
5823 local guildName = GetGuildName(guildId)
5824
5825 -- Occurs sometimes
5826 if(not guildName or (guildName):len() < 1) then
5827 guildName = "Guild " .. guildId
5828 end
5829
5830 -- If recently added to a new guild and never go in menu db.formatguild[guildName] won't exist
5831 if not (db.formatguild[guildName]) then
5832 -- 2 is default value
5833 db.formatguild[guildName] = 2
5834 end
5835 optionsData[#optionsData + 1] = {
5836 type = "submenu",
5837 name = guildName,
5838 controls = {
5839 {
5840 type = "editbox",
5841 name = GetString(PCHAT_NICKNAMEFOR),
5842 tooltip = GetString(PCHAT_NICKNAMEFORTT) .. " " .. guildName,
5843 getFunc = function() return db.guildTags[guildName] end,
5844 setFunc = function(newValue)
5845 db.guildTags[guildName] = newValue
5846 UpdateCharCorrespondanceTableChannelNames()
5847 end,
5848 width = "full",
5849 default = "",
5850 },
5851 {
5852 type = "editbox",
5853 name = GetString(PCHAT_OFFICERTAG),
5854 tooltip = GetString(PCHAT_OFFICERTAGTT),
5855 width = "full",
5856 default = "",
5857 getFunc = function() return db.officertag[guildName] end,
5858 setFunc = function(newValue)
5859 db.officertag[guildName] = newValue
5860 UpdateCharCorrespondanceTableChannelNames()
5861 end
5862 },
5863 {
5864 type = "editbox",
5865 name = GetString(PCHAT_SWITCHFOR),
5866 tooltip = GetString(PCHAT_SWITCHFORTT),
5867 getFunc = function() return db.switchFor[guildName] end,
5868 setFunc = function(newValue)
5869 db.switchFor[guildName] = newValue
5870 UpdateCharCorrespondanceTableSwitchs()
5871 CHAT_SYSTEM:CreateChannelData()
5872 end,
5873 width = "full",
5874 default = "",
5875 },
5876 {
5877 type = "editbox",
5878 name = GetString(PCHAT_OFFICERSWITCHFOR),
5879 tooltip = GetString(PCHAT_OFFICERSWITCHFORTT),
5880 width = "full",
5881 default = "",
5882 getFunc = function() return db.officerSwitchFor[guildName] end,
5883 setFunc = function(newValue)
5884 db.officerSwitchFor[guildName] = newValue
5885 UpdateCharCorrespondanceTableSwitchs()
5886 CHAT_SYSTEM:CreateChannelData()
5887 end
5888 },
5889 -- Config store 1/2/3 to avoid language switchs
5890 -- TODO : Optimize
5891 {
5892 type = "dropdown",
5893 name = GetString(PCHAT_NAMEFORMAT),
5894 tooltip = GetString(PCHAT_NAMEFORMATTT),
5895 choices = {GetString(PCHAT_FORMATCHOICE1), GetString(PCHAT_FORMATCHOICE2), GetString(PCHAT_FORMATCHOICE3)},
5896 getFunc = function()
5897 -- Config per guild
5898 if db.formatguild[guildName] == 1 then
5899 return GetString(PCHAT_FORMATCHOICE1)
5900 elseif db.formatguild[guildName] == 2 then
5901 return GetString(PCHAT_FORMATCHOICE2)
5902 elseif db.formatguild[guildName] == 3 then
5903 return GetString(PCHAT_FORMATCHOICE3)
5904 else
5905 -- When user click on LAM reinit button
5906 return GetString(PCHAT_FORMATCHOICE2)
5907 end
5908 end,
5909 setFunc = function(choice)
5910 if choice == GetString(PCHAT_FORMATCHOICE1) then
5911 db.formatguild[guildName] = 1
5912 elseif choice == GetString(PCHAT_FORMATCHOICE2) then
5913 db.formatguild[guildName] = 2
5914 elseif choice == GetString(PCHAT_FORMATCHOICE3) then
5915 db.formatguild[guildName] = 3
5916 else
5917 -- When user click on LAM reinit button
5918 db.formatguild[guildName] = 2
5919 end
5920 end,
5921 width = "full",
5922 default = defaults.formatguild[0],
5923 },
5924 {
5925 type = "colorpicker",
5926 name = zo_strformat(PCHAT_MEMBERS, guildName),
5927 tooltip = zo_strformat(PCHAT_SETCOLORSFORTT, guildName),
5928 getFunc = function() return ConvertHexToRGBA(db.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1)]) end,
5929 setFunc = function(r, g, b) db.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1)] = ConvertRGBToHex(r, g, b) end,
5930 default = ConvertHexToRGBAPacked(defaults.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1)]),
5931 disabled = function() return db.useESOcolors end,
5932 },
5933 {
5934 type = "colorpicker",
5935 name = zo_strformat(PCHAT_CHAT, guildName),
5936 tooltip = zo_strformat(PCHAT_SETCOLORSFORCHATTT, guildName),
5937 getFunc = function() return ConvertHexToRGBA(db.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1) + 1]) end,
5938 setFunc = function(r, g, b) db.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1) + 1] = ConvertRGBToHex(r, g, b) end,
5939 default = ConvertHexToRGBAPacked(defaults.colours[2*(CHAT_CHANNEL_GUILD_1 + guild - 1) + 1]),
5940 disabled = function() return db.useESOcolors end,
5941 },
5942 {
5943 type = "colorpicker",
5944 name = guildName .. GetString(PCHAT_OFFICERSTT) .. GetString(PCHAT_MEMBERS),
5945 tooltip = zo_strformat(PCHAT_SETCOLORSFOROFFICIERSTT, guildName),
5946 getFunc = function() return ConvertHexToRGBA(db.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1)]) end,
5947 setFunc = function(r, g, b) db.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1)] = ConvertRGBToHex(r, g, b) end,
5948 default = ConvertHexToRGBAPacked(defaults.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1)]),
5949 disabled = function() return db.useESOcolors end,
5950 },
5951 {
5952 type = "colorpicker",
5953 name = guildName .. GetString(PCHAT_OFFICERSTT) .. GetString(PCHAT_CHAT),
5954 tooltip = zo_strformat(PCHAT_SETCOLORSFOROFFICIERSCHATTT, guildName),
5955 getFunc = function() return ConvertHexToRGBA(db.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1) + 1]) end,
5956 setFunc = function(r, g, b) db.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1) + 1] = ConvertRGBToHex(r, g, b) end,
5957 default = ConvertHexToRGBAPacked(defaults.colours[2*(CHAT_CHANNEL_OFFICER_1 + guild - 1) + 1]),
5958 disabled = function() return db.useESOcolors end,
5959 },
5960 },
5961 }
5962 end
5963
5964
5965
5966
5967 --[[
5968 index = index + 1
5969 optionsTable[index] = {
5970 type = "header",
5971 name = GetString(PCHAT_DEBUGH),
5972 width = "full",
5973 }
5974
5975 index = index + 1
5976 optionsTable[index] = {
5977 type = "checkbox",
5978 name = GetString(PCHAT_DEBUG),
5979 tooltip = GetString(PCHAT_DEBUGTT),
5980 getFunc = function() return db.debug end,
5981 setFunc = function(newValue) db.debug = newValue end,
5982 width = "full",
5983 default = defaults.debug,
5984 },
5985 ]]--
5986
5987 LAM:RegisterOptionControls("pChatOptions", optionsData)
5988
5989end
5990
5991-- Initialises the settings and settings menu
5992local function GetDBAndBuildLAM()
5993
5994 db = ZO_SavedVars:NewAccountWide('PCHAT_OPTS', 0.9, nil, defaults)
5995 pChat.db = db
5996
5997 local panelData = {
5998 type = "panel",
5999 name = ADDON_NAME,
6000 displayName = ZO_HIGHLIGHT_TEXT:Colorize("pChat"),
6001 author = ADDON_AUTHOR,
6002 version = ADDON_VERSION,
6003 slashCommand = "/pchat",
6004 website = "http://www.esoui.com/downloads/info93-pChat.html",
6005 registerForRefresh = true,
6006 registerForDefaults = true,
6007 website = ADDON_WEBSITE,
6008 }
6009
6010 pChat.LAMPanel = LAM:RegisterAddonPanel("pChatOptions", panelData)
6011
6012 -- Build OptionTable. In a separate func in order to rebuild it in case of Guild Reorg.
6013 SyncCharacterSelectChoices()
6014 BuildLAMPanel()
6015
6016end
6017--**Settings End
6018-- Triggered by EVENT_GUILD_SELF_JOINED_GUILD
6019local function OnSelfJoinedGuild(_, _, guildName)
6020
6021 -- It will rebuild optionsTable and recreate tables if user didn't went in this section before
6022 BuildLAMPanel()
6023
6024 -- If recently added to a new guild and never go in menu db.formatguild[guildName] won't exist, it won't create the value if joining an known guild
6025 if not db.formatguild[guildName] then
6026 -- 2 is default value
6027 db.formatguild[guildName] = 2
6028 end
6029
6030 -- Save Guild indexes for guild reorganization
6031 SaveGuildIndexes()
6032
6033end
6034
6035-- Revert category settings
6036local function RevertCategories(guildName)
6037
6038 -- Old GuildId
6039 local oldIndex = pChatData.guildIndexes[guildName]
6040 -- old Total Guilds
6041 local totGuilds = GetNumGuilds() + 1
6042
6043 if oldIndex and oldIndex < totGuilds then
6044
6045 -- If our guild was not the last one, need to revert colors
6046 --d("pChat will revert starting from " .. oldIndex .. " to " .. totGuilds)
6047
6048 -- Does not need to reset chat settings for first guild if the 2nd has been left, same for 1-2/3 and 1-2-3/4
6049 for iGuilds=oldIndex, (totGuilds - 1) do
6050
6051 -- If default channel was g1, keep it g1
6052 if not (db.defaultchannel == CHAT_CATEGORY_GUILD_1 or db.defaultchannel == CHAT_CATEGORY_OFFICER_1) then
6053
6054 if db.defaultchannel == (CHAT_CATEGORY_GUILD_1 + iGuilds) then
6055 db.defaultchannel = (CHAT_CATEGORY_GUILD_1 + iGuilds - 1)
6056 elseif db.defaultchannel == (CHAT_CATEGORY_OFFICER_1 + iGuilds) then
6057 db.defaultchannel = (CHAT_CATEGORY_OFFICER_1 + iGuilds - 1)
6058 end
6059
6060 end
6061
6062 -- New Guild color for Guild #X is the old #X+1
6063 SetChatCategoryColor(CHAT_CATEGORY_GUILD_1 + iGuilds - 1, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_GUILD_1 + iGuilds].red, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_GUILD_1 + iGuilds].green, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_GUILD_1 + iGuilds].blue)
6064 -- New Officer color for Guild #X is the old #X+1
6065 SetChatCategoryColor(CHAT_CATEGORY_OFFICER_1 + iGuilds - 1, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_OFFICER_1 + iGuilds].red, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_OFFICER_1 + iGuilds].green, db.chatConfSync[pChatData.localPlayer].colors[CHAT_CATEGORY_OFFICER_1 + iGuilds].blue)
6066
6067 -- Restore tab config previously set.
6068 for numTab in ipairs (CHAT_SYSTEM.primaryContainer.windows) do
6069 if db.chatConfSync[pChatData.localPlayer].tabs[numTab] then
6070 SetChatContainerTabCategoryEnabled(1, numTab, (CHAT_CATEGORY_GUILD_1 + iGuilds - 1), db.chatConfSync[pChatData.localPlayer].tabs[numTab].enabledCategories[CHAT_CATEGORY_GUILD_1 + iGuilds])
6071 SetChatContainerTabCategoryEnabled(1, numTab, (CHAT_CATEGORY_OFFICER_1 + iGuilds - 1), db.chatConfSync[pChatData.localPlayer].tabs[numTab].enabledCategories[CHAT_CATEGORY_OFFICER_1 + iGuilds])
6072 end
6073 end
6074
6075 end
6076 end
6077
6078end
6079
6080-- Registers the formatMessage function with the libChat to handle chat formatting.
6081-- Unregisters itself from the player activation event with the event manager.
6082local function OnPlayerActivated()
6083 pChatData.sceneFirst = false
6084
6085 if isAddonLoaded then
6086
6087 pChatData.activeTab = 1
6088
6089 if CHAT_SYSTEM then
6090 if CHAT_SYSTEM.ValidateChatChannel then
6091 ZO_PreHook(CHAT_SYSTEM, "ValidateChatChannel", function(self)
6092 if (db.enableChatTabChannel == true) and (self.currentChannel ~= CHAT_CHANNEL_WHISPER) then
6093 local tabIndex = self.primaryContainer.currentBuffer:GetParent().tab.index
6094 db.chatTabChannel[tabIndex] = db.chatTabChannel[tabIndex] or {}
6095 db.chatTabChannel[tabIndex].channel = self.currentChannel
6096 db.chatTabChannel[tabIndex].target = self.currentTarget
6097 end
6098 end)
6099 end
6100
6101 if CHAT_SYSTEM.primaryContainer and CHAT_SYSTEM.primaryContainer.HandleTabClick then
6102 ZO_PreHook(CHAT_SYSTEM.primaryContainer, "HandleTabClick", function(self, tab)
6103 pChatData.activeTab = tab.index
6104 if (db.enableChatTabChannel == true) then
6105 local tabIndex = tab.index
6106 if db.chatTabChannel[tabIndex] then
6107 CHAT_SYSTEM:SetChannel(db.chatTabChannel[tabIndex].channel, db.chatTabChannel[tabIndex].target)
6108 end
6109 end
6110 --ZO_TabButton_Text_RestoreDefaultColors(tab)
6111 end)
6112 end
6113
6114 if CHAT_SYSTEM.Maximize then
6115 -- Visual Notification PreHook
6116 ZO_PreHook(CHAT_SYSTEM, "Maximize", function(self)
6117 CHAT_SYSTEM.IMLabelMin:SetHidden(true)
6118 end)
6119 end
6120 end
6121
6122
6123 --local fontPath = ZoFontChat:GetFontInfo()
6124 --CHAT_SYSTEM:AddMessage(fontPath)
6125 --CHAT_SYSTEM:AddMessage("|C3AF24BLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.|r")
6126 --CHAT_SYSTEM:AddMessage("Characters below should be well displayed :")
6127 --CHAT_SYSTEM:AddMessage("!\"#$%&'()*+,-./0123456789:;<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|} ~¡£¤¥¦§©«-®°²³´µ¶·»½¿ ÀÁÂÄÆÇÈÉÊËÌÍÎÏÑÒÓÔÖ×ÙÚÛÜßàáâäæçèéêëìíîïñòóôöùúûüÿŸŒœ")
6128
6129 -- AntiSpam
6130 pChatData.spamLookingForEnabled = true
6131 pChatData.spamWantToEnabled = true
6132 pChatData.spamGuildRecruitEnabled = true
6133
6134 -- Show 1000 lines instead of 200 & Change fade delay
6135 ShowFadedLines()
6136 -- Get Chat Tab Namse stored in chatTabNames {}
6137 getTabNames()
6138 -- Rebuild Lam Panel
6139 BuildLAMPanel()
6140 --
6141 CreateNewChatTabPostHook()
6142
6143 -- Should we minimize ?
6144 MinimizeChatAtLaunch()
6145
6146 -- Message for new chars
6147 AutoSyncSettingsForNewPlayer()
6148
6149 -- Chat Config synchronization
6150 SyncChatConfig(db.chatSyncConfig, "lastChar")
6151 SaveChatConfig()
6152
6153 -- Tags next to entry box
6154 UpdateCharCorrespondanceTableChannelNames()
6155
6156 -- Update Swtches
6157 UpdateCharCorrespondanceTableSwitchs()
6158 CHAT_SYSTEM:CreateChannelData()
6159
6160 -- Set default channel at login
6161 SetToDefaultChannel()
6162
6163 -- Save all category colors
6164 SaveGuildIndexes()
6165
6166 -- Handle Copy text
6167 CopyToTextEntryText()
6168
6169 -- Restore History if needed
6170 RestoreChatHistory()
6171 -- Default Tab
6172 SetDefaultTab(db.defaultTab)
6173 -- Change Window apparence
6174 ChangeChatWindowDarkness()
6175
6176 -- libChat
6177 -- registerFormat = message for EVENT_CHAT_MESSAGE_CHANNEL
6178 -- registerFriendStatus = message for EVENT_FRIEND_PLAYER_STATUS_CHANGED
6179 -- registerIgnoreAdd = message for EVENT_IGNORE_ADDED, registerIgnoreRemove = message for EVENT_IGNORE_REMOVED
6180 -- registerGroupTypeChanged = message for EVENT_GROUP_TYPE_CHANGED
6181 -- All those events outputs to the ChatSystem
6182 PCHATLC:registerFormat(FormatMessage, ADDON_NAME)
6183
6184 if not PCHATLC.manager.registerFriendStatus then
6185 PCHATLC:registerFriendStatus(OnFriendPlayerStatusChanged, ADDON_NAME)
6186 end
6187
6188 PCHATLC:registerIgnoreAdd(OnIgnoreAdded, ADDON_NAME)
6189 PCHATLC:registerIgnoreRemove(OnIgnoreRemoved, ADDON_NAME)
6190 PCHATLC:registerGroupMemberLeft(OnGroupMemberLeft, ADDON_NAME)
6191 PCHATLC:registerGroupTypeChanged(OnGroupTypeChanged, ADDON_NAME)
6192
6193 isAddonInitialized = true
6194
6195 EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_PLAYER_ACTIVATED)
6196
6197 end
6198
6199end
6200
6201
6202-- Runs whenever "me" left a guild (or get kicked)
6203local function OnSelfLeftGuild(_, _, guildName)
6204
6205 -- It will rebuild optionsTable and recreate tables if user didn't went in this section before
6206 BuildLAMPanel()
6207
6208 -- Revert category colors & options
6209 RevertCategories(guildName)
6210
6211end
6212
6213local function SwitchToParty(characterName)
6214
6215 zo_callLater(function(characterName) -- characterName = avoid ZOS bug
6216 -- If "me" join group
6217 if(GetRawUnitName("player") == characterName) then
6218
6219 -- Switch to party channel when joinin a group
6220 if db.enablepartyswitch then
6221 CHAT_SYSTEM:SetChannel(CHAT_CHANNEL_PARTY)
6222 end
6223
6224 else
6225
6226 -- Someone else joined group
6227 -- If GetGroupSize() == 2 : Means "me" just created a group and "someone" just joining
6228 if GetGroupSize() == 2 then
6229 -- Switch to party channel when joinin a group
6230 if db.enablepartyswitch then
6231 CHAT_SYSTEM:SetChannel(CHAT_CHANNEL_PARTY)
6232 end
6233 end
6234
6235 end
6236 end, 200)
6237
6238end
6239
6240-- Triggers when EVENT_GROUP_MEMBER_JOINED
6241local function OnGroupMemberJoined(_, characterName)
6242 SwitchToParty(characterName)
6243end
6244
6245-- triggers when EVENT_GROUP_MEMBER_LEFT
6246local function OnGroupMemberLeft(_, characterName, reason, wasMeWhoLeft)
6247
6248 -- Go back to default channel
6249 if GetGroupSize() <= 1 then
6250 -- Go back to default channel when leaving a group
6251 if db.enablepartyswitch then
6252 -- Only if we was on party
6253 if CHAT_SYSTEM.currentChannel == CHAT_CHANNEL_PARTY and db.defaultchannel ~= PCHAT_CHANNEL_NONE then
6254 SetToDefaultChannel()
6255 end
6256 end
6257 end
6258
6259end
6260
6261-- Save a category color for guild chat, set by ChatSystem at launch + when user change manually
6262local function SaveChatCategoriesColors(category, r, g, b)
6263 if db.chatConfSync[pChatData.localPlayer] then
6264 if db.chatConfSync[pChatData.localPlayer].colors[category] == nil then
6265 db.chatConfSync[pChatData.localPlayer].colors[category] = {}
6266 end
6267 db.chatConfSync[pChatData.localPlayer].colors[category] = { red = r, green = g, blue = b }
6268 end
6269end
6270
6271-- PreHook of ZO_ChatSystem_ShowOptions() and ZO_ChatWindow_OpenContextMenu(control.index)
6272local function ChatSystemShowOptions(tabIndex)
6273 local self = CHAT_SYSTEM.primaryContainer
6274 tabIndex = tabIndex or (self.currentBuffer and self.currentBuffer:GetParent() and self.currentBuffer:GetParent().tab and self.currentBuffer:GetParent().tab.index)
6275 local window = self.windows[tabIndex]
6276 if window then
6277 ClearMenu()
6278
6279 if not ZO_Dialogs_IsShowingDialog() then
6280 AddMenuItem(GetString(SI_CHAT_CONFIG_CREATE_NEW), function() self.system:CreateNewChatTab(self) end)
6281 end
6282
6283 if not ZO_Dialogs_IsShowingDialog() and not window.combatLog and (not self:IsPrimary() or tabIndex ~= 1) then
6284 AddMenuItem(GetString(SI_CHAT_CONFIG_REMOVE), function() self:ShowRemoveTabDialog(tabIndex) end)
6285 end
6286
6287 if not ZO_Dialogs_IsShowingDialog() then
6288 AddMenuItem(GetString(SI_CHAT_CONFIG_OPTIONS), function() self:ShowOptions(tabIndex) end)
6289 end
6290
6291 if not ZO_Dialogs_IsShowingDialog() then
6292 AddMenuItem(GetString(PCHAT_CLEARBUFFER), function()
6293 pChatData.tabNotBefore[tabIndex] = GetTimeStamp()
6294 self.windows[tabIndex].buffer:Clear()
6295 self:SyncScrollToBuffer()
6296 end)
6297 end
6298
6299 if self:IsPrimary() and tabIndex == 1 then
6300 if self:IsLocked(tabIndex) then
6301 AddMenuItem(GetString(SI_CHAT_CONFIG_UNLOCK), function() self:SetLocked(tabIndex, false) end)
6302 else
6303 AddMenuItem(GetString(SI_CHAT_CONFIG_LOCK), function() self:SetLocked(tabIndex, true) end)
6304 end
6305 end
6306
6307 if window.combatLog then
6308 if self:AreTimestampsEnabled(tabIndex) then
6309 AddMenuItem(GetString(SI_CHAT_CONFIG_HIDE_TIMESTAMP), function() self:SetTimestampsEnabled(tabIndex, false) end)
6310 else
6311 AddMenuItem(GetString(SI_CHAT_CONFIG_SHOW_TIMESTAMP), function() self:SetTimestampsEnabled(tabIndex, true) end)
6312 end
6313 end
6314
6315 --[[
6316 if db.chatConfSync[GetUnitName("player")].textEntryDocked then
6317 AddMenuItem(GetString(PCHAT_UNDOCKTEXTENTRY), function() UndockTextEntry() end)
6318 else
6319 AddMenuItem(GetString(PCHAT_REDOCKTEXTENTRY), function() RedockTextEntry() end)
6320 end
6321 ]]
6322
6323 ShowMenu(window.tab)
6324 end
6325
6326 return true
6327
6328end
6329
6330-- Please note that some things are delayed in OnPlayerActivated() because Chat isn't ready when this function triggers
6331local function OnAddonLoaded(_, addonName)
6332
6333 --Protect
6334 if addonName == ADDON_NAME then
6335
6336 -- Resize, must be loaded before CHAT_SYSTEM is set
6337 --local width, height = GuiRoot:GetDimensions()
6338 --CHAT_SYSTEM.maxContainerWidth, CHAT_SYSTEM.maxContainerHeight = width, height
6339
6340 do
6341 local orgCalculateConstraints = SharedChatContainer.CalculateConstraints
6342 function SharedChatContainer.CalculateConstraints(...)
6343 local self = ...
6344 local w, h = GuiRoot:GetDimensions()
6345 self.system.maxContainerWidth, self.system.maxContainerHeight = w * 0.95, h * 0.95
6346 return orgCalculateConstraints(...)
6347 end
6348 end
6349
6350 -- Char name
6351 pChatData.localPlayer = GetUnitName("player")
6352
6353 --LAM and db for saved vars
6354 GetDBAndBuildLAM()
6355
6356 -- Used for CopySystem
6357
6358 if not db.lineNumber then
6359 db.lineNumber = 1
6360 elseif type(db.lineNumber) ~= "number" then
6361 db.lineNumber = 1
6362 db.LineStrings = {}
6363 elseif db.lineNumber > 5000 then
6364 StripLinesFromLineStrings(0)
6365 end
6366
6367 if not db.chatTabChannel then
6368 db.chatTabChannel = {}
6369 end
6370
6371 if not db.LineStrings then
6372 db.LineStrings = {}
6373 end
6374
6375 if not tabNames then
6376 tabNames = {}
6377 end
6378
6379 -- Will set Keybind for "switch to next tab" if needed
6380 SetSwitchToNextBinding()
6381
6382 -- Will change font if needed
6383 ChangeChatFont()
6384
6385 -- Automated messages
6386 InitAutomatedMessages()
6387
6388 -- Minimize Chat in Menus
6389 MinimizeChatInMenus()
6390
6391 BuildNicknames()
6392
6393 InitializeURLHandling()
6394
6395 -- PreHook ReloadUI, SetCVar, LogOut & Quit to handle Chat Import/Export
6396 ZO_PreHook("ReloadUI", function()
6397 SaveChatHistory(1)
6398 SaveChatConfig()
6399 end)
6400
6401 ZO_PreHook("SetCVar", function()
6402 SaveChatHistory(1)
6403 SaveChatConfig()
6404 end)
6405
6406 ZO_PreHook("Logout", function()
6407 SaveChatHistory(2)
6408 SaveChatConfig()
6409 end)
6410
6411 ZO_PreHook("Quit", function()
6412 SaveChatHistory(3)
6413 SaveChatConfig()
6414 end)
6415
6416 -- Social option change color
6417 ZO_PreHook("SetChatCategoryColor", SaveChatCategoriesColors)
6418 -- Chat option change categories filters, add a callLater because settings are set after this function triggers.
6419 ZO_PreHook("ZO_ChatOptions_ToggleChannel", function() zo_callLater(SaveTabsCategories, 100) end)
6420
6421 -- Right click on a tab name
6422 ZO_PreHook("ZO_ChatSystem_ShowOptions", function(control) return ChatSystemShowOptions() end)
6423 ZO_PreHook("ZO_ChatWindow_OpenContextMenu", function(control) return ChatSystemShowOptions(control.index) end)
6424 -- Bindings
6425 ZO_CreateStringId("SI_BINDING_NAME_PCHAT_TOGGLE_CHAT_WINDOW", GetString(PCHAT_TOGGLECHATBINDING))
6426 ZO_CreateStringId("SI_BINDING_NAME_PCHAT_WHISPER_MY_TARGET", GetString(PCHAT_WHISPMYTARGETBINDING))
6427 ZO_CreateStringId("SI_BINDING_NAME_TAB_1", GetString(PCHAT_Tab1))
6428 ZO_CreateStringId("SI_BINDING_NAME_TAB_2", GetString(PCHAT_Tab2))
6429 ZO_CreateStringId("SI_BINDING_NAME_TAB_3", GetString(PCHAT_Tab3))
6430 ZO_CreateStringId("SI_BINDING_NAME_TAB_4", GetString(PCHAT_Tab4))
6431 ZO_CreateStringId("SI_BINDING_NAME_TAB_5", GetString(PCHAT_Tab5))
6432 ZO_CreateStringId("SI_BINDING_NAME_TAB_6", GetString(PCHAT_Tab6))
6433 ZO_CreateStringId("SI_BINDING_NAME_TAB_7", GetString(PCHAT_Tab7))
6434 ZO_CreateStringId("SI_BINDING_NAME_TAB_8", GetString(PCHAT_Tab8))
6435 ZO_CreateStringId("SI_BINDING_NAME_TAB_9", GetString(PCHAT_Tab9))
6436 ZO_CreateStringId("SI_BINDING_NAME_TAB_10", GetString(PCHAT_Tab10))
6437 ZO_CreateStringId("SI_BINDING_NAME_TAB_11", GetString(PCHAT_Tab11))
6438 ZO_CreateStringId("SI_BINDING_NAME_TAB_12", GetString(PCHAT_Tab12))
6439 -- Register OnSelfJoinedGuild with EVENT_GUILD_SELF_JOINED_GUILD
6440 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_GUILD_SELF_JOINED_GUILD, OnSelfJoinedGuild)
6441
6442 -- Register OnSelfLeftGuild with EVENT_GUILD_SELF_LEFT_GUILD
6443 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_GUILD_SELF_LEFT_GUILD, OnSelfLeftGuild)
6444
6445 -- Because ChatSystem is loaded after EVENT_ADDON_LOADED triggers, we use 1st EVENT_PLAYER_ACTIVATED wich is run bit after
6446 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_PLAYER_ACTIVATED, OnPlayerActivated)
6447
6448 -- Whisp my target
6449 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_RETICLE_TARGET_CHANGED, OnReticleTargetChanged)
6450
6451 -- Party switches
6452 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_GROUP_MEMBER_JOINED, OnGroupMemberJoined)
6453 EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_GROUP_MEMBER_LEFT, OnGroupMemberLeft)
6454
6455 -- Unregisters
6456 EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED)
6457
6458 isAddonLoaded = true
6459
6460 end
6461
6462end
6463
6464--Handled by keybind
6465function pChat_ToggleChat()
6466
6467 if CHAT_SYSTEM:IsMinimized() then
6468 CHAT_SYSTEM:Maximize()
6469 else
6470 CHAT_SYSTEM:Minimize()
6471 end
6472
6473end
6474
6475-- Called by bindings
6476function pChat_WhispMyTarget()
6477 if targetToWhisp then
6478 CHAT_SYSTEM:StartTextEntry(nil, CHAT_CHANNEL_WHISPER, targetToWhisp)
6479 end
6480end
6481
6482-- For compatibility. Called by others addons.
6483function pChat.formatSysMessage(statusMessage)
6484 return FormatSysMessage(statusMessage)
6485end
6486
6487-- For compatibility. Called by others addons.
6488function pChat_FormatSysMessage(statusMessage)
6489 return FormatSysMessage(statusMessage)
6490end
6491
6492-- For compatibility. Called by others addons.
6493function pChat_GetChannelColors(channel, from)
6494 return GetChannelColors(channel, from)
6495end
6496
6497EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, OnAddonLoaded)