A pocket map of the 12.1.5-era surface as it applies to WoW: Forever. If a row says observed, it was seen on beta build 1.60.1.69913 and can move. If a row says confirmed, Blizzard stated it.
This reference is part of the WoW Forever AI Addon Guide. To understand client architecture and secret values, review WoW Forever Addon Patterns. To see how AI models fail on these calls, study Common AI Addon Pitfalls.
Globals that were gone
Legacy globals from Classic Era and older expansions are completely missing in the Forever runtime. Models trained on legacy code frequently emit these:
| AI will write | Use instead | Notes |
|---|---|---|
GetSpellInfo(id) | C_Spell.GetSpellInfo(id) | Returns table: name, iconID, castTime. Nil until cached. |
GetItemInfo(id) | C_Item.GetItemInfo(id) | Returns table: itemName, itemLink, itemQuality. Nil until cached. |
GetSpellBookItemName | C_SpellBook | Old spellbook globals were absent on build 69913. |
GetTalentInfo / GetNumTalentTabs | C_Traits or current talent API | There is no Classic talent tab API on this client. |
GetAddOnMetadata(name, field) | C_AddOns.GetAddOnMetadata | Same namespace migration as Midnight. |
CombatLogGetCurrentEventInfo() | Nothing | Do not replace it with a parser. Drop the feature. |
Spells and items
Information queries are asynchronous. Calling C_Spell.GetSpellInfo or C_Item.GetItemInfo immediately after login or on a fresh item ID can return nil while the engine loads the data record.
local info = C_Spell.GetSpellInfo(spellID)
if not info then
if C_Spell.RequestLoadSpellData then
C_Spell.RequestLoadSpellData(spellID)
end
return
end
-- info.name may still be secret. Guard before you print it.
Listen for SPELL_DATA_LOAD_RESULT and ITEM_DATA_LOAD_RESULT. A nil is not a removed spell or invalid item; it is an unloaded record.
Units and secrets
Units in Forever are governed by Midnight's secret value system. Arithmetic or string formatting on secret values will cause execution failure:
| Call | Can be secret | Safe use |
|---|---|---|
UnitHealth / UnitHealthMax | Yes, number | StatusBar:SetMinMaxValues and StatusBar:SetValue |
UnitName / creature names | Yes, string | Font string only after issecretvalue is false |
UnitCanAttack / UnitExists | Yes, boolean | Do not branch until the guard says plain |
UnitIsEnemy | Often the wrong question | Means attackable now, not opposite faction |
UnitFactionGroup | Check before compare | them ~= mine is the faction test |
Use this guard to test values before branching or displaying:
local function Sealed(value)
return type(issecretvalue) == "function" and issecretvalue(value)
end
Inspect guarded status-bar examples in our Code Templates and the Forever Beacon sample, then test them on your current build.
Events instead of the combat log
Community testing found COMBAT_LOG_EVENT_UNFILTERED unavailable to third-party addons on build 69913. Register unit-specific events instead, and retest before treating that restriction as final:
| You wanted | Register |
|---|---|
| Player health | RegisterUnitEvent("UNIT_HEALTH", "player") |
| Power | UNIT_POWER_UPDATE |
| A cast started or finished | UNIT_SPELLCAST_START, _STOP, _SUCCEEDED, _FAILED, _INTERRUPTED |
| Auras | Prefer an AuraContainer. UNIT_AURA is not a license to enumerate in combat. |
| Entering and leaving combat | PLAYER_REGEN_DISABLED and PLAYER_REGEN_ENABLED |
| A boss pull | ENCOUNTER_START and ENCOUNTER_END, if the encounter fires them |
| Zone changes | ZONE_CHANGED_NEW_AREA, PLAYER_ENTERING_WORLD |
Frames, time, chat
Modern frame templates require explicit template inheritance, and timers should use C_Timer:
local f = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
f:SetSize(240, 48)
f:SetPoint("CENTER")
f:SetScript("OnEvent", function(self, event, ...) end)
C_Timer.NewTimer(2, function() end) -- cancellable
C_Timer.After(2, function() end) -- returns nothing
SLASH_MYADDON1 = "/myaddon"
SlashCmdList["MYADDON"] = function(msg) end
DEFAULT_CHAT_FRAME:AddMessage(text, 0.83, 0.66, 0.35)
SetTexCoord parameter order
SetTexCoord takes parameters in the order: left, right, top, bottom. It is not left, top, right, bottom. Values are floats from 0.0 to 1.0, not pixel coordinates.
Calls that get you a silent strike
Do not call protected or deprecated UI functions:
| Avoid | Use |
|---|---|
ChatFrame_OpenChat / ChatEdit_ActivateChat | Leave chat editing to the client |
C_SuperTrack.SetSuperTrackedUserWaypoint | C_Map.SetUserWaypoint |
| Secure attributes on Blizzard unit frames | Your own buttons |
PlaySoundFile on Sound\Interface\*.ogg | PlaySound with a SOUNDKIT id |
pcall around any of the above | Do not call them |
TOC fields that matter here
Every Forever addon must declare interface 16001 on beta build 69913:
## Interface: 16001
## Title: My Addon
## Notes: What it does in one line
## Author: YourName
## Version: 0.1.0
## SavedVariables: MyAddonDB
## SavedVariablesPerCharacter: MyAddonCharDB
## IconTexture: Interface\Icons\INV_Misc_Note_01
## Category: Miscellaneous
## AddonCompartmentFunc: MyAddon_OnCompartmentClick
Compartment callbacks must be real globals; the TOC looks them up by name. Everything else in your files should be file-scoped locals. Saved variable names are also globals, filled in by the client runtime only after ADDON_LOADED fires for your addon.
Settings API
The modern Settings category API from Dragonflight onward is part of the Mainline surface Forever shares. Prefer it to a private options window when you only need checkboxes and sliders. If you do build a custom window, inherit BackdropTemplate, save the anchor on drag stop, and do not move protected frames during combat lockdown.
Interface options categories registered through the legacy InterfaceOptions_AddCategory path are the Midnight-era mistake AI models frequently generate.