AltSystem/Roll.lua

175 lines
6.4 KiB
Lua

-- AltSystem Roll Logic
-- Handles /roll 20, captures the result, and applies modifiers.
AltSystem = AltSystem or {}
local pendingRollType = nil -- "attack" or "defense"
-- Get the TRP3 character first name, falling back to the WoW unit name
local function GetCharacterName()
if TRP3_API and TRP3_API.profile and TRP3_API.profile.getData then
local ok, characteristics = pcall(TRP3_API.profile.getData, "player/characteristics")
if ok and characteristics and characteristics.FN and characteristics.FN ~= "" then
return characteristics.FN
end
end
return UnitName("player")
end
-- Build the modifier description string for the announce message
local function BuildModifierString(modifiers)
local parts = {}
for _, mod in ipairs(modifiers) do
local sign = mod.value >= 0 and "+" or ""
table.insert(parts, sign .. mod.value .. " (" .. mod.name .. ")")
end
return table.concat(parts, " ")
end
-- Send a message to the given channel.
-- Note: EMOTE channel uses SendChatMessage like all others. The WoW API
-- SendChatMessage(msg, "EMOTE") sends a proper /e emote from any context,
-- unlike RunMacroText which is a protected function requiring a hardware event.
local function SendToChannel(msg, channel)
SendChatMessage(msg, channel)
end
-- Announce the roll result to the selected chat channel
local function AnnounceRoll(rollValue, modifiers, total)
if not AltSystem.State.announceEnabled then return end
local channelDef = AltSystem.AnnounceChannels[AltSystem.State.announceChannelIndex]
if not channelDef then return end
local name = GetCharacterName()
local modStr = BuildModifierString(modifiers)
local msg
if modStr ~= "" then
msg = name .. " rolled " .. rollValue .. " " .. modStr .. " = " .. total
else
msg = name .. " rolled " .. rollValue .. " = " .. total
end
SendToChannel(msg, channelDef.channel)
end
-- Perform a roll: triggers the WoW native /roll 20 command
function AltSystem:PerformRoll(rollType)
pendingRollType = rollType
RandomRoll(1, 20)
end
-- Listen for the system message that contains the roll result
local rollListener = CreateFrame("Frame")
rollListener:RegisterEvent("CHAT_MSG_SYSTEM")
rollListener:SetScript("OnEvent", function(self, event, message)
if not pendingRollType then return end
-- Match the roll result pattern: "PlayerName rolls X (1-20)"
local roll = message:match("rolls (%d+) %(1%-20%)")
if not roll then return end
local rollValue = tonumber(roll)
local rollType = pendingRollType
pendingRollType = nil
AltSystem:CalculateAndDisplayResult(rollType, rollValue)
end)
-- Calculate the final result based on the roll type and selected modifiers
function AltSystem:CalculateAndDisplayResult(rollType, rollValue)
-- Critical rolls bypass normal calculation
if rollValue == 1 then
if AltSystem.ResultText then
AltSystem.ResultText:SetText("|cffff0000Critical Failure|r")
end
if AltSystem.State.announceEnabled then
local channelDef = AltSystem.AnnounceChannels[AltSystem.State.announceChannelIndex]
if channelDef then
SendToChannel(GetCharacterName() .. " rolled a Critical Failure!", channelDef.channel)
end
end
return
elseif rollValue == 20 then
if AltSystem.ResultText then
AltSystem.ResultText:SetText("|cff00ff00Critical Success|r")
end
if AltSystem.State.announceEnabled then
local channelDef = AltSystem.AnnounceChannels[AltSystem.State.announceChannelIndex]
if channelDef then
SendToChannel(GetCharacterName() .. " rolled a Critical Success!", channelDef.channel)
end
end
return
end
local state = AltSystem.State
local skill = AltSystem.Data.Skills[state.selectedSkillIndex]
local item = AltSystem.Data.Items[state.selectedItemIndex]
local skillMod = skill and skill.modifier or 0
local itemMod = item and item.modifier or 0
local total = rollValue
local breakdown = "Roll: " .. rollValue
local modifiers = {}
local isBaseRoll = skill and skill.name == "Base roll"
if rollType == "attack" then
-- Attack Roll = roll + skill modifier + item modifier
total = rollValue + skillMod + itemMod
if not isBaseRoll then
breakdown = breakdown .. "\nSkill: " .. FormatModifier(skillMod)
table.insert(modifiers, { name = skill and skill.name or "Skill", value = skillMod })
end
if itemMod ~= 0 then
breakdown = breakdown .. " | Item: " .. FormatModifier(itemMod)
table.insert(modifiers, { name = item and item.name or "Item", value = itemMod })
end
breakdown = breakdown .. "\n|cffffd100Attack Total: " .. total .. "|r"
elseif rollType == "defense" then
-- Defense Roll = roll + skill modifier + item modifier + defense modifier + shield modifier
local defense = AltSystem.Data.Defenses[state.selectedDefenseIndex]
local defenseMod = defense and defense.modifier or 0
local shieldMod = state.shieldEnabled and AltSystem.Data.ShieldModifier or 0
total = rollValue + skillMod + itemMod + defenseMod + shieldMod
if not isBaseRoll then
breakdown = breakdown .. "\nSkill: " .. FormatModifier(skillMod)
table.insert(modifiers, { name = skill and skill.name or "Skill", value = skillMod })
end
if itemMod ~= 0 then
breakdown = breakdown .. " | Item: " .. FormatModifier(itemMod)
table.insert(modifiers, { name = item and item.name or "Item", value = itemMod })
end
breakdown = breakdown .. "\nDefense: " .. FormatModifier(defenseMod)
table.insert(modifiers, { name = defense and defense.name or "Defense", value = defenseMod })
if shieldMod ~= 0 then
breakdown = breakdown .. " | Shield: " .. FormatModifier(shieldMod)
table.insert(modifiers, { name = "Shield", value = shieldMod })
end
breakdown = breakdown .. "\n|cff00ccffDefense Total: " .. total .. "|r"
end
if AltSystem.ResultText then
AltSystem.ResultText:SetText(breakdown)
end
AnnounceRoll(rollValue, modifiers, total)
end
-- Format a modifier value with sign
function FormatModifier(value)
if value >= 0 then
return "+" .. value
else
return tostring(value)
end
end