From 150e52842eaea55cd087c346fe0b702b06f53829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Correia?= Date: Sat, 11 Apr 2026 16:05:04 +0100 Subject: [PATCH] First working version --- .idea/.gitignore | 10 +++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 ++ AltSystem.iml | 11 +++ AltSystem.toc | 12 +++ Core.lua | 97 ++++++++++++++++++++++ Data.lua | 44 ++++++++++ README.md | 13 +++ Roll.lua | 85 ++++++++++++++++++++ UI.lua | 190 ++++++++++++++++++++++++++++++++++++++++++++ docs/1-interface.md | 38 +++++++++ docs/2-skills.md | 1 + 12 files changed, 515 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 AltSystem.iml create mode 100644 AltSystem.toc create mode 100644 Core.lua create mode 100644 Data.lua create mode 100644 README.md create mode 100644 Roll.lua create mode 100644 UI.lua create mode 100644 docs/1-interface.md create mode 100644 docs/2-skills.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4b151ab --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2aaa495 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/AltSystem.iml b/AltSystem.iml new file mode 100644 index 0000000..0495363 --- /dev/null +++ b/AltSystem.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/AltSystem.toc b/AltSystem.toc new file mode 100644 index 0000000..57c8602 --- /dev/null +++ b/AltSystem.toc @@ -0,0 +1,12 @@ +## Interface: 120001 +## Title: AltSystem +## Notes: Enhances RP gameplay with a custom rolling system +## Author: Goncalo +## Version: 1.0.0 +## Dependencies: totalRP3, totalRP3_Extended +## SavedVariables: AltSystemDB + +Data.lua +Core.lua +UI.lua +Roll.lua diff --git a/Core.lua b/Core.lua new file mode 100644 index 0000000..a2118e3 --- /dev/null +++ b/Core.lua @@ -0,0 +1,97 @@ +-- AltSystem Core +-- Addon initialization, slash command registration, and TRP3 integration. + +AltSystem = AltSystem or {} +AltSystem.State = { + selectedSkillIndex = 1, + selectedItemIndex = 1, -- 1 = No item + selectedDefenseIndex = 1, -- 1 = Base armor + shieldEnabled = false, +} + +-- Initialization on ADDON_LOADED +local frame = CreateFrame("Frame") +frame:RegisterEvent("ADDON_LOADED") +frame:RegisterEvent("PLAYER_LOGIN") + +frame:SetScript("OnEvent", function(self, event, arg1) + if event == "ADDON_LOADED" and arg1 == "AltSystem" then + AltSystem:Init() + elseif event == "PLAYER_LOGIN" then + AltSystem:RegisterTRP3Button() + AltSystem:RegisterMinimapButton() + end +end) + +function AltSystem:Init() + -- Register slash command /altsystem + SLASH_ALTSYSTEM1 = "/altsystem" + SlashCmdList["ALTSYSTEM"] = function() + AltSystem:ToggleWindow() + end + + print("|cff00ccffAltSystem|r loaded. Type /altsystem to open.") +end + +function AltSystem:ToggleWindow() + if AltSystem.MainFrame then + if AltSystem.MainFrame:IsShown() then + AltSystem.MainFrame:Hide() + else + AltSystem.MainFrame:Show() + end + end +end + +-- TRP3 toolbar button registration +function AltSystem:RegisterTRP3Button() + if TRP3_API and TRP3_API.toolbar then + local toolbarButton = { + id = "altsystem_toolbar_btn", + icon = "Interface\\Icons\\INV_Misc_Dice_02", + tooltip = "AltSystem", + tooltipSub = "Open the AltSystem rolling window", + onClick = function() + AltSystem:ToggleWindow() + end, + } + TRP3_API.toolbar.toolbarAddButton(toolbarButton) + end +end + +-- Minimap button using LibDBIcon (lightweight fallback if not available) +function AltSystem:RegisterMinimapButton() + -- Simple minimap button without external libraries + local minimapButton = CreateFrame("Button", "AltSystemMinimapButton", Minimap) + minimapButton:SetSize(32, 32) + minimapButton:SetFrameStrata("MEDIUM") + minimapButton:SetFrameLevel(8) + minimapButton:SetPoint("TOPLEFT", Minimap, "TOPLEFT", 2, -2) + + local icon = minimapButton:CreateTexture(nil, "ARTWORK") + icon:SetTexture("Interface\\Icons\\INV_Misc_Dice_02") + icon:SetSize(20, 20) + icon:SetPoint("CENTER") + + local border = minimapButton:CreateTexture(nil, "OVERLAY") + border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder") + border:SetSize(54, 54) + border:SetPoint("TOPLEFT", -2, 2) + + minimapButton:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") + + minimapButton:SetScript("OnClick", function() + AltSystem:ToggleWindow() + end) + + minimapButton:SetScript("OnEnter", function(self) + GameTooltip:SetOwner(self, "ANCHOR_LEFT") + GameTooltip:AddLine("AltSystem") + GameTooltip:AddLine("Click to toggle the rolling window", 1, 1, 1) + GameTooltip:Show() + end) + + minimapButton:SetScript("OnLeave", function() + GameTooltip:Hide() + end) +end diff --git a/Data.lua b/Data.lua new file mode 100644 index 0000000..ab7984a --- /dev/null +++ b/Data.lua @@ -0,0 +1,44 @@ +-- AltSystem Data Definitions +-- Contains dummy skill data, item options, defense options, and modifier constants. + +AltSystem = AltSystem or {} +AltSystem.Data = {} + +-- Skill levels and their modifiers +AltSystem.Data.SkillLevels = { + ["Novice"] = -2, + ["Adept"] = 0, + ["Expert"] = 2, + ["Master"] = 4, +} + +-- Dummy skill data: each skill has a name, icon, and level +AltSystem.Data.Skills = { + { name = "Swordsmanship", icon = "Interface\\Icons\\INV_Sword_04", level = "Expert" }, + { name = "Archery", icon = "Interface\\Icons\\INV_Weapon_Bow_05", level = "Adept" }, + { name = "Fire Magic", icon = "Interface\\Icons\\Spell_Fire_FlameBolt", level = "Master" }, + { name = "Healing", icon = "Interface\\Icons\\Spell_Holy_FlashHeal", level = "Novice" }, + { name = "Stealth", icon = "Interface\\Icons\\Ability_Stealth", level = "Adept" }, +} + +-- Pre-compute modifier for each skill based on its level +for _, skill in ipairs(AltSystem.Data.Skills) do + skill.modifier = AltSystem.Data.SkillLevels[skill.level] or 0 +end + +-- Item options: name and modifier (first entry = no item) +AltSystem.Data.Items = { + { name = "No item", modifier = 0 }, + { name = "Rare item", modifier = 3 }, + { name = "Epic item", modifier = 5 }, +} + +-- Defense options: name and modifier +AltSystem.Data.Defenses = { + { name = "Base armor", modifier = 0 }, + { name = "Extra small armor", modifier = 1 }, + { name = "Extra large armor", modifier = 2 }, +} + +-- Shield modifier +AltSystem.Data.ShieldModifier = 1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..35b32f7 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# AltSystem +This project is a WoW Addon, designed to enhance RP gameplay while using a specific rolling system. +The rolling system relies on TRP3 and TRP3:Enhanced addons, so these are explicit dependencies. + +## Features +- Main features defined in the /docs folder + +## Installation +To use AltSystem, ensure you have the following addons installed: +- TRP3 +- TRP3:Enhanced + +Follow the installation instructions for these addons before installing AltSystem. \ No newline at end of file diff --git a/Roll.lua b/Roll.lua new file mode 100644 index 0000000..28f3752 --- /dev/null +++ b/Roll.lua @@ -0,0 +1,85 @@ +-- AltSystem Roll Logic +-- Handles /roll 20, captures the result, and applies modifiers. + +AltSystem = AltSystem or {} + +local pendingRollType = nil -- "attack" or "defense" + +-- 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) + 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 + + if rollType == "attack" then + -- Attack Roll = roll + skill modifier + item modifier + total = rollValue + skillMod + itemMod + + breakdown = breakdown .. "\nSkill: " .. FormatModifier(skillMod) + if itemMod ~= 0 then + breakdown = breakdown .. " | Item: " .. FormatModifier(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 + + breakdown = breakdown .. "\nSkill: " .. FormatModifier(skillMod) + if itemMod ~= 0 then + breakdown = breakdown .. " | Item: " .. FormatModifier(itemMod) + end + breakdown = breakdown .. "\nDefense: " .. FormatModifier(defenseMod) + if shieldMod ~= 0 then + breakdown = breakdown .. " | Shield: " .. FormatModifier(shieldMod) + end + breakdown = breakdown .. "\n|cff00ccffDefense Total: " .. total .. "|r" + end + + if AltSystem.ResultText then + AltSystem.ResultText:SetText(breakdown) + end +end + +-- Format a modifier value with sign +function FormatModifier(value) + if value >= 0 then + return "+" .. value + else + return tostring(value) + end +end diff --git a/UI.lua b/UI.lua new file mode 100644 index 0000000..c5c4a69 --- /dev/null +++ b/UI.lua @@ -0,0 +1,190 @@ +-- AltSystem UI +-- Creates the main dialog window with all interface elements. +-- Uses the modern DropdownButton API (WoW 10.2.5+ / 12.0+). + +AltSystem = AltSystem or {} + +local WINDOW_WIDTH = 300 +local WINDOW_HEIGHT = 380 +local PADDING = 12 +local ROW_HEIGHT = 30 +local LABEL_WIDTH = 80 + +-- Helper: Create a modern dropdown (WowStyle1DropdownTemplate) +local function CreateDropdown(parent, name, yOffset, labelText, options, defaultIndex, onSelect) + local label = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal") + label:SetPoint("TOPLEFT", parent, "TOPLEFT", PADDING, yOffset) + label:SetText(labelText) + label:SetWidth(LABEL_WIDTH) + label:SetJustifyH("LEFT") + + local selectedIndex = defaultIndex or 1 + + local dropdown = CreateFrame("DropdownButton", name, parent, "WowStyle1DropdownTemplate") + dropdown:SetPoint("LEFT", label, "RIGHT", 4, 0) + dropdown:SetWidth(160) + + dropdown:SetupMenu(function(dropdown, rootDescription) + for i, option in ipairs(options) do + rootDescription:CreateRadio( + option.text, + function(data) return data == selectedIndex end, + function(data) + selectedIndex = data + if onSelect then onSelect(data, options[data]) end + end, + i + ) + end + end) + + return dropdown +end + +function AltSystem:CreateMainFrame() + if AltSystem.MainFrame then return end + + -- Main frame + local f = CreateFrame("Frame", "AltSystemMainFrame", UIParent, "BasicFrameTemplateWithInset") + f:SetSize(WINDOW_WIDTH, WINDOW_HEIGHT) + f:SetPoint("CENTER") + f:SetMovable(true) + f:EnableMouse(true) + f:RegisterForDrag("LeftButton") + f:SetScript("OnDragStart", f.StartMoving) + f:SetScript("OnDragStop", f.StopMovingOrSizing) + f:SetClampedToScreen(true) + + f.TitleBg:SetHeight(30) + f.title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + f.title:SetPoint("TOPLEFT", f.TitleBg, "TOPLEFT", 5, -3) + f.title:SetText("AltSystem") + + -- Track current Y offset for layout + local yPos = -40 + + ------------------------- + -- Skill dropdown + ------------------------- + local skillOptions = {} + for _, skill in ipairs(AltSystem.Data.Skills) do + local levelMod = skill.modifier + local sign = levelMod >= 0 and "+" or "" + table.insert(skillOptions, { + text = skill.name .. " (" .. skill.level .. " " .. sign .. levelMod .. ")", + icon = skill.icon, + }) + end + + CreateDropdown(f, "AltSystemSkillDropdown", yPos, "Skill:", skillOptions, AltSystem.State.selectedSkillIndex, + function(index) + AltSystem.State.selectedSkillIndex = index + end) + yPos = yPos - ROW_HEIGHT - 8 + + ------------------------- + -- Item dropdown + ------------------------- + local itemOptions = {} + for _, item in ipairs(AltSystem.Data.Items) do + local sign = item.modifier >= 0 and "+" or "" + local modText = item.modifier ~= 0 and (" (" .. sign .. item.modifier .. ")") or "" + table.insert(itemOptions, { + text = item.name .. modText, + }) + end + + CreateDropdown(f, "AltSystemItemDropdown", yPos, "Item:", itemOptions, AltSystem.State.selectedItemIndex, + function(index) + AltSystem.State.selectedItemIndex = index + end) + yPos = yPos - ROW_HEIGHT - 8 + + ------------------------- + -- Defense dropdown + ------------------------- + local defenseOptions = {} + for _, def in ipairs(AltSystem.Data.Defenses) do + local sign = def.modifier >= 0 and "+" or "" + local modText = " (" .. sign .. def.modifier .. ")" + table.insert(defenseOptions, { + text = def.name .. modText, + }) + end + + CreateDropdown(f, "AltSystemDefenseDropdown", yPos, "Defense:", defenseOptions, AltSystem.State.selectedDefenseIndex, + function(index) + AltSystem.State.selectedDefenseIndex = index + end) + yPos = yPos - ROW_HEIGHT - 8 + + ------------------------- + -- Shield checkbox + ------------------------- + local shieldLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal") + shieldLabel:SetPoint("TOPLEFT", f, "TOPLEFT", PADDING, yPos) + shieldLabel:SetText("Shield:") + shieldLabel:SetWidth(LABEL_WIDTH) + shieldLabel:SetJustifyH("LEFT") + + local shieldCheck = CreateFrame("CheckButton", "AltSystemShieldCheck", f, "UICheckButtonTemplate") + shieldCheck:SetPoint("LEFT", shieldLabel, "RIGHT", -6, 0) + shieldCheck:SetChecked(AltSystem.State.shieldEnabled) + + local shieldText = shieldCheck:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + shieldText:SetPoint("LEFT", shieldCheck, "RIGHT", 2, 0) + shieldText:SetText("+1 modifier") + + shieldCheck:SetScript("OnClick", function(self) + AltSystem.State.shieldEnabled = self:GetChecked() + end) + + yPos = yPos - ROW_HEIGHT - 12 + + ------------------------- + -- Roll buttons + ------------------------- + local btnWidth = (WINDOW_WIDTH - PADDING * 3) / 2 + + local attackBtn = CreateFrame("Button", "AltSystemAttackRollBtn", f, "UIPanelButtonTemplate") + attackBtn:SetSize(btnWidth, 28) + attackBtn:SetPoint("TOPLEFT", f, "TOPLEFT", PADDING, yPos) + attackBtn:SetText("Attack Roll") + + local defenseBtn = CreateFrame("Button", "AltSystemDefenseRollBtn", f, "UIPanelButtonTemplate") + defenseBtn:SetSize(btnWidth, 28) + defenseBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -PADDING, yPos) + defenseBtn:SetText("Defense Roll") + + yPos = yPos - 40 + + ------------------------- + -- Roll result area + ------------------------- + local resultBg = CreateFrame("Frame", nil, f, "InsetFrameTemplate") + resultBg:SetPoint("TOPLEFT", f, "TOPLEFT", PADDING, yPos) + resultBg:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -PADDING, PADDING) + + local resultText = resultBg:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + resultText:SetPoint("CENTER") + resultText:SetText("Roll result will appear here") + resultText:SetJustifyH("CENTER") + resultText:SetWidth(resultBg:GetWidth() - 10) + + AltSystem.ResultText = resultText + + -- Button click handlers + attackBtn:SetScript("OnClick", function() + AltSystem:PerformRoll("attack") + end) + + defenseBtn:SetScript("OnClick", function() + AltSystem:PerformRoll("defense") + end) + + f:Hide() + AltSystem.MainFrame = f +end + +-- Create the frame on file load so it's ready when Init runs +AltSystem:CreateMainFrame() diff --git a/docs/1-interface.md b/docs/1-interface.md new file mode 100644 index 0000000..d6a4f75 --- /dev/null +++ b/docs/1-interface.md @@ -0,0 +1,38 @@ +# Feature: Interface +- The addon's main interface is a simple dialog window. +- This window can be shown/hidden via: + - A slash command `/altsystem` + - A button inside the TRP toolbar + - A button in the minimap menu + +## Window features +### Skill dropdown +- A small dropdown menu to select the skill to be used. (use dummy data for now) +- 1 skill per line +- Each skill has a name, an icon, a level (Novice, Adept, Expert, Master), and a corresponding modifier + - Novice: -2 + - Adept: +0 + - Expert: +2 + - Master: +4 +### Item dropdown +- A small dropdown menu to select if an item should be used or not. +- Default to no item selected +- Static data for available selections: + - Rare item (+3 modifier) + - Epic item (+5 modifier) +### Defense dropdown +- A small dropdown menu to select the defense to be used. +- Static data for available selections: + - Base armor (+0) + - Extra small armor (+1) + - Extra large armor (+2) +- Default to Base armor +### Shield checkbox +- A checkbox to select if a shield (+1) should be used or not. +- Default to unchecked +### Roll buttons +- Two buttons, each will perform the WoW native `/roll 20` command when clicked +### Roll result +- A small area, to show the result of the rolls based on which button was clicked +- The 'Attack Roll' button will show the sum of the roll, plus any skill and item modifiers +- The 'Defense Roll' button will show the sum of the roll, plus any skill, item, defense, and shield modifier \ No newline at end of file diff --git a/docs/2-skills.md b/docs/2-skills.md new file mode 100644 index 0000000..9eae222 --- /dev/null +++ b/docs/2-skills.md @@ -0,0 +1 @@ +# Feature: Skills \ No newline at end of file