-----Declaring namespace and some variables along with tables----- local LAM = LibStub:GetLibrary("LibAddonMenu-2.0") local LMP = LibStub:GetLibrary("LibMediaProvider-1.0") RaidTimer = {} RaidTimer.name = 'RaidTimer' RaidTimer.slash = '/rt' RaidTimer.version = '1.3.0' RaidTimer.versionDB = 1 RaidTimer.loaded = false RaidTimer.author = 'Noshiz, Garkin & silentgecko' RaidTimer.tempVars = { stop = false, complete = false, showTimers = false, instance = false, } RaidTimer.variables = { TotalOffsetX = 45, TotalOffsetY = 30, ScoreOffsetX = 45, ScoreOffsetY = 60, FontFace = "Univers 67", FontSize = 16, FontStyle = "soft-shadow-thin", TotalFonts = "ZoFontHeader", ScoreFonts = "ZoFontHeader", TotalColor = { ZO_NORMAL_TEXT:UnpackRGBA() }, ScoreColor = { ZO_NORMAL_TEXT:UnpackRGBA() }, Movable = true, hardMode = false, hardModePoints = 40000, -- Hardmode Bonus Points for AA, HR and SO maSpeedBonusPoints = 15000, -- Speed Bonus Points when under 90 mins topScores = { [1] = { time = 0, score = 0, }, [2] = { time = 0, score = 0, }, [3] = { time = 0, score = 0, }, [4] = { time = 0, score = 0, }, [6] = { time = 0, score = 0, }, }, } RaidTimer.timeLimits = { [0] = 0, --none [1] = 720, --Hel Ra Citadel (12 minutes) [2] = 720, --Aetherian Archive (12 minutes) [3] = 1500, --Sanctum Ophidia (25 minutes) [4] = 3900, --Dragonstar Arena (Veteran) (65 minutes) [5] = 0, --none [6] = 5400, --Maelstrom Arena (Veteran) (4 hours 16 min 40 sek) } RaidTimer.raidPoints = { [0] = 0, --none [1] = 69300, --Hel Ra Citadel [2] = 63000, --Aetherian Archive [3] = 100750,--Sanctum Ophidia (117.750 with troll archievement) [4] = 20000, --Dragonstar Arena (Veteran) [5] = 0, --none [6] = 396000, --Maelstrom Arena (Veteran) } local function CreateSettingsMenu() local self = RaidTimer ------Creating the menu with LibAddonMenu-2.0 (thank you Seerah)------- self.panelData = { type = "panel", name = self.name, author = self.author, version = self.version, registerForRefresh = false, } self.optionsData = { { type = "description", text = GetString(RAIDTIMER_DESCRIPTION), }, { type = "checkbox", name = GetString(RAIDTIMER_HARDMODE), tooltip = GetString(RAIDTIMER_HARDMODE_TOOLTIP), getFunc = function() return RaidTimer.savedVariables.hardMode end, setFunc = function(value) RaidTimer.savedVariables.hardMode = value end, }, { type = "checkbox", name = GetString(RAIDTIMER_SHOW_TIMERS_OUTSIDE), tooltip = GetString(RAIDTIMER_SHOW_TIMERS_OUTSIDE_TOOLTIP), getFunc = function() return RaidTimer.tempVars.showTimers end, setFunc = function(value) RaidTimer.tempVars.showTimers = value RaidTimer.Total_Timer:SetHidden(RaidTimer.tempVars.instance and not value) RaidTimer.Raid_Score:SetHidden(RaidTimer.tempVars.instance and not value) end, }, { type = "checkbox", name = GetString(RAIDTIMER_UNLOCK_TIMERS), tooltip = GetString(RAIDTIMER_UNLOCK_TIMERS_TOOLTIP), getFunc = function() return RaidTimer.savedVariables.Movable end, setFunc = function(value) RaidTimer.Total_Timer:SetMovable(value) RaidTimer.Raid_Score:SetMovable(value) RaidTimer.savedVariables.Movable = value end, }, { type = "colorpicker", name = GetString(RAIDTIMER_TOTAL_TIME_COLOR), tooltip = GetString(RAIDTIMER_TOTAL_TIME_COLOR_TOOLTIP), getFunc = function() return unpack(RaidTimer.savedVariables.TotalColor) end, setFunc = function(r,g,b,a) RaidTimer.Total_Timer:SetColor(r, g, b, a) RaidTimer.savedVariables.TotalColor = {r,g,b,a} end, }, { type = "colorpicker", name = GetString(RAIDTIMER_RAID_SCORE_COLOR), tooltip = GetString(RAIDTIMER_RAID_SCORE_COLOR_TOOLTIP), getFunc = function() return unpack(RaidTimer.savedVariables.ScoreColor) end, setFunc = function(r,g,b,a) RaidTimer.Raid_Score:SetColor(r, g, b, a) RaidTimer.savedVariables.ScoreColor = {r,g,b,a} end, }, { type = "dropdown", name = GetString(RAIDTIMER_FONTS), tooltip = GetString(RAIDTIMER_FONTS_TOOLTIP), choices = LMP:List("font"), getFunc = function() return RaidTimer.savedVariables.FontFace end, setFunc = function(choice) RaidTimer.savedVariables.FontFace = choice end, }, { type = "slider", name = GetString(RAIDTIMER_FONT_SIZE), tooltip = GetString(RAIDTIMER_FONT_SIZE_TOOLTIP), min = 16, max = 40, getFunc = function() return RaidTimer.savedVariables.FontSize end, setFunc = function(size) RaidTimer.savedVariables.FontSize = size end, }, { type = "dropdown", name = GetString(RAIDTIMER_FONT_STYLE), tooltip = GetString(RAIDTIMER_FONT_STYLE_TOOLTIP), choices = {"none", "soft-shadow-thin", "soft-shadow-thick", "shadow"}, getFunc = function() return RaidTimer.savedVariables.FontStyle end, setFunc = function(choice) RaidTimer.savedVariables.FontStyle = choice end, }, { type = "checkbox", name = GetString(RAIDTIMER_DEBUG), tooltip = GetString(RAIDTIMER_DEBUG_TOOLTIP), getFunc = function() return RaidTimer.savedVariables.debug end, setFunc = function(value) RaidTimer.savedVariables.debug = value end, }, { type = "button", name = GetString(RAIDTIMER_APPLY), tooltip = GetString(RAIDTIMER_APPLY_TOOLTIP), func = function() local formatstring = "%s|%d" if RaidTimer.savedVariables.FontStyle ~= "none" then formatstring = formatstring .. "|%s" end RaidTimer.finalFont = (formatstring):format(LMP:Fetch("font", RaidTimer.savedVariables.FontFace), RaidTimer.savedVariables.FontSize, RaidTimer.savedVariables.FontStyle) RaidTimer.Total_Timer:SetFont(RaidTimer.finalFont) RaidTimer.Raid_Score:SetFont(RaidTimer.finalFont) RaidTimer.savedVariables.TotalFonts = RaidTimer.finalFont RaidTimer.savedVariables.ScoreFonts = RaidTimer.finalFont end, }, } LAM:RegisterAddonPanel("RaidTimerPanel", self.panelData) LAM:RegisterOptionControls("RaidTimerPanel", self.optionsData) end ---------Passing saved variables to the labels at initialize------- function RaidTimer.Initialize(event, addonName) local self = RaidTimer if addonName ~= self.name then return end EVENT_MANAGER:UnregisterForEvent(self.name, EVENT_ADD_ON_LOADED) SLASH_COMMANDS[self.slash] = self.Commands self.savedVariables = ZO_SavedVars:NewAccountWide("RTVars", self.versionDB, nil, self.variables) self.pointReasons = { [RAID_POINT_REASON_KILL_NOXP_MONSTER] = GetString(RAIDTIMER_KILL_NOXP_MONSTER), -- 0 [RAID_POINT_REASON_KILL_NORMAL_MONSTER] = GetString(RAIDTIMER_KILL_NORMAL_MONSTER), -- 1 [RAID_POINT_REASON_KILL_BANNERMEN] = GetString(RAIDTIMER_KILL_BANNERMEN), -- 2 [RAID_POINT_REASON_KILL_CHAMPION] = GetString(RAIDTIMER_KILL_CHAMPION), -- 3 [RAID_POINT_REASON_KILL_MINIBOSS] = GetString(RAIDTIMER_KILL_MINIBOSS), -- 4 [RAID_POINT_REASON_KILL_BOSS] = GetString(RAIDTIMER_KILL_BOSS), -- 5 [RAID_POINT_REASON_BONUS_ACTIVITY_LOW] = GetString(RAIDTIMER_BONUS_ACTIVITY_LOW), -- 6 [RAID_POINT_REASON_BONUS_ACTIVITY_MEDIUM] = GetString(RAIDTIMER_BONUS_ACTIVITY_MEDIUM), -- 7 [RAID_POINT_REASON_BONUS_ACTIVITY_HIGH] = GetString(RAIDTIMER_BONUS_ACTIVITY_HIGH), -- 8 [RAID_POINT_REASON_LIFE_REMAINING] = GetString(RAIDTIMER_LIFE_REMAINING), -- 9 [RAID_POINT_REASON_BONUS_POINT_ONE] = GetString(RAIDTIMER_BONUS_POINT_ONE), -- 10 [RAID_POINT_REASON_BONUS_POINT_TWO] = GetString(RAIDTIMER_BONUS_POINT_THREE), -- 11 [RAID_POINT_REASON_BONUS_POINT_THREE] = GetString(RAIDTIMER_BONUS_POINT_THREE), -- 12 [RAID_POINT_REASON_SOLO_ARENA_PICKUP_ONE] = GetString(RAIDTIMER_SYGILLS_USED_THREE), -- 13 [RAID_POINT_REASON_SOLO_ARENA_PICKUP_TWO] = GetString(RAIDTIMER_SYGILLS_USED_TWO), -- 14 [RAID_POINT_REASON_SOLO_ARENA_PICKUP_THREE] = GetString(RAIDTIMER_SYGILLS_USED_ONE), -- 15 [RAID_POINT_REASON_SOLO_ARENA_PICKUP_FOUR] = GetString(RAIDTIMER_SYGILLS_USED_NONE), -- 16 [RAID_POINT_REASON_SOLO_ARENA_COMPLETE] = GetString(RAIDTIMER_ARENA_COMPLETE), -- 17 } -------Creating the two labels--------- self.Root_Window = WINDOW_MANAGER:CreateTopLevelWindow(nil) self.Total_Timer = WINDOW_MANAGER:CreateControl(nil, self.Root_Window, CT_LABEL) self.Total_Timer:SetText(GetString(RAIDTIMER_TOTAL_TIME_TEMPLATE)) self.Total_Timer:SetMouseEnabled(true) self.Total_Timer:SetHidden(true) self.Total_Timer:SetAnchor(TOPLEFT, self.Root_Window, TOPLEFT, self.savedVariables.TotalOffsetX, self.savedVariables.TotalOffsetY) self.Total_Timer:SetFont(self.savedVariables.TotalFonts) self.Total_Timer:SetMovable(self.savedVariables.Movable) self.Total_Timer:SetClampedToScreen(true) self.Total_Timer:SetColor(unpack(self.savedVariables.TotalColor)) self.Total_Timer:SetHandler("OnMoveStop", self.SaveLoc) self.Raid_Score = WINDOW_MANAGER:CreateControl(nil, self.Root_Window, CT_LABEL) self.Raid_Score:SetText(GetString(RAIDTIMER_RAID_SCORE_TEMPLATE)) self.Raid_Score:SetMouseEnabled(true) self.Raid_Score:SetHidden(true) self.Raid_Score:SetAnchor(TOPLEFT, self.Root_Window, TOPLEFT, self.savedVariables.ScoreOffsetX, self.savedVariables.ScoreOffsetY) self.Raid_Score:SetFont(self.savedVariables.ScoreFonts) self.Raid_Score:SetMovable(self.savedVariables.Movable) self.Raid_Score:SetClampedToScreen(true) self.Raid_Score:SetColor(unpack(self.savedVariables.ScoreColor)) self.Raid_Score:SetHandler("OnMoveStop", self.SaveLoc) local RaidTimerSceneFragment = ZO_HUDFadeSceneFragment:New(self.Root_Window) HUD_SCENE:AddFragment(RaidTimerSceneFragment) HUD_UI_SCENE:AddFragment(RaidTimerSceneFragment) CreateSettingsMenu() if IsRaidInProgress() then self.TimerStart() else self.savedVariables.raidStart = nil end end ---------The function that does all the calculation magic-------- function RaidTimer.TimerUpdate() local self = RaidTimer if self.tempVars.stop == true then EVENT_MANAGER:UnregisterForUpdate("RAID_TIMER_UPDATE") return end local currentTime = GetTimeStamp() local raidDuration = GetDiffBetweenTimeStamps(currentTime, self.raidStart) local formatedTime = ZO_FormatTime(raidDuration, TIME_FORMAT_STYLE_COLONS, TIME_FORMAT_PRECISION_SECONDS) self.Total_Timer:SetText(zo_strformat(GetString(RAIDTIMER_TOTAL_TIME), formatedTime)) if self.score > 0 then self.raidId = self.raidId or GetCurrentParticipatingRaidId() local timeLimit = self.timeLimits[self.raidId] or 0 local maxPoints = self.raidPoints[self.raidId] or 0 if timeLimit > 0 and maxPoints > 0 then -- hardmode only on the first three raids local currentPoints = self.score if self.raidId > 0 and self.raidId <= 4 and self.savedVariables.hardMode then maxPoints = maxPoints + self.variables.hardModePoints currentPoints = self.score + self.variables.hardModePoints end -- add the bonus points for MA Veteran if self.raidId == 6 and raidDuration < timeLimit then maxPoints = maxPoints + self.variables.maSpeedBonusPoints currentPoints = self.score + self.variables.maSpeedBonusPoints end local estimatedScore = 0 --if self.raidId == 6 then estimatedScore = (currentPoints+((currentPoints)*((timeLimit-raidDuration)/10000))) --else --old formula --estimatedScore = zo_max(zo_round(((timeLimit - (raidDuration * maxPoints / currentPoints)) * (maxPoints / 1000)) + maxPoints), zo_floor(currentPoints / 100)) --end local currentBestScore = self.savedVariables.topScores[self.raidId].score or 0 local currentBestTime = self.savedVariables.topScores[self.raidId].time or 0 if estimatedScore > currentBestScore then self.Raid_Score:SetText(zo_strformat(GetString(RAIDTIMER_RAID_SCORE_WITH_NEW_TOPSCORE), ZO_CommaDelimitNumber(currentPoints), ZO_CommaDelimitNumber(estimatedScore))) else self.Raid_Score:SetText(zo_strformat(GetString(RAIDTIMER_RAID_SCORE_WITH_ESTIMATION), ZO_CommaDelimitNumber(currentPoints), ZO_CommaDelimitNumber(estimatedScore))) end end end end function RaidTimer.ScoreUpdate(event, scoreType, scoreAmount, totalScore) local self = RaidTimer self.score = self.score or GetCurrentRaidScore() if totalScore > self.score then self.raidId = self.raidId or GetCurrentParticipatingRaidId() local currentTime = GetTimeStamp() local raidDuration = GetDiffBetweenTimeStamps(currentTime, self.raidStart) local timeLimit = self.timeLimits[self.raidId] or 0 local maxPoints = self.raidPoints[self.raidId] or 0 -- hardmode only on the first three raids local currentPoints = totalScore if self.raidId > 0 and self.raidId <= 4 and self.savedVariables.hardMode then maxPoints = maxPoints + self.variables.hardModePoints currentPoints = totalScore + self.variables.hardModePoints end -- add the bonus points for MA Veteran if self.raidId == 6 and raidDuration < timeLimit then maxPoints = maxPoints + self.variables.maSpeedBonusPoints currentPoints = self.score + self.variables.maSpeedBonusPoints end if timeLimit > 0 and maxPoints > 0 then local estimatedScore = 0 --if self.raidId == 6 then estimatedScore = (currentPoints+((currentPoints)*((timeLimit-raidDuration)/10000))) --else --old formula --estimatedScore = zo_max(zo_round(((timeLimit - (raidDuration * maxPoints / currentPoints)) * (maxPoints / 1000)) + maxPoints), zo_floor(currentPoints / 100)) --end --local estimatedScore = zo_max(zo_round(((timeLimit - (raidDuration * maxPoints / currentPoints)) * (maxPoints / 1000)) + maxPoints), zo_floor(currentPoints / 100)) local currentBestScore = self.savedVariables.topScores[self.raidId].score or 0 local currentBestTime = self.savedVariables.topScores[self.raidId].time or 0 if estimatedScore > currentBestScore then d(zo_strformat(GetString(RAIDTIMER_POSSIBLE_NEW_TOPSCORE_DEBUG), ZO_CommaDelimitNumber(currentBestScore), ZO_FormatTimeMilliseconds(currentBestTime, TIME_FORMAT_STYLE_COLONS, TIME_FORMAT_PRECISION_SECONDS))) end else self.Raid_Score:SetText(zo_strformat(GetString(RAIDTIMER_RAID_SCORE_WITHOUT_ESTIMATION), ZO_CommaDelimitNumber(currentPoints))) end self.score = totalScore end if self.savedVariables.debug then d(zo_strformat(GetString(RAIDTIMER_DEBUG_MESSAGE), scoreAmount, totalScore, self.pointReasons[scoreType])) end end function RaidTimer.TimerStart() local self = RaidTimer self.tempVars.stop = false self.tempVars.instance = true if self.savedVariables.raidStart then self.raidStart = self.savedVariables.raidStart else self.raidStart = GetTimeStamp() self.savedVariables.raidStart = self.raidStart end self.score = GetCurrentRaidScore() or 0 self.raidId = GetCurrentParticipatingRaidId() if self.savedVariables.debug then local currentTopScore = self.savedVariables.topScores[self.raidId].score or 0 local currentTopTime = self.savedVariables.topScores[self.raidId].time or 0 d(zo_strformat(GetString(RAIDTIMER_TRIAL_START_MESSAGE), ZO_CommaDelimitNumber(currentTopScore), ZO_FormatTimeMilliseconds(currentTopTime, TIME_FORMAT_STYLE_COLONS, TIME_FORMAT_PRECISION_SECONDS))) end self.Total_Timer:SetHidden(false) self.Raid_Score:SetHidden(false) self.TimerUpdate() EVENT_MANAGER:RegisterForUpdate("RAID_TIMER_UPDATE", 1000, self.TimerUpdate) end function RaidTimer.TimerStop(event, trialName, totalScore, totalTime) local self = RaidTimer self.tempVars.stop = true self.tempVars.instance = false local template = GetString(RAIDTIMER_TRIAL_COMPLETE) local raidId = GetCurrentParticipatingRaidId() if totalTime == nil then local currentTime = GetTimeStamp() totalTime = GetDiffBetweenTimeStamps(currentTime, self.raidStart) * 1000 template = GetString(RAIDTIMER_TRIAL_FAILED) end -- set savedVariables.topScores local currentTopScore = self.savedVariables.topScores[raidId].score or 0 local currentTopTime = self.savedVariables.topScores[raidId].time or 0 if totalScore > currentTopScore then self.savedVariables.topScores[raidId].time = totalTime self.savedVariables.topScores[raidId].score = totalScore d(zo_strformat(GetString(RAIDTIMER_NEW_TOPSCORE))) end local formatedTime = ZO_FormatTimeMilliseconds(totalTime, TIME_FORMAT_STYLE_COLONS, TIME_FORMAT_PRECISION_SECONDS) d(zo_strformat(template, trialName, formatedTime, ZO_CommaDelimitNumber(totalScore))) self.Total_Timer:SetHidden(true) self.Raid_Score:SetHidden(true) self.score = 0 self.raidId = nil self.raidStart = nil self.savedVariables.raidStart = nil end -------Saving the location of the labels when /rt show------- function RaidTimer.SaveLoc() local self = RaidTimer self.savedVariables.TotalOffsetX = self.Total_Timer:GetLeft() self.savedVariables.TotalOffsetY = self.Total_Timer:GetTop() self.savedVariables.ScoreOffsetX = self.Raid_Score:GetLeft() self.savedVariables.ScoreOffsetY = self.Raid_Score:GetTop() end ---------Chat commands--------- function RaidTimer.Commands(text) local self = RaidTimer if not text or text =="" or text =="help" or text =="h" then d(GetString(RAIDTIMER_SLASH_HELP)) d(GetString(RAIDTIMER_SLASH_START)) d(GetString(RAIDTIMER_SLASH_STOP)) d(GetString(RAIDTIMER_SLASH_SHOW)) d(GetString(RAIDTIMER_SLASH_HIDE)) d(GetString(RAIDTIMER_SLASH_DEBUG)) d(GetString(RAIDTIMER_SLASH_SURPRISE)) d(GetString(RAIDTIMER_SLASH_SETTINGS_HINT)) elseif text == "start" or text == "s" then if not self.tempVars.instance then self.TimerStart() end elseif text =="stop" then if self.tempVars.instance then local raidName = GetRaidName(GetCurrentParticipatingRaidId()) if #raidName == 0 then raidName = GetString(RAIDTIMER_TRIALNAME_UNKNOWN) end local raidScore = GetCurrentRaidScore() local totalTime if HasRaidEnded() and WasRaidSuccessful() then totalTime = GetGameTimeMilliseconds() - self.raidStart end self.TimerStop(nil, raidName, raidScore, totalTime) end elseif text =="show" then self.Total_Timer:SetHidden(false) self.Raid_Score:SetHidden(false) self.tempVars.showTimers = true elseif text =="hide" then self.Total_Timer:SetHidden(true) self.Raid_Score:SetHidden(true) self.tempVars.showTimers = false elseif text == "debug" then self.savedVariables.debug = not self.savedVariables.debug elseif text == "surprise" then ---A little bit of harmless trolling---- d(GetString(RAIDTIMER_SURPRISE)) else d(GetString(RAIDTIMER_HELP)) end end EVENT_MANAGER:RegisterForEvent(RaidTimer.name, EVENT_ADD_ON_LOADED, RaidTimer.Initialize) EVENT_MANAGER:RegisterForEvent("RAID_TIMER_UPDATE", EVENT_RAID_TRIAL_SCORE_UPDATE, RaidTimer.ScoreUpdate) EVENT_MANAGER:RegisterForEvent("RAID_TIMER_START", EVENT_RAID_TRIAL_STARTED, RaidTimer.TimerStart) EVENT_MANAGER:RegisterForEvent("RAID_TIMER_STOP", EVENT_RAID_TRIAL_COMPLETE, RaidTimer.TimerStop) EVENT_MANAGER:RegisterForEvent("RAID_TIMER_STOP", EVENT_RAID_TRIAL_FAILED, RaidTimer.TimerStop)