commit 150e52842eaea55cd087c346fe0b702b06f53829 Author: Gonçalo Correia Date: Sat Apr 11 16:05:04 2026 +0100 First working version 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