framexml: the twenty-one rows of the chain's own toc the manifest still lacked

benilla loads `assets/ui/benilla.toc`, not the player's `Interface\FrameXML\FrameXML.toc`, so a row
the chain carries and the manifest omits is silently absent — no read attempt, no warning. Six went
in with the arena templates; this is the rest of the diff but one, each with a comment on what it
is for and in the chain's own order.

The six baked Octo extensions are the player-visible half. `/pvp` now asks before a War Mode
character spends its permanent, persisted opt-out. The exhaustion tooltip reads this realm's 175%
instead of 1.12's baked 150%, and `/rested` answers. A player's hover shows the realm's own two
challenges, Samurai and Together Forever: the server was already setting bits 10 and 11, and
`TargetFrame_UpdateChallenges` walks a list that stopped at 10. The one-shot War Mode offer on
arrival from the hardcore realm renders instead of being dropped. `/bug` and `/suggest` exist again
— Turtle's FrameXML dropped the BugReport frame, and this rebuilds the dialog over chunked `.bug`
SAY commands. And on C'Thun the Ghost debuff's tooltip carries the hardcore afterlife line, which
is why the realm reverted that string in Spell.dbc.

With them: `OctoToolReqTip`, the realm's own 40 KB recipe-to-tool table wrapping
`GetTradeSkillTools`, so a recipe whose tool OctoWoW changed names its real one; six `OctoLocale`
rows, each gated on `GetLocale()` and inert here; and the three Turtle windows the manifest said
needed verbs built first — arena (4 rows), barbershop, guild bank (2). They need exactly one,
`CameraZoomOut`, now built. All three publish their frames and open only on an exact gossip trigger
string, so answering nil for `GetGossipText` cannot hide ordinary gossip.

`StatsFrame.xml` is the row left out, and the manifest says so where it would sit: the debug-build
overlay whose OnUpdate is the only reader of `GetDebugStats`, a binding we do not have, so the row
would publish a `ToggleStats` that raises twice a second once pressed.

`UNLEARNED_SPELL` joins `UNPRODUCED` rather than getting a producer. It is the only entry there that
is not a 1.12 event at all: 5875's event-name pool carries `LEARNED_SPELL_IN_TAB` and
`SPELLS_CHANGED` and no unlearn sibling, so the reference ignores that registration exactly as we
do, and the War Mode re-scan rides PLAYER_LOGIN and LEARNED_SPELL_IN_TAB, which both fire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-10-18 07:52:12 -06:00
co-authored by Claude Opus 5
parent f185f3b549
commit 4764e4fb2d
2 changed files with 88 additions and 12 deletions
+79 -12
View File
@@ -17,6 +17,22 @@ Interface\FrameXML\Fonts.xml
# Second, not first as in the reference, because entry 0 must be Fonts.xml.
Interface\FrameXML\GlobalStrings.lua
# OctoWoW's own seven rows between GlobalStrings and Globals (its `FrameXML.toc` 4-10). Each
# `OctoLocale_*` file is one `if GetLocale() == "xxXX"` block of GlobalStrings overrides and is
# inert on an enUS chain, but they load as the reference loads them, so a client started in
# another locale reads the realm's own strings rather than ours. `OctoToolReqData.lua` is the
# realm's 40 KB recipe -> required-tool-item table and `OctoToolReqTip.lua` wraps
# `GetTradeSkillTools` over it: a recipe whose tool OctoWoW changed (the jeweler's kits, the
# Whittle) reads its real tool in the trade-skill window, and the universal knife (item 50006)
# satisfies any of them. The wrap is engine-level (`GetTradeSkillTools` is a binding, not
# FrameXML), so its place this early is the reference's and costs nothing.
Interface\FrameXML\OctoLocale\OctoLocale_deDE.lua
Interface\FrameXML\OctoLocale\OctoLocale_esES.lua
Interface\FrameXML\OctoLocale\OctoLocale_ptBR.lua
Interface\FrameXML\OctoLocale\OctoLocale_ruRU.lua
Interface\FrameXML\OctoLocale\OctoLocale_zhCN.lua
Interface\FrameXML\OctoToolReqTip\OctoToolReqData.lua
Interface\FrameXML\OctoToolReqTip\OctoToolReqTip.lua
# TurtleWoW's own two rows after GlobalStrings (its `FrameXML.toc` 11-12), both the client half of
# server-side systems. `Globals.lua` publishes `print`, `TURTLE_WOW_VERSION`, `TW_CLASS_TOKEN`,
# `Turtle_AvailableChallenges`, `GAME_YELLOW` and the three `ADDON_MSG_*_DELIMITER`s that every
@@ -27,6 +43,11 @@ Interface\FrameXML\GlobalStrings.lua
# row the chain's `WorldMapContinent.dbc` carries.
Interface\FrameXML\Globals.lua
Interface\FrameXML\Overrides.lua
# The chain's row 14, immediately after its own Fonts.xml (our entry 0): it repoints the ~50
# FrameXML font objects at `Fonts\FZLBJW.TTF` for ruRU and zhCN only, so on an enUS client every
# `GetFont`/`SetFont` pair it runs is a no-op. Faithful and inert, and the one row that makes a
# Cyrillic or CJK login legible.
Interface\FrameXML\OctoLocale\OctoLocale_Fonts.lua
# `Localize()` runs at load and overwrites GlobalStrings keys, so this follows them.
Interface\FrameXML\Localization.xml
# `GetText` is a Lua global, not an engine binding: the client's `0x703bf0` calls it.
@@ -137,6 +158,12 @@ Interface\FrameXML\HonorFrame.xml
# Ours: the sixth tab page TurtleWoW's `CharacterFrame.lua` lists and 1.12 never shipped.
CharacterFrameAdapters.xml
Interface\FrameXML\DressUpFrame.xml
# Deliberately absent, the chain's `StatsFrame.xml` would sit here (its `FrameXML.toc` 60): the
# debug-build frame-stat overlay, `hidden="true"` with an OnUpdate that is the only reader of
# `GetDebugStats()` — a binding 5875 has and benilla does not, and whose readout is a debug
# build's own, not something a player sees. Loading the row would publish a `ToggleStats` that
# raises twice a second once pressed; leaving it out leaves `ToggleStats` nil, which is what an
# unbound key already does. Build `GetDebugStats` and this row costs nothing.
Interface\FrameXML\SpellBookFrame.xml
# Ours: the pet page's autocast widgets in the pet action button's proportions.
SpellBookAdapters.xml
@@ -179,7 +206,29 @@ Interface\FrameXML\LFT\LFT_Data.lua
Interface\FrameXML\LFT\LFT.lua
Interface\FrameXML\LFT\LFTTemplates.xml
Interface\FrameXML\LFT\LFT.xml
# OctoWoW's six baked single-file extensions (its `FrameXML.toc` 139-148), all Lua over verbs that
# already exist, and baked into the chain rather than shipped as AddOns precisely so a player
# cannot switch them off. In the reference's order, which puts the first of them above
# OctoLFTBlinkPause.
# `OctoWowWarModeConfirm` wraps `SlashCmdList["PVP"]`: on the War Mode challenge (spell named
# "War Mode" in the spellbook) /pvp raises a confirm popup first, because the server reads a
# /pvp from such a character as a permanent, persisted opt-out.
Interface\FrameXML\OctoWowWarModeConfirm\OctoWowWarModeConfirm.lua
Interface\FrameXML\OctoLFTBlinkPause\OctoLFTBlinkPause.lua
# `OctoRestedTooltip` wraps `GetRestState` so the exhaustion tooltip reads the realm's 175% rather
# than 1.12's baked 150%, and adds `/rested`; the multiplier is display-only in 1.12, the XP bar
# itself reads the state id.
Interface\FrameXML\OctoRestedTooltip\OctoRestedTooltip.lua
# `OctoChallengeTip` appends entries 11 and 12 to `Turtle_AvailableChallenges` (Globals.lua above),
# which is what `TargetFrame_UpdateChallenges` walks bit by bit — so the realm's own two
# challenges, Samurai and Together Forever, stop being dropped from a player's hover.
Interface\FrameXML\OctoChallengeTip\OctoChallengeTip.lua
# `OctoWarModeOffer` renders the one-shot War Mode offer the server sends as a `TW_WARMODE`
# `S2C_OFFER` addon message on arrival from the hardcore realm, and answers C2S_ACCEPT/C2S_DECLINE.
Interface\FrameXML\OctoWarModeOffer\OctoWarModeOffer.lua
# `RestoreBugCommand` rebuilds `/bug` and `/suggest`: Turtle's FrameXML dropped the BugReport frame
# altogether, so this builds its own dialog and sends the report as chunked `.bug` SAY commands.
Interface\FrameXML\RestoreBugCommand\RestoreBugCommand.lua
# TurtleWoW's own three loose rows (its `FrameXML.toc` 103-105), all Lua over verbs that already
# exist. `Hooks.lua` is the realm's tooltip layer: the guild line under a player's name (gated on
# its own `TOOLTIP_GUILD_NAMES` CVar), the shift-click hint while a trade, auction or mail window
@@ -191,14 +240,30 @@ Interface\FrameXML\OctoLFTBlinkPause\OctoLFTBlinkPause.lua
Interface\FrameXML\Hooks.lua
Interface\FrameXML\ChronoboonTimers.lua
Interface\FrameXML\SpellChatLinks.lua
# Turtle's `# Arena` block (its `FrameXML.toc` 108-112), in its own order. `Turtle_ArenaUI.lua`
# is the whole client half of the realm's arena: the `TW_ARENA` addon-message protocol, the team
# roster and the queue. `Turtle_ArenaUITemplates.xml` carries `ArenaTeamTemplate`, which
# `Blizzard_InspectUI`'s own `InspectArenaFrame.xml` inherits for its three team buttons before
# reading `$parentText`, `$parentDetails` and nine `$parentDetails*` children by name — without
# that row the inspect window raised four times per inspect, three OnLoads and
# `InspectArenaFrame_OnShow`.
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaUI.lua
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaUITemplates.xml
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaFrame.xml
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaQueueFrame.xml
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaRegistrarFrame.xml
# Turtle's barbershop, one row that scripts its own `Turtle_Barbershop.lua`: the window opens on a
# `TW_BARBERSHOP` addon message (no gossip hook — it watches CHAT_MSG_ADDON, PLAYER_MONEY and
# UNIT_MODEL_CHANGED) and drives a live 3-D preview, zooming the world camera out two yards at the
# open (`Turtle_Barbershop.lua:211`). `CameraZoomOut` was the one verb these three windows call
# that we did not have; it is built now, with `CameraZoomIn`.
Interface\FrameXML\Turtle_BarbershopUI\Turtle_Barbershop.xml
# TurtleWoW's own FrameXML additions, in the reference `FrameXML.toc` order (patch-3.mpq). These
# are the client half of Turtle's custom systems: `Turtle_TransmogUI` hooks `GOSSIP_SHOW`, hides
# the stock gossip frame for its NPCs and drives the transmog window over `TW_TRANSMOG` addon
# messages; `Turtle_ShopUI` (prefix `TW_SHOP`) is the custom merchant/shop. Without these rows the
# server's trigger gossip text (`TRANSMOG_TRIGGER`, `CUSTOM_MERCHANT_TRIGGER`) is what the stock
# gossip window shows, and neither custom window exists. Turtle's Inspect-Talents and Guild-Bank
# UIs are the same pattern but need `ToggleInspect`/`SetTalentButtonLocation` and the GuildBank
# globals built first, so they are not loaded here yet.
# gossip window shows, and neither custom window exists.
Interface\FrameXML\Turtle_TransmogUI\Turtle_TransmogSets.lua
# The slot buttons in Turtle_TransmogUI.xml inherit TransmogPlayerSlotTemplate, and the look grid
# and new-transmog alert inherit TransmogFrameLookTemplate/TransmogWonItemTemplate; without this
@@ -207,15 +272,12 @@ Interface\FrameXML\Turtle_TransmogUI\Turtle_TransmogUITemplates.xml
Interface\FrameXML\Turtle_TransmogUI\Turtle_TransmogUI.xml
Interface\FrameXML\Turtle_ShopUI\Turtle_ShopUITemplates.xml
Interface\FrameXML\Turtle_ShopUI\Turtle_ShopUI.xml
# Turtle's arena templates, the one row of its `# Arena` block (its `FrameXML.toc` 108-112) that
# stands alone: it inherits nothing but stock fonts and declares no handler of its own at load.
# `Blizzard_InspectUI`'s own `InspectArenaFrame.xml` inherits `ArenaTeamTemplate` for its three
# team buttons and then reads `$parentText`, `$parentDetails` and nine `$parentDetails*` children
# by name, so without this row the inspect window raised four times per inspect — three OnLoads
# and `InspectArenaFrame_OnShow`. The other four rows (`Turtle_ArenaUI.lua` and the arena, queue
# and registrar windows) are the same pattern as the Inspect-Talents and Guild-Bank UIs above:
# they need the arena verbs built first, so they are not loaded here yet.
Interface\FrameXML\Turtle_ArenaUI\Turtle_ArenaUITemplates.xml
# Turtle's guild bank (its `FrameXML.toc` 126-127): the templates first, then the window, which
# scripts its own 60 KB `Turtle_GuildBankUI.lua` — a `GOSSIP_SHOW` hook for the banker NPCs over
# `TW_GUILDBANK` messages, with the tab rights read off `GuildControlGetNumRanks`/`GetRankName`
# and so a `GUILD_ROSTER_UPDATE`/`PLAYER_GUILD_UPDATE` listener too.
Interface\FrameXML\Turtle_GuildBankUI\Turtle_GuildBankUITemplates.xml
Interface\FrameXML\Turtle_GuildBankUI\Turtle_GuildBankUI.xml
# Turtle's honour/arena merchant (Stormwind armoury PvP gear, the Custom_Merchant NPCs): it hooks
# `GOSSIP_SHOW`, hides the gossip frame for an NPC whose greeting is `CUSTOM_MERCHANT_TRIGGER` and
# fills over `TW_Merchant` addon messages. Without it that trigger text is what the stock gossip
@@ -231,6 +293,11 @@ Interface\FrameXML\Custom_Merchant\CustomMerchantFrame.xml
# `SMSG_PLAY_MUSIC` naming a `SoundEntries.dbc` row whose file is a live HTTP stream URL.
Interface\FrameXML\EverlookBroadcastingCo\EverlookBroadcastingCo.xml
Interface\FrameXML\OctoRadioPlaceholder\OctoRadioPlaceholder.lua
# `OctoGhostGate`, last of the realm's six baked extensions: it post-hooks
# `GameTooltip:SetUnitDebuff` and, when the hovered debuff is titled exactly "Ghost", rewrites
# line 2 with the hardcore afterlife line — gated at PLAYER_LOGIN on `GetRealmName() == "C'Thun"`,
# because Spell.dbc loads before a realm is chosen and the realm wants the line on C'Thun only.
Interface\FrameXML\OctoGhostGate\OctoGhostGate.lua
# AIO, the realm's client<->server transport (its FrameXML.toc bakes it so no AddOn is needed).
# Before OctoCalendar, which feeds from it: the calendar registers an AIO handler at load and
# queues its guild-permission request until AIO is up (`OctoCalendar.lua:919-920`).
@@ -1895,6 +1895,15 @@ mod tests {
"four files — the paperdoll model refresh",
),
("UNIT_PORTRAIT_UPDATE", "three files — the portrait refresh"),
(
"UNLEARNED_SPELL",
"OctoWowWarModeConfirm.lua — and the only entry here that is not a 1.12 event at \
all: `UNLEARNED_SPELL` is absent from 5875's own event-name pool (which carries \
`LEARNED_SPELL_IN_TAB` and `SPELLS_CHANGED` right beside where it would sit), so \
the reference ignores the registration exactly as we do. The addon re-scans the \
spellbook for the \"War Mode\" spell on PLAYER_LOGIN and LEARNED_SPELL_IN_TAB \
too, and both of those fire, so its /pvp guard is live either way",
),
(
"ZONE_UNDER_ATTACK",
"ChatFrame.lua — the reference's `SMSG_ZONE_UNDER_ATTACK` line (\"%s is under \