Portrait Michael Malura

WoW Addon Entwicklung - Komplette Referenz

Link zum Projekt: GitHub - WoW Addons

Umfassende deutschsprachige Dokumentation für die World of Warcraft Addon-Entwicklung mit Fokus auf TBC/Classic.


Inhaltsverzeichnis

  1. Erste Schritte
  2. Addon-Struktur & TOC-Datei
  3. Lua Grundlagen
  4. Event-System
  5. Widget API - UI Elemente
  6. Häufige API-Funktionen
  7. Slash-Befehle
  8. SavedVariables - Persistente Daten
  9. XML UI Layout
  10. Secure Templates & Combat Lockdown
  11. TBC Classic Besonderheiten
  12. Ressourcen

Erste Schritte

Was du brauchst

  • Texteditor: VS Code, Notepad++, Sublime Text
  • WoW Client: Classic/TBC installiert
  • Grundkenntnisse: Keine Programmiererfahrung nötig

Addon-Speicherort

World of Warcraft\_classic_\Interface\AddOns\DeinAddonName\

Dein erstes Addon

1. Ordner erstellen: Interface\AddOns\HalloWelt\

2. TOC-Datei erstellen (HalloWelt.toc):

## Interface: 11508
## Title: Hallo Welt
## Notes: Mein erstes Addon!
## Author: DeinName
## Version: 1.0.0

HalloWelt.lua

3. Lua-Datei erstellen (HalloWelt.lua):

local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:SetScript("OnEvent", function(self, event)
    print("Hallo, Welt!")
end)

4. Addon laden: /reload im Spiel eingeben

Entwicklungswerkzeuge

Befehl Beschreibung
/reload UI neu laden
/dump ausdruck Lua-Ausdruck auswerten
/etrace Event-Trace-Fenster
/fstack Frame-Stack-Inspektor

Addon-Struktur & TOC-Datei

Typische Ordnerstruktur

MeinAddon/
├── MeinAddon.toc        # Pflicht: Addon-Manifest
├── MeinAddon.lua        # Haupt-Code-Datei
├── Config.lua           # Einstellungen
├── embeds.xml           # Bibliotheks-Includes
├── libs/                # Externe Bibliotheken
└── Locales/             # Lokalisierung

TOC-Datei Format

## Interface: 11508
## Title: Mein Addon
## Notes: Beschreibung des Addons
## Author: Dein Name
## Version: 1.0.0
## SavedVariables: MeinAddonDB
## SavedVariablesPerCharacter: MeinAddonCharDB
## OptionalDeps: Ace3

embeds.xml
Core.lua
Config.lua

Wichtige TOC-Direktiven

Direktive Beschreibung
Interface Client-Version
Title Anzeigename in der Addon-Liste
Notes Beschreibung als Tooltip
SavedVariables Account-weite gespeicherte Daten
SavedVariablesPerCharacter Pro-Charakter-Daten
Dependencies Benötigte Addons
OptionalDeps Optionale Abhängigkeiten
LoadOnDemand Bei Bedarf laden (1 = ja)

Interface-Versionen

Client Version
Classic Era/Anniversary 11508
TBC Classic 20504
Wrath Classic 30403
Cataclysm Classic 40400

Aktuelle Version prüfen: /dump select(4, GetBuildInfo())


Lua Grundlagen

Variablen

-- Lokale Variable (bevorzugt)
local meinWert = "Hallo"

-- Globale Variable (vermeiden wenn möglich)
MeineGlobaleVar = "Welt"

-- Datentypen
local text = "String"           -- Text
local zahl = 100                -- Zahl
local dezimal = 0.75            -- Dezimalzahl
local aktiv = true              -- Boolean
local nichts = nil              -- Nil (kein Wert)
local tabelle = {1, 2, 3}       -- Array
local dict = {name = "Held"}    -- Dictionary

Operatoren

-- Arithmetik
local a = 10 + 5    -- 15
local b = 10 - 5    -- 5
local c = 10 * 5    -- 50
local d = 10 / 5    -- 2
local e = 10 % 3    -- 1 (Modulo)

-- Vergleich
a == b              -- gleich
a ~= b              -- ungleich (NICHT !=)
a < b               -- kleiner
a > b               -- größer

-- Logisch
true and false      -- false
true or false       -- true
not true            -- false

-- String-Verkettung
"Hallo" .. " " .. "Welt"  -- "Hallo Welt"

Kontrollstrukturen

-- If/Else
local leben = UnitHealth("player")

if leben > 50 then
    print("Alles gut")
elseif leben > 25 then
    print("Vorsicht!")
else
    print("Kritisch!")
end

-- Ternärer Stil (Lua-Idiom)
local status = (leben > 50) and "Gut" or "Schlecht"

Schleifen

-- For-Schleife (numerisch)
for i = 1, 10 do
    print(i)
end

-- For-Schleife (Array)
local items = {"Schwert", "Schild", "Trank"}
for index, item in ipairs(items) do
    print(index, item)
end

-- For-Schleife (Dictionary)
local stats = {staerke = 100, beweglichkeit = 50}
for key, value in pairs(stats) do
    print(key, value)
end

-- While-Schleife
local count = 0
while count < 5 do
    print(count)
    count = count + 1
end

Funktionen

-- Einfache Funktion
local function gruessen(name)
    print("Hallo, " .. name)
end

gruessen("Spieler")

-- Funktion mit Rückgabe
local function addieren(a, b)
    return a + b
end

local summe = addieren(5, 3)  -- 8

-- Mehrere Rückgabewerte
local function getSpielerInfo()
    return "Spielername", 60, "Krieger"
end

local name, level, klasse = getSpielerInfo()

-- Anonyme Funktion
frame:SetScript("OnClick", function(self, button)
    print("Geklickt mit:", button)
end)

Tabellen

-- Array (1-indiziert!)
local items = {"Schwert", "Schild"}
print(items[1])      -- "Schwert"
print(#items)        -- 2 (Länge)

table.insert(items, "Trank")
table.remove(items, 1)

-- Dictionary
local spieler = {
    name = "Held",
    level = 60,
    klasse = "Krieger"
}

print(spieler.name)       -- "Held"
print(spieler["level"])   -- 60

-- Tabelle als Objekt
local MeinAddon = {}

function MeinAddon:Initialisieren()
    self.aktiv = true
end

MeinAddon:Initialisieren()

Event-System

Grundlegendes Event-Handling

-- 1. Frame erstellen
local frame = CreateFrame("Frame")

-- 2. Events registrieren
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_LOGOUT")

-- 3. Event-Handler setzen
frame:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_LOGIN" then
        print("Spieler eingeloggt!")
    elseif event == "PLAYER_LOGOUT" then
        print("Spieler loggt aus!")
    end
end)

Event-Handler Parameter

Parameter Beschreibung
self Der empfangende Frame
event Event-Name (String)
... Event-spezifische Argumente

Event-Registrierung

frame:RegisterEvent("UNIT_HEALTH")
frame:UnregisterEvent("UNIT_HEALTH")
frame:UnregisterAllEvents()

-- Unit-spezifisches Event
frame:RegisterUnitEvent("UNIT_HEALTH", "player", "target")

Wichtige Events

Login/Logout:

Event Beschreibung
PLAYER_LOGIN Spieler vollständig eingeloggt
PLAYER_LOGOUT Spieler loggt aus
PLAYER_ENTERING_WORLD Ladebildschirm beendet
ADDON_LOADED Addon geladen (für SavedVariables)

Kampf:

Event Beschreibung
PLAYER_REGEN_DISABLED Kampf beginnt
PLAYER_REGEN_ENABLED Kampf endet
COMBAT_LOG_EVENT_UNFILTERED Kampflog-Event
PLAYER_DEAD Spieler gestorben

Einheiten:

Event Argumente Beschreibung
UNIT_HEALTH unitId Leben geändert
UNIT_POWER_UPDATE unitId, powerType Kraft geändert
UNIT_AURA unitId Buffs/Debuffs geändert
UNIT_TARGET unitId Ziel geändert

Gruppe:

Event Beschreibung
GROUP_ROSTER_UPDATE Gruppenzusammensetzung geändert
PARTY_MEMBER_ENABLE Gruppenmitglied online

Dispatch-Table-Pattern

local frame = CreateFrame("Frame")
local events = {}

function events:PLAYER_LOGIN()
    print("Eingeloggt!")
end

function events:UNIT_HEALTH(unit)
    if unit == "player" then
        print("Leben:", UnitHealth("player"))
    end
end

frame:SetScript("OnEvent", function(self, event, ...)
    if events[event] then
        events[event](self, ...)
    end
end)

for event in pairs(events) do
    frame:RegisterEvent(event)
end

Widget API - UI Elemente

Frame erstellen

-- CreateFrame(frameType, name, parent, template)
local frame = CreateFrame("Frame", "MeinFrame", UIParent)
frame:SetSize(200, 100)
frame:SetPoint("CENTER")

Häufige Frame-Typen

Typ Beschreibung
Frame Basis-Container
Button Klickbarer Button
CheckButton Checkbox
EditBox Texteingabefeld
ScrollFrame Scrollbarer Bereich
Slider Schieberegler
StatusBar Fortschrittsbalken

Größe und Position

frame:SetSize(200, 100)
frame:SetWidth(200)
frame:SetHeight(100)

-- Ankerpunkte: TOPLEFT, TOP, TOPRIGHT, LEFT, CENTER, RIGHT, BOTTOMLEFT, BOTTOM, BOTTOMRIGHT
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
frame:SetPoint("TOPLEFT", parentFrame, "BOTTOMLEFT", 10, -5)
frame:ClearAllPoints()

Sichtbarkeit

frame:Show()
frame:Hide()
frame:SetShown(true)
local isShown = frame:IsShown()
local isVisible = frame:IsVisible()

Texturen erstellen

-- Einfarbige Textur
local texture = frame:CreateTexture(nil, "BACKGROUND")
texture:SetAllPoints(frame)
texture:SetColorTexture(0, 0, 0, 0.8)  -- RGBA

-- Bild-Textur
local icon = frame:CreateTexture(nil, "ARTWORK")
icon:SetSize(32, 32)
icon:SetPoint("LEFT", 5, 0)
icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")

FontStrings (Text)

local text = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
text:SetPoint("CENTER")
text:SetText("Hallo Welt")
text:SetTextColor(1, 1, 0)  -- Gelb

Buttons

local button = CreateFrame("Button", "MeinButton", UIParent, "UIPanelButtonTemplate")
button:SetSize(100, 25)
button:SetPoint("CENTER")
button:SetText("Klick mich")

button:SetScript("OnClick", function(self, mouseButton, down)
    print("Button geklickt mit:", mouseButton)
end)

StatusBar (Lebensbalken)

local bar = CreateFrame("StatusBar", nil, UIParent)
bar:SetSize(200, 20)
bar:SetPoint("CENTER")
bar:SetMinMaxValues(0, 100)
bar:SetValue(75)
bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
bar:SetStatusBarColor(0, 1, 0)  -- Grün

Script-Handler

frame:SetScript("OnLoad", function(self) end)
frame:SetScript("OnShow", function(self) end)
frame:SetScript("OnHide", function(self) end)
frame:SetScript("OnUpdate", function(self, elapsed) end)
frame:SetScript("OnEvent", function(self, event, ...) end)
frame:SetScript("OnEnter", function(self) end)
frame:SetScript("OnLeave", function(self) end)
frame:SetScript("OnMouseDown", function(self, button) end)
frame:SetScript("OnMouseUp", function(self, button) end)

Häufige API-Funktionen

Unit IDs

UnitId Beschreibung
player Der Spieler
target Aktuelles Ziel
focus Fokus-Ziel
pet Begleiter
party1-party4 Gruppenmitglieder
raid1-raid40 Schlachtzugmitglieder
mouseover Einheit unter Mauszeiger
targettarget Ziel des Ziels

Unit-Funktionen

-- Grundinfos
local name = UnitName("target")
local level = UnitLevel("target")
local class, classFile = UnitClass("target")  -- "Krieger", "WARRIOR"
local race = UnitRace("target")
local guid = UnitGUID("target")

-- Klassifikation
local classification = UnitClassification("target")
-- "normal", "elite", "rareelite", "rare", "worldboss"

-- Fraktion
local faction = UnitFactionGroup("target")  -- "Horde", "Alliance"
local isEnemy = UnitIsEnemy("player", "target")
local isFriend = UnitIsFriend("player", "target")

-- Existenz prüfen
local exists = UnitExists("target")
local isPlayer = UnitIsPlayer("target")
local isSameUnit = UnitIsUnit("player", "target")

Leben und Kraft

-- Leben
local health = UnitHealth("player")
local maxHealth = UnitHealthMax("player")
local healthPercent = (health / maxHealth) * 100

-- Kraft (Mana, Wut, Energie)
local power = UnitPower("player")
local maxPower = UnitPowerMax("player")
local powerType = UnitPowerType("player")
-- 0=Mana, 1=Wut, 2=Fokus, 3=Energie

-- Tot?
local isDead = UnitIsDead("target")
local isGhost = UnitIsGhost("player")

Buff/Debuff-Funktionen

-- Buff nach Name
local name, icon, count, debuffType, duration, expirationTime =
    UnitAura("player", "Segen der Macht", "HELPFUL")

-- Alle Buffs durchlaufen
for i = 1, 40 do
    local name, _, _, _, _, _, source, _, _, spellId =
        UnitAura("player", i, "HELPFUL")
    if not name then break end
    print(i, name, spellId)
end

-- Alle Debuffs durchlaufen
for i = 1, 40 do
    local name = UnitAura("player", i, "HARMFUL")
    if not name then break end
    print(i, name)
end

Zauber-Funktionen

local name, rank, icon, castTime, minRange, maxRange = GetSpellInfo(spellId)

local start, duration, enabled = GetSpellCooldown(spellId)
local remaining = (start + duration) - GetTime()

local isKnown = IsSpellKnown(spellId)

Item-Funktionen

local name, link, quality, ilvl, reqLevel, class, subclass,
      maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemId)

local count = GetItemCount(itemId)
local countMitBank = GetItemCount(itemId, true)

Chat-Funktionen

SendChatMessage("Hallo!", "SAY")
SendChatMessage("Gruppennachricht", "PARTY")
SendChatMessage("Schlachtzugnachricht", "RAID")
SendChatMessage("Flüstern", "WHISPER", nil, "Spielername")
SendChatMessage("Gildennachricht", "GUILD")

print("Nachricht")
DEFAULT_CHAT_FRAME:AddMessage("Rote Nachricht", 1, 0, 0)

Zeit-Funktionen

local time = GetTime()  -- Sekunden, hohe Präzision
local hours, minutes = GetGameTime()  -- Serverzeit
local formatted = date("%Y-%m-%d %H:%M:%S")

Gruppen-Funktionen

local numMembers = GetNumGroupMembers()
local inRaid = IsInRaid()
local inGroup = IsInGroup()

local name, rank, subgroup, level, class, fileName, zone,
      online, isDead, role, isML = GetRaidRosterInfo(i)

Slash-Befehle

Einfacher Slash-Befehl

SLASH_MEINADDON1 = "/meinaddon"
SLASH_MEINADDON2 = "/ma"

SlashCmdList["MEINADDON"] = function(msg, editBox)
    print("Befehl empfangen:", msg)
end

Argumente parsen

SLASH_MEINADDON1 = "/meinaddon"

SlashCmdList["MEINADDON"]