Modèles de code d’addon WoW Forever à coller
Copiez ces modèles pour l’interface 16001 : hello world, SavedVariables, barre sécurisée contre les secrets, Addon Compartment et verrouillage du combat. Ils suivent la documentation Mainline du Warcraft Wiki, donc vérifiez chacun sur votre build bêta.
Posez vos questions sur les modèles de code d’addon à notre IA de tryhardeur dégénéré
Hello World, SavedVariables, barres sûres pour les secrets, compartiment d’addon et plus
Tout ce que couvrent nos guides. Les réponses proviennent de cette page et du reste de nos guides, avec les vraies valeurs en graphique et les sections de guide liées. C’est une IA : vérifiez la source avant de la citer.
Chaque bloc est un pattern complet pour l’interface 16001. Le nom du dossier et celui du fichier TOC doivent correspondre.
- Interface TOC
- 16001
- SavedVariables
- Bug signalé comme corrigé
- Addon compartment
- Non testé ici
- Verrouillage du combat
- File d’attente jusqu’à la régénération
Cette bibliothèque fait partie du guide du développeur d’addons WoW Forever. Pour la conception côté client derrière ces extraits, voir les patterns d’addons WoW Forever. Pour vérifier chaque signature, utilisez l’aide-mémoire de l’API Forever. Pour un addon fini et téléchargeable qui relie notes, sonde, compartment et barre sécurisée contre les secrets, consultez l’addon de référence Forever Beacon.
Ce site n’a exécuté aucun de ces modèles dans un client Forever. Ils suivent la documentation Mainline du Warcraft Wiki, les rapports de la bêta cités et le code client de Blizzard conservé de la build 70338. La sonde d’ID de projet distincte a été exécutée en jeu ; cela ne signifie pas que ces exemples ont été testés en jeu.
Les ajouts du 13 octobre citent l’extrait client conservé 70338. Les miroirs de sources liés peuvent afficher une build plus récente.
Fonctions avec plusieurs commandes
Une fonction Lua peut contenir plusieurs instructions. Placez chaque opération sur sa propre ligne entre function et end ; elles s’exécutent dans l’ordre lorsque vous appelez la fonction. Cet exemple affiche un message local et joue un son d’interface :
local function AnnounceReady()
print("[Forever Notes] Ready.")
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
end
AnnounceReady()Vous n’avez pas besoin de plusieurs définitions de fonction ni de points-virgules. Un return anticipé termine la fonction, et une erreur non interceptée arrête les instructions restantes.Source : Lua 5,1 Reference Manual, function definitions and blocks et error handling, vérifiés le 13 oct. 2026. Les instructions Lua diffèrent des commandes slash de macros telles que /cast. Ces exemples affichent du texte et jouent un son ; ils ne réalisent pas d’actions de combat protégées.
Dans la discussion, le diagnostic équivalent est /run print("Ready."); PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON). Gardez le code réutilisable dans un fichier Lua répertorié dans votre TOC. L’aide-mémoire des ID de sons liste les constantes utilisées ici.
Commande de message et alias de commandes slash
Pour un message visible uniquement par vous, utilisez print("Hello.") ou DEFAULT_CHAT_FRAME:AddMessage("Hello.", 1, 0.82, 0). Dans la discussion, tapez /run print("Hello."). L’affichage est local ; cela n’envoie ni message de groupe ni chuchotement.
Pour définir une fonction avec plusieurs commandes slash, donnez à la même clé SlashCmdList des alias numérotés. Cet exemple complet à deux fichiers fait afficher le texte fourni localement par /wfgmessage Hello et /wfgmsg Hello :
## Interface: 16001
## Title: WFG Message Example
## Notes: Two slash commands for one local message handler.
## Version: 0.1.0
WFGMessageExample.lualocal function ShowLocalMessage(text)
if not text:find("%S") then
print("Usage: /wfgmessage Hello")
return
end
DEFAULT_CHAT_FRAME:AddMessage("[WFG Message] " .. text, 1, 0.82, 0)
end
SLASH_WFGMESSAGEEXAMPLE1 = "/wfgmessage"
SLASH_WFGMESSAGEEXAMPLE2 = "/wfgmsg"
SlashCmdList["WFGMESSAGEEXAMPLE"] = ShowLocalMessageUtilisez le nom de dossier WFGMessageExample, puis redémarrez le client lors de l’ajout. La clé d’enregistrement en majuscules doit correspondre aux deux variables globales SLASH_. Enregistrez les alias au chargement du fichier, pas à chaque exécution du gestionnaire. Le registre de commandes slash de Blizzard utilise ce même modèle de variables globales numérotées.Source : registre de commandes slash de Blizzard, build du client conservée 70338, inspectée le 13 oct. 2026.
Si "message command" désigne l’envoi de messages à d’autres personnes, c’est une opération distincte : C_ChatInfo.SendChatMessage("Hello.", "PARTY") envoie un message de groupe lorsque le client l’autorise. Appelez-la uniquement à la suite d’une action délibérée du joueur et vérifiez les restrictions actuelles de discussion. La documentation générée marque cette API HasRestrictions ; cette page n’affirme pas que l’envoi automatisé arbitraire est autorisé.Source : documentation ChatInfo de Blizzard, SendChatMessage, build du client conservée 70338, inspectée le 13 oct. 2026.
Afficher un message dans une fenêtre
Enregistrez une entrée propre à l’addon dans StaticPopupDialogs, puis appelez StaticPopup_Show avec cette clé. Cet exemple affiche un message d’information fixe avec un bouton OK et une fermeture par Échap. Placez-le dans un fichier Lua chargé par votre TOC :
StaticPopupDialogs["WFG_EXAMPLE_READY_MESSAGE"] = {
text = "Forever Notes is ready.",
button1 = OKAY,
timeout = 0,
whileDead = true,
hideOnEscape = true,
}
SLASH_WFGPOPUPEXAMPLE1 = "/wfgpopup"
SlashCmdList["WFGPOPUPEXAMPLE"] = function()
StaticPopup_Show("WFG_EXAMPLE_READY_MESSAGE")
endAprès avoir chargé l’addon, tapez /wfgpopup. Le message reste affiché jusqu’à sa fermeture car timeout = 0. Utilisez votre propre clé, gardez intactes les définitions de fenêtres de Blizzard et demandez délibérément l’ouverture plutôt que de la répéter dans une boucle de mise à jour. Cet exemple n’a pas été exécuté dans le client Forever.Source : implémentation StaticPopup de Blizzard, StaticPopup_Show, timeout, whileDead et hideOnEscape, build du client conservée 70338, inspectée le 13 oct. 2026.
Hello
Le plus petit addon possible : il affiche un message à la connexion et ne touche jamais un nom qui pourrait être secret.
## Interface: 16001
## Title: Hello Forever
## Notes: Prints once on login, without touching a secret name.
## Author: YourName
## Version: 0.1.0
## Category: Miscellaneous
HelloForever.lualocal addonName = ...
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", function()
print("|cffd4a85a[" .. addonName .. "]|r Forever client accepted this addon.")
end)
frame:RegisterEvent("PLAYER_LOGIN")SavedVariables
Déclarez la table dans le TOC : ## SavedVariables: BeaconNotesDB. Le nom est une globale, car le client la remplit après l’exécution de vos fichiers. Ne la touchez que dans ADDON_LOADED, et fusionnez les clés par défaut pour ne jamais écraser les paramètres d’un joueur.
local addonName, ns = ...
local defaults = { scale = 1, locked = false }
local events = {}
function events:ADDON_LOADED(loaded)
if loaded ~= addonName then return end
BeaconNotesDB = BeaconNotesDB or {}
local db = BeaconNotesDB
for key, value in pairs(defaults) do
if db[key] == nil then db[key] = value end
end
ns.db = db
end
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", function(self, event, ...)
if events[event] then events[event](self, ...) end
end)
frame:RegisterEvent("ADDON_LOADED")Ne définissez pas BeaconNotesDB = BeaconNotesDB or {} au niveau du fichier. C’est le piège 08 des pièges courants des addons écrits par IA.
Barre sécurisée contre les secrets
Sur la build 69913, UnitHealth("player") est revenu sous forme de nombre secret. Les règles Midnight du Warcraft Wiki disent que UnitHealthMax peut aussi être secret. Vous ne pouvez pas en calculer un pourcentage en Lua, mais un StatusBar les accepte directement.
local bar = CreateFrame("StatusBar", nil, UIParent)
bar:SetSize(200, 14)
bar:SetPoint("CENTER", 0, -40)
bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
bar:SetStatusBarColor(0.55, 0.12, 0.12)
local function Paint()
-- Both values may be secret. The bar may have them. Lua may not do math on them.
bar:SetMinMaxValues(0, UnitHealthMax("player"))
bar:SetValue(UnitHealth("player"))
end
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", Paint)
frame:RegisterUnitEvent("UNIT_HEALTH", "player")
frame:RegisterUnitEvent("UNIT_MAXHEALTH", "player")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")Addon Compartment
L’Addon Compartment de la minicarte n’a pas besoin de LibDataBroker : le TOC nomme des fonctions globales et le client les appelle. Le Warcraft Wiki documente ces champs pour Mainline. Ce site ne les a pas testés sur un client Forever, vérifiez donc que l’entrée apparaît.
## Interface: 16001
## Title: Compartment Stub
## Notes: Minimap compartment without LibDataBroker.
## IconTexture: Interface\Icons\INV_Misc_Note_01
## AddonCompartmentFunc: CompartmentStub_OnClick
## AddonCompartmentFuncOnEnter: CompartmentStub_OnEnter
## AddonCompartmentFuncOnLeave: CompartmentStub_OnLeave
CompartmentStub.luafunction CompartmentStub_OnClick()
print("|cffd4a85a[Stub]|r compartment click")
end
function CompartmentStub_OnEnter(_, owner)
GameTooltip:SetOwner(owner, "ANCHOR_LEFT")
GameTooltip:SetText("Compartment Stub", 1, 0.82, 0.45)
GameTooltip:Show()
end
function CompartmentStub_OnLeave()
GameTooltip:Hide()
endFile d’attente du verrouillage du combat
En combat, tant que InCombatLockdown() est vrai, les addons ne peuvent ni afficher, ni masquer, ni déplacer les cadres protégés, ni changer leurs attributs. Mettez ces changements en file d’attente et exécutez-les quand PLAYER_REGEN_ENABLED se déclenche.
local pending = {}
local function Queue(fn)
if InCombatLockdown() then
pending[#pending + 1] = fn
else
fn()
end
end
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:SetScript("OnEvent", function()
for i = 1, #pending do pending[i]() end
wipe(pending)
end)
-- Use Queue only for protected frames.
-- Your own unprotected frames may Show() during combat.Pour des prompts qui produisent du code sous cette forme, voir les prompts IA prêts à l’emploi.
Écrire pour Forever ; comparer la constante nommée d’ID de projet
WOW_PROJECT_IDvalait 18 dans la sonde en direct conservée sur la build bêta Forever 1.60.1.70338, le 12 octobre 2026. Le code source de Blizzard nomme cette valeur WOW_PROJECT_CAMELOT. WOW_PROJECT_MAINLINE valait 1 et WOW_PROJECT_CLASSIC valait 2 ; la branche habituelle if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE était donc fausse sur cette build. L’ancien rapport communautaire de 1 concerne la build 69913 ; conservez son numéro de build au lieu de le traiter comme la constante actuelle.Source : constantes de projet Camelot de Blizzard, fichiers du client 70338 conservés, inspectés le 13 oct. 2026. Constantes mesurées dans le client bêta 1.60.1.70338 le 12 oct. 2026.
Un addon qui ne tourne que sur Forever n’a rien à brancher. Écrivez la version Forever et dites-le en commentaire, pour que le prochain lecteur ne cherche pas la branche.
-- Build 70338 recorded WOW_PROJECT_ID 18, named WOW_PROJECT_CAMELOT.
-- WOW_PROJECT_MAINLINE was 1 and WOW_PROJECT_CLASSIC was 2, so an
-- "is this Retail" or "is this Classic" branch was false; retest.
-- A Forever-only add-on writes for Forever directly.
local FOREVER_PROJECT_ID = WOW_PROJECT_CAMELOTL’ancien exemple du wiki nomme une branche "camelot/forever" parce que Forever est un type de jeu au sein de la famille Mainline. Cette architecture commune ne détermine pas son ID de projet. La déclaration de Blizzard sur le Discord WoW UI, citée par Wowhead, décrit Forever et Midnight comme "two game types within the Mainline code family." (« deux types de jeu au sein de la famille de code Mainline »). La même déclaration nomme le type de Forever "Camelot (to be renamed before launch)" (« Camelot, qui sera renommé avant le lancement ») et indique que Forever partage "the vast majority of APIs available in 12.1.5," (« la grande majorité des API disponibles dans cette version »), ce qui explique pourquoi les pages Mainline du wiki ci-dessous s’appliquent.Source : WoW: Forever Will Have Addon Changes from Midnight, vérifié le 28 sept. 2026.
Pour les addons communs à plusieurs clients, comparez WOW_PROJECT_ID à WOW_PROJECT_CAMELOT lorsque cette constante existe, puis vérifiez l’API de la fonctionnalité. Un addon réservé à Forever peut cibler Forever directement. Vous pouvez aussi séparer les fichiers via le TOC. Pour les règles actuelles, le statut Hardcore ou le préréglage d’expérience Classic/Modern, utilisez la référence GameRules ; un ID de client ne répond pas à ces questions.
<details><summary>Notes techniques : constantes d’extension</summary>
L’exemple du wiki conservé imbrique LE_EXPANSION_LEVEL_CURRENT et LE_EXPANSION_CLASSIC dans sa branche d’ID de projet Mainline. Cette branche est fausse sur le client Forever 70338 capturé. Le client de l’ère Midnight est un autre type de jeu de la famille Mainline ; ne déduisez pas son ID de projet de ce lien.
</details>
Séparer les fichiers avec des variables TOC
Les variables TOC [Family] et [Game] sont résolues au chargement : un seul AddonName.toc peut donc pointer vers des fichiers différents selon le client, sans aucune branche Lua.
## Interface: 16001
## Title: Split Example
[Family]\File.lua
[Game]\File.lua[Family]devient Mainline ou Classic. [Game] devient Camelot sur un client Forever. Les autres types de jeu listés sont Standard, Vanilla et TBC.Source : format TOC, vérifié le 28 sept. 2026.
La même page répertorie un suffixe camelot propre au client, de sorte que AddonName_Camelot.toc se charge à la place du fichier par défaut. Sa table d’interface place 16001 sur la ligne « Forever Beta » et laisse « Forever Test » et « Forever » vides : ne supposez donc pas que ce numéro survive après la bêta.
Rechercher un objet sans course contre le cache
C_Item.GetItemInforenvoie 18 valeurs distinctes, et non une table : nom, lien, qualité, niveau, et ainsi de suite jusqu’à itemDescription. Il répond nil tant que le client n’a pas mis cet objet en cache, que l’objet existe ou non.Source : C_Item.GetItemInfo, vérifié le 28 sept. 2026.
Demander les données, puis lire l’événement
local function OnItemData(_, event, itemID, success)
if not success then return end
local name = C_Item.GetItemInfo(itemID)
if name then print(name, "is cached now") end
end
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", OnItemData)
frame:RegisterEvent("ITEM_DATA_LOAD_RESULT")
C_Item.RequestLoadItemDataByID(4306)Depuis le patch 10.0.5, le serveur peut répondre success = false pour un ID d’objet précis ; vérifiez donc ce drapeau avant d’appeler à nouveau GetItemInfo sur la même session.Source : ITEM_DATA_LOAD_RESULT, vérifié le 28 sept. 2026.
RequestLoadItemDataByID accepte aussi un lien d’objet complet, ce qui permet de transmettre tel quel ce qu’un hook d’infobulle ou un lien de chat vous a fourni, sans extraire d’abord l’ID numérique.
Rechercher un sort de la même façon
C_Spell.GetSpellInforenvoie une seule table, contrairement à l’appel pour les objets : spellInfo.name, spellInfo.iconID, spellInfo.castTime et le reste. Il a remplacé les anciennes fonctions GetSpellInfo et C_SpellBook.GetSpellInfo, qui étaient globales.Source : C_Spell.GetSpellInfo, vérifié le 28 sept. 2026.
local function OnSpellData(_, event, spellID, success)
local info = C_Spell.GetSpellInfo(spellID)
if not info then return end
-- success == false can still mean a partial record, such as no description.
print(info.name, info.castTime, success and "full" or "partial")
end
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", OnSpellData)
frame:RegisterEvent("SPELL_DATA_LOAD_RESULT")
C_Spell.RequestLoadSpellData(2061)Le wiki précise que success "Might return false when only partial spell data is available," (« peut renvoyer false quand seules des données partielles du sort sont disponibles »), par exemple tout sauf la description.Source : SPELL_DATA_LOAD_RESULT, vérifié le 28 sept. 2026. C’est pourquoi le modèle lit la table même sur un résultat false au lieu de s’arrêter. La liste des pièges de l’IA pour les addons couvre d’autres endroits où une réponse générée oublie une protection de ce genre.
Les deux appels acceptent un ID ou un nom de sort. Si vous passez un nom, C_Spell.GetSpellInfo cherche d’abord le remplacement actuel de ce sort pour le joueur ; une capacité transformée peut donc renvoyer l’icône du sort qui la remplace.
Différer une tâche sans script OnUpdate
C_Timer.Afterplanifie un rappel unique. Un post de Blizzard cité sur le wiki indique que le système de minuteurs ne travaille que lorsqu’un minuteur est créé ou détruit, alors qu’un gestionnaire OnUpdate coûte un appel Lua à chaque frame affichée.Source : C_Timer.After, vérifié le 28 sept. 2026.
local pendingSave = false
local function ScheduleSave()
if pendingSave then return end
pendingSave = true
C_Timer.After(2, function()
pendingSave = false
-- update an in-memory table or refresh a preview here
end)
endUse this to debounce follow-up work after a setting changes, such as updating an in-memory table or refreshing a preview. The timer does not write SavedVariables to disk; the client persists declared variables on logout or UI reload.
Lire les métadonnées de votre propre TOC
C_AddOns.GetAddOnMetadata(name, variable)lit Title, Notes, Author, Version ou tout champ X- personnalisé directement depuis votre propre fichier TOC, sans tenir compte de la casse.Source : C_AddOns.GetAddOnMetadata, vérifié le 28 sept. 2026.
local addonName = ...
local version = C_AddOns.GetAddOnMetadata(addonName, "Version") or "dev"
print(("%s v%s loaded"):format(addonName, version))Contrairement à l’ancien global GetAddOnMetadata, cet appel lève une erreur pour un nom qui ne correspond à aucun addon installé ; enveloppez donc toute recherche dont vous n’êtes pas sûr dans pcall. Affichez la version dans une infobulle du compartiment pour qu’un joueur qui signale un bug puisse vous la donner sans ouvrir le fichier TOC.
Ajouter un panneau d’options avec l’API Settings
Le wiki indique que l’API Settings a été refaite dans le patch 10.0.0, avec d’autres changements cassants dans le patch 11.0.2. Le code d’options copié d’un tutoriel antérieur au patch 10,0 ne correspondra pas aux appels ci-dessous, pas plus qu’une réponse d’IA entraînée sur ces tutoriels.Source : Settings API, vérifié le 28 sept. 2026.
local addonName, ns = ...
function ns.BuildOptions(db)
local category = Settings.RegisterVerticalLayoutCategory("Beacon Notes")
local setting = Settings.RegisterAddOnSetting(
category, "BeaconNotes_Locked", "locked", db,
"boolean", "Lock the notes frame", false
)
Settings.CreateCheckbox(category, setting, "Prevents dragging the frame.")
Settings.RegisterAddOnCategory(category)
end
-- Call ns.BuildOptions(ns.db) at the end of your ADDON_LOADED handler.Construisez le panneau dans ADDON_LOADED, une fois que le modèle SavedVariables ci-dessus a rempli la table. Au niveau du fichier, la table sauvegardée n’existe pas encore, et le réglage serait donc lié à nil.
Définir un repère sans appel protégé
Un rapport de bêta de la communauté sur Warcraft Forever indique que C_SuperTrack.SetSuperTrackedUserWaypoint est protégé sur ce client. L’appel échoue en silence et ajoute seulement un au compteur d’erreurs d’interface du panneau AddOns, qui "only resets on a full client restart, not on /reload."Source : Addons, vérifié le 28 sept. 2026. (« ne se réinitialise qu’au redémarrage complet du client, pas avec /reload »). Le même rapport cite C_Map.SetUserWaypoint comme moyen sûr de poser un repère. Considérez les deux comme non confirmés tant que vous ne les avez pas testés.
Les repères sont le terrain des addons de guides. Zygor Guides met en avant une "3D Waypoint Arrow" et RestedXP a pour slogan "Follow the arrow" ; vérifiez donc comment se comporte un addon d’itinéraire sur la bêta avant de bâtir votre propre code de repères par-dessus.
local mapID = C_Map.GetBestMapForUnit("player")
if mapID and C_Map.CanSetUserWaypointOnMap(mapID) then
local pos = C_Map.GetPlayerMapPosition(mapID, "player")
if pos then
C_Map.SetUserWaypoint(UiMapPoint.CreateFromVector2D(mapID, pos))
end
endLe même rapport range aussi ChatFrame_OpenChat et l’écriture d’attributs sécurisés sur les cadres d’unité de Blizzard parmi les opérations protégées, avec HandleModifiedItemClick comme voie sûre pour les liens par Maj+clic. Aucune des trois ne lève d’erreur interceptable : une enveloppe pcall ne vous dira donc pas que l’appel a échoué. Comparez un nouveau modèle avec le guide du développeur d’addons et le téléchargement de Forever Beacon avant de le publier, car rien sur cette page n’a encore été exécuté sur un client Forever.
Faits clés
- Interface TOC Modifiée16001 dans la ligne Forever Beta du tableau TOC du Warcraft Wiki ; vérifiez avec /dump select(4, GetBuildInfo())Classic : Classic Era indique 11509 dans le même tableau.
- SavedVariablesRapportées comme perdues entre deux sessions à la mi-septembre ; une réponse du 25 septembre indique que la build 70009 les recharge
- Addon compartment Nouveau dans ForeverLes champs TOC sont documentés pour Mainline ; pas encore testés ici sur un client Forever
- Verrouillage du combat Identique à ClassicLes cadres protégés ne peuvent pas être affichés, masqués ni déplacés en combat ; mettez en file d’attente jusqu’à PLAYER_REGEN_ENABLED
Sources
- TOC formatWarcraft Wiki
- Saving variables between game sessionsWarcraft Wiki
- WOWF Beta: Addon SavedVariables appear to write correctly to disk but are not restored at startupWorld of Warcraft Forums (player bug report)
- Addon compartmentWarcraft Wiki
- InCombatLockdownWarcraft Wiki
- Secret ValuesWarcraft Wiki
- AddonsWarcraft Forever
- WOW_PROJECT_IDWarcraft Wiki
- WoW: Forever Will Have Addon Changes from MidnightWowhead
- C_Item.GetItemInfoWarcraft Wiki
- ITEM_DATA_LOAD_RESULTWarcraft Wiki
- C_Spell.GetSpellInfoWarcraft Wiki
- C_Timer.AfterWarcraft Wiki
- C_AddOns.GetAddOnMetadataWarcraft Wiki
- Settings APIWarcraft Wiki
- What the WoW Forever beta breaks for addons: secret health values, dead secure snippets, new APIsWoW Forever Builds
- SPELL_DATA_LOAD_RESULTWarcraft Wiki
- RestedXP home pageRestedXP
- Zygor Guides home pageZygor Guides
- Blizzard client source: ProjectConstants.lua (retained build 70338; mirror may change)Blizzard Entertainment (source mirrored by Gethe)
- Blizzard client source: SlashCommandsRegistry.lua (retained build 70338; mirror may change)Blizzard Entertainment (source mirrored by Gethe)
- Blizzard client source: StaticPopup.lua (retained build 70338; mirror may change)Blizzard Entertainment (source mirrored by Gethe)
- Lua 5.1 Reference ManualLua.org
- Blizzard client source: ChatInfoDocumentation.lua (retained build 70338; mirror may change)Blizzard Entertainment (source mirrored by Gethe)