Skip to content

Khormin/SimpleD20

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

SimpleD20.toc

## Interface: 120001
## Title: SimpleD20
## Notes: A clickable D20 that animates a roll.
## Author: Zenithas
## Version: 1.0

SimpleD20.lua

SimpleD20.lua

-- 1. Create the Main Frame
local d20 = CreateFrame("Button", "SimpleD20Frame", UIParent, "BackdropTemplate")
d20:SetSize(64, 64)
d20:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
d20:SetMovable(true)
d20:EnableMouse(true)
d20:RegisterForDrag("RightButton")
d20:SetScript("OnDragStart", d20.StartMoving)
d20:SetScript("OnDragStop", d20.StopMovingOrSizing)

-- 2. Visuals
local texture = d20:CreateTexture(nil, "BACKGROUND")
texture:SetTexture("Interface\\Icons\\INV_Misc_Dice_01")
texture:SetAllPoints(d20)
d20.texture = texture

-- Changed to GameFontNormalLarge so two numbers stack nicely inside the frame
d20.text = d20:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
d20.text:SetPoint("CENTER", 0, 0)
d20.text:SetText("")
d20.text:SetTextColor(1, 1, 1, 1)

-- NEW: The Toggle Button
local expectedRolls = 1 -- How many dice are we rolling?

local toggleBtn = CreateFrame("Button", nil, d20, "UIPanelButtonTemplate")
toggleBtn:SetSize(24, 24)
toggleBtn:SetPoint("LEFT", d20, "RIGHT", 2, 0) -- Attach to the right side
toggleBtn:SetText("1x")

toggleBtn:SetScript("OnClick", function()
    if expectedRolls == 1 then
        expectedRolls = 2
        toggleBtn:SetText("2x")
    else
        expectedRolls = 1
        toggleBtn:SetText("1x")
    end
    PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
end)

-- 3. Logic & Cooldown Setup
local isRolling = false
local rollTimer = nil
local timeOutTimer = nil
local rollResults = {} -- Table to store our incoming rolls

-- Cooldown variables
local COOLDOWN_SECONDS = 2.0 
local lastRollTime = 0

-- Helper function to color individual text strings
local function GetColorCode(res)
    if res == "?" then return "|cFFFFFFFF" end -- White for errors
    
    local num = tonumber(res)
    if num == 20 then 
        return "|cFF00FF00" -- Green
    elseif num == 1 then 
        return "|cFFFF0000" -- Red
    else 
        return "|cFFFFD100" -- Yellow
    end
end

-- Function to handle the final result
local function FinishRoll()
    -- Stop the flicker timers
    if rollTimer then rollTimer:Cancel() end
    if timeOutTimer then timeOutTimer:Cancel() end
    
    -- Unregister the listener
    d20:UnregisterEvent("CHAT_MSG_SYSTEM")
    
    local finalString = ""
    local playVictory = false
    local playDefeat = false
    
    -- Loop through our results and build a stacked string with colors
    for i, res in ipairs(rollResults) do
        local num = tonumber(res)
        if num == 20 then playVictory = true end
        if num == 1 then playDefeat = true end
        
        -- Append the colored number
        finalString = finalString .. GetColorCode(res) .. res .. "|r"
        
        -- Add a line break if this isn't the last number
        if i < #rollResults then
            finalString = finalString .. "\n"
        end
    end
    
    -- Sound Effects based on best/worst outcomes
    if playVictory then
        PlaySound(34089) -- Victory
    elseif playDefeat then
        PlaySound(34092) -- Defeat
    end
    
    -- Display the final stacked string
    d20.text:SetText(finalString)
    isRolling = false
end

-- 4. Event Handler (Listening for the Server)
d20:SetScript("OnEvent", function(self, event, msg)
    if event == "CHAT_MSG_SYSTEM" and isRolling then
        local myName = UnitName("player")
        
        if string.find(msg, myName) and string.find(msg, "%(1%-20%)") then
            local rollResult = string.match(msg, "rolls (%d+) %(")
            
            if rollResult then
                -- Add the caught roll to our table
                table.insert(rollResults, rollResult)
                
                -- Check if we have caught all the rolls we asked for
                if #rollResults >= expectedRolls then
                    FinishRoll()
                end
            end
        end
    end
end)

-- 5. Click Handler
d20:SetScript("OnClick", function(self, button)
    if isRolling or button == "RightButton" then return end
    
    local currentTime = GetTime()
    if (currentTime - lastRollTime) < COOLDOWN_SECONDS then
        local timeRemaining = math.ceil(COOLDOWN_SECONDS - (currentTime - lastRollTime))
        print("|cff00ccff[SimpleD20]|r You must wait " .. timeRemaining .. " more seconds before rolling again.")
        return
    end
    
    lastRollTime = currentTime
    isRolling = true
    rollResults = {} -- Clear old results
    
    PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
    d20:RegisterEvent("CHAT_MSG_SYSTEM")
    
    -- Fire off the rolls based on the toggle state
    for i = 1, expectedRolls do
        RandomRoll(1, 20)
    end
    
    -- Start Visual Flicker (Wait for server)
    rollTimer = C_Timer.NewTicker(0.05, function()
        if expectedRolls == 1 then
            d20.text:SetText("|cFFFFFFFF" .. math.random(1, 20) .. "|r")
        else
            d20.text:SetText("|cFFFFFFFF" .. math.random(1, 20) .. "\n" .. math.random(1, 20) .. "|r")
        end
    end)
    
    -- Safety Timeout
    timeOutTimer = C_Timer.NewTimer(3.0, function()
        if isRolling then
            -- Fill in any missing responses with a "?"
            while #rollResults < expectedRolls do
                table.insert(rollResults, "?")
            end
            FinishRoll() 
            print("|cff00ccff[SimpleD20]|r Error: Server took too long to respond.")
        end
    end)
end)

-- 6. Tooltip
d20:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:AddLine("Official D20")
    GameTooltip:AddLine("Left Click: Roll Dice", 1, 1, 1)
    GameTooltip:AddLine("Right Click: Drag", 1, 1, 1)
    GameTooltip:Show()
end)

d20:SetScript("OnLeave", function(self)
    GameTooltip:Hide()
end)

-- 7. Minimap Button
local minimapBtn = CreateFrame("Button", "SimpleD20MinimapButton", Minimap)
minimapBtn:SetSize(32, 32)
minimapBtn:SetFrameStrata("MEDIUM")
minimapBtn:SetFrameLevel(8)
minimapBtn:SetMovable(true)
minimapBtn:RegisterForDrag("RightButton")
minimapBtn:RegisterForClicks("LeftButtonUp")

local minimapIcon = minimapBtn:CreateTexture(nil, "BACKGROUND")
minimapIcon:SetTexture("Interface\\Icons\\INV_Misc_Dice_01")
minimapIcon:SetSize(20, 20)
minimapIcon:SetPoint("CENTER", 0, 0)

local border = minimapBtn:CreateTexture(nil, "OVERLAY")
border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
border:SetSize(54, 54)
border:SetPoint("TOPLEFT", 0, 0)

minimapBtn:SetScript("OnClick", function(self, button)
    if button == "LeftButton" then
        if d20:IsShown() then
            d20:Hide()
        else
            d20:Show()
        end
    end
end)

minimapBtn:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_LEFT")
    GameTooltip:AddLine("SimpleD20")
    GameTooltip:AddLine("Left Click: Toggle Dice Frame", 1, 1, 1)
    GameTooltip:AddLine("Right Click: Drag Icon", 1, 1, 1)
    GameTooltip:Show()
end)

minimapBtn:SetScript("OnLeave", function(self)
    GameTooltip:Hide()
end)

local function UpdateMinimapButtonPosition(angle)
    local radius = 80
    local x = math.cos(angle) * radius
    local y = math.sin(angle) * radius
    minimapBtn:SetPoint("CENTER", Minimap, "CENTER", x, y)
end

minimapBtn:SetScript("OnDragStart", function(self)
    self:LockHighlight()
    self:SetScript("OnUpdate", function(self)
        local mx, my = Minimap:GetCenter()
        local px, py = GetCursorPosition()
        local scale = Minimap:GetEffectiveScale()
        px, py = px / scale, py / scale
        local angle = math.atan2(py - my, px - mx)
        UpdateMinimapButtonPosition(angle)
    end)
end)

minimapBtn:SetScript("OnDragStop", function(self)
    self:UnlockHighlight()
    self:SetScript("OnUpdate", nil)
end)

UpdateMinimapButtonPosition(math.rad(225))

About

Source code for SimpleD20 WoW addon

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors