Quantcast

Minor text update

urnati [11-26-25 - 01:45]
Minor text update
Filename
TitanLootType/TitanClassicLootType.lua
TitanLootType/TitanClassicLootType.xml
TitanRegen/TitanRegen.lua
TitanUI/Tools.lua
diff --git a/TitanLootType/TitanClassicLootType.lua b/TitanLootType/TitanClassicLootType.lua
index 8184a07..32d71ef 100644
--- a/TitanLootType/TitanClassicLootType.lua
+++ b/TitanLootType/TitanClassicLootType.lua
@@ -1,1270 +1,1270 @@
---[===[ File
-NAME: TitanLootType.lua
-DESC:
-This Titan plugin will show group type and loot type in the button text.
-A roll tracker is used to show rolls in party to help make passing out loot and chests.
-This is a simplistic roll helper! It is NOT intended as a loot tracker!
-
-On right-click it will show the normal Titan options.
-The left-click it will depend whether the user is group leader or loot master :
-  if not leader a /roll will be done.
-  if leader the tracker window will pop, giving them additional options
-  - Start   : Start a new roll
-  - Remind  : Nag those who have not rolled with a whisper
-  - Results : State the results
-
-Once a leader initiates a roll, the tracker will pop for other Titan users who are using LootType.
-:DESC
---]===]
-TitanPanelLootType                 = {} -- declare name space
-local LT                           = TitanPanelLootType -- save some typing...
-
--- ******************************** Constants *******************************
-local TITAN_LOOTTYPE_ID            = "LootType";
-local _G                           = getfenv(0);
-local L                            = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true)
-local TitanLootMethod              = {};
-local updateTable                  = { TITAN_LOOTTYPE_ID, TITAN_PANEL_UPDATE_ALL };
-TitanLootMethod["freeforall"]      = { text = L["TITAN_LOOTTYPE_FREE_FOR_ALL"] };
-TitanLootMethod["roundrobin"]      = { text = L["TITAN_LOOTTYPE_ROUND_ROBIN"] };
-TitanLootMethod["master"]          = { text = L["TITAN_LOOTTYPE_MASTER_LOOTER"] };
-TitanLootMethod["group"]           = { text = L["TITAN_LOOTTYPE_GROUP_LOOT"] };
-TitanLootMethod["needbeforegreed"] = { text = L["TITAN_LOOTTYPE_NEED_BEFORE_GREED"] };
-TitanLootMethod["personalloot"] = {text = L["TITAN_LOOTTYPE_PERSONAL"]};
--- For new method...
-TitanLootMethod[0] = {text = L["TITAN_LOOTTYPE_FREE_FOR_ALL"]};
-TitanLootMethod[1] = {text = L["TITAN_LOOTTYPE_ROUND_ROBIN"]};
-TitanLootMethod[2] = {text = L["TITAN_LOOTTYPE_MASTER_LOOTER"]};
-TitanLootMethod[3] = {text = L["TITAN_LOOTTYPE_GROUP_LOOT"]};
-TitanLootMethod[4] = {text = L["TITAN_LOOTTYPE_NEED_BEFORE_GREED"]};
-TitanLootMethod[5] = {text = L["TITAN_LOOTTYPE_PERSONAL"]};
-
-local TOCNAME                      = "TitanLootType"
-local Track                        = {}
-Track.DB = {}
-
--- High level constants
-Track.IconDice                     = "Interface\\Buttons\\UI-GroupLoot-Dice-Up"
---Track.IconGreed= "Interface\\Buttons\\UI-GroupLoot-Coin-Up"
-Track.IconPass                     = "Interface\\Buttons\\UI-GroupLoot-Pass-Up"
-Track.IconLoot                     = "Interface\\GroupFrame\\UI-Group-MasterLooter"
-Track.TxtEscapePicture             = "|T%s:0|t"
-Track.TxtEscapeIcon                = "|T%s:0:0:0:0:64:64:4:60:4:60|t"
-
--- These are encoded 'messages' this addon searches for to start and end the roll process
-Track.MSGPREFIX                    = "Titan LootType Roller: " -- also frame title
-Track.MSGPREFIX_START              = Track.MSGPREFIX .. ">>: "
-Track.MSGPREFIX_END                = Track.MSGPREFIX .. "<<: "
-Track.MSGPREFIX_CLOSE              = Track.MSGPREFIX .. "__: "
-
-
--- This will be debugged real-time so put the debug on 'switches'
--- Also useful when debugging 'solo'
-LT.Debug = {
-	-- Used when creating dummy player list (see flags) or solo debug to get 'self'
-	-- And debug output
-	on    = false, -- true false
-
-	show  = { -- for LootDebug messages
-		events = false, -- show debug for events
-		players = false, -- show debug for players
-		-- nil will show regardless
-	},
-
-	flags = { -- solo debug
-		force_leader = false,
-		force_master = false,
-		force_loot_master = false,
-		-- These 3 are used when creating dummy player list WITH 'on' = true
-		add_players = false,
-		is_raid = false,
-		is_party = false,
-	},
-}
---[[
-The commands (use WoWLua addon) below will
-- set debug depending on what you want to test
-- create a player list (via GetPlayerList on start roll) to play with
-AND add_players is true
-	is_raid will make a 40 player list...
-	is_party will make a 5 player list
-	if neither makes you a group of 1
-- update rolls to check various errors conditions
-
-TitanPanelLootType.Debug.on = true
-TitanPanelLootType.Debug.flags.is_raid = true
-TitanPanelLootType.Debug.show.players = true
-TitanPanelLootType.Debug.show.events = true
-
-TitanPanelLootType.AddAllRollsDebug()
-
-TitanPanelLootType.AddRollDebug("raid6", "999", "1", "1000")
---]]
--- ******************************** Variables *******************************
-
--- ******************************** Deprecated Retail Functions *******************************
---[[ local
-NAME: LootDebug
-DESC: Set the Tian bars and plugins to the selected scale then adjust other frames as needed.
-VAR: msg   - message to be output
-VAR: mtype - the type of message
-OUT: None
---]]
--- Might be overkill but prepare for an API update as Blizz updates classic API with retail...
--- Diag marked per line to make deprecation obvious
-
--- As of 11.2.0 : Returns different values!
-local LootMethod = nil
-if C_PartyInfo and C_PartyInfo.GetLootMethod then
-	LootMethod = C_PartyInfo.GetLootMethod
-else
----@diagnostic disable-next-line: undefined-global
-	LootMethod = GetLootMethod
-end
-
--- As of 11.2.0
-local SendMsg = nil
-if C_ChatInfo and C_ChatInfo.SendChatMessage then
-	SendMsg = C_ChatInfo.SendChatMessage
-else
----@diagnostic disable-next-line: deprecated
-	SendMsg = SendChatMessage
-end
-
--- ******************************** Functions *******************************
-local function LootDebug(msg, mtype)
-	local show = false
-	if mtype == nil then
-		show = true                   -- just show it
-	elseif mtype == "events" and LT.Debug.show.events then
-		show = true
-	elseif mtype == "players" and LT.Debug.show.players then
-		show = true
-	end
-
-	if show then
-		TitanPluginDebug(TITAN_LOOTTYPE_ID, tostring(msg))
-	end
-end
-
---====== Tools for the tracker and Routines to allow resizing of the Loot frame
-
-local Tool = {}
-Tool.IconClassTexture = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
-Tool.IconClassTextureWithoutBorder = "Interface\\WorldStateFrame\\ICONS-CLASSES"
-Tool.IconClassTextureCoord = CLASS_ICON_TCOORDS
-Tool.IconClass = {
-	["WARRIOR"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:0:64|t",
-	["MAGE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:64:128:0:64|t",
-	["ROGUE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:128:192:0:64|t",
-	["DRUID"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:192:256:0:64|t",
-	["HUNTER"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:64:128|t",
-	["SHAMAN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:64:128:64:128|t",
-	["PRIEST"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:128:192:64:128|t",
-	["WARLOCK"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:192:256:64:128|t",
-	["PALADIN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:128:192|t",
-}
-Tool.IconClassBig = {
-	["WARRIOR"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:0:64|t",
-	["MAGE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:64:128:0:64|t",
-	["ROGUE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:128:192:0:64|t",
-	["DRUID"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:192:256:0:64|t",
-	["HUNTER"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:64:128|t",
-	["SHAMAN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:64:128:64:128|t",
-	["PRIEST"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:128:192:64:128|t",
-	["WARLOCK"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:192:256:64:128|t",
-	["PALADIN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:128:192|t",
-}
-
-Tool.RaidIconNames = ICON_TAG_LIST
-Tool.RaidIcon = {
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:0|t", -- [1]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:0|t", -- [2]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:0|t", -- [3]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:0|t", -- [4]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:0|t", -- [5]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:0|t", -- [6]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:0|t", -- [7]
-	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:0|t", -- [8]
-}
-
-Tool.Classes = CLASS_SORT_ORDER
-Tool.ClassName = LOCALIZED_CLASS_NAMES_MALE
-Tool.ClassColor = RAID_CLASS_COLORS
-
-Tool.ButtonFontObj = {}
-Tool.Font = ""
-Tool.FontSize = ""
-
-function Tool.CreatePattern(pattern, maximize)
-	pattern = string.gsub(pattern, "[%(%)%-%+%[%]]", "%%%1")
-	if not maximize then
-		pattern = string.gsub(pattern, "%%s", "(.-)")
-	else
-		pattern = string.gsub(pattern, "%%s", "(.+)")
-	end
-	pattern = string.gsub(pattern, "%%d", "%(%%d-%)")
-	if not maximize then
-		pattern = string.gsub(pattern, "%%%d%$s", "(.-)")
-	else
-		pattern = string.gsub(pattern, "%%%d%$s", "(.+)")
-	end
-	pattern = string.gsub(pattern, "%%%d$d", "%(%%d-%)")
-	--pattern = string.gsub(pattern, "%[", "%|H%(%.%-%)%[")
-	--pattern = string.gsub(pattern, "%]", "%]%|h")
-	return pattern
-end
-
----@class FrameSizeBorder
----@field GPI_SIZETYPE string
----@field GPI_Cursor string
----@field GPI_Rotation string
----@field GPI_DoStart string
----@field GPI_DoStop string
-local FrameSizeBorder ---@type Frame
-local sizecount = 0
-function Tool.SetButtonFont(button)
-	-- Just Return. This changed WAY too much...
-end
-
-function Tool.Split(inputstr, sep)
-	if sep == nil then
-		sep = "%s"
-	end
-	local t = {}
-	for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
-		if tContains(t, str) == false then
-			table.insert(t, str)
-		end
-	end
-	return t
-end
-
-function Tool.RGBtoEscape(r, g, b, a)
-	if type(r) == "table" then
-		a = r.a
-		g = r.g
-		b = r.b
-		r = r.r
-	end
-
-	r = r ~= nil and r <= 1 and r >= 0 and r or 1
-	g = g ~= nil and g <= 1 and g >= 0 and g or 1
-	b = b ~= nil and b <= 1 and b >= 0 and b or 1
-	a = a ~= nil and a <= 1 and a >= 0 and a or 1
-	return string.format("|c%02x%02x%02x%02x", a * 255, r * 255, g * 255, b * 255)
-	--	return ""
-end
-
-function Tool.Combine(t, sep, first, last)
-	if type(t) ~= "table" then return "" end
-	sep = sep or " "
-	first = first or 1
-	last = last or #t
-
-	local ret = ""
-	for i = first, last do
-		ret = ret .. sep .. tostring(t[i])
-	end
-	return string.sub(ret, string.len(sep) + 1)
-end
-
---====== Routines for the 'track' rolls feature
-
----Determine if the roll is valid.
----@param roll any
----@param low any
----@param high any
----@return boolean valid_roll
----@return boolean valid_bounds
----@return number? ro - numeric roll
----@return number? lo - numeric low
----@return number? hi - numeric high
-local function IsRoll(roll, low, high)
-	local lo = tonumber(low)
-	local hi = tonumber(high)
-	local ro = tonumber(roll)
-
-	local valid_roll = false
-	local valid_bounds = false
-
-	if (lo == 1 and hi == 100) then
-		valid_bounds = true
-	end
-	if (ro >= 0) and (ro <= 100) then -- allows a pass as valid
-		valid_roll = true
-	end
-
-	if valid_bounds then
-		-- all is good
-	else
-		-- for now roll is invalid, treat as a pass
-		valid_roll = false
-		ro = 0
-	end
-
-	local str = " >>"
-		.. " vr'" .. tostring(valid_roll) .. "'"
-		.. " vb'" .. tostring(valid_bounds) .. "'"
-		.. " r'" .. tostring(ro) .. "'"
-		.. " l'" .. tostring(lo) .. "'"
-		.. " h'" .. tostring(hi) .. "'"
-	LootDebug(str, "players")
-
-	return valid_roll, valid_bounds, ro, lo, hi
-end
-
----Get name, class, guild rank (if in same guild) a the given player.
----@param id string
----@return string name - name of the player
----@return string rank - localized guild rank
----@return string class - WoW internal class name
-local function GetPlayer(id)
-	local name = GetUnitName(id)
-	local localizedClass, class, classIndex = UnitClass(id)
-
-	local rank = ""
-	if IsInGuild() and UnitIsInMyGuild(id) then
-		rank = "<" .. GuildControlGetRankName(C_GuildInfo.GetGuildRankOrder(UnitGUID(id))) .. ">"
-	else
-		local guildName, guildRankName, guildRankIndex, realm = GetGuildInfo(id)
-		if guildName and guildRankName then
-			rank = "<" .. guildName .. " / " .. guildRankName .. ">"
-		end
-	end
-
-	return name, rank, class
-end
-
----Determine whether the player is the leader of the group.
----@return boolean
-local function IsLead()
-	if UnitIsGroupLeader("player") then
-		return true
-	end
-	-- The way this flows is both leader AND master looter will have the extra buttons
-	local lootmethod, masterlooterPartyID, masterlooterRaidID = LootMethod()
-	if (lootmethod == "master") or (lootmethod == 3) then
-		if IsInRaid() and (masterlooterRaidID == UnitInRaid("player")) then
-			return true
-		end
-		if IsInGroup() and (masterlooterPartyID == UnitInParty("player")) then
-			return true
-		end
-	end
-	if LT.Debug.flags.force_leader then
-		return true
-	end
-	if LT.Debug.flags.force_master then
-		return true
-	end
-	return false
-end
-
----Debug : output player info
----@param player table
-local function OutPlayer(player)
-	if LT.Debug.on then --
-		if player then
-			TitanPluginDebug(TITAN_LOOTTYPE_ID, "GetPlayerList:"
-				.. " p'" .. (player.name or "nyl") .. "'"
-				.. " r'" .. (player.rank or "nyl") .. "'"
-				.. " c'" .. (player.class or "nyl") .. "'"
-			)
-		end
-	end
-end
-
----Collect name, class, and guild rank (if in same guild) of players in the group. This routine will generate group lists (5 or 40) for debug based on debug flags.
----@param unsort boolean? if true sort by class then name
----@return table group indexed table of players in  the group
----@return table group_names table of player names pointing into ret
-function Track.GetPlayerList(unsort)
-	-- https://warcraft.wiki.gg/wiki/ClassId
-
-	local count, start
-	local prefix
-	local ret = {}
-	local retName = {}
-
-	if IsInRaid() or LT.Debug.flags.is_raid then
-		prefix = "raid"
-		count = MAX_RAID_MEMBERS
-		start = 1
-	elseif IsInGroup() or LT.Debug.flags.is_party then
-		prefix = "party"
-		count = MAX_PARTY_MEMBERS
-		start = 0
-	else
-		prefix = "solo"
-		count = 0
-		start = 0
-	end
-
-	if LT.Debug.on then -- safety...
-		if LT.Debug.flags.add_players then
-			-- player list has already been created, just return
-		elseif prefix == "solo" then
-			local name, rank, englishClass = GetPlayer("player")
-			if name ~= nil then
-				local entry = {
-					["name"] = name,
-					["rank"] = rank,
-					["class"] = englishClass,
-				}
-				tinsert(ret, entry)
-				retName[name] = entry
-			end
-		else
-			local class = 0
-			local class_max = 11
-			for index = start, count do
-				local guildName, guildRankName, guildRankIndex, realm
-				local id
-				if index > 0 then
-					id = prefix .. index
-					if class >= class_max then
-						class = 1
-					else
-						class = class + 1
-					end
-				else
-					id = "player"
-				end
-				-- handle name and class
-				local name = id
-				local localizedClass, englishClass, classIndex
-				if index == 0 then -- get the real player info
-					localizedClass, englishClass, classIndex = UnitClass(id)
-				elseif class == 1 then
-					englishClass = "WARRIOR"
-				elseif class == 2 then
-					englishClass = "PALADIN"
-				elseif class == 3 then
-					englishClass = "HUNTER"
-				elseif class == 4 then
-					englishClass = "ROGUE"
-				elseif class == 5 then
-					englishClass = "PRIEST"
-				elseif class == 6 then
-					englishClass = "MAGE" -- DK after CE
-				elseif class == 7 then
-					englishClass = "SHAMAN"
-				elseif class == 8 then
-					englishClass = "MAGE"
-				elseif class == 9 then
-					englishClass = "WARLOCK"
-				elseif class == 10 then
-					englishClass = "WARLOCK" -- monk after CE
-				elseif class == 11 then
-					englishClass = "DRUID"
-				end
-
-				-- Guild section assume this works... :)
-				local rank = ""
-
-				if name ~= nil then
-					local entry = {
-						["name"] = name,
-						["rank"] = rank,
-						["class"] = englishClass,
-					}
-					tinsert(ret, entry)
-					retName[name] = entry
-					OutPlayer(entry)
-				end
-			end
-		end
-	else
-		-- normal operation
-		for index = start, count do
-			local guildName, guildRankName, guildRankIndex, realm
-			local id
-			if index > 0 then
-				id = prefix .. index
-			else
-				id = "player"
-			end
-			if UnitInParty(id) then
-				local name, rank, englishClass = GetPlayer(id)
-
-				if name ~= nil then
-					local entry = {
-						["name"] = name,
-						["rank"] = rank,
-						["class"] = englishClass,
-					}
-					tinsert(ret, entry)
-					retName[name] = entry
-					OutPlayer(entry)
-				end
-			end
-		end
-	end
-
-	if unsort then
-		sort(ret, function(a, b) return (a.class < b.class or (a.class == b.class and a.name < b.name)) end)
-	end
-
-	return ret, retName
-end
-
----Select the channel type depending on the  type of group the player is in.
----@return string
-function Track.GetAutoChannel()
-	-- Return an appropriate channel in order of preference: /raid, /p, /s
-	local channel
-	if IsInRaid() then
-		channel = "RAID"
-	elseif IsInGroup() then
-		channel = "PARTY"
-	else
-		channel = "SAY"
-	end
-	return channel
-end
-
----Send the message to the channel type depending on the type of group the player is in.
----@param msg string
-function Track.AddChat(msg)
-	if msg ~= nil and msg ~= "" then
-		if IsInGroup() or IsInRaid() then
-			SendMsg(msg, Track.GetAutoChannel())
-		else
-			DEFAULT_CHAT_FRAME:AddMessage(msg, Track.DB.ColorChat.r, Track.DB.ColorChat.g, Track.DB.ColorChat.b,
-				Track.DB.ColorChat.a)
-		end
-	end
-end
-
----Save where the window is and its size.
-function Track.SaveAnchors()
-	Track.DB.X = TitanPanelLootTypeMainWindow:GetLeft()
-	Track.DB.Y = TitanPanelLootTypeMainWindow:GetTop()
-	Track.DB.Width = TitanPanelLootTypeMainWindow:GetWidth()
-	Track.DB.Height = TitanPanelLootTypeMainWindow:GetHeight()
-end
-
----Enable buttons; Show window; Update the player list with any rolls so far
-function Track.ShowWindow()
-	if IsLead() then
-		TitanPanelLootTypeFrameClearButton:Enable()
-		TitanPanelLootTypeFrameAnnounceButton:Enable()
-		TitanPanelLootTypeFrameNotRolledButton:Enable()
-	else
-		TitanPanelLootTypeFrameClearButton:Disable()
-		TitanPanelLootTypeFrameAnnounceButton:Disable()
-		TitanPanelLootTypeFrameNotRolledButton:Disable()
-	end
-	TitanPanelLootTypeMainWindow:Show()
-	Track.UpdateRollList()
-end
-
----Reset window to default position and size
-function Track.ResetWindow()
-	TitanPanelLootTypeMainWindow:ClearAllPoints()
-	TitanPanelLootTypeMainWindow:SetPoint("Center", UIParent, "Center", 0, 0)
-	TitanPanelLootTypeMainWindow:SetWidth(200)
-	TitanPanelLootTypeMainWindow:SetHeight(200)
-	Track.SaveAnchors()
-	Track.ShowWindow()
-end
-
----Hide the main tracker window
-function Track.HideWindow()
-	TitanPanelLootTypeMainWindow:Hide()
-end
-
----Initialize variables; Get last position and size of main frame; Register for needed events
-function Track.Init()
-	-- Add color
-	Track.DB.ColorChat     = { a = 1, r = 1, g = 1, b = 1 }
-	Track.DB.ColorNormal   = { a = 1, r = 1, g = 1, b = 1 }
-	Track.DB.ColorCheat    = { a = 1, r = 1, g = 0, b = 0 }
-	Track.DB.ColorGuild    = { a = 1, r = .2, g = 1, b = .2 }
-	Track.DB.ColorInfo     = { a = 1, r = .6, g = .6, b = .6 }
-	Track.DB.ColorScroll   = { a = 1, r = .8, g = .8, b = .8 }
-
-	-- For now, hard code some options
-	Track.DB.ClearOnStart  = true
-	Track.DB.OpenOnStart   = true
-	Track.DB.ShowNotRolled = true
-	Track.DB.ShowGuildRank = true
-
-	Track.DB.tie_breaker   = 0
-
-	Track.rollArray        = {}
-	Track.rollNames        = {}
-
-	Track.allRolled        = false
-
-	--	TitanPanelLootTypeMainWindow:SetMinResize(194,170)
-	TitanPanelLootTypeMainWindow:SetResizeBounds(200, 250) -- (225, 250, 225, 250)
-	local x, y, w, h = Track.DB.X, Track.DB.Y, Track.DB.Width, Track.DB.Height
-	if not x or not y or not w or not h then
-		Track.SaveAnchors()
-	else
-		TitanPanelLootTypeMainWindow:ClearAllPoints()
-		TitanPanelLootTypeMainWindow:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
-		TitanPanelLootTypeMainWindow:SetWidth(w)
-		TitanPanelLootTypeMainWindow:SetHeight(h)
-	end
-
-	-- using strings from GlobalStrings.lua
-	Track.PatternRoll = Tool.CreatePattern(RANDOM_ROLL_RESULT)
-
-	local media = LibStub("LibSharedMedia-3.0")
-	local newfont = media:Fetch("font", TitanPanelGetVar("FontName"))
-	Tool.Font = newfont
-	Tool.FontSize = TitanPanelGetVar("FontSize")
-
-	--	TitanPanelLootTypeMainWindowTitle:SetFont(Tool.Font, Tool.FontSize)
-	TitanPanelLootTypeMainWindowTitle:SetText(
-		string.format(Track.TxtEscapePicture, Track.IconDice)
-		.. " " .. Track.MSGPREFIX
-	)
-	Tool.SetButtonFont(TitanPanelLootTypeFrameRollButton) -- sets all buttons...
-
-	TitanPanelLootTypeFrameRollButton:SetText(string.format(Track.TxtEscapePicture, Track.IconDice) ..
-	L["TITAN_LOOTTYPE_TRACKER_BTNROLL"])
-	TitanPanelLootTypeFramePassButton:SetText(string.format(Track.TxtEscapePicture, Track.IconPass) ..
-	L["TITAN_LOOTTYPE_TRACKER_BTNPASS"])
-
-	TitanPanelLootTypeFrameAnnounceButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNANNOUNCE"])
-	TitanPanelLootTypeFrameNotRolledButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNNOTROLLED"])
-	TitanPanelLootType.ResizeButtons()
-	TitanPanelLootTypeFrameClearButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNCLEAR"])
-
-	TitanPanelLootTypeMainWindow:RegisterForDrag("LeftButton")
-	TitanPanelLootTypeMainWindow:EnableMouse(true)
-	TitanPanelLootTypeMainWindow:SetResizable(true)
-	TitanPanelLootTypeMainWindow:RegisterForDrag("LeftButton")
-	TitanPanelLootTypeMainWindow:SetScript("OnDragStart", function(self)
-		self:StartMoving()
-		Track.SaveAnchors()
-	end)
-	TitanPanelLootTypeMainWindow:SetScript("OnDragStop", function(self)
-		self:StopMovingOrSizing()
-		Track.SaveAnchors()
-	end)
-
-	TitanPanelLootTypeFrame:Show()
-
-	local str = ".Init"
-		.. " register for events"
-	LootDebug(str, "events")
-	-- Should be ready for events we are interested in
-	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_SYSTEM", TitanPanelLootTypeButton_OnEvent)
-
-	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_PARTY", TitanPanelLootTypeButton_OnEvent)
-	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_PARTY_LEADER", TitanPanelLootTypeButton_OnEvent)
-	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_RAID", TitanPanelLootTypeButton_OnEvent)
-	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_RAID_LEADER", TitanPanelLootTypeButton_OnEvent)
-end
-
----Close frame and cleanup
-function Track.Close()
-	Track.DB.RollInProcess = false
-	Track.HideWindow()
-	if Track.DB.ClearOnClose then
-		Track.ClearRolls()
-	end
-end
-
----Monitor system chat for player rolls; add the roll when one is found
----@param arg1 string
-function Track.Event_CHAT_MSG_SYSTEM(arg1)
-	local str = "Event_CHAT_MSG_SYSTEM"
-		.. " m'" .. tostring(arg1) .. "'"
-	LootDebug(str, "events")
-
-	if Track.DB.RollInProcess then
-		for name, roll, low, high in string.gmatch(arg1, Track.PatternRoll) do
-			--print(".."..name.." "..roll.." "..low.." "..high)
-			Track.AddRoll(name, roll, low, high)
-		end
-	end
-end
-
----Monitor general chat for Loot commands
----@param msg string
----@param name string
-function Track.Event_Generic_CHAT_MSG(msg, name)
---[[
-- Monitor general chat for:
-- a pass ('pass' or localized version)
-- Roll start
-- Roll end
---]]
-	local str = "Event_Generic_CHAT_MSG"
-		.. " '" .. tostring(name) .. "'"
-		.. " m'" .. tostring(msg) .. "'"
-	LootDebug(str, "events")
-
-	-- prevent 'random' rolls from popping windows
-	if Track.DB.RollInProcess then
-		if msg == L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"] or msg == "pass" then
-			name = Tool.Split(name, "-")[1]
-			Track.AddRoll(name, "0", "1", "100")
-		end
-	end
-
-	-- Assume a 'leader' requested a roll so pop the window
-	if string.sub(msg, 1, string.len(Track.MSGPREFIX_START)) == Track.MSGPREFIX_START then
-		Track.DB.RollInProcess = true
-		if Track.DB.ClearOnStart then
-			Track.ClearRolls()
-		end
-		if Track.DB.OpenOnStart then
-			Track.ShowWindow()
-		end
-	end
-	-- Check for the 'end' of the roll
-	if string.sub(msg, 1, string.len(Track.MSGPREFIX_END)) == Track.MSGPREFIX_END then
-		Track.DB.RollInProcess = false
-		if Track.DB.ClearOnStart then
-			Track.ClearRolls()
-		end
-	end
-	-- Check for the 'close' of the roll
-	if string.sub(msg, 1, string.len(Track.MSGPREFIX_CLOSE)) == Track.MSGPREFIX_CLOSE then
-		Track.Close()
-	end
-end
-
----Process the roll the player made
----@param name string
----@param roll string
----@param low string
----@param high string
-function Track.AddRoll(name, roll, low, high)
---[[
-- A pass has a roll of "0"
-- Only the first roll is marked as valid / invalid
-- The number of rolls is saved (Count)
-- A running number (tie_breaker) is added to ensure the first arrived of a tie wins; stored in Place
-- Always show the main frame to ensure it pops, no harm if already shown
---]]
-	local act = "nyl"
-	local valid = false
-
-	local valid_ro, valid_bounds, ro, lo, hi = IsRoll(roll, low, high)             -- numeric
-	if Track.rollNames[name] == nil then
-		Track.DB.tie_breaker = Track.DB.tie_breaker + 1                            -- only count the first roll for each player
-		act = "insert"
-		Track.rollNames[name] = Track.rollNames[name] and Track.rollNames[name] + 1 or 1 -- mark player as having rolled
-		table.insert(Track.rollArray, {
-			Name = name,
-			Roll = ro,
-			Low = lo,
-			High = hi,
-			Count = Track.rollNames[name],
-			Place = Track.DB.tie_breaker,
-			Valid_roll = valid_ro,
-			Valid_bounds = valid_bounds,
-			IsPass = (valid_ro and valid_bounds and ro == 0),
-		})
-		local str = "AddRoll >>"
-			.. " '" .. tostring(act) .. "'"
-			.. " '" .. tostring(name) .. "'"
-			.. " r'" .. tostring(roll) .. "'"
-			.. " l'" .. tostring(low) .. "'"
-			.. " h'" .. tostring(high) .. "'"
-			.. " #'" .. tostring(Track.rollNames[name]) .. "'"
-		LootDebug(str, "players")
-	else
-		-- check for re-rolls. >1 if rolled before
-		act = "update"
-		Track.rollNames[name] = Track.rollNames[name] and Track.rollNames[name] + 1 or
-		1                                                                          -- mark player as having rolled again
-		for i, p in ipairs(Track.rollArray) do
-			if p.Name == name then
-				-- Only first roll is valid, Ignore additional rolls but count them for display
-				p.Count = Track.rollNames[name]
-				local str = "AddRoll >>"
-					.. " '" .. tostring(act) .. "'"
-					.. " '" .. tostring(name) .. "'"
-					.. " r'" .. tostring(roll) .. "'"
-					.. " l*'" .. tostring(low) .. "'"
-					.. " h*'" .. tostring(high) .. "'"
-					.. " #*'" .. tostring(Track.rollNames[name]) .. "'"
-				LootDebug(str, "players")
-			end
-		end
-	end
-	Track.ShowWindow()
-end
-
----Sort ascending by name then place
----@param a table
----@param b table
----@return boolean
-function Track.SortRolls(a, b)
-	--	return a.Roll < b.Roll
-	if a.Roll ~= b.Roll then
-		return a.Roll < b.Roll
-	elseif a.Roll == b.Roll then
-		return a.Place > b.Place
-	else
-		return false -- for IDE and sanity
-	end
-end
-
----Sort descending by name then place
----@param a table
----@param b table
----@return boolean
-function Track.SortRollsRev(a, b)
-	--	return a.Roll > b.Roll
-	if a.Roll ~= b.Roll then
-		return a.Roll > b.Roll
-	elseif a.Roll == b.Roll then
-		return a.Place < b.Place
-	else
-		return false -- for IDE and sanity
-	end
-end
-
-
----Format the given roll for display
----@param roll table
----@param party any
----@param partyName table
----@return string
-function Track.FormatRollText(roll, party, partyName)
-	local colorTied = Tool.RGBtoEscape(Track.DB.ColorNormal)
-	local colorCheat = Tool.RGBtoEscape(Track.DB.ColorCheat)
-	local txtRange = (not roll.Valid_bounds) and format(" (%d-%d)", roll.Low, roll.High) or ""
-
-	local colorName
-	local iconClass
-	local colorRank = Tool.RGBtoEscape(Track.DB.ColorGuild)
-	local rank = ""
-
-	if partyName[roll.Name] and partyName[roll.Name].class then
-		colorName = "|c" .. RAID_CLASS_COLORS[partyName[roll.Name].class].colorStr
-		iconClass = Tool.IconClass[partyName[roll.Name].class]
-	end
-	if colorName == nil or Track.DB.ColorName == false then colorName = colorCheat end
-	if iconClass == nil or Track.DB.ShowClassIcon == false then iconClass = "" end
-	if Track.DB.ColorName == false then colorRank = colorCheat end
-
-	if Track.DB.ShowGuildRank and partyName[roll.Name] and partyName[roll.Name].rank then
-		rank = " " .. partyName[roll.Name].rank
-	end
-
-	local txtCount = roll.Count > 1 and format(" [%d]", roll.Count) or ""
-
-	local txt_roll = ""
-	if roll.IsPass then
-		txt_roll = L["TITAN_LOOTTYPE_TRACKER_BTNPASS"]
-	else
-		txt_roll = string.format("%3d", roll.Roll)
-	end
-
-	return "|Hplayer:" .. roll.Name .. "|h"
-		..txt_roll .. " : "
-		..iconClass.." "
-		..colorName .. roll.Name .. "|r "
-		..colorRank .. rank .. "|r "
-		..colorCheat.. txtRange .. "|r"
-		..colorTied..txtCount .. "|r"
-		.. "|h"
-		--			colorCheat..roll.Place.."|h"..
-		.."\n"
-end
-
----Create the player list for display including rolls, 'cheats', guild rank (if in same guild).
---- Rolls are above the line; no rolls yet are below the line
-function Track.UpdateRollList()
-	local rollText = ""
-
-	local party, partyName = Track.GetPlayerList()
-
-	table.sort(Track.rollArray, Track.SortRolls)
-
-	-- format and print rolls, check for ties
-	for i, roll in pairs(Track.rollArray) do
-		rollText = Track.FormatRollText(roll, party, partyName) .. rollText
-	end
-
-	--if IsInGroup() or IsInRaid() then
-	rollText = rollText .. Tool.RGBtoEscape(Track.DB.ColorInfo) .. L["TITAN_LOOTTYPE_TRACKER_TXTLINE"] .. "\n"
-	local gtxt = Tool.RGBtoEscape(Track.DB.ColorInfo)
-	local missClasses = {}
-	Track.allRolled = true
-	for i, p in ipairs(party) do
-		if Track.rollNames[p.name] == nil or Track.rollNames[p.name] == 0 then
-			local iconClass = Tool.IconClass[partyName[p.name].class]
-			local rank = ""
-			if iconClass == nil or Track.DB.ShowClassIcon == false then
-				iconClass = ""
-			else
-				missClasses[partyName[p.name].class] = missClasses[partyName[p.name].class] and
-				missClasses[partyName[p.name].class] + 1 or 1
-			end
-			if Track.DB.ShowGuildRank and partyName[p.name] and partyName[p.name].rank then
-				rank = " " .. partyName[p.name].rank
-			end
-			gtxt = gtxt .. "|Hplayer:" .. p.name .. "|h" .. iconClass .. p.name .. rank .. "|h\n"
-			Track.allRolled = false
-		end
-	end
-
-	local ctxt = ""
-	if IsInRaid() then
-		local isHorde = (UnitFactionGroup("player")) == "Horde"
-		for i, class in pairs(Tool.Classes) do
-			--for class,count in pairs(missClasses) do
-			if not (isHorde and class == "PALADIN") and not (not isHorde and class == "SHAMAN") then
-				ctxt = ctxt .. Tool.IconClass[class] .. (missClasses[class] or 0) .. " "
-			end
-		end
-		if ctxt ~= "" then ctxt = ctxt .. "\n" .. L["TxtLine"] .. "\n" end
-	end
-	if LT.Debug.on then --
-		TitanPluginDebug(TITAN_LOOTTYPE_ID, "UpdateRollList"
-			.. " '" .. (rollText or "nyl") .. "'"
-			.. " '" .. (ctxt or "nyl") .. "'"
-			.. " '" .. (gtxt or "nyl") .. "'"
-		)
-	end
-
-	rollText = rollText .. ctxt .. gtxt
-	LootDebug(rollText, "rolls")
-
-	--end
-
-	--	RollTrackerRollText:SetFont(Tool.Font, Tool.FontSize)
-	RollTrackerRollText:SetText(rollText)
-
-	--	TitanPanelLootTypeFrameStatusText:SetFont(Tool.Font, Tool.FontSize)
-	TitanPanelLootTypeFrameStatusText:SetText(string.format(L["TITAN_LOOTTYPE_TRACKER_MSGNBROLLS"],
-		#Track.rollArray))
-
-	--	TitanPanelLootTypeFrameClearButton:SetFont(Tool.Font, Tool.FontSize)
-	TitanPanelLootTypeFrameClearButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNCLEAR"])
-end
-
----Clear the player list of any rolls
-function Track.ClearRolls()
-	if #Track.rollArray > 0 then
-		Track.rollArray = {}
-		Track.rollNames = {}
-	end
-
-	Track.DB.tie_breaker = 0
-	Track.UpdateRollList()
-end
-
----If isLead : Send a nag message via whisper to players who have not rolled; Send a message to group that reminders were sent
-function Track.NotRolled()
-	if IsLead() then
-		local party, partyName = Track.GetPlayerList()
-		local names = ""
-
-		local group = ""
-		if IsInRaid() then
-			group = L["TITAN_LOOTTYPE_TRACKER_RAIDPASS"]
-		elseif IsInGroup() then
-			group = L["TITAN_LOOTTYPE_TRACKER_PARTYPASS"]
-		else
-			group = ""
-		end
-
-		for i, p in ipairs(party) do
-			if Track.rollNames[p.name] == nil or Track.rollNames[p.name] == 0 then
-				SendMsg(Track.MSGPREFIX .. L["TITAN_LOOTTYPE_TRACKER_NOTROLLEDNAG"] .. group, WHISPER, nil,
-					p.name)
-				names = "send"
-			end
-		end
-
-		if names == "send" then
-			Track.AddChat(Track.MSGPREFIX .. L["TITAN_LOOTTYPE_TRACKER_MSGNOTROLLED"])
-		end
-	end
-end
-
----If isLead : Pop the main frame;
---- Clear all rolls for a new set;
---- Start a new roll process;
---- Send a message to the group of a new roll
-function Track.StartRoll()
-	Track.ShowWindow()
-	Track.ClearRolls()
-	Track.DB.RollInProcess = true
-	Track.AddChat(Track.MSGPREFIX_START ..
-	"{circle} " .. string.format(L["TITAN_LOOTTYPE_TRACKER_MSGSTART"], L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"]))
-	Track.AddChat(L["TITAN_LOOTTYPE_TRACKER_MSGBAR"])
-end
-
----If isLead : Send a message to the group of the winner; Stop the roll process so new rolls are not processed
-function Track.RollAnnounce()
-	local winName = ""
-	local winRoll = 0
-	local addPrefix = ""
-	local msg = ""
-	local list = {}
-
-	table.sort(Track.rollArray, Track.SortRollsRev)
-
-	for i, roll in pairs(Track.rollArray) do
-		local str = "AddRoll >>"
-			.. " '" .. roll.Name .. "'"
-			.. " r'" .. tostring(roll.Roll) .. "'"
-		LootDebug(str, "players")
-		if roll.Valid_roll then
-			winName = roll.Name
-			winRoll = roll.Roll
-			break -- sort breaks ties, grab first one
-		end
-	end
-
-	if winName == "" then
-		msg = Track.MSGPREFIX_END .. addPrefix .. "{circle} No winners"
-	else
-		msg = Track.MSGPREFIX_END ..
-		addPrefix .. "{circle} " .. string.format(L["TITAN_LOOTTYPE_TRACKER_MSGANNOUNCE"], winName, winRoll)
-	end
-
-	Track.AddChat(msg)
-
-	Track.DB.RollInProcess = false
-end
-
----Determine the size of the buttons so they fill the line on the main frame.
-function TitanPanelLootType.ResizeButtons()
-	local w = TitanPanelLootTypeFrameHelperButton:GetWidth()
-	TitanPanelLootTypeFrameRollButton:SetWidth(w / 2)
-	TitanPanelLootTypeFramePassButton:SetWidth(w / 2)
-
-	if Track.DB.ShowNotRolled then
-		TitanPanelLootTypeFrameAnnounceButton:SetWidth(w / 3)
-		TitanPanelLootTypeFrameClearButton:SetWidth(w / 3)
-		TitanPanelLootTypeFrameNotRolledButton:Show()
-	else
-		TitanPanelLootTypeFrameAnnounceButton:SetWidth(w / 2)
-		TitanPanelLootTypeFrameClearButton:SetWidth(w / 2)
-		TitanPanelLootTypeFrameNotRolledButton:Hide()
-	end
-end
-
----On Close of main frame cleanup current roll process
-function TitanPanelLootType.BtnClose()
-	Track.Close()
-
-	if IsLead() then
-		Track.AddChat(Track.MSGPREFIX_CLOSE .. L["TITAN_LOOTTYPE_TRACKER_MSGCLOSING"])
-	end
-end
-
----On click of "roll": Send the roll to be processed
-function TitanPanelLootType.BtnRoll()
-	RandomRoll(1, 100)
-end
-
----On click "pass": Send the pass to be processed
-function TitanPanelLootType.BtnPass()
-	Track.AddChat(L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"])
-	--[[
-	Note: When in solo debug mode, this just does a /say pass
-	which is NOT picked up by an event. This only monitors party & raid chat...
-	--]]
-end
-
----On click of "clear": Only if IsLead, Clear all rolls and Start a new roll process
-function TitanPanelLootType.BtnClearRolls()
-	if #Track.rollArray > 0 then
-		Track.ClearRolls()
-		if Track.DB.CloseOnClear then
-			Track.HideWindow()
-		end
-	end
-	Track.StartRoll()
-end
-
----On click of "start": Only if IsLead, Start a new roll process
----@param button any
-function TitanPanelLootType.BtnAnnounce(button)
-	Track.RollAnnounce()
-	if Track.DB.ClearOnAnnounce then
-		Track.ClearRolls()
-	end
-	if Track.DB.CloseOnAnnounce then
-		Track.HideWindow()
-	end
-end
-
----On click of "remind": Only if IsLead, nag those who have not rolled
-function TitanPanelLootType.BtnNotRolled()
-	Track.NotRolled()
-end
-
--- Debug!!!
-
-function TitanPanelLootType.AddAllRollsDebug() -- rolls for all players
-	local party, partyName = Track.GetPlayerList()
-
-	-- walk the player list, adding rolls
-	for i, p in ipairs(party) do
-		-- 0 (zero) allows a 'pass'
-		if i == 5 then -- cheater :)
-			Track.AddRoll(p.name, tostring(random(0, 100)), "90", "100")
-		elseif i == 13 then -- doubler :)
-			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
-			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
-		elseif i == 21 then -- passer :)
-			Track.AddRoll(p.name, tostring(0), "1", "100")
-		else
-			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
-		end
-	end
-	-- Now show the results
-	Track.UpdateRollList()
-end
-
-function TitanPanelLootType.AddRollDebug(...) -- single roll
-	Track.AddRoll(...)
-end
-
----On load : Set Titan registry values and register for events
----@param self any
-function TitanPanelLootTypeButton_OnLoad(self)
-	self.registry = {
-		id = TITAN_LOOTTYPE_ID,
-		category = "Built-ins",
-		version = TITAN_VERSION,
-		menuText = L["TITAN_LOOTTYPE_MENU_TEXT"],
-		buttonTextFunction = "TitanPanelLootTypeButton_GetButtonText",
-		tooltipTitle = L["TITAN_LOOTTYPE_TOOLTIP"],
-		tooltipTextFunction = "TitanPanelLootTypeButton_GetTooltipText",
-		icon = "Interface\\AddOns\\TitanLootType\\TitanLootType",
-		iconWidth = 16,
-		controlVariables = {
-			ShowIcon = true,
-			ShowLabelText = true,
-			ShowRegularText = false,
-			ShowColoredText = false,
-			DisplayOnRightSide = true,
-		},
-		savedVariables = {
-			ShowIcon = 1,
-			ShowLabelText = 1,
-			RandomRoll = 100,
-			DB = {},
-			DisplayOnRightSide = false,
-			--			ShowDungeonDiff = false,
-			--			DungeonDiffType = "AUTO",
-		}
-	};
-
-	self:RegisterEvent("PLAYER_ENTERING_WORLD", TitanPanelLootTypeButton_OnEvent)
-	self:RegisterEvent("GROUP_ROSTER_UPDATE");
-	self:RegisterEvent("RAID_ROSTER_UPDATE");
-	self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED");
-	self:RegisterEvent("CHAT_MSG_SYSTEM");
-end
-
----Parse events registered to LootType and act on them
----@param self any
----@param event string
----@param ... unknown
-function TitanPanelLootTypeButton_OnEvent(self, event, ...)
-	LootDebug(event, "events") -- could generate a lot of messages...
-
-	if (event == "CHAT_MSG_SYSTEM") then
-		Track.Event_CHAT_MSG_SYSTEM(...)
-	end
-
-	if (event == "CHAT_MSG_PARTY") then
-		Track.Event_Generic_CHAT_MSG(...)
-	end
-
-	if (event == "CHAT_MSG_PARTY_LEADER") then
-		Track.Event_Generic_CHAT_MSG(...)
-	end
-
-	if (event == "CHAT_MSG_RAID") then
-		Track.Event_Generic_CHAT_MSG(...)
-	end
-
-	if (event == "CHAT_MSG_RAID_LEADER") then
-		Track.Event_Generic_CHAT_MSG(...)
-	end
-
-	if (event == "PLAYER_ENTERING_WORLD") then
-		Track.Init()
-	end
-
-	TitanPanelPluginHandle_OnUpdate(updateTable)
-end
-
----Determine loot type and then display on button
----@param id any
----@return string
----@return string
-function TitanPanelLootTypeButton_GetButtonText(id)
-	local lootTypeText, lootThreshold, color
-
-	--	if (GetNumSubgroupMembers() > 0) or (GetNumGroupMembers() > 0) then
-
-	if IsInRaid() or IsInGroup() then
-		lootTypeText = TitanLootMethod[LootMethod()].text;
-		lootThreshold = GetLootThreshold();
-		color = _G["ITEM_QUALITY_COLORS"][lootThreshold];
-	else
-		lootTypeText = _G["SOLO"];
-		color = _G["GRAY_FONT_COLOR"];
-	end
-	return L["TITAN_LOOTTYPE_BUTTON_LABEL"], TitanUtils_GetColoredText(lootTypeText, color);
-end
-
----Prepare the tool tip text. The tool tip is determined by whether the player is in a group or not
----@return string
-function TitanPanelLootTypeButton_GetTooltipText()
-	--	if (GetNumSubgroupMembers() > 0) or (GetNumGroupMembers() > 0) then
-	if IsInRaid() or IsInGroup() then
-		local lootTypeText = TitanLootMethod[LootMethod()].text;
-		local lootThreshold = GetLootThreshold();
-		local itemQualityDesc = _G["ITEM_QUALITY" .. lootThreshold .. "_DESC"];
-		local color = _G["ITEM_QUALITY_COLORS"][lootThreshold];
-		return "" ..
-			_G["LOOT_METHOD"] .. ": \t" .. TitanUtils_GetHighlightText(lootTypeText) .. "\n" ..
-			_G["LOOT_THRESHOLD"] .. ": \t" .. TitanUtils_GetColoredText(itemQualityDesc, color) .. "\n" ..
-			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT1"]) .. "\n"
-		--			..TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT2"])
-	else
-		return --TitanUtils_GetNormalText(_G["ERR_NOT_IN_GROUP"]).."\n"..
-			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT1"]) .. "\n"
-		--			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT2"]);
-	end
-end
-
----Display rightclick menu options.
-function TitanPanelRightClickMenu_PrepareLootTypeMenu()
-	local info = {};
-
-	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_LOOTTYPE_ID].menuText);
-	info = {};
-	info.notCheckable = true
-
-	TitanPanelRightClickMenu_AddToggleIcon(TITAN_LOOTTYPE_ID);
-	TitanPanelRightClickMenu_AddToggleLabelText(TITAN_LOOTTYPE_ID);
-	TitanPanelRightClickMenu_AddToggleRightSide(TITAN_LOOTTYPE_ID);
-	TitanPanelRightClickMenu_AddSpacer();
-	TitanPanelRightClickMenu_AddCommand(L["TITAN_PANEL_MENU_HIDE"], TITAN_LOOTTYPE_ID, TITAN_PANEL_MENU_FUNC_HIDE);
-end
-
---- On left click: If isLead then start a new group roll; If not isLead then do a roll
----@param self any
----@param button string
-function TitanPanelLootTypeButton_OnClick(self, button)
-	if button == "LeftButton" then
-		if IsLead() then
-			TitanPanelLootType.BtnClearRolls()
-		else
-			RandomRoll(1, 100)
-		end
-	end
-end
+--[===[ File
+NAME: TitanLootType.lua
+DESC:
+This Titan plugin will show group type and loot type in the button text.
+A roll tracker is used to show rolls in party to help make passing out loot and chests.
+This is a simplistic roll helper! It is NOT intended as a loot tracker!
+
+On right-click it will show the normal Titan options.
+The left-click it will depend whether the user is group leader or loot master :
+  if not leader a /roll will be done.
+  if leader the tracker window will pop, giving them additional options
+  - Start   : Start a new roll
+  - Remind  : Nag those who have not rolled with a whisper
+  - Results : State the results
+
+Once a leader initiates a roll, the tracker will pop for other Titan users who are using LootType.
+:DESC
+--]===]
+TitanPanelLootType                 = {} -- declare name space
+local LT                           = TitanPanelLootType -- save some typing...
+
+-- ******************************** Constants *******************************
+local TITAN_LOOTTYPE_ID            = "LootType";
+local _G                           = getfenv(0);
+local L                            = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true)
+local TitanLootMethod              = {};
+local updateTable                  = { TITAN_LOOTTYPE_ID, TITAN_PANEL_UPDATE_ALL };
+TitanLootMethod["freeforall"]      = { text = L["TITAN_LOOTTYPE_FREE_FOR_ALL"] };
+TitanLootMethod["roundrobin"]      = { text = L["TITAN_LOOTTYPE_ROUND_ROBIN"] };
+TitanLootMethod["master"]          = { text = L["TITAN_LOOTTYPE_MASTER_LOOTER"] };
+TitanLootMethod["group"]           = { text = L["TITAN_LOOTTYPE_GROUP_LOOT"] };
+TitanLootMethod["needbeforegreed"] = { text = L["TITAN_LOOTTYPE_NEED_BEFORE_GREED"] };
+TitanLootMethod["personalloot"] = {text = L["TITAN_LOOTTYPE_PERSONAL"]};
+-- For new method...
+TitanLootMethod[0] = {text = L["TITAN_LOOTTYPE_FREE_FOR_ALL"]};
+TitanLootMethod[1] = {text = L["TITAN_LOOTTYPE_ROUND_ROBIN"]};
+TitanLootMethod[2] = {text = L["TITAN_LOOTTYPE_MASTER_LOOTER"]};
+TitanLootMethod[3] = {text = L["TITAN_LOOTTYPE_GROUP_LOOT"]};
+TitanLootMethod[4] = {text = L["TITAN_LOOTTYPE_NEED_BEFORE_GREED"]};
+TitanLootMethod[5] = {text = L["TITAN_LOOTTYPE_PERSONAL"]};
+
+local TOCNAME                      = "TitanLootType"
+local Track                        = {}
+Track.DB = {}
+
+-- High level constants
+Track.IconDice                     = "Interface\\Buttons\\UI-GroupLoot-Dice-Up"
+--Track.IconGreed= "Interface\\Buttons\\UI-GroupLoot-Coin-Up"
+Track.IconPass                     = "Interface\\Buttons\\UI-GroupLoot-Pass-Up"
+Track.IconLoot                     = "Interface\\GroupFrame\\UI-Group-MasterLooter"
+Track.TxtEscapePicture             = "|T%s:0|t"
+Track.TxtEscapeIcon                = "|T%s:0:0:0:0:64:64:4:60:4:60|t"
+
+-- These are encoded 'messages' this addon searches for to start and end the roll process
+Track.MSGPREFIX                    = "Titan LootType Roller: " -- also frame title
+Track.MSGPREFIX_START              = Track.MSGPREFIX .. ">>: "
+Track.MSGPREFIX_END                = Track.MSGPREFIX .. "<<: "
+Track.MSGPREFIX_CLOSE              = Track.MSGPREFIX .. "__: "
+
+
+-- This will be debugged real-time so put the debug on 'switches'
+-- Also useful when debugging 'solo'
+LT.Debug = {
+	-- Used when creating dummy player list (see flags) or solo debug to get 'self'
+	-- And debug output
+	on    = false, -- true false
+
+	show  = { -- for LootDebug messages
+		events = false, -- show debug for events
+		players = false, -- show debug for players
+		-- nil will show regardless
+	},
+
+	flags = { -- solo debug
+		force_leader = false,
+		force_master = false,
+		force_loot_master = false,
+		-- These 3 are used when creating dummy player list WITH 'on' = true
+		add_players = false,
+		is_raid = false,
+		is_party = false,
+	},
+}
+--[[
+The commands (use WoWLua addon) below will
+- set debug depending on what you want to test
+- create a player list (via GetPlayerList on start roll) to play with
+AND add_players is true
+	is_raid will make a 40 player list...
+	is_party will make a 5 player list
+	if neither makes you a group of 1
+- update rolls to check various errors conditions
+
+TitanPanelLootType.Debug.on = true
+TitanPanelLootType.Debug.flags.is_raid = true
+TitanPanelLootType.Debug.show.players = true
+TitanPanelLootType.Debug.show.events = true
+
+TitanPanelLootType.AddAllRollsDebug()
+
+TitanPanelLootType.AddRollDebug("raid6", "999", "1", "1000")
+--]]
+-- ******************************** Variables *******************************
+
+-- ******************************** Deprecated Retail Functions *******************************
+--[[ local
+NAME: LootDebug
+DESC: Set the Tian bars and plugins to the selected scale then adjust other frames as needed.
+VAR: msg   - message to be output
+VAR: mtype - the type of message
+OUT: None
+--]]
+-- Might be overkill but prepare for an API update as Blizz updates classic API with retail...
+-- Diag marked per line to make deprecation obvious
+
+-- As of 11.2.0 : Returns different values!
+local LootMethod = nil
+if C_PartyInfo and C_PartyInfo.GetLootMethod then
+	LootMethod = C_PartyInfo.GetLootMethod
+else
+---@diagnostic disable-next-line: undefined-global
+	LootMethod = GetLootMethod
+end
+
+-- As of 11.2.0
+local SendMsg = nil
+if C_ChatInfo and C_ChatInfo.SendChatMessage then
+	SendMsg = C_ChatInfo.SendChatMessage
+else
+---@diagnostic disable-next-line: deprecated
+	SendMsg = SendChatMessage
+end
+
+-- ******************************** Functions *******************************
+local function LootDebug(msg, mtype)
+	local show = false
+	if mtype == nil then
+		show = true                   -- just show it
+	elseif mtype == "events" and LT.Debug.show.events then
+		show = true
+	elseif mtype == "players" and LT.Debug.show.players then
+		show = true
+	end
+
+	if show then
+		TitanPluginDebug(TITAN_LOOTTYPE_ID, tostring(msg))
+	end
+end
+
+--====== Tools for the tracker and Routines to allow resizing of the Loot frame
+
+local Tool = {}
+Tool.IconClassTexture = "Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES"
+Tool.IconClassTextureWithoutBorder = "Interface\\WorldStateFrame\\ICONS-CLASSES"
+Tool.IconClassTextureCoord = CLASS_ICON_TCOORDS
+Tool.IconClass = {
+	["WARRIOR"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:0:64|t",
+	["MAGE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:64:128:0:64|t",
+	["ROGUE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:128:192:0:64|t",
+	["DRUID"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:192:256:0:64|t",
+	["HUNTER"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:64:128|t",
+	["SHAMAN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:64:128:64:128|t",
+	["PRIEST"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:128:192:64:128|t",
+	["WARLOCK"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:192:256:64:128|t",
+	["PALADIN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:0:0:0:0:256:256:0:64:128:192|t",
+}
+Tool.IconClassBig = {
+	["WARRIOR"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:0:64|t",
+	["MAGE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:64:128:0:64|t",
+	["ROGUE"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:128:192:0:64|t",
+	["DRUID"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:192:256:0:64|t",
+	["HUNTER"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:64:128|t",
+	["SHAMAN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:64:128:64:128|t",
+	["PRIEST"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:128:192:64:128|t",
+	["WARLOCK"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:192:256:64:128|t",
+	["PALADIN"] = "|TInterface\\WorldStateFrame\\ICONS-CLASSES:18:18:-4:4:256:256:0:64:128:192|t",
+}
+
+Tool.RaidIconNames = ICON_TAG_LIST
+Tool.RaidIcon = {
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:0|t", -- [1]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:0|t", -- [2]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:0|t", -- [3]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:0|t", -- [4]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:0|t", -- [5]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:0|t", -- [6]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:0|t", -- [7]
+	"|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:0|t", -- [8]
+}
+
+Tool.Classes = CLASS_SORT_ORDER
+Tool.ClassName = LOCALIZED_CLASS_NAMES_MALE
+Tool.ClassColor = RAID_CLASS_COLORS
+
+Tool.ButtonFontObj = {}
+Tool.Font = ""
+Tool.FontSize = ""
+
+function Tool.CreatePattern(pattern, maximize)
+	pattern = string.gsub(pattern, "[%(%)%-%+%[%]]", "%%%1")
+	if not maximize then
+		pattern = string.gsub(pattern, "%%s", "(.-)")
+	else
+		pattern = string.gsub(pattern, "%%s", "(.+)")
+	end
+	pattern = string.gsub(pattern, "%%d", "%(%%d-%)")
+	if not maximize then
+		pattern = string.gsub(pattern, "%%%d%$s", "(.-)")
+	else
+		pattern = string.gsub(pattern, "%%%d%$s", "(.+)")
+	end
+	pattern = string.gsub(pattern, "%%%d$d", "%(%%d-%)")
+	--pattern = string.gsub(pattern, "%[", "%|H%(%.%-%)%[")
+	--pattern = string.gsub(pattern, "%]", "%]%|h")
+	return pattern
+end
+
+---@class FrameSizeBorder
+---@field GPI_SIZETYPE string
+---@field GPI_Cursor string
+---@field GPI_Rotation string
+---@field GPI_DoStart string
+---@field GPI_DoStop string
+local FrameSizeBorder ---@type Frame
+local sizecount = 0
+function Tool.SetButtonFont(button)
+	-- Just Return. This changed WAY too much...
+end
+
+function Tool.Split(inputstr, sep)
+	if sep == nil then
+		sep = "%s"
+	end
+	local t = {}
+	for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
+		if tContains(t, str) == false then
+			table.insert(t, str)
+		end
+	end
+	return t
+end
+
+function Tool.RGBtoEscape(r, g, b, a)
+	if type(r) == "table" then
+		a = r.a
+		g = r.g
+		b = r.b
+		r = r.r
+	end
+
+	r = r ~= nil and r <= 1 and r >= 0 and r or 1
+	g = g ~= nil and g <= 1 and g >= 0 and g or 1
+	b = b ~= nil and b <= 1 and b >= 0 and b or 1
+	a = a ~= nil and a <= 1 and a >= 0 and a or 1
+	return string.format("|c%02x%02x%02x%02x", a * 255, r * 255, g * 255, b * 255)
+	--	return ""
+end
+
+function Tool.Combine(t, sep, first, last)
+	if type(t) ~= "table" then return "" end
+	sep = sep or " "
+	first = first or 1
+	last = last or #t
+
+	local ret = ""
+	for i = first, last do
+		ret = ret .. sep .. tostring(t[i])
+	end
+	return string.sub(ret, string.len(sep) + 1)
+end
+
+--====== Routines for the 'track' rolls feature
+
+---Determine if the roll is valid.
+---@param roll any
+---@param low any
+---@param high any
+---@return boolean valid_roll
+---@return boolean valid_bounds
+---@return number? ro - numeric roll
+---@return number? lo - numeric low
+---@return number? hi - numeric high
+local function IsRoll(roll, low, high)
+	local lo = tonumber(low)
+	local hi = tonumber(high)
+	local ro = tonumber(roll)
+
+	local valid_roll = false
+	local valid_bounds = false
+
+	if (lo == 1 and hi == 100) then
+		valid_bounds = true
+	end
+	if (ro >= 0) and (ro <= 100) then -- allows a pass as valid
+		valid_roll = true
+	end
+
+	if valid_bounds then
+		-- all is good
+	else
+		-- for now roll is invalid, treat as a pass
+		valid_roll = false
+		ro = 0
+	end
+
+	local str = " >>"
+		.. " vr'" .. tostring(valid_roll) .. "'"
+		.. " vb'" .. tostring(valid_bounds) .. "'"
+		.. " r'" .. tostring(ro) .. "'"
+		.. " l'" .. tostring(lo) .. "'"
+		.. " h'" .. tostring(hi) .. "'"
+	LootDebug(str, "players")
+
+	return valid_roll, valid_bounds, ro, lo, hi
+end
+
+---Get name, class, guild rank (if in same guild) a the given player.
+---@param id string
+---@return string name - name of the player
+---@return string rank - localized guild rank
+---@return string class - WoW internal class name
+local function GetPlayer(id)
+	local name = GetUnitName(id)
+	local localizedClass, class, classIndex = UnitClass(id)
+
+	local rank = ""
+	if IsInGuild() and UnitIsInMyGuild(id) then
+		rank = "<" .. GuildControlGetRankName(C_GuildInfo.GetGuildRankOrder(UnitGUID(id))) .. ">"
+	else
+		local guildName, guildRankName, guildRankIndex, realm = GetGuildInfo(id)
+		if guildName and guildRankName then
+			rank = "<" .. guildName .. " / " .. guildRankName .. ">"
+		end
+	end
+
+	return name, rank, class
+end
+
+---Determine whether the player is the leader of the group.
+---@return boolean
+local function IsLead()
+	if UnitIsGroupLeader("player") then
+		return true
+	end
+	-- The way this flows is both leader AND master looter will have the extra buttons
+	local lootmethod, masterlooterPartyID, masterlooterRaidID = LootMethod()
+	if (lootmethod == "master") or (lootmethod == 3) then
+		if IsInRaid() and (masterlooterRaidID == UnitInRaid("player")) then
+			return true
+		end
+		if IsInGroup() and (masterlooterPartyID == UnitInParty("player")) then
+			return true
+		end
+	end
+	if LT.Debug.flags.force_leader then
+		return true
+	end
+	if LT.Debug.flags.force_master then
+		return true
+	end
+	return false
+end
+
+---Debug : output player info
+---@param player table
+local function OutPlayer(player)
+	if LT.Debug.on then --
+		if player then
+			TitanPluginDebug(TITAN_LOOTTYPE_ID, "GetPlayerList:"
+				.. " p'" .. (player.name or "nyl") .. "'"
+				.. " r'" .. (player.rank or "nyl") .. "'"
+				.. " c'" .. (player.class or "nyl") .. "'"
+			)
+		end
+	end
+end
+
+---Collect name, class, and guild rank (if in same guild) of players in the group. This routine will generate group lists (5 or 40) for debug based on debug flags.
+---@param unsort boolean? if true sort by class then name
+---@return table group indexed table of players in  the group
+---@return table group_names table of player names pointing into ret
+function Track.GetPlayerList(unsort)
+	-- https://warcraft.wiki.gg/wiki/ClassId
+
+	local count, start
+	local prefix
+	local ret = {}
+	local retName = {}
+
+	if IsInRaid() or LT.Debug.flags.is_raid then
+		prefix = "raid"
+		count = MAX_RAID_MEMBERS
+		start = 1
+	elseif IsInGroup() or LT.Debug.flags.is_party then
+		prefix = "party"
+		count = MAX_PARTY_MEMBERS
+		start = 0
+	else
+		prefix = "solo"
+		count = 0
+		start = 0
+	end
+
+	if LT.Debug.on then -- safety...
+		if LT.Debug.flags.add_players then
+			-- player list has already been created, just return
+		elseif prefix == "solo" then
+			local name, rank, englishClass = GetPlayer("player")
+			if name ~= nil then
+				local entry = {
+					["name"] = name,
+					["rank"] = rank,
+					["class"] = englishClass,
+				}
+				tinsert(ret, entry)
+				retName[name] = entry
+			end
+		else
+			local class = 0
+			local class_max = 11
+			for index = start, count do
+				local guildName, guildRankName, guildRankIndex, realm
+				local id
+				if index > 0 then
+					id = prefix .. index
+					if class >= class_max then
+						class = 1
+					else
+						class = class + 1
+					end
+				else
+					id = "player"
+				end
+				-- handle name and class
+				local name = id
+				local localizedClass, englishClass, classIndex
+				if index == 0 then -- get the real player info
+					localizedClass, englishClass, classIndex = UnitClass(id)
+				elseif class == 1 then
+					englishClass = "WARRIOR"
+				elseif class == 2 then
+					englishClass = "PALADIN"
+				elseif class == 3 then
+					englishClass = "HUNTER"
+				elseif class == 4 then
+					englishClass = "ROGUE"
+				elseif class == 5 then
+					englishClass = "PRIEST"
+				elseif class == 6 then
+					englishClass = "MAGE" -- DK after CE
+				elseif class == 7 then
+					englishClass = "SHAMAN"
+				elseif class == 8 then
+					englishClass = "MAGE"
+				elseif class == 9 then
+					englishClass = "WARLOCK"
+				elseif class == 10 then
+					englishClass = "WARLOCK" -- monk after CE
+				elseif class == 11 then
+					englishClass = "DRUID"
+				end
+
+				-- Guild section assume this works... :)
+				local rank = ""
+
+				if name ~= nil then
+					local entry = {
+						["name"] = name,
+						["rank"] = rank,
+						["class"] = englishClass,
+					}
+					tinsert(ret, entry)
+					retName[name] = entry
+					OutPlayer(entry)
+				end
+			end
+		end
+	else
+		-- normal operation
+		for index = start, count do
+			local guildName, guildRankName, guildRankIndex, realm
+			local id
+			if index > 0 then
+				id = prefix .. index
+			else
+				id = "player"
+			end
+			if UnitInParty(id) then
+				local name, rank, englishClass = GetPlayer(id)
+
+				if name ~= nil then
+					local entry = {
+						["name"] = name,
+						["rank"] = rank,
+						["class"] = englishClass,
+					}
+					tinsert(ret, entry)
+					retName[name] = entry
+					OutPlayer(entry)
+				end
+			end
+		end
+	end
+
+	if unsort then
+		sort(ret, function(a, b) return (a.class < b.class or (a.class == b.class and a.name < b.name)) end)
+	end
+
+	return ret, retName
+end
+
+---Select the channel type depending on the  type of group the player is in.
+---@return string
+function Track.GetAutoChannel()
+	-- Return an appropriate channel in order of preference: /raid, /p, /s
+	local channel
+	if IsInRaid() then
+		channel = "RAID"
+	elseif IsInGroup() then
+		channel = "PARTY"
+	else
+		channel = "SAY"
+	end
+	return channel
+end
+
+---Send the message to the channel type depending on the type of group the player is in.
+---@param msg string
+function Track.AddChat(msg)
+	if msg ~= nil and msg ~= "" then
+		if IsInGroup() or IsInRaid() then
+			SendMsg(msg, Track.GetAutoChannel())
+		else
+			DEFAULT_CHAT_FRAME:AddMessage(msg, Track.DB.ColorChat.r, Track.DB.ColorChat.g, Track.DB.ColorChat.b,
+				Track.DB.ColorChat.a)
+		end
+	end
+end
+
+---Save where the window is and its size.
+function Track.SaveAnchors()
+	Track.DB.X = TitanPanelLootTypeMainWindow:GetLeft()
+	Track.DB.Y = TitanPanelLootTypeMainWindow:GetTop()
+	Track.DB.Width = TitanPanelLootTypeMainWindow:GetWidth()
+	Track.DB.Height = TitanPanelLootTypeMainWindow:GetHeight()
+end
+
+---Enable buttons; Show window; Update the player list with any rolls so far
+function Track.ShowWindow()
+	if IsLead() then
+		TitanPanelLootTypeFrameClearButton:Enable()
+		TitanPanelLootTypeFrameAnnounceButton:Enable()
+		TitanPanelLootTypeFrameNotRolledButton:Enable()
+	else
+		TitanPanelLootTypeFrameClearButton:Disable()
+		TitanPanelLootTypeFrameAnnounceButton:Disable()
+		TitanPanelLootTypeFrameNotRolledButton:Disable()
+	end
+	TitanPanelLootTypeMainWindow:Show()
+	Track.UpdateRollList()
+end
+
+---Reset window to default position and size
+function Track.ResetWindow()
+	TitanPanelLootTypeMainWindow:ClearAllPoints()
+	TitanPanelLootTypeMainWindow:SetPoint("Center", UIParent, "Center", 0, 0)
+	TitanPanelLootTypeMainWindow:SetWidth(200)
+	TitanPanelLootTypeMainWindow:SetHeight(200)
+	Track.SaveAnchors()
+	Track.ShowWindow()
+end
+
+---Hide the main tracker window
+function Track.HideWindow()
+	TitanPanelLootTypeMainWindow:Hide()
+end
+
+---Initialize variables; Get last position and size of main frame; Register for needed events
+function Track.Init()
+	-- Add color
+	Track.DB.ColorChat     = { a = 1, r = 1, g = 1, b = 1 }
+	Track.DB.ColorNormal   = { a = 1, r = 1, g = 1, b = 1 }
+	Track.DB.ColorCheat    = { a = 1, r = 1, g = 0, b = 0 }
+	Track.DB.ColorGuild    = { a = 1, r = .2, g = 1, b = .2 }
+	Track.DB.ColorInfo     = { a = 1, r = .6, g = .6, b = .6 }
+	Track.DB.ColorScroll   = { a = 1, r = .8, g = .8, b = .8 }
+
+	-- For now, hard code some options
+	Track.DB.ClearOnStart  = true
+	Track.DB.OpenOnStart   = true
+	Track.DB.ShowNotRolled = true
+	Track.DB.ShowGuildRank = true
+
+	Track.DB.tie_breaker   = 0
+
+	Track.rollArray        = {}
+	Track.rollNames        = {}
+
+	Track.allRolled        = false
+
+	--	TitanPanelLootTypeMainWindow:SetMinResize(194,170)
+	TitanPanelLootTypeMainWindow:SetResizeBounds(200, 250) -- (225, 250, 225, 250)
+	local x, y, w, h = Track.DB.X, Track.DB.Y, Track.DB.Width, Track.DB.Height
+	if not x or not y or not w or not h then
+		Track.SaveAnchors()
+	else
+		TitanPanelLootTypeMainWindow:ClearAllPoints()
+		TitanPanelLootTypeMainWindow:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
+		TitanPanelLootTypeMainWindow:SetWidth(w)
+		TitanPanelLootTypeMainWindow:SetHeight(h)
+	end
+
+	-- using strings from GlobalStrings.lua
+	Track.PatternRoll = Tool.CreatePattern(RANDOM_ROLL_RESULT)
+
+	local media = LibStub("LibSharedMedia-3.0")
+	local newfont = media:Fetch("font", TitanPanelGetVar("FontName"))
+	Tool.Font = newfont
+	Tool.FontSize = TitanPanelGetVar("FontSize")
+
+	--	TitanPanelLootTypeMainWindowTitle:SetFont(Tool.Font, Tool.FontSize)
+	TitanPanelLootTypeMainWindowTitle:SetText(
+		string.format(Track.TxtEscapePicture, Track.IconDice)
+		.. " " .. Track.MSGPREFIX
+	)
+	Tool.SetButtonFont(TitanPanelLootTypeFrameRollButton) -- sets all buttons...
+
+	TitanPanelLootTypeFrameRollButton:SetText(string.format(Track.TxtEscapePicture, Track.IconDice) ..
+	L["TITAN_LOOTTYPE_TRACKER_BTNROLL"])
+	TitanPanelLootTypeFramePassButton:SetText(string.format(Track.TxtEscapePicture, Track.IconPass) ..
+	L["TITAN_LOOTTYPE_TRACKER_BTNPASS"])
+
+	TitanPanelLootTypeFrameAnnounceButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNANNOUNCE"])
+	TitanPanelLootTypeFrameNotRolledButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNNOTROLLED"])
+	TitanPanelLootType.ResizeButtons()
+	TitanPanelLootTypeFrameClearButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNCLEAR"])
+
+	TitanPanelLootTypeMainWindow:RegisterForDrag("LeftButton")
+	TitanPanelLootTypeMainWindow:EnableMouse(true)
+	TitanPanelLootTypeMainWindow:SetResizable(true)
+	TitanPanelLootTypeMainWindow:RegisterForDrag("LeftButton")
+	TitanPanelLootTypeMainWindow:SetScript("OnDragStart", function(self)
+		self:StartMoving()
+		Track.SaveAnchors()
+	end)
+	TitanPanelLootTypeMainWindow:SetScript("OnDragStop", function(self)
+		self:StopMovingOrSizing()
+		Track.SaveAnchors()
+	end)
+
+	TitanPanelLootTypeFrame:Show()
+
+	local str = ".Init"
+		.. " register for events"
+	LootDebug(str, "events")
+	-- Should be ready for events we are interested in
+	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_SYSTEM", TitanPanelLootTypeButton_OnEvent)
+
+	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_PARTY", TitanPanelLootTypeButton_OnEvent)
+	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_PARTY_LEADER", TitanPanelLootTypeButton_OnEvent)
+	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_RAID", TitanPanelLootTypeButton_OnEvent)
+	TitanPanelLootTypeButton:RegisterEvent("CHAT_MSG_RAID_LEADER", TitanPanelLootTypeButton_OnEvent)
+end
+
+---Close frame and cleanup
+function Track.Close()
+	Track.DB.RollInProcess = false
+	Track.HideWindow()
+	if Track.DB.ClearOnClose then
+		Track.ClearRolls()
+	end
+end
+
+---Monitor system chat for player rolls; add the roll when one is found
+---@param arg1 string
+function Track.Event_CHAT_MSG_SYSTEM(arg1)
+	local str = "Event_CHAT_MSG_SYSTEM"
+		.. " m'" .. tostring(arg1) .. "'"
+	LootDebug(str, "events")
+
+	if Track.DB.RollInProcess then
+		for name, roll, low, high in string.gmatch(arg1, Track.PatternRoll) do
+			--print(".."..name.." "..roll.." "..low.." "..high)
+			Track.AddRoll(name, roll, low, high)
+		end
+	end
+end
+
+---Monitor general chat for Loot commands
+---@param msg string
+---@param name string
+function Track.Event_Generic_CHAT_MSG(msg, name)
+--[[
+- Monitor general chat for:
+- a pass ('pass' or localized version)
+- Roll start
+- Roll end
+--]]
+	local str = "Event_Generic_CHAT_MSG"
+		.. " '" .. tostring(name) .. "'"
+		.. " m'" .. tostring(msg) .. "'"
+	LootDebug(str, "events")
+
+	-- prevent 'random' rolls from popping windows
+	if Track.DB.RollInProcess then
+		if msg == L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"] or msg == "pass" then
+			name = Tool.Split(name, "-")[1]
+			Track.AddRoll(name, "0", "1", "100")
+		end
+	end
+
+	-- Assume a 'leader' requested a roll so pop the window
+	if string.sub(msg, 1, string.len(Track.MSGPREFIX_START)) == Track.MSGPREFIX_START then
+		Track.DB.RollInProcess = true
+		if Track.DB.ClearOnStart then
+			Track.ClearRolls()
+		end
+		if Track.DB.OpenOnStart then
+			Track.ShowWindow()
+		end
+	end
+	-- Check for the 'end' of the roll
+	if string.sub(msg, 1, string.len(Track.MSGPREFIX_END)) == Track.MSGPREFIX_END then
+		Track.DB.RollInProcess = false
+		if Track.DB.ClearOnStart then
+			Track.ClearRolls()
+		end
+	end
+	-- Check for the 'close' of the roll
+	if string.sub(msg, 1, string.len(Track.MSGPREFIX_CLOSE)) == Track.MSGPREFIX_CLOSE then
+		Track.Close()
+	end
+end
+
+---Process the roll the player made
+---@param name string
+---@param roll string
+---@param low string
+---@param high string
+function Track.AddRoll(name, roll, low, high)
+--[[
+- A pass has a roll of "0"
+- Only the first roll is marked as valid / invalid
+- The number of rolls is saved (Count)
+- A running number (tie_breaker) is added to ensure the first arrived of a tie wins; stored in Place
+- Always show the main frame to ensure it pops, no harm if already shown
+--]]
+	local act = "nyl"
+	local valid = false
+
+	local valid_ro, valid_bounds, ro, lo, hi = IsRoll(roll, low, high)             -- numeric
+	if Track.rollNames[name] == nil then
+		Track.DB.tie_breaker = Track.DB.tie_breaker + 1                            -- only count the first roll for each player
+		act = "insert"
+		Track.rollNames[name] = Track.rollNames[name] and Track.rollNames[name] + 1 or 1 -- mark player as having rolled
+		table.insert(Track.rollArray, {
+			Name = name,
+			Roll = ro,
+			Low = lo,
+			High = hi,
+			Count = Track.rollNames[name],
+			Place = Track.DB.tie_breaker,
+			Valid_roll = valid_ro,
+			Valid_bounds = valid_bounds,
+			IsPass = (valid_ro and valid_bounds and ro == 0),
+		})
+		local str = "AddRoll >>"
+			.. " '" .. tostring(act) .. "'"
+			.. " '" .. tostring(name) .. "'"
+			.. " r'" .. tostring(roll) .. "'"
+			.. " l'" .. tostring(low) .. "'"
+			.. " h'" .. tostring(high) .. "'"
+			.. " #'" .. tostring(Track.rollNames[name]) .. "'"
+		LootDebug(str, "players")
+	else
+		-- check for re-rolls. >1 if rolled before
+		act = "update"
+		Track.rollNames[name] = Track.rollNames[name] and Track.rollNames[name] + 1 or
+		1                                                                          -- mark player as having rolled again
+		for i, p in ipairs(Track.rollArray) do
+			if p.Name == name then
+				-- Only first roll is valid, Ignore additional rolls but count them for display
+				p.Count = Track.rollNames[name]
+				local str = "AddRoll >>"
+					.. " '" .. tostring(act) .. "'"
+					.. " '" .. tostring(name) .. "'"
+					.. " r'" .. tostring(roll) .. "'"
+					.. " l*'" .. tostring(low) .. "'"
+					.. " h*'" .. tostring(high) .. "'"
+					.. " #*'" .. tostring(Track.rollNames[name]) .. "'"
+				LootDebug(str, "players")
+			end
+		end
+	end
+	Track.ShowWindow()
+end
+
+---Sort ascending by name then place
+---@param a table
+---@param b table
+---@return boolean
+function Track.SortRolls(a, b)
+	--	return a.Roll < b.Roll
+	if a.Roll ~= b.Roll then
+		return a.Roll < b.Roll
+	elseif a.Roll == b.Roll then
+		return a.Place > b.Place
+	else
+		return false -- for IDE and sanity
+	end
+end
+
+---Sort descending by name then place
+---@param a table
+---@param b table
+---@return boolean
+function Track.SortRollsRev(a, b)
+	--	return a.Roll > b.Roll
+	if a.Roll ~= b.Roll then
+		return a.Roll > b.Roll
+	elseif a.Roll == b.Roll then
+		return a.Place < b.Place
+	else
+		return false -- for IDE and sanity
+	end
+end
+
+
+---Format the given roll for display
+---@param roll table
+---@param party any
+---@param partyName table
+---@return string
+function Track.FormatRollText(roll, party, partyName)
+	local colorTied = Tool.RGBtoEscape(Track.DB.ColorNormal)
+	local colorCheat = Tool.RGBtoEscape(Track.DB.ColorCheat)
+	local txtRange = (not roll.Valid_bounds) and format(" (%d-%d)", roll.Low, roll.High) or ""
+
+	local colorName
+	local iconClass
+	local colorRank = Tool.RGBtoEscape(Track.DB.ColorGuild)
+	local rank = ""
+
+	if partyName[roll.Name] and partyName[roll.Name].class then
+		colorName = "|c" .. RAID_CLASS_COLORS[partyName[roll.Name].class].colorStr
+		iconClass = Tool.IconClass[partyName[roll.Name].class]
+	end
+	if colorName == nil or Track.DB.ColorName == false then colorName = colorCheat end
+	if iconClass == nil or Track.DB.ShowClassIcon == false then iconClass = "" end
+	if Track.DB.ColorName == false then colorRank = colorCheat end
+
+	if Track.DB.ShowGuildRank and partyName[roll.Name] and partyName[roll.Name].rank then
+		rank = " " .. partyName[roll.Name].rank
+	end
+
+	local txtCount = roll.Count > 1 and format(" [%d]", roll.Count) or ""
+
+	local txt_roll = ""
+	if roll.IsPass then
+		txt_roll = L["TITAN_LOOTTYPE_TRACKER_BTNPASS"]
+	else
+		txt_roll = string.format("%3d", roll.Roll)
+	end
+
+	return "|Hplayer:" .. roll.Name .. "|h"
+		..txt_roll .. " : "
+		..iconClass.." "
+		..colorName .. roll.Name .. "|r "
+		..colorRank .. rank .. "|r "
+		..colorCheat.. txtRange .. "|r"
+		..colorTied..txtCount .. "|r"
+		.. "|h"
+		--			colorCheat..roll.Place.."|h"..
+		.."\n"
+end
+
+---Create the player list for display including rolls, 'cheats', guild rank (if in same guild).
+--- Rolls are above the line; no rolls yet are below the line
+function Track.UpdateRollList()
+	local rollText = ""
+
+	local party, partyName = Track.GetPlayerList()
+
+	table.sort(Track.rollArray, Track.SortRolls)
+
+	-- format and print rolls, check for ties
+	for i, roll in pairs(Track.rollArray) do
+		rollText = Track.FormatRollText(roll, party, partyName) .. rollText
+	end
+
+	--if IsInGroup() or IsInRaid() then
+	rollText = rollText .. Tool.RGBtoEscape(Track.DB.ColorInfo) .. L["TITAN_LOOTTYPE_TRACKER_TXTLINE"] .. "\n"
+	local gtxt = Tool.RGBtoEscape(Track.DB.ColorInfo)
+	local missClasses = {}
+	Track.allRolled = true
+	for i, p in ipairs(party) do
+		if Track.rollNames[p.name] == nil or Track.rollNames[p.name] == 0 then
+			local iconClass = Tool.IconClass[partyName[p.name].class]
+			local rank = ""
+			if iconClass == nil or Track.DB.ShowClassIcon == false then
+				iconClass = ""
+			else
+				missClasses[partyName[p.name].class] = missClasses[partyName[p.name].class] and
+				missClasses[partyName[p.name].class] + 1 or 1
+			end
+			if Track.DB.ShowGuildRank and partyName[p.name] and partyName[p.name].rank then
+				rank = " " .. partyName[p.name].rank
+			end
+			gtxt = gtxt .. "|Hplayer:" .. p.name .. "|h" .. iconClass .. p.name .. rank .. "|h\n"
+			Track.allRolled = false
+		end
+	end
+
+	local ctxt = ""
+	if IsInRaid() then
+		local isHorde = (UnitFactionGroup("player")) == "Horde"
+		for i, class in pairs(Tool.Classes) do
+			--for class,count in pairs(missClasses) do
+			if not (isHorde and class == "PALADIN") and not (not isHorde and class == "SHAMAN") then
+				ctxt = ctxt .. Tool.IconClass[class] .. (missClasses[class] or 0) .. " "
+			end
+		end
+		if ctxt ~= "" then ctxt = ctxt .. "\n" .. L["TxtLine"] .. "\n" end
+	end
+	if LT.Debug.on then --
+		TitanPluginDebug(TITAN_LOOTTYPE_ID, "UpdateRollList"
+			.. " '" .. (rollText or "nyl") .. "'"
+			.. " '" .. (ctxt or "nyl") .. "'"
+			.. " '" .. (gtxt or "nyl") .. "'"
+		)
+	end
+
+	rollText = rollText .. ctxt .. gtxt
+	LootDebug(rollText, "rolls")
+
+	--end
+
+	--	RollTrackerRollText:SetFont(Tool.Font, Tool.FontSize)
+	RollTrackerRollText:SetText(rollText)
+
+	--	TitanPanelLootTypeFrameStatusText:SetFont(Tool.Font, Tool.FontSize)
+	TitanPanelLootTypeFrameStatusText:SetText(string.format(L["TITAN_LOOTTYPE_TRACKER_MSGNBROLLS"],
+		#Track.rollArray))
+
+	--	TitanPanelLootTypeFrameClearButton:SetFont(Tool.Font, Tool.FontSize)
+	TitanPanelLootTypeFrameClearButton:SetText(L["TITAN_LOOTTYPE_TRACKER_BTNCLEAR"])
+end
+
+---Clear the player list of any rolls
+function Track.ClearRolls()
+	if #Track.rollArray > 0 then
+		Track.rollArray = {}
+		Track.rollNames = {}
+	end
+
+	Track.DB.tie_breaker = 0
+	Track.UpdateRollList()
+end
+
+---If isLead : Send a nag message via whisper to players who have not rolled; Send a message to group that reminders were sent
+function Track.NotRolled()
+	if IsLead() then
+		local party, partyName = Track.GetPlayerList()
+		local names = ""
+
+		local group = ""
+		if IsInRaid() then
+			group = L["TITAN_LOOTTYPE_TRACKER_RAIDPASS"]
+		elseif IsInGroup() then
+			group = L["TITAN_LOOTTYPE_TRACKER_PARTYPASS"]
+		else
+			group = ""
+		end
+
+		for i, p in ipairs(party) do
+			if Track.rollNames[p.name] == nil or Track.rollNames[p.name] == 0 then
+				SendMsg(Track.MSGPREFIX .. L["TITAN_LOOTTYPE_TRACKER_NOTROLLEDNAG"] .. group, WHISPER, nil,
+					p.name)
+				names = "send"
+			end
+		end
+
+		if names == "send" then
+			Track.AddChat(Track.MSGPREFIX .. L["TITAN_LOOTTYPE_TRACKER_MSGNOTROLLED"])
+		end
+	end
+end
+
+---If isLead : Pop the main frame;
+--- Clear all rolls for a new set;
+--- Start a new roll process;
+--- Send a message to the group of a new roll
+function Track.StartRoll()
+	Track.ShowWindow()
+	Track.ClearRolls()
+	Track.DB.RollInProcess = true
+	Track.AddChat(Track.MSGPREFIX_START ..
+	"{circle} " .. string.format(L["TITAN_LOOTTYPE_TRACKER_MSGSTART"], L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"]))
+	Track.AddChat(L["TITAN_LOOTTYPE_TRACKER_MSGBAR"])
+end
+
+---If isLead : Send a message to the group of the winner; Stop the roll process so new rolls are not processed
+function Track.RollAnnounce()
+	local winName = ""
+	local winRoll = 0
+	local addPrefix = ""
+	local msg = ""
+	local list = {}
+
+	table.sort(Track.rollArray, Track.SortRollsRev)
+
+	for i, roll in pairs(Track.rollArray) do
+		local str = "AddRoll >>"
+			.. " '" .. roll.Name .. "'"
+			.. " r'" .. tostring(roll.Roll) .. "'"
+		LootDebug(str, "players")
+		if roll.Valid_roll then
+			winName = roll.Name
+			winRoll = roll.Roll
+			break -- sort breaks ties, grab first one
+		end
+	end
+
+	if winName == "" then
+		msg = Track.MSGPREFIX_END .. addPrefix .. "{circle} No winners"
+	else
+		msg = Track.MSGPREFIX_END ..
+		addPrefix .. "{circle} " .. string.format(L["TITAN_LOOTTYPE_TRACKER_MSGANNOUNCE"], winName, winRoll)
+	end
+
+	Track.AddChat(msg)
+
+	Track.DB.RollInProcess = false
+end
+
+---Determine the size of the buttons so they fill the line on the main frame.
+function TitanPanelLootType.ResizeButtons()
+	local w = TitanPanelLootTypeFrameHelperButton:GetWidth()
+	TitanPanelLootTypeFrameRollButton:SetWidth(w / 2)
+	TitanPanelLootTypeFramePassButton:SetWidth(w / 2)
+
+	if Track.DB.ShowNotRolled then
+		TitanPanelLootTypeFrameAnnounceButton:SetWidth(w / 3)
+		TitanPanelLootTypeFrameClearButton:SetWidth(w / 3)
+		TitanPanelLootTypeFrameNotRolledButton:Show()
+	else
+		TitanPanelLootTypeFrameAnnounceButton:SetWidth(w / 2)
+		TitanPanelLootTypeFrameClearButton:SetWidth(w / 2)
+		TitanPanelLootTypeFrameNotRolledButton:Hide()
+	end
+end
+
+---On Close of main frame cleanup current roll process
+function TitanPanelLootType.BtnClose()
+	Track.Close()
+
+	if IsLead() then
+		Track.AddChat(Track.MSGPREFIX_CLOSE .. L["TITAN_LOOTTYPE_TRACKER_MSGCLOSING"])
+	end
+end
+
+---On click of "roll": Send the roll to be processed
+function TitanPanelLootType.BtnRoll()
+	RandomRoll(1, 100)
+end
+
+---On click "pass": Send the pass to be processed
+function TitanPanelLootType.BtnPass()
+	Track.AddChat(L["TITAN_LOOTTYPE_TRACKER_TEXTPASS"])
+	--[[
+	Note: When in solo debug mode, this just does a /say pass
+	which is NOT picked up by an event. This only monitors party & raid chat...
+	--]]
+end
+
+---On click of "clear": Only if IsLead, Clear all rolls and Start a new roll process
+function TitanPanelLootType.BtnClearRolls()
+	if #Track.rollArray > 0 then
+		Track.ClearRolls()
+		if Track.DB.CloseOnClear then
+			Track.HideWindow()
+		end
+	end
+	Track.StartRoll()
+end
+
+---On click of "start": Only if IsLead, Start a new roll process
+---@param button any
+function TitanPanelLootType.BtnAnnounce(button)
+	Track.RollAnnounce()
+	if Track.DB.ClearOnAnnounce then
+		Track.ClearRolls()
+	end
+	if Track.DB.CloseOnAnnounce then
+		Track.HideWindow()
+	end
+end
+
+---On click of "remind": Only if IsLead, nag those who have not rolled
+function TitanPanelLootType.BtnNotRolled()
+	Track.NotRolled()
+end
+
+-- Debug!!!
+
+function TitanPanelLootType.AddAllRollsDebug() -- rolls for all players
+	local party, partyName = Track.GetPlayerList()
+
+	-- walk the player list, adding rolls
+	for i, p in ipairs(party) do
+		-- 0 (zero) allows a 'pass'
+		if i == 5 then -- cheater :)
+			Track.AddRoll(p.name, tostring(random(0, 100)), "90", "100")
+		elseif i == 13 then -- doubler :)
+			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
+			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
+		elseif i == 21 then -- passer :)
+			Track.AddRoll(p.name, tostring(0), "1", "100")
+		else
+			Track.AddRoll(p.name, tostring(random(0, 100)), "1", "100")
+		end
+	end
+	-- Now show the results
+	Track.UpdateRollList()
+end
+
+function TitanPanelLootType.AddRollDebug(...) -- single roll
+	Track.AddRoll(...)
+end
+
+---On load : Set Titan registry values and register for events
+---@param self any
+function TitanPanelLootTypeButton_OnLoad(self)
+	self.registry = {
+		id = TITAN_LOOTTYPE_ID,
+		category = "Built-ins",
+		version = TITAN_VERSION,
+		menuText = L["TITAN_LOOTTYPE_MENU_TEXT"],
+		buttonTextFunction = "TitanPanelLootTypeButton_GetButtonText",
+		tooltipTitle = L["TITAN_LOOTTYPE_TOOLTIP"],
+		tooltipTextFunction = "TitanPanelLootTypeButton_GetTooltipText",
+		icon = "Interface\\AddOns\\TitanLootType\\TitanLootType",
+		iconWidth = 16,
+		controlVariables = {
+			ShowIcon = true,
+			ShowLabelText = true,
+			ShowRegularText = false,
+			ShowColoredText = false,
+			DisplayOnRightSide = true,
+		},
+		savedVariables = {
+			ShowIcon = 1,
+			ShowLabelText = 1,
+			RandomRoll = 100,
+			DB = {},
+			DisplayOnRightSide = false,
+			--			ShowDungeonDiff = false,
+			--			DungeonDiffType = "AUTO",
+		}
+	};
+
+	self:RegisterEvent("PLAYER_ENTERING_WORLD", TitanPanelLootTypeButton_OnEvent)
+	self:RegisterEvent("GROUP_ROSTER_UPDATE");
+	self:RegisterEvent("RAID_ROSTER_UPDATE");
+	self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED");
+	self:RegisterEvent("CHAT_MSG_SYSTEM");
+end
+
+---Parse events registered to LootType and act on them
+---@param self any
+---@param event string
+---@param ... unknown
+function TitanPanelLootTypeButton_OnEvent(self, event, ...)
+	LootDebug(event, "events") -- could generate a lot of messages...
+
+	if (event == "CHAT_MSG_SYSTEM") then
+		Track.Event_CHAT_MSG_SYSTEM(...)
+	end
+
+	if (event == "CHAT_MSG_PARTY") then
+		Track.Event_Generic_CHAT_MSG(...)
+	end
+
+	if (event == "CHAT_MSG_PARTY_LEADER") then
+		Track.Event_Generic_CHAT_MSG(...)
+	end
+
+	if (event == "CHAT_MSG_RAID") then
+		Track.Event_Generic_CHAT_MSG(...)
+	end
+
+	if (event == "CHAT_MSG_RAID_LEADER") then
+		Track.Event_Generic_CHAT_MSG(...)
+	end
+
+	if (event == "PLAYER_ENTERING_WORLD") then
+		Track.Init()
+	end
+
+	TitanPanelPluginHandle_OnUpdate(updateTable)
+end
+
+---Determine loot type and then display on button
+---@param id any
+---@return string
+---@return string
+function TitanPanelLootTypeButton_GetButtonText(id)
+	local lootTypeText, lootThreshold, color
+
+	--	if (GetNumSubgroupMembers() > 0) or (GetNumGroupMembers() > 0) then
+
+	if IsInRaid() or IsInGroup() then
+		lootTypeText = TitanLootMethod[LootMethod()].text;
+		lootThreshold = GetLootThreshold();
+		color = _G["ITEM_QUALITY_COLORS"][lootThreshold];
+	else
+		lootTypeText = _G["SOLO"];
+		color = _G["GRAY_FONT_COLOR"];
+	end
+	return L["TITAN_LOOTTYPE_BUTTON_LABEL"], TitanUtils_GetColoredText(lootTypeText, color);
+end
+
+---Prepare the tool tip text. The tool tip is determined by whether the player is in a group or not
+---@return string
+function TitanPanelLootTypeButton_GetTooltipText()
+	--	if (GetNumSubgroupMembers() > 0) or (GetNumGroupMembers() > 0) then
+	if IsInRaid() or IsInGroup() then
+		local lootTypeText = TitanLootMethod[LootMethod()].text;
+		local lootThreshold = GetLootThreshold();
+		local itemQualityDesc = _G["ITEM_QUALITY" .. lootThreshold .. "_DESC"];
+		local color = _G["ITEM_QUALITY_COLORS"][lootThreshold];
+		return "" ..
+			_G["LOOT_METHOD"] .. ": \t" .. TitanUtils_GetHighlightText(lootTypeText) .. "\n" ..
+			_G["LOOT_THRESHOLD"] .. ": \t" .. TitanUtils_GetColoredText(itemQualityDesc, color) .. "\n" ..
+			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT1"]) .. "\n"
+		--			..TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT2"])
+	else
+		return --TitanUtils_GetNormalText(_G["ERR_NOT_IN_GROUP"]).."\n"..
+			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT1"]) .. "\n"
+		--			TitanUtils_GetGreenText(L["TITAN_LOOTTYPE_TOOLTIP_HINT2"]);
+	end
+end
+
+---Display rightclick menu options.
+function TitanPanelRightClickMenu_PrepareLootTypeMenu()
+	local info = {};
+
+	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_LOOTTYPE_ID].menuText);
+	info = {};
+	info.notCheckable = true
+
+	TitanPanelRightClickMenu_AddToggleIcon(TITAN_LOOTTYPE_ID);
+	TitanPanelRightClickMenu_AddToggleLabelText(TITAN_LOOTTYPE_ID);
+	TitanPanelRightClickMenu_AddToggleRightSide(TITAN_LOOTTYPE_ID);
+	TitanPanelRightClickMenu_AddSpacer();
+	TitanPanelRightClickMenu_AddCommand(L["TITAN_PANEL_MENU_HIDE"], TITAN_LOOTTYPE_ID, TITAN_PANEL_MENU_FUNC_HIDE);
+end
+
+--- On left click: If isLead then start a new group roll; If not isLead then do a roll
+---@param self any
+---@param button string
+function TitanPanelLootTypeButton_OnClick(self, button)
+	if button == "LeftButton" then
+		if IsLead() then
+			TitanPanelLootType.BtnClearRolls()
+		else
+			RandomRoll(1, 100)
+		end
+	end
+end
diff --git a/TitanLootType/TitanClassicLootType.xml b/TitanLootType/TitanClassicLootType.xml
index effa361..6d56436 100644
--- a/TitanLootType/TitanClassicLootType.xml
+++ b/TitanLootType/TitanClassicLootType.xml
@@ -1,274 +1,274 @@
-<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
-..\FrameXML\UI.xsd">
-	<Script file="TitanClassicLootType.lua"/>
-	<Frame parent="UIParent">
-		<Frames>
-			<Button name="TitanPanelLootTypeButton" inherits="TitanPanelComboTemplate" frameStrata="FULLSCREEN" toplevel="true">
-				<Scripts>
-					<OnLoad>
-						TitanPanelLootTypeButton_OnLoad(self);
-						TitanPanelButton_OnLoad(self);
-					</OnLoad>
-					<OnEvent>
-						TitanPanelLootTypeButton_OnEvent(self, event, ...);
-					</OnEvent>
-					<OnClick>
-					TitanPanelLootTypeButton_OnClick(self, button);
-					TitanPanelButton_OnClick(self, button);
-					</OnClick>
-				</Scripts>
-			</Button>
-		</Frames>
-	</Frame>
-
-	<Button name="TitanPanelLootType_MiniButton" inherits="UIPanelButtonTemplate" virtual="true">
-		<NormalFont style="GameFontNormalSmall"/>
-		<HighlightFont style="GameFontHighlightSmall"/>
-		<DisabledFont style="GameFontDisableSmall"/>
-		<Size><AbsDimension x="20" y="18"/></Size>
-	</Button>
-	<Button name="TitanPanelLootType_SmallButton" inherits="UIPanelButtonTemplate" virtual="true">
-		<NormalFont style="GameFontNormalSmall"/>
-		<HighlightFont style="GameFontHighlightSmall"/>
-		<DisabledFont style="GameFontDisableSmall"/>
-		<Size><AbsDimension y="16"/></Size>
-	</Button>
-
-	<!-- For the Track feature -->
-	<Frame name="TitanPanelLootTypeMainWindow" parent="UIParent" hidden="true" toplevel="true" inherits="BackdropTemplate"
-		movable="true" enableMouse="true" frameStrata="HIGH" resizable="true">
-		<Size><AbsDimension x="194" y="170"/></Size>
-		<Anchors>
-			<Anchor point="CENTER">
-			<Offset><AbsDimension x="300" y="0"/></Offset>
-			</Anchor>
-		</Anchors>
-		<KeyValues>
-			<KeyValue key="backdropInfo" value="BACKDROP_TUTORIAL_16_16" type="global"/>
-		</KeyValues>
-
-		<Layers>
-			<Layer level="BACKGROUND">
-				<FontString name="$parentTitle" inherits="GameFontNormal" text="RollTracker Classic" justifyH="LEFT" justifyV="TOP">
-					<Anchors>
-						<Anchor point="TOPLEFT">
-							<Offset>
-								<AbsDimension x="10" y="-10"/>
-							</Offset>
-						</Anchor>
-						<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT">
-							<Offset>
-								<AbsDimension x="-10" y="-30"/>
-							</Offset>
-						</Anchor>
-					</Anchors>
-				</FontString>
-			</Layer>
-		</Layers>
-
-		<Frames>
-			<!-- headline -->
-			<Button name="$parentCloseButton" inherits="TitanPanelLootType_MiniButton" Text="|TInterface\Buttons\UI-StopButton:0|t">
-				<Anchors>
-					<Anchor point="TOPRIGHT" relativeTo="$parent" relativePoint="TOPRIGHT">
-						<Offset>
-							<AbsDimension x="-6" y="-6"/>
-						</Offset>
-					</Anchor>
-				</Anchors>
-				<Scripts>
-					<OnClick>
-						 TitanPanelLootType.BtnClose()
-					</OnClick>
-				</Scripts>
-			</Button>
-			<Button name="$parentResizeCorner">
-				<Size x="16" y="16"/>
-				<Anchors>
-					<Anchor point="BOTTOMRIGHT">
-						<Offset x="-3" y="3"/>
-					</Anchor>
-				</Anchors>
-				<Scripts>
-					<OnMouseDown>
-						self:GetParent():StartSizing()
-					</OnMouseDown>
-					<OnLoad>
-						self:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6)
-					</OnLoad>
-					<OnMouseUp>
-						self:GetParent():StopMovingOrSizing()
-					</OnMouseUp>
-					<OnHide>
-						self:GetParent():StopMovingOrSizing()
-					</OnHide>
-				</Scripts>
-				<NormalTexture file="Interface\AddOns\TitanLootType\Artwork\resize"/>
-			</Button>
-
-			<Frame name="TitanPanelLootTypeFrame" hidden="true" >
-				<Anchors>
-					<Anchor point="TOPLEFT" >
-						<Offset>
-							<AbsDimension x="8" y="-30"/>
-						</Offset>
-					</Anchor>
-					<Anchor point="BOTTOMRIGHT" >
-						<Offset>
-							<AbsDimension x="-8" y="8"/>
-						</Offset>
-					</Anchor>
-				</Anchors>
-				<Layers>
-					<Layer level="BACKGROUND">
-						<FontString name="$parentStatusText" inherits="GameFontNormalSmall" text="0 Rolls" justifyH="LEFT" justifyV="TOP">
-							<Color r="0.5" g="0.5" b="1.0"/>
-							<Anchors>
-								<Anchor point="BOTTOMLEFT">
-									<Offset>
-										<AbsDimension x="2" y="2"/>
-									</Offset>
-								</Anchor>
-								<Anchor point="BOTTOMRIGHT">
-									<Offset>
-										<AbsDimension x="-2" y="12"/>
-									</Offset>
-								</Anchor>
-							</Anchors>
-						</FontString>
-					</Layer>
-				</Layers>
-				<Frames>
-					<!-- helper button -->
-					<Button name="$parentHelperButton" inherits="UIPanelButtonTemplate" hidden="true" text="">
-						<Anchors>
-							<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" relativeTo="$parentStatusText"/>
-							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentStatusText"/>
-						</Anchors>
-						<Size><AbsDimension y="5"/></Size>
-						<Scripts>
-							<OnSizeChanged>
-								TitanPanelLootType.ResizeButtons()
-							</OnSizeChanged>
-						</Scripts>
-					</Button>
-
-					<!-- lower button line -->
-					<Button name="$parentRollButton" inherits="TitanPanelLootType_SmallButton" text="Roll"> <!--1-->
-						<Anchors>
-							<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" relativeTo="$parentHelperButton"/>
-						</Anchors>
-						<Scripts>
-							<OnClick>
-								TitanPanelLootType.BtnRoll()
-							</OnClick>
-						</Scripts>
-					</Button>
-
-					<Button name="$parentPassButton" inherits="TitanPanelLootType_SmallButton" text="pass"> <!--3-->
-						<Anchors>
-							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentHelperButton"/>
-						</Anchors>
-						<Scripts>
-							<OnClick>
-								TitanPanelLootType.BtnPass()
-							</OnClick>
-						</Scripts>
-					</Button>
-					<!-- $parentGreedButton  Not used by Titan -->
-
-					<!-- upper button line -->
-
-					<Button name="$parentClearButton" inherits="TitanPanelLootType_SmallButton" text="announce"><!--1-->
-						<Anchors>
-							<Anchor point="LEFT" relativePoint="LEFT" relativeTo="$parentHelperButton"/>
-							<Anchor point="BOTTOM" relativePoint="TOP" relativeTo="$parentRollButton">
-								<Offset>
-									<AbsDimension y="4"/>
-								</Offset>
-							</Anchor>
-						</Anchors>
-						<Scripts>
-							<OnClick>
-								TitanPanelLootType.BtnClearRolls()
-							</OnClick>
-						</Scripts>
-					</Button>
-
-					<Button name="$parentAnnounceButton" inherits="TitanPanelLootType_SmallButton" text="Clear"><!--3-->
-						<Anchors>
-							<Anchor point="RIGHT" relativePoint="RIGHT" relativeTo="$parentHelperButton"/>
-							<Anchor point="BOTTOM" relativePoint="BOTTOM" relativeTo="$parentClearButton"/>
-						</Anchors>
-						<Scripts>
-							<OnClick>
-								TitanPanelLootType.BtnAnnounce()
-							</OnClick>
-						</Scripts>
-					</Button>
-
-					<Button name="$parentNotRolledButton" inherits="TitanPanelLootType_SmallButton" text="Not Rolled"><!--2-->
-						<Anchors>
-							<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClearButton"/>
-							<Anchor point="RIGHT" relativePoint="LEFT" relativeTo="$parentAnnounceButton"/>
-							<Anchor point="BOTTOM" relativePoint="BOTTOM" relativeTo="$parentClearButton"/>
-						</Anchors>
-						<Scripts>
-							<OnClick>
-								TitanPanelLootType.BtnNotRolled()
-							</OnClick>
-						</Scripts>
-					</Button>
-
-					<!--button end -->
-
-					<ScrollFrame name="$parentRollScrollFrame" inherits="UIPanelScrollFrameTemplate">
-						<Anchors>
-							<Anchor point="TOP" />
-							<Anchor point="LEFT" relativePoint="LEFT" relativeTo="$parentClearButton"/>
-							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentAnnounceButton">
-								<Offset>
-									<AbsDimension x="-20" y="5"/>
-								</Offset>
-							</Anchor>
-						</Anchors>
-						<ScrollChild>
-							<Frame name="$parentScrollChild">
-								<Size>
-									<AbsDimension x="30" y="30"/>
-								</Size>
-								<Frames>
-									<SimpleHTML name="RollTrackerRollText">
-										<Anchors>
-											<Anchor point="TOPLEFT" relativeTo="TitanPanelLootTypeFrameRollScrollFrameScrollChild">
-												<Offset>
-													<AbsDimension x="0" y="-2"/>
-												</Offset>
-											</Anchor>
-
-											<Anchor point="BOTTOMRIGHT" relativeTo="TitanPanelLootTypeFrameRollScrollFrame">
-												<Offset>
-													<AbsDimension x="0" y="2"/>
-												</Offset>
-											</Anchor>
-										</Anchors>
-
-										<FontString name="RollTrackerFontString" inherits="ChatFontNormal" justifyH="LEFT" justifyV="TOP">
-											<Size>
-												<AbsDimension x="270" y="0"/>
-											</Size>
-											<Color r="1" g="1" b="1" a="1.0" />
-										</FontString>
-									</SimpleHTML>
-								</Frames>
-							</Frame>
-						</ScrollChild>
-					</ScrollFrame>
-				</Frames>
-			</Frame>
-
-			<!-- <>LOOTFRAME Not used by Titan -->
-
-		</Frames>
-	</Frame>
-</Ui>
+<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
+..\FrameXML\UI.xsd">
+	<Script file="TitanClassicLootType.lua"/>
+	<Frame parent="UIParent">
+		<Frames>
+			<Button name="TitanPanelLootTypeButton" inherits="TitanPanelComboTemplate" frameStrata="FULLSCREEN" toplevel="true">
+				<Scripts>
+					<OnLoad>
+						TitanPanelLootTypeButton_OnLoad(self);
+						TitanPanelButton_OnLoad(self);
+					</OnLoad>
+					<OnEvent>
+						TitanPanelLootTypeButton_OnEvent(self, event, ...);
+					</OnEvent>
+					<OnClick>
+					TitanPanelLootTypeButton_OnClick(self, button);
+					TitanPanelButton_OnClick(self, button);
+					</OnClick>
+				</Scripts>
+			</Button>
+		</Frames>
+	</Frame>
+
+	<Button name="TitanPanelLootType_MiniButton" inherits="UIPanelButtonTemplate" virtual="true">
+		<NormalFont style="GameFontNormalSmall"/>
+		<HighlightFont style="GameFontHighlightSmall"/>
+		<DisabledFont style="GameFontDisableSmall"/>
+		<Size><AbsDimension x="20" y="18"/></Size>
+	</Button>
+	<Button name="TitanPanelLootType_SmallButton" inherits="UIPanelButtonTemplate" virtual="true">
+		<NormalFont style="GameFontNormalSmall"/>
+		<HighlightFont style="GameFontHighlightSmall"/>
+		<DisabledFont style="GameFontDisableSmall"/>
+		<Size><AbsDimension y="16"/></Size>
+	</Button>
+
+	<!-- For the Track feature -->
+	<Frame name="TitanPanelLootTypeMainWindow" parent="UIParent" hidden="true" toplevel="true" inherits="BackdropTemplate"
+		movable="true" enableMouse="true" frameStrata="HIGH" resizable="true">
+		<Size><AbsDimension x="194" y="170"/></Size>
+		<Anchors>
+			<Anchor point="CENTER">
+			<Offset><AbsDimension x="300" y="0"/></Offset>
+			</Anchor>
+		</Anchors>
+		<KeyValues>
+			<KeyValue key="backdropInfo" value="BACKDROP_TUTORIAL_16_16" type="global"/>
+		</KeyValues>
+
+		<Layers>
+			<Layer level="BACKGROUND">
+				<FontString name="$parentTitle" inherits="GameFontNormal" text="RollTracker Classic" justifyH="LEFT" justifyV="TOP">
+					<Anchors>
+						<Anchor point="TOPLEFT">
+							<Offset>
+								<AbsDimension x="10" y="-10"/>
+							</Offset>
+						</Anchor>
+						<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT">
+							<Offset>
+								<AbsDimension x="-10" y="-30"/>
+							</Offset>
+						</Anchor>
+					</Anchors>
+				</FontString>
+			</Layer>
+		</Layers>
+
+		<Frames>
+			<!-- headline -->
+			<Button name="$parentCloseButton" inherits="TitanPanelLootType_MiniButton" Text="|TInterface\Buttons\UI-StopButton:0|t">
+				<Anchors>
+					<Anchor point="TOPRIGHT" relativeTo="$parent" relativePoint="TOPRIGHT">
+						<Offset>
+							<AbsDimension x="-6" y="-6"/>
+						</Offset>
+					</Anchor>
+				</Anchors>
+				<Scripts>
+					<OnClick>
+						 TitanPanelLootType.BtnClose()
+					</OnClick>
+				</Scripts>
+			</Button>
+			<Button name="$parentResizeCorner">
+				<Size x="16" y="16"/>
+				<Anchors>
+					<Anchor point="BOTTOMRIGHT">
+						<Offset x="-3" y="3"/>
+					</Anchor>
+				</Anchors>
+				<Scripts>
+					<OnMouseDown>
+						self:GetParent():StartSizing()
+					</OnMouseDown>
+					<OnLoad>
+						self:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6)
+					</OnLoad>
+					<OnMouseUp>
+						self:GetParent():StopMovingOrSizing()
+					</OnMouseUp>
+					<OnHide>
+						self:GetParent():StopMovingOrSizing()
+					</OnHide>
+				</Scripts>
+				<NormalTexture file="Interface\AddOns\TitanLootType\Artwork\resize"/>
+			</Button>
+
+			<Frame name="TitanPanelLootTypeFrame" hidden="true" >
+				<Anchors>
+					<Anchor point="TOPLEFT" >
+						<Offset>
+							<AbsDimension x="8" y="-30"/>
+						</Offset>
+					</Anchor>
+					<Anchor point="BOTTOMRIGHT" >
+						<Offset>
+							<AbsDimension x="-8" y="8"/>
+						</Offset>
+					</Anchor>
+				</Anchors>
+				<Layers>
+					<Layer level="BACKGROUND">
+						<FontString name="$parentStatusText" inherits="GameFontNormalSmall" text="0 Rolls" justifyH="LEFT" justifyV="TOP">
+							<Color r="0.5" g="0.5" b="1.0"/>
+							<Anchors>
+								<Anchor point="BOTTOMLEFT">
+									<Offset>
+										<AbsDimension x="2" y="2"/>
+									</Offset>
+								</Anchor>
+								<Anchor point="BOTTOMRIGHT">
+									<Offset>
+										<AbsDimension x="-2" y="12"/>
+									</Offset>
+								</Anchor>
+							</Anchors>
+						</FontString>
+					</Layer>
+				</Layers>
+				<Frames>
+					<!-- helper button -->
+					<Button name="$parentHelperButton" inherits="UIPanelButtonTemplate" hidden="true" text="">
+						<Anchors>
+							<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" relativeTo="$parentStatusText"/>
+							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentStatusText"/>
+						</Anchors>
+						<Size><AbsDimension y="5"/></Size>
+						<Scripts>
+							<OnSizeChanged>
+								TitanPanelLootType.ResizeButtons()
+							</OnSizeChanged>
+						</Scripts>
+					</Button>
+
+					<!-- lower button line -->
+					<Button name="$parentRollButton" inherits="TitanPanelLootType_SmallButton" text="Roll"> <!--1-->
+						<Anchors>
+							<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT" relativeTo="$parentHelperButton"/>
+						</Anchors>
+						<Scripts>
+							<OnClick>
+								TitanPanelLootType.BtnRoll()
+							</OnClick>
+						</Scripts>
+					</Button>
+
+					<Button name="$parentPassButton" inherits="TitanPanelLootType_SmallButton" text="pass"> <!--3-->
+						<Anchors>
+							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentHelperButton"/>
+						</Anchors>
+						<Scripts>
+							<OnClick>
+								TitanPanelLootType.BtnPass()
+							</OnClick>
+						</Scripts>
+					</Button>
+					<!-- $parentGreedButton  Not used by Titan -->
+
+					<!-- upper button line -->
+
+					<Button name="$parentClearButton" inherits="TitanPanelLootType_SmallButton" text="announce"><!--1-->
+						<Anchors>
+							<Anchor point="LEFT" relativePoint="LEFT" relativeTo="$parentHelperButton"/>
+							<Anchor point="BOTTOM" relativePoint="TOP" relativeTo="$parentRollButton">
+								<Offset>
+									<AbsDimension y="4"/>
+								</Offset>
+							</Anchor>
+						</Anchors>
+						<Scripts>
+							<OnClick>
+								TitanPanelLootType.BtnClearRolls()
+							</OnClick>
+						</Scripts>
+					</Button>
+
+					<Button name="$parentAnnounceButton" inherits="TitanPanelLootType_SmallButton" text="Clear"><!--3-->
+						<Anchors>
+							<Anchor point="RIGHT" relativePoint="RIGHT" relativeTo="$parentHelperButton"/>
+							<Anchor point="BOTTOM" relativePoint="BOTTOM" relativeTo="$parentClearButton"/>
+						</Anchors>
+						<Scripts>
+							<OnClick>
+								TitanPanelLootType.BtnAnnounce()
+							</OnClick>
+						</Scripts>
+					</Button>
+
+					<Button name="$parentNotRolledButton" inherits="TitanPanelLootType_SmallButton" text="Not Rolled"><!--2-->
+						<Anchors>
+							<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClearButton"/>
+							<Anchor point="RIGHT" relativePoint="LEFT" relativeTo="$parentAnnounceButton"/>
+							<Anchor point="BOTTOM" relativePoint="BOTTOM" relativeTo="$parentClearButton"/>
+						</Anchors>
+						<Scripts>
+							<OnClick>
+								TitanPanelLootType.BtnNotRolled()
+							</OnClick>
+						</Scripts>
+					</Button>
+
+					<!--button end -->
+
+					<ScrollFrame name="$parentRollScrollFrame" inherits="UIPanelScrollFrameTemplate">
+						<Anchors>
+							<Anchor point="TOP" />
+							<Anchor point="LEFT" relativePoint="LEFT" relativeTo="$parentClearButton"/>
+							<Anchor point="BOTTOMRIGHT" relativePoint="TOPRIGHT" relativeTo="$parentAnnounceButton">
+								<Offset>
+									<AbsDimension x="-20" y="5"/>
+								</Offset>
+							</Anchor>
+						</Anchors>
+						<ScrollChild>
+							<Frame name="$parentScrollChild">
+								<Size>
+									<AbsDimension x="30" y="30"/>
+								</Size>
+								<Frames>
+									<SimpleHTML name="RollTrackerRollText">
+										<Anchors>
+											<Anchor point="TOPLEFT" relativeTo="TitanPanelLootTypeFrameRollScrollFrameScrollChild">
+												<Offset>
+													<AbsDimension x="0" y="-2"/>
+												</Offset>
+											</Anchor>
+
+											<Anchor point="BOTTOMRIGHT" relativeTo="TitanPanelLootTypeFrameRollScrollFrame">
+												<Offset>
+													<AbsDimension x="0" y="2"/>
+												</Offset>
+											</Anchor>
+										</Anchors>
+
+										<FontString name="RollTrackerFontString" inherits="ChatFontNormal" justifyH="LEFT" justifyV="TOP">
+											<Size>
+												<AbsDimension x="270" y="0"/>
+											</Size>
+											<Color r="1" g="1" b="1" a="1.0" />
+										</FontString>
+									</SimpleHTML>
+								</Frames>
+							</Frame>
+						</ScrollChild>
+					</ScrollFrame>
+				</Frames>
+			</Frame>
+
+			<!-- <>LOOTFRAME Not used by Titan -->
+
+		</Frames>
+	</Frame>
+</Ui>
diff --git a/TitanRegen/TitanRegen.lua b/TitanRegen/TitanRegen.lua
index accede2..7c52d67 100644
--- a/TitanRegen/TitanRegen.lua
+++ b/TitanRegen/TitanRegen.lua
@@ -1,329 +1,329 @@
----@diagnostic disable: duplicate-set-field
--- **************************************************************************
--- * TitanRegen.lua
--- *
--- * By: TitanMod, Dark Imakuni, Adsertor and the Titan Panel Development Team
--- **************************************************************************
-
--- ******************************** Constants *******************************
-local TITAN_REGEN_ID = "Regen"
-local TITAN_BUTTON = "TitanPanel"..TITAN_REGEN_ID.."Button"
-
-local TITAN_REGEN_HP_FORMAT = "%d";
-local TITAN_REGEN_HP_FORMAT_PERCENT = "%.2f";
-local TITAN_REGEN_MP_FORMAT = "%d";
-local TITAN_REGEN_MP_FORMAT_PERCENT = "%.2f";
-local updateTable = {TITAN_REGEN_ID, TITAN_PANEL_UPDATE_ALL};
--- ******************************** Variables *******************************
-local TITAN_RegenCurrHealth = 0;
-local TITAN_RegenCurrMana = 0;
-local TITAN_RegenMP         = 0;
-local TITAN_RegenHP         = 0;
-local TITAN_RegenCheckedManaState = 0;
-local TITAN_RegenMaxHPRate = 0;
-local TITAN_RegenMinHPRate = 9999;
-local TITAN_RegenMaxMPRate = 0;
-local TITAN_RegenMinMPRate = 9999;
-local TITAN_RegenMPDuringCombat = 0;
-local TITAN_RegenMPCombatTrack = 0;
-local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true)
--- ******************************** Functions *******************************
-
----Color a text tring based on the RBG passed
----@param text string To color
----@param r number Red (0.0 - 1.0)
----@param g any Green (0.0 - 1.0)
----@param b any Blue (0.0 - 1.0)
----@return string Color_string
-local function SetTextColorRBG(text, r, g, b)
-	local str = ""
-     if (text and r and g and b) then
-          local redColorCode = format("%02x", r * 255);
-          local greenColorCode = format("%02x", g * 255);
-          local blueColorCode = format("%02x", b * 255);
-          local colorCode = "|cff"..redColorCode..greenColorCode..blueColorCode.."|r"
-          str = colorCode..text..FONT_COLOR_CODE_CLOSE
-     end
-
-	 return str
-end
-
----local Build the plugin .registry and register events
----@param self Button plugin frame
-function OnLoad(self)
-	local notes = ""
-		.."Adds a regen monitor to Titan Panel to show HP/MANA regen - Classic versions only.\n"
-	self.registry = {
-		id = TITAN_REGEN_ID,
-		category = "Built-ins",
-		version = TITAN_VERSION,
-		menuText = L["TITAN_REGEN_MENU_TEXT"],
-		buttonTextFunction = "GetButtonText",
-		tooltipTitle = L["TITAN_REGEN_MENU_TOOLTIP_TITLE"],
-		tooltipTextFunction = "TitanPanelRegenButton_GetTooltipText",
-		icon = "Interface\\AddOns\\TitanRegen\\TitanRegen",
-		iconWidth = 16,
-		notes = notes,
-		controlVariables = {
-			ShowIcon = true,
-			ShowLabelText = true,
-			ShowRegularText = false,
-			ShowColoredText = true,
-			DisplayOnRightSide = true,
-		},
-		savedVariables = {
-			ShowIcon = true,
-			ShowLabelText = 1,
-			ShowHPRegen = 1,
-			ShowPercentage = false,
-			ShowColoredText = false,
-			DisplayOnRightSide = false,
-		}
-	}
-end
-
----local Handle events the clock plugin is interested in.
----@param self Button plugin frame
----@param event string Event
----@param ... any Event parameters
-function TitanPanelRegenButton_OnEvent(self, event, a1, a2, ...)
-	if ( event == "PLAYER_ENTERING_WORLD") then
-	end
-
-     if ( event == "PLAYER_REGEN_DISABLED") then
-          TITAN_RegenMPDuringCombat = 0;
-          TITAN_RegenMPCombatTrack = 1;
-     end
-
-     if ( event == "PLAYER_REGEN_ENABLED") then
-          TITAN_RegenMPCombatTrack = 0;
-     end
-
-     local currHealth = 0;
-     local currMana = 0;
-     local runUpdate = 0;
-
-     if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == 1) then
-          if ( event == "UNIT_HEALTH" and a1 == "player") then
-               currHealth = UnitHealth("player");
-               runUpdate = 1;
-               if ( currHealth > TITAN_RegenCurrHealth and TITAN_RegenCurrHealth ~= 0 ) then
-                    TITAN_RegenHP = currHealth-TITAN_RegenCurrHealth;
-
-                    if (TITAN_RegenHP > TITAN_RegenMaxHPRate) then
-                         TITAN_RegenMaxHPRate = TITAN_RegenHP;
-                    end
-                    if (TITAN_RegenHP < TITAN_RegenMinHPRate or TITAN_RegenMinHPRate == 9999) then
-                         TITAN_RegenMinHPRate = TITAN_RegenHP;
-                    end
-               end
-               TITAN_RegenCurrHealth = currHealth;
-          end
-     end
-
-	local pval, ptype = UnitPowerType("player")
-	if (pval == 0) then -- Mana
-		if ( event == "UNIT_POWER_UPDATE" and a1 == "player" and a2 == "MANA") then
-			currMana = UnitPower("player");
-			runUpdate = 1;
-			if ( currMana  > TITAN_RegenCurrMana and TITAN_RegenCurrMana ~= 0 ) then
-				TITAN_RegenMP = currMana-TITAN_RegenCurrMana;
-
-				if (TITAN_RegenMPCombatTrack == 1) then
-					TITAN_RegenMPDuringCombat = TITAN_RegenMPDuringCombat + TITAN_RegenMP;
-				end
-
-				if (TITAN_RegenMP > TITAN_RegenMaxMPRate) then
-					TITAN_RegenMaxMPRate = TITAN_RegenMP;
-				end
-				if (TITAN_RegenMP < TITAN_RegenMinMPRate or TITAN_RegenMinMPRate == 9999) then
-					TITAN_RegenMinMPRate = TITAN_RegenMP;
-				end
-			end
-			TITAN_RegenCurrMana = currMana;
-		end
-	end
-
-	if (runUpdate == 1) then
-		TitanPanelPluginHandle_OnUpdate(updateTable)
-	end
-end
-
----Generate button text
----@param id string
----@return string label_hit_points
----@return string text_hit_points
----@return string label_mana
----@return string text_mana
-function GetButtonText(id)
-	local labelTextHP = "";
-	local valueTextHP = "";
-	local labelTextMP = "";
-	local valueTextMP = "";
-
-	if UnitHealth("player") == UnitHealthMax("player") then
-		TITAN_RegenHP = 0;
-	end
-	if UnitPower("player") == UnitPowerMax("player", 0) then
-		TITAN_RegenMP = 0;
-	end
-
-	-- safety in case both are off, then cant ever turn em on
-	if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == nil) then
-		TitanSetVar(TITAN_REGEN_ID,"ShowHPRegen",1);
-	end
-
-	if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == 1) then
-		labelTextHP = L["TITAN_REGEN_BUTTON_TEXT_HP"];
-		if (TitanGetVar(TITAN_REGEN_ID,"ShowPercentage") == 1) then
-			valueTextHP = format(TITAN_REGEN_HP_FORMAT_PERCENT, (TITAN_RegenHP/UnitHealthMax("player"))*100);
-		else
-			valueTextHP = format(TITAN_REGEN_HP_FORMAT, TITAN_RegenHP);
-		end
-		if (TitanGetVar(TITAN_REGEN_ID, "ShowColoredText")) then
-			valueTextHP = TitanUtils_GetGreenText(valueTextHP);
-		else
-			valueTextHP = TitanUtils_GetHighlightText(valueTextHP);
-		end
-	end
-
-	local pval, ptype = UnitPowerType("player")
-	if (pval == 0) then -- Mana only
-		labelTextMP = L["TITAN_REGEN_BUTTON_TEXT_MP"];
-		if (TitanGetVar(TITAN_REGEN_ID,"ShowPercentage") == 1) then
-			valueTextMP = format(TITAN_REGEN_MP_FORMAT_PERCENT, (TITAN_RegenMP/UnitPowerMax("player", 0))*100);
-		else
-			valueTextMP = format(TITAN_REGEN_MP_FORMAT, TITAN_RegenMP);
-		end
-		if (TitanGetVar(TITAN_REGEN_ID, "ShowColoredText")) then
-			valueTextMP = SetTextColorRBG(valueTextMP, 0.0, 0.0, 1.0);
-		else
-			valueTextMP = TitanUtils_GetHighlightText(valueTextMP);
-		end
-	else
-		-- Not mana so do not show
-	end
-
-	-- supports turning off labels
---[[
-print("Regen text"
-.." hp'"..tostring(labelTextHP)..""
-.." "..tostring(valueTextHP).."'"
-.." mp'"..tostring(labelTextMP)..""
-.." "..tostring(valueTextMP).."'"
-)
---]]
-	return labelTextHP, valueTextHP, labelTextMP, valueTextMP;
-end
-
----Generate tooltip text
----@return string Tool_tip Formatted text
-function TitanPanelRegenButton_GetTooltipText()
-	local minHP = TITAN_RegenMinHPRate;
-	local minMP = TITAN_RegenMinMPRate;
-
-	if minHP == 9999 then minHP = 0 end;
-	if minMP == 9999 then minMP = 0 end;
-
-	local txt = ""
-
-	txt = txt..
-		format(L["TITAN_REGEN_TOOLTIP1"], UnitHealth("player"),UnitHealthMax("player"),UnitHealthMax("player")-UnitHealth("player")).."\n"..
-		format(L["TITAN_REGEN_TOOLTIP3"], TITAN_RegenMaxHPRate).."\n"..
-		format(L["TITAN_REGEN_TOOLTIP4"], minHP).."\n"
-
-	local pval, ptype = UnitPowerType("player")
-	if (pval == 0) then
-		local regenPercent = 0
-		regenPercent = (TITAN_RegenMPDuringCombat/UnitPowerMax("player", 0))*100;
-
-		txt = txt.."\n"..
-			format(L["TITAN_REGEN_TOOLTIP2"], UnitPower("player"),UnitPowerMax("player", 0),UnitPowerMax("player", 0)-UnitPower("player")).."\n"..
-			format(L["TITAN_REGEN_TOOLTIP5"], TITAN_RegenMaxMPRate).."\n"..
-			format(L["TITAN_REGEN_TOOLTIP6"], minMP).."\n"..
-			format(L["TITAN_REGEN_TOOLTIP7"], TITAN_RegenMPDuringCombat, regenPercent).."\n"
-	else
-		-- L["TITAN_REGEN_TOOLTIP2"] = "Mana: \t"..GREEN_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." / " ..HIGHLIGHT_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." ("..RED_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE..")";
-		POWER = GREEN_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." / " ..HIGHLIGHT_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE
-		txt = txt.."\n"..
-			ptype.." \t"..
-			format(POWER, UnitPower("player"),UnitPowerMax("player", pval)).."\n"
-			-- Energy : The formula is (energyRegen)*(1+hastePercent)
-	end
-
-	return txt
-end
-
----Generate right click menu options
-function TitanPanelRightClickMenu_PrepareRegenMenu()
-	local id = TITAN_REGEN_ID;
-	local info;
-
-	TitanPanelRightClickMenu_AddTitle(TitanPlugins[id].menuText);
-
-	info = {};
-	info.text = L["TITAN_REGEN_MENU_HP"];
-	info.func = function()
-		TitanToggleVar(TITAN_REGEN_ID, "ShowHPRegen");
-		TitanPanelButton_UpdateButton(TITAN_REGEN_ID);
-		end
-	info.checked = TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen");
-	L_UIDropDownMenu_AddButton(info);
-
-	info = {};
-	info.text = L["TITAN_REGEN_MENU_PERCENT"];
-	info.func = function()
-		TitanToggleVar(TITAN_REGEN_ID, "ShowPercentage");
-		TitanPanelButton_UpdateButton(TITAN_REGEN_ID);
-		end
-	info.checked = TitanGetVar(TITAN_REGEN_ID,"ShowPercentage");
-	L_UIDropDownMenu_AddButton(info);
-
-	TitanPanelRightClickMenu_AddControlVars(TITAN_REGEN_ID)
-end
-
-local function OnShow(self)
-	self:RegisterEvent("UNIT_HEALTH");
-	self:RegisterEvent("UNIT_POWER_UPDATE");
-	self:RegisterEvent("PLAYER_REGEN_DISABLED");
-	self:RegisterEvent("PLAYER_REGEN_ENABLED");
-end
-
-local function OnHide(self)
-	self:UnregisterEvent("UNIT_HEALTH");
-	self:UnregisterEvent("UNIT_POWER_UPDATE");
-	self:UnregisterEvent("PLAYER_REGEN_DISABLED");
-	self:UnregisterEvent("PLAYER_REGEN_ENABLED");
-end
-
--- ====== Create needed frames
-local function Create_Frames()
-	if _G[TITAN_BUTTON] then
-		return -- if already created
-	end
-
-	-- general container frame
-	local f = CreateFrame("Frame", nil, UIParent)
---	f:Hide()
-
-	-- Titan plugin button
-	local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate")
-	window:SetFrameStrata("FULLSCREEN")
-	-- Using SetScript("OnLoad",   does not work
-	OnLoad(window);
---	TitanPanelButton_OnLoad(window); -- Titan XML template calls this...
-
-	window:SetScript("OnShow", function(self)
-		OnShow(self);
-		TitanPanelButton_OnShow(self);
-	end)
-	window:SetScript("OnHide", function(self)
-		OnHide(self)
-	end)
-	window:SetScript("OnEvent", function(self, event, ...)
-		TitanPanelRegenButton_OnEvent(self, event, ...)
-	end)
-end
-
-
-Create_Frames() -- do the work
+---@diagnostic disable: duplicate-set-field
+-- **************************************************************************
+-- * TitanRegen.lua
+-- *
+-- * By: TitanMod, Dark Imakuni, Adsertor and the Titan Panel Development Team
+-- **************************************************************************
+
+-- ******************************** Constants *******************************
+local TITAN_REGEN_ID = "Regen"
+local TITAN_BUTTON = "TitanPanel"..TITAN_REGEN_ID.."Button"
+
+local TITAN_REGEN_HP_FORMAT = "%d";
+local TITAN_REGEN_HP_FORMAT_PERCENT = "%.2f";
+local TITAN_REGEN_MP_FORMAT = "%d";
+local TITAN_REGEN_MP_FORMAT_PERCENT = "%.2f";
+local updateTable = {TITAN_REGEN_ID, TITAN_PANEL_UPDATE_ALL};
+-- ******************************** Variables *******************************
+local TITAN_RegenCurrHealth = 0;
+local TITAN_RegenCurrMana = 0;
+local TITAN_RegenMP         = 0;
+local TITAN_RegenHP         = 0;
+local TITAN_RegenCheckedManaState = 0;
+local TITAN_RegenMaxHPRate = 0;
+local TITAN_RegenMinHPRate = 9999;
+local TITAN_RegenMaxMPRate = 0;
+local TITAN_RegenMinMPRate = 9999;
+local TITAN_RegenMPDuringCombat = 0;
+local TITAN_RegenMPCombatTrack = 0;
+local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true)
+-- ******************************** Functions *******************************
+
+---Color a text tring based on the RBG passed
+---@param text string To color
+---@param r number Red (0.0 - 1.0)
+---@param g any Green (0.0 - 1.0)
+---@param b any Blue (0.0 - 1.0)
+---@return string Color_string
+local function SetTextColorRBG(text, r, g, b)
+	local str = ""
+     if (text and r and g and b) then
+          local redColorCode = format("%02x", r * 255);
+          local greenColorCode = format("%02x", g * 255);
+          local blueColorCode = format("%02x", b * 255);
+          local colorCode = "|cff"..redColorCode..greenColorCode..blueColorCode.."|r"
+          str = colorCode..text..FONT_COLOR_CODE_CLOSE
+     end
+
+	 return str
+end
+
+---local Build the plugin .registry and register events
+---@param self Button plugin frame
+function OnLoad(self)
+	local notes = ""
+		.."Adds a regen monitor to Titan Panel to show HP/MANA regen - Classic versions only.\n"
+	self.registry = {
+		id = TITAN_REGEN_ID,
+		category = "Built-ins",
+		version = TITAN_VERSION,
+		menuText = L["TITAN_REGEN_MENU_TEXT"],
+		buttonTextFunction = "GetButtonText",
+		tooltipTitle = L["TITAN_REGEN_MENU_TOOLTIP_TITLE"],
+		tooltipTextFunction = "TitanPanelRegenButton_GetTooltipText",
+		icon = "Interface\\AddOns\\TitanRegen\\TitanRegen",
+		iconWidth = 16,
+		notes = notes,
+		controlVariables = {
+			ShowIcon = true,
+			ShowLabelText = true,
+			ShowRegularText = false,
+			ShowColoredText = true,
+			DisplayOnRightSide = true,
+		},
+		savedVariables = {
+			ShowIcon = true,
+			ShowLabelText = 1,
+			ShowHPRegen = 1,
+			ShowPercentage = false,
+			ShowColoredText = false,
+			DisplayOnRightSide = false,
+		}
+	}
+end
+
+---local Handle events the clock plugin is interested in.
+---@param self Button plugin frame
+---@param event string Event
+---@param ... any Event parameters
+function TitanPanelRegenButton_OnEvent(self, event, a1, a2, ...)
+	if ( event == "PLAYER_ENTERING_WORLD") then
+	end
+
+     if ( event == "PLAYER_REGEN_DISABLED") then
+          TITAN_RegenMPDuringCombat = 0;
+          TITAN_RegenMPCombatTrack = 1;
+     end
+
+     if ( event == "PLAYER_REGEN_ENABLED") then
+          TITAN_RegenMPCombatTrack = 0;
+     end
+
+     local currHealth = 0;
+     local currMana = 0;
+     local runUpdate = 0;
+
+     if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == 1) then
+          if ( event == "UNIT_HEALTH" and a1 == "player") then
+               currHealth = UnitHealth("player");
+               runUpdate = 1;
+               if ( currHealth > TITAN_RegenCurrHealth and TITAN_RegenCurrHealth ~= 0 ) then
+                    TITAN_RegenHP = currHealth-TITAN_RegenCurrHealth;
+
+                    if (TITAN_RegenHP > TITAN_RegenMaxHPRate) then
+                         TITAN_RegenMaxHPRate = TITAN_RegenHP;
+                    end
+                    if (TITAN_RegenHP < TITAN_RegenMinHPRate or TITAN_RegenMinHPRate == 9999) then
+                         TITAN_RegenMinHPRate = TITAN_RegenHP;
+                    end
+               end
+               TITAN_RegenCurrHealth = currHealth;
+          end
+     end
+
+	local pval, ptype = UnitPowerType("player")
+	if (pval == 0) then -- Mana
+		if ( event == "UNIT_POWER_UPDATE" and a1 == "player" and a2 == "MANA") then
+			currMana = UnitPower("player");
+			runUpdate = 1;
+			if ( currMana  > TITAN_RegenCurrMana and TITAN_RegenCurrMana ~= 0 ) then
+				TITAN_RegenMP = currMana-TITAN_RegenCurrMana;
+
+				if (TITAN_RegenMPCombatTrack == 1) then
+					TITAN_RegenMPDuringCombat = TITAN_RegenMPDuringCombat + TITAN_RegenMP;
+				end
+
+				if (TITAN_RegenMP > TITAN_RegenMaxMPRate) then
+					TITAN_RegenMaxMPRate = TITAN_RegenMP;
+				end
+				if (TITAN_RegenMP < TITAN_RegenMinMPRate or TITAN_RegenMinMPRate == 9999) then
+					TITAN_RegenMinMPRate = TITAN_RegenMP;
+				end
+			end
+			TITAN_RegenCurrMana = currMana;
+		end
+	end
+
+	if (runUpdate == 1) then
+		TitanPanelPluginHandle_OnUpdate(updateTable)
+	end
+end
+
+---Generate button text
+---@param id string
+---@return string label_hit_points
+---@return string text_hit_points
+---@return string label_mana
+---@return string text_mana
+function GetButtonText(id)
+	local labelTextHP = "";
+	local valueTextHP = "";
+	local labelTextMP = "";
+	local valueTextMP = "";
+
+	if UnitHealth("player") == UnitHealthMax("player") then
+		TITAN_RegenHP = 0;
+	end
+	if UnitPower("player") == UnitPowerMax("player", 0) then
+		TITAN_RegenMP = 0;
+	end
+
+	-- safety in case both are off, then cant ever turn em on
+	if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == nil) then
+		TitanSetVar(TITAN_REGEN_ID,"ShowHPRegen",1);
+	end
+
+	if (TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen") == 1) then
+		labelTextHP = L["TITAN_REGEN_BUTTON_TEXT_HP"];
+		if (TitanGetVar(TITAN_REGEN_ID,"ShowPercentage") == 1) then
+			valueTextHP = format(TITAN_REGEN_HP_FORMAT_PERCENT, (TITAN_RegenHP/UnitHealthMax("player"))*100);
+		else
+			valueTextHP = format(TITAN_REGEN_HP_FORMAT, TITAN_RegenHP);
+		end
+		if (TitanGetVar(TITAN_REGEN_ID, "ShowColoredText")) then
+			valueTextHP = TitanUtils_GetGreenText(valueTextHP);
+		else
+			valueTextHP = TitanUtils_GetHighlightText(valueTextHP);
+		end
+	end
+
+	local pval, ptype = UnitPowerType("player")
+	if (pval == 0) then -- Mana only
+		labelTextMP = L["TITAN_REGEN_BUTTON_TEXT_MP"];
+		if (TitanGetVar(TITAN_REGEN_ID,"ShowPercentage") == 1) then
+			valueTextMP = format(TITAN_REGEN_MP_FORMAT_PERCENT, (TITAN_RegenMP/UnitPowerMax("player", 0))*100);
+		else
+			valueTextMP = format(TITAN_REGEN_MP_FORMAT, TITAN_RegenMP);
+		end
+		if (TitanGetVar(TITAN_REGEN_ID, "ShowColoredText")) then
+			valueTextMP = SetTextColorRBG(valueTextMP, 0.0, 0.0, 1.0);
+		else
+			valueTextMP = TitanUtils_GetHighlightText(valueTextMP);
+		end
+	else
+		-- Not mana so do not show
+	end
+
+	-- supports turning off labels
+--[[
+print("Regen text"
+.." hp'"..tostring(labelTextHP)..""
+.." "..tostring(valueTextHP).."'"
+.." mp'"..tostring(labelTextMP)..""
+.." "..tostring(valueTextMP).."'"
+)
+--]]
+	return labelTextHP, valueTextHP, labelTextMP, valueTextMP;
+end
+
+---Generate tooltip text
+---@return string Tool_tip Formatted text
+function TitanPanelRegenButton_GetTooltipText()
+	local minHP = TITAN_RegenMinHPRate;
+	local minMP = TITAN_RegenMinMPRate;
+
+	if minHP == 9999 then minHP = 0 end;
+	if minMP == 9999 then minMP = 0 end;
+
+	local txt = ""
+
+	txt = txt..
+		format(L["TITAN_REGEN_TOOLTIP1"], UnitHealth("player"),UnitHealthMax("player"),UnitHealthMax("player")-UnitHealth("player")).."\n"..
+		format(L["TITAN_REGEN_TOOLTIP3"], TITAN_RegenMaxHPRate).."\n"..
+		format(L["TITAN_REGEN_TOOLTIP4"], minHP).."\n"
+
+	local pval, ptype = UnitPowerType("player")
+	if (pval == 0) then
+		local regenPercent = 0
+		regenPercent = (TITAN_RegenMPDuringCombat/UnitPowerMax("player", 0))*100;
+
+		txt = txt.."\n"..
+			format(L["TITAN_REGEN_TOOLTIP2"], UnitPower("player"),UnitPowerMax("player", 0),UnitPowerMax("player", 0)-UnitPower("player")).."\n"..
+			format(L["TITAN_REGEN_TOOLTIP5"], TITAN_RegenMaxMPRate).."\n"..
+			format(L["TITAN_REGEN_TOOLTIP6"], minMP).."\n"..
+			format(L["TITAN_REGEN_TOOLTIP7"], TITAN_RegenMPDuringCombat, regenPercent).."\n"
+	else
+		-- L["TITAN_REGEN_TOOLTIP2"] = "Mana: \t"..GREEN_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." / " ..HIGHLIGHT_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." ("..RED_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE..")";
+		POWER = GREEN_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE.." / " ..HIGHLIGHT_FONT_COLOR_CODE.."%d"..FONT_COLOR_CODE_CLOSE
+		txt = txt.."\n"..
+			ptype.." \t"..
+			format(POWER, UnitPower("player"),UnitPowerMax("player", pval)).."\n"
+			-- Energy : The formula is (energyRegen)*(1+hastePercent)
+	end
+
+	return txt
+end
+
+---Generate right click menu options
+function TitanPanelRightClickMenu_PrepareRegenMenu()
+	local id = TITAN_REGEN_ID;
+	local info;
+
+	TitanPanelRightClickMenu_AddTitle(TitanPlugins[id].menuText);
+
+	info = {};
+	info.text = L["TITAN_REGEN_MENU_HP"];
+	info.func = function()
+		TitanToggleVar(TITAN_REGEN_ID, "ShowHPRegen");
+		TitanPanelButton_UpdateButton(TITAN_REGEN_ID);
+		end
+	info.checked = TitanGetVar(TITAN_REGEN_ID,"ShowHPRegen");
+	L_UIDropDownMenu_AddButton(info);
+
+	info = {};
+	info.text = L["TITAN_REGEN_MENU_PERCENT"];
+	info.func = function()
+		TitanToggleVar(TITAN_REGEN_ID, "ShowPercentage");
+		TitanPanelButton_UpdateButton(TITAN_REGEN_ID);
+		end
+	info.checked = TitanGetVar(TITAN_REGEN_ID,"ShowPercentage");
+	L_UIDropDownMenu_AddButton(info);
+
+	TitanPanelRightClickMenu_AddControlVars(TITAN_REGEN_ID)
+end
+
+local function OnShow(self)
+	self:RegisterEvent("UNIT_HEALTH");
+	self:RegisterEvent("UNIT_POWER_UPDATE");
+	self:RegisterEvent("PLAYER_REGEN_DISABLED");
+	self:RegisterEvent("PLAYER_REGEN_ENABLED");
+end
+
+local function OnHide(self)
+	self:UnregisterEvent("UNIT_HEALTH");
+	self:UnregisterEvent("UNIT_POWER_UPDATE");
+	self:UnregisterEvent("PLAYER_REGEN_DISABLED");
+	self:UnregisterEvent("PLAYER_REGEN_ENABLED");
+end
+
+-- ====== Create needed frames
+local function Create_Frames()
+	if _G[TITAN_BUTTON] then
+		return -- if already created
+	end
+
+	-- general container frame
+	local f = CreateFrame("Frame", nil, UIParent)
+--	f:Hide()
+
+	-- Titan plugin button
+	local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate")
+	window:SetFrameStrata("FULLSCREEN")
+	-- Using SetScript("OnLoad",   does not work
+	OnLoad(window);
+--	TitanPanelButton_OnLoad(window); -- Titan XML template calls this...
+
+	window:SetScript("OnShow", function(self)
+		OnShow(self);
+		TitanPanelButton_OnShow(self);
+	end)
+	window:SetScript("OnHide", function(self)
+		OnHide(self)
+	end)
+	window:SetScript("OnEvent", function(self, event, ...)
+		TitanPanelRegenButton_OnEvent(self, event, ...)
+	end)
+end
+
+
+Create_Frames() -- do the work
diff --git a/TitanUI/Tools.lua b/TitanUI/Tools.lua
index 850596b..1171d7a 100755
--- a/TitanUI/Tools.lua
+++ b/TitanUI/Tools.lua
@@ -105,7 +105,7 @@ end
 local function GetTooltipText()
 	local returnstring = ""
 	returnstring = returnstring.."Left Click: Reloads the User Interface\n"
-	returnstring = returnstring.."Right Click: For Debug Tools\n"
+	returnstring = returnstring.."Right Click: For Shortcuts and Debug Tools\n"
 	return returnstring
 end