- the combat log's last eight wire bodies decode — PARTYKILLLOG, SPELLINSTAKILLLOG, PROCRESIST, SPELLORDAMAGE_IMMUNE, SPELLDISPELLOG, DISPEL_FAILED, ENCHANTMENTLOG, SPELLLOGEXECUTE — each layout read off vmangos's own writer and pinned by a byte-exact golden (DISPEL_FAILED carries no count, the list runs to the end of the body; SPELLLOGEXECUTE's POWER_DRAIN row is (amount, power, multiplier), verified at the client's bytes as well as the server's); with the eleven chat types that were waiting on them, 44 chat types become 55 — 29 sentence families, the death pair and the aura rows riding descriptor diffs because 1.12 has no "unit died" opcode, plus the six trailers ((glancing), (30 blocked), (12 absorbed) and kin) that had been missing from every family; also corrected: the durability-death line was going to the red error frame with hard-coded English, and SMSG_SPELLNONMELEEDAMAGELOG lacked its split-damage branch and its blocked wording
- PlayerModel is its own frame kind: SetUnit, RefreshUnit and SetRotation were published on Model, but they belong to the <PlayerModel> method table (0x84f1fc), and the client's lookup chains derived → base only, so a plain <Model> can never reach them — they got there from a strings scan read as ownership, and a strings hit answers whether a name EXISTS, not who owns it (SetUnit's one pooled string is referenced by the PlayerModel and GameTooltip tables and by no Model entry); the new PlayerModel → Model → Frame → Region chain unblocks CreateFrame("PlayerModel"), which is how pfUI builds every unit-frame portrait — and through pfUI, pfQuest and ShaguDPS
- a nil where a number goes is four shapes, not one law: a census of all 408 widget-registrar entries found 62 numeric positions that validate-or-raise, 43 that gate then stage an alternate, 64 that silently coerce to 0.0 and 5 that gate then store nothing — so SetMaxLetters(nil) completes and stores 0, "no limit" (the argument COUNT is checked exactly, the type is not), and the backdrop colour setters are asymmetric on purpose: a nil r/g/b channel is 0.0 but a nil alpha is OPAQUE, and reading every nil as 0.0 would have turned those borders transparent; both setters now also quantize ×255 into the packed 0xAARRGGBB byte quad the client actually stores, so 0.09 reads back as 23/255
- two more addon-killers: LIGHTYELLOW_FONT_COLOR_CODE was the one missing line of Fonts.xml's seven-line colour block (aux-addon concatenates it at file scope and died on its own first line), and the guard now enumerates the whole block l.4-20 instead of the names an earlier round had noticed absent; and the unit frames publish the reference's names — 1.12 has no *PowerBar anywhere, every bar is ManaBar and the colour table is ManaBarColor (8 of the top-20 addons read it by name), so ManaBarColor is the published table our own bars index into, with 22 more regions renamed to the reference's own
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1993 lines
135 KiB
XML
1993 lines
135 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's character window (decision 0208, phase 1a display + phase 1b equip interactions
|
||
— the C-key window, paper doll first):
|
||
the round player portrait + name + level line + close button + the five-tab row, dressed
|
||
from the real 1.12 `CharacterFrame.xml`/`.lua` + `PaperDollFrame.xml`/`.lua` +
|
||
`CharacterFrameTemplates.xml` + the `Model_*` rotate helpers (`UIParent.lua:1421-1462`) —
|
||
extracted from the MPQ chain to session scratch this session (director-local reference
|
||
artifacts, never committed — the 0068/0138 pattern; line cites below are into that
|
||
extraction's own `ref-CharacterFrame.xml`/`.lua`, `ref-PaperDollFrame.xml`/`.lua`,
|
||
`ref-UIParent.lua`, `ref-GlobalStrings.lua`). `CharacterFrameTabButtonTemplate` is ALREADY
|
||
defined in `UiPanels.xml:507-563` (battle-tested by Merchant/QuestLog, 0138) — reused
|
||
here, not redefined.
|
||
|
||
Docks the left UIPanel slot (`UiPanels.xml` `UIPanelWindows["CharacterFrame"] =
|
||
{ area = "left", pushable = 2, whileDead = 1 }`, the ref's own `UIParent.lua l.19` row —
|
||
decision 1507; pushable was wrongly 0 from 0208 until then). pushable=2 means it does NOT
|
||
simply replace the NPC-session windows: a pushable-0 window opening under it slides this
|
||
sheet to the CENTER seat (vendor left, your equipment beside it), and showing this over a
|
||
pushable-0 occupant parks it at center likewise. `ToggleCharacter(tab)` (ref
|
||
`CharacterFrame.lua:3-23`) is the show/hide/tab-switch entry point;
|
||
the app's 'C' binding calls it (`ui_script/mod.rs`).
|
||
|
||
Every frame this file defines wears the REFERENCE's name (`CharacterFrame`,
|
||
`PaperDollFrame`, …) — including the strings `ToggleCharacter`/`CharacterFrame_ShowSubFrame`
|
||
pass around internally (`BENILLA_CHARACTERFRAME_SUBFRAMES` lists `"PaperDollFrame"`). The
|
||
`Benilla` prefix these carried until the reference-naming pass is gone: addons index these
|
||
globals by the reference's name, and a prefixed frame is simply the wrong name for a frame
|
||
that IS the reference's.
|
||
|
||
Phase 1a shipped the window, display-only. Phase 1b (THIS pass) adds the equip
|
||
interactions over the SAME display — `PickupInventoryItem`/`UseInventoryItem`/
|
||
`AutoEquipCursorItem`/`CursorCanGoInSlot`/`IsInventoryItemLocked`, joining the paper doll
|
||
onto the ONE cursor-payload space via its sentinel `EQUIPMENT_BAG` bag id (decision 0216
|
||
§1, extended by decision 0208's own phasing, §"Phasing"/"1a"/"1b", and 0216/0218's
|
||
cursor-arc design). Tabs 2-5 (Pet/Reputation/Skills/Honor) were all OMITTED at 1b, the 0138
|
||
merchant-tab precedent ("tabs arrive with their pages") — `BENILLA_CHARACTERFRAME_SUBFRAMES`
|
||
only lists the pages that exist. Skills arrived with decision 0437 phase 4
|
||
(`SkillFrame.xml`), **Pet with decision 1057** (`PetPaperDollFrame.xml`), which takes the
|
||
real client's own slot 2, **Reputation** (`ReputationFrame.xml`), which takes its own
|
||
slot 3 and puts Skills back on the reference's 4, and **Honor** (`HonorFrame.xml`) on its
|
||
own 5 — so the row is COMPLETE: all five tabs are the reference's, in its order, at its
|
||
numbers, and nothing is omitted any more. Three things here are shared
|
||
WITH the pet page rather than owned by this one, and each is flagged at its definition: the
|
||
`(unit, prefix)` stat setters (including `_SetDefense`, which exists for the pet row alone),
|
||
the `BenillaPaperDollModel_*` pane quartet (driven through each pane's own `frame.setFacing`),
|
||
and the tab row itself, whose tab 2 the pet page raises and hides.
|
||
|
||
Named deferrals/OMITs (each re-cited at its own site below):
|
||
- Guild line (`CharacterGuildText`) and the PVP rank name (`UnitPVPName` — plain `UnitName`
|
||
ships instead): both decision 0208's own named deferrals (guild needs `CMSG_GUILD_QUERY`;
|
||
rank needs the honor arc). `CharacterTitleText` (also PVP-rank-driven) is dropped with it.
|
||
- Shift-click chat-link insert (decision 1059) and ctrl-click `DressUpItemLink` (the
|
||
dressing room, decision 1060) both LANDED — the left-click fork below is now the
|
||
reference's own three arms (ctrl → preview, shift → post the link, else pick up).
|
||
They were named deferrals when this file was written; the note stays because the fork
|
||
below reads as a transcription of that history.
|
||
- The ammo slot (id 0) LOADS ammo by entry (`CMSG_SET_AMMO`) — it does NOT swap into an
|
||
equip slot (decision 0526; wow-re `cursor-dragdrop-slots.md`: the client's auto-equip
|
||
sender forks ammo-class → SET_AMMO). So it can't share the 19 named slots'
|
||
`PickupInventoryItem` path — its click/drop route to `BenillaCharacterAmmoSlot_OnClick`
|
||
→ `AutoEquipCursorItem` (the app's autoequip drain resolves the held entry and forks to
|
||
SET_AMMO), gated by `CursorCanGoInSlot(0)` so only an ammo payload fits. It carries no
|
||
ring, so the `CURSOR_UPDATE` highlight / `ITEM_LOCK` dim legs no-op, and there is no
|
||
drag-OUT of loaded ammo; it keeps sharing `BenillaPaperDollSlot_OnLoad`/`_Update`/
|
||
`_OnEvent` for its DISPLAY. (The four equipped-bag icons, ids 20-23, joined the
|
||
`EQUIPMENT_BAG` payload space in decision 0216/0218 — no longer out of the drag space.)
|
||
- Cooldowns (`GetInventoryItemCooldown`/`CooldownFrameTemplate`), the broken-red tint
|
||
(`GetInventoryItemBroken`), and the shift-compare tooltip (`SHOW_COMPARE_TOOLTIP`):
|
||
none of their backing feeds/engine affordances exist yet — the item stats feed has no
|
||
durability/cooldown channel (the same named gap as 0138's damaged-sell-price).
|
||
- The `CURSOR_UPDATE` slot highlight is an EMULATION, not the reference's true
|
||
`LockHighlight`/`UnlockHighlight` (grepped `benilla-ui/src/script/button.rs` this
|
||
session — no such Button methods exist; a Button's highlight texture only ever shows
|
||
on REAL mouse hover, `ButtonState::region_visible`'s hardwired `enabled && hovered`, no
|
||
forced-show path). A real forced-highlight affordance is a `benilla-ui` follow-up, not
|
||
blocking this slice — `BenillaPaperDollSlot_LockHighlight`/`_UnlockHighlight` below
|
||
tint the slot's Quickslot2 ring instead, flagged at their own definition.
|
||
- The relic slot: `UnitHasRelicSlot` is vanilla-always-false (there is no relic slot in
|
||
1.12), so the ref's `CharacterAmmoSlot:Hide()`/relic-texture branches are DEAD CODE even
|
||
in the real client — omitted outright rather than transcribing unreachable branches; the
|
||
ammo slot always shows.
|
||
- Class-specific stat-tooltip flavor text (`WARRIOR_STRENGTH_TOOLTIP` and its ~20 siblings):
|
||
only the 5 `DEFAULT_*_TOOLTIP` fallbacks ship. `PaperDollStatTooltip` still looks
|
||
the class-specific global up FIRST exactly like the ref, so dropping in the per-class
|
||
table later is pure string data, no logic change — the numeric stat lines (the
|
||
load-bearing content) are complete either way.
|
||
- The model pane ships as a booth-texture stand-in, not a live `<Model>`/`<PlayerModel>`
|
||
widget (decision 0208 §5): our engine's `FrameKind::Model` parses but has no
|
||
`SetUnit`/`RefreshUnit` surface (verified this session — grepped `benilla-ui/src/script`),
|
||
so `CharacterModelFrame` materializes here as a plain `<Frame>` sampling the paper-doll
|
||
booth bake via `BenillaSetBoothTexture(region, "paperdoll")` (the `SetPortraitTexture`
|
||
plumbing's sibling, per this session's parallel-build contract) — `DISPLAY_SIZE_CHANGED`/
|
||
`RefreshUnit` don't apply and are dropped. `OnMouseUp`-to-equip DOES apply, though (1b):
|
||
it needs no live 3D — just `EnableMouse(true)` + the two script hooks, added below. The
|
||
held-button continuous spin (`Model_OnUpdate`, ref `UIParent.lua:1444-1462`) needs
|
||
`GetButtonState()=="PUSHED"` — grepped, no such method exists on our `Button` — so this
|
||
ships CLICK-ONLY (±0.03 rad/click); the held-spin is a follow-up once/if `GetButtonState`
|
||
lands.
|
||
- The ammo slot's data path (verified this session, not the speculative framing in decision
|
||
0208 §4): the ref's `CharacterAmmoSlot` is NOT driven by a separate `PLAYER_AMMO_ID`
|
||
Lua global — it shares the exact same `PaperDollItemSlotButton_OnLoad`/`_Update` functions
|
||
the 19 named slots use (ref `ref-PaperDollFrame.xml:999-1028`, byte-identical to the
|
||
shared template's own Scripts block at l.8-37), just keyed off `GetInventorySlotInfo(
|
||
"AmmoSlot")` instead of e.g. `"HeadSlot"`. Whatever `PLAYER_AMMO_ID`/bag-summing happens
|
||
for that particular slot id is the parallel binding's own implementation detail, invisible
|
||
to this Lua — re-expressed here exactly as the ref wires it.
|
||
- `$parentStock` (the ammo slot's yellow "in bags" count, ref `ref-PaperDollFrame.xml:
|
||
970-978`): no Lua in this session's extraction ever populates it (likely an ammo-picker-
|
||
addon-only overlay outside this pull) — dropped rather than guessed at.
|
||
|
||
Engine-gap notes (transcribed anyway per this file's own instructions, or worked around) —
|
||
the first two are CLOSED, kept only because the workarounds below still read as if they held:
|
||
- `HitRectInsets` (both `CharacterFrame` and `PaperDollFrame`, ref's identical
|
||
0/30/0/45 on both) was a loader no-op when this file was written; it landed with the
|
||
micro menu (decision 0655) and now really insets the mouse rect.
|
||
- `enableMouse`/`setAllPoints` (frame-level) were no-ops on `<Frame>` too; both are wired
|
||
now (`loader/geometry.rs`'s `apply_attrs`/`apply_anchors`, and
|
||
`loader/tests.rs::frame_set_all_points_pins_to_parent`). `PaperDollFrame` still
|
||
carries an explicit `Size`+`TOPLEFT` anchor rather than the ref's `setAllPoints="true"`
|
||
— exactly equivalent for a child sized to fill its parent, so it is left alone rather
|
||
than churned.
|
||
- A plain `<Frame>` isn't mouse-enabled by construction in this engine (only Button/
|
||
CheckButton/EditBox/ScrollingMessageFrame are — `widget/mod.rs`'s ctor comment, already
|
||
the reason `UnitFrames.xml` calls `EnableMouse(true)` on its own root frame) — every
|
||
hover-tooltip `<Frame>` below (the 5 attribute rows, armor/attack/damage/ranged rows, the
|
||
5 resistance frames — none of them Buttons) gets its own `self:EnableMouse(true)` in
|
||
`OnLoad` for this reason; the 19 item slots are Buttons and need no such call.
|
||
- `TEXT(x)` (the ref's localization-tooling identity macro) has no engine equivalent and
|
||
needs none — it's a build-time no-op wrapper in the real client, so every `TEXT(FOO)` call
|
||
below is transcribed as the bare `FOO` global.
|
||
- The font color codes (`HIGHLIGHT_FONT_COLOR_CODE`/`GREEN_FONT_COLOR_CODE`/
|
||
`RED_FONT_COLOR_CODE`/`FONT_COLOR_CODE_CLOSE`, `NORMAL_FONT_COLOR`/`HIGHLIGHT_FONT_COLOR`)
|
||
are defined by the real `Fonts.xml`'s own <Script> block (ref l.8-19 — extracted and
|
||
verified this session), so ours live in our `Fonts.xml` (loaded first), not here.
|
||
|
||
Sounds (decision 0090): `igCharacterInfoOpen`/`Close` on Show/Hide (ref `CharacterFrame.lua:
|
||
83/96`), `igCharacterInfoTab` on the tab click (ref `CharacterFrameTab_OnClick`, l.47),
|
||
`igInventoryRotateCharacter` on each rotate click (ref `UIParent.lua:1432/1441`).
|
||
-->
|
||
<Script><![CDATA[
|
||
-- ── GlobalStrings values this window uses (ref-GlobalStrings.lua, cited per line — the
|
||
-- `X = X or "..."` idiom matches CastingBar.xml's own convention: a real GlobalStrings.lua,
|
||
-- if one ever loads, wins over this fallback) ──────────────────────────────────────────────
|
||
CHARACTER = CHARACTER or "Character" -- :481
|
||
SKILLS = SKILLS or "Skills" -- :3477 (decision 0437 phase 4, the Skills tab label)
|
||
PET = PET or "Pet" -- :3010 (the Pet tab label, decision 1057)
|
||
REPUTATION = REPUTATION or "Reputation" -- :3328 (the Reputation tab label)
|
||
PLAYER_LEVEL = PLAYER_LEVEL or "Level %d %s %s" -- :3075
|
||
ARMOR = ARMOR or "Armor" -- :62
|
||
ARMOR_COLON = ARMOR_COLON or "Armor:" -- :63
|
||
DEFENSE_COLON = DEFENSE_COLON or "Defense:" -- :917 (the shared
|
||
-- _SetDefense's label; only
|
||
-- the pet page has the row)
|
||
ARMOR_TOOLTIP = ARMOR_TOOLTIP or
|
||
"Decreases the amount of damage taken from physical attacks. The amount of reduction is influenced by the level of the attacker.\nDamage reduction against a level %d attacker: %.1f%%" -- :65
|
||
ATTACK_POWER_COLON = ATTACK_POWER_COLON or "Power:" -- :71
|
||
ATTACK_SPEED_COLON = ATTACK_SPEED_COLON or "Attack Speed (seconds):" -- :73
|
||
ATTACK_TOOLTIP = ATTACK_TOOLTIP or "Attack Rating" -- :75
|
||
ATTACK_TOOLTIP_SUBTEXT = ATTACK_TOOLTIP_SUBTEXT or
|
||
"Your attack rating affects your chance to hit a target, and is based on the weapon skill of the weapon you are currently wielding." -- :76
|
||
DAMAGE_COLON = DAMAGE_COLON or "Damage:" -- :888
|
||
DAMAGE_PER_SECOND = DAMAGE_PER_SECOND or "Damage per Second:" -- :889
|
||
DPS_TEMPLATE = DPS_TEMPLATE or "(%.1f damage per second)" -- :942
|
||
MELEE_ATTACK = MELEE_ATTACK or "Melee Attack" -- :2680
|
||
MELEE_ATTACK_POWER = MELEE_ATTACK_POWER or "Melee Attack Power" -- :2681
|
||
MELEE_ATTACK_POWER_TOOLTIP = MELEE_ATTACK_POWER_TOOLTIP or
|
||
"Increases damage with melee weapons by %.1f damage per second." -- :2682
|
||
NOT_APPLICABLE = NOT_APPLICABLE or "N/A" -- :2802
|
||
RANGED_ATTACK = RANGED_ATTACK or "Ranged Attack" -- :3292
|
||
RANGED_ATTACK_POWER = RANGED_ATTACK_POWER or "Ranged Attack Power" -- :3293
|
||
RANGED_ATTACK_POWER_TOOLTIP = RANGED_ATTACK_POWER_TOOLTIP or
|
||
"Increases damage with ranged weapons by %.1f damage per second." -- :3294
|
||
RANGED_ATTACK_TOOLTIP = RANGED_ATTACK_TOOLTIP or "Ranged Attack Rating" -- :3295
|
||
INVTYPE_WEAPONMAINHAND = INVTYPE_WEAPONMAINHAND or "Main Hand" -- :2375
|
||
INVTYPE_WEAPONOFFHAND = INVTYPE_WEAPONOFFHAND or "Off Hand" -- :2376
|
||
INVTYPE_RANGED = INVTYPE_RANGED or "Ranged" -- :2366
|
||
|
||
SPELL_STAT0_NAME = SPELL_STAT0_NAME or "Strength" -- :4118
|
||
SPELL_STAT1_NAME = SPELL_STAT1_NAME or "Agility" -- :4119
|
||
SPELL_STAT2_NAME = SPELL_STAT2_NAME or "Stamina" -- :4120
|
||
SPELL_STAT3_NAME = SPELL_STAT3_NAME or "Intellect" -- :4121
|
||
SPELL_STAT4_NAME = SPELL_STAT4_NAME or "Spirit" -- :4122
|
||
|
||
RESISTANCE1_NAME = RESISTANCE1_NAME or "Holy Resistance" -- :3347 (unused: Holy never rides the paper doll)
|
||
RESISTANCE2_NAME = RESISTANCE2_NAME or "Fire Resistance" -- :3348
|
||
RESISTANCE3_NAME = RESISTANCE3_NAME or "Nature Resistance" -- :3349
|
||
RESISTANCE4_NAME = RESISTANCE4_NAME or "Frost Resistance" -- :3350
|
||
RESISTANCE5_NAME = RESISTANCE5_NAME or "Shadow Resistance" -- :3351
|
||
RESISTANCE6_NAME = RESISTANCE6_NAME or "Arcane Resistance" -- :3352
|
||
RESISTANCE_TYPE1 = RESISTANCE_TYPE1 or "holy" -- :3362
|
||
RESISTANCE_TYPE2 = RESISTANCE_TYPE2 or "fire" -- :3363
|
||
RESISTANCE_TYPE3 = RESISTANCE_TYPE3 or "nature" -- :3364
|
||
RESISTANCE_TYPE4 = RESISTANCE_TYPE4 or "frost" -- :3365
|
||
RESISTANCE_TYPE5 = RESISTANCE_TYPE5 or "shadow" -- :3366
|
||
RESISTANCE_TYPE6 = RESISTANCE_TYPE6 or "arcane" -- :3367
|
||
RESISTANCE_EXCELLENT = RESISTANCE_EXCELLENT or "Excellent" -- :3353
|
||
RESISTANCE_VERYGOOD = RESISTANCE_VERYGOOD or "Very Good" -- :3368
|
||
RESISTANCE_GOOD = RESISTANCE_GOOD or "Good" -- :3355
|
||
RESISTANCE_FAIR = RESISTANCE_FAIR or "Fair" -- :3354
|
||
RESISTANCE_POOR = RESISTANCE_POOR or "Poor" -- :3358
|
||
RESISTANCE_NONE = RESISTANCE_NONE or "None" -- :3357
|
||
RESISTANCE_TOOLTIP_SUBTEXT = RESISTANCE_TOOLTIP_SUBTEXT or
|
||
"Increases the ability to resist %s-based attacks, spells and abilities.\nResistance against level %d: |cffffffff%s|r" -- :3360
|
||
|
||
-- Default (class-agnostic) stat tooltips only — see this file's header comment on the
|
||
-- class-specific (WARRIOR_STRENGTH_TOOLTIP, …) omission.
|
||
DEFAULT_STRENGTH_TOOLTIP = DEFAULT_STRENGTH_TOOLTIP or "Increases attack power with melee weapons." -- :916
|
||
DEFAULT_AGILITY_TOOLTIP = DEFAULT_AGILITY_TOOLTIP or
|
||
"Increases attack power with ranged weapons.\nImproves chance to score a critical hit with all weapons.\nIncreases armor and chance to dodge attacks." -- :911
|
||
DEFAULT_STAMINA_TOOLTIP = DEFAULT_STAMINA_TOOLTIP or "Increases health points." -- :915
|
||
DEFAULT_INTELLECT_TOOLTIP = DEFAULT_INTELLECT_TOOLTIP or "Increases the rate at which weapon skills improve." -- :913
|
||
DEFAULT_SPIRIT_TOOLTIP = DEFAULT_SPIRIT_TOOLTIP or "Increases health and mana regeneration rates." -- :914
|
||
|
||
HEADSLOT = HEADSLOT or "Head" -- :2123
|
||
NECKSLOT = NECKSLOT or "Neck" -- :2713
|
||
SHOULDERSLOT = SHOULDERSLOT or "Shoulders" -- :3428
|
||
BACKSLOT = BACKSLOT or "Back" -- :133
|
||
CHESTSLOT = CHESTSLOT or "Chest" -- :746
|
||
SHIRTSLOT = SHIRTSLOT or "Shirt" -- :3427
|
||
TABARDSLOT = TABARDSLOT or "Tabard" -- :4217
|
||
WRISTSLOT = WRISTSLOT or "Wrist" -- :5458
|
||
HANDSSLOT = HANDSSLOT or "Hands" -- :2115
|
||
WAISTSLOT = WAISTSLOT or "Waist" -- :5428
|
||
LEGSSLOT = LEGSSLOT or "Legs" -- :2565
|
||
FEETSLOT = FEETSLOT or "Feet" -- :1967
|
||
FINGER0SLOT = FINGER0SLOT or "Finger" -- :1971
|
||
FINGER1SLOT = FINGER1SLOT or "Finger" -- :1972
|
||
TRINKET0SLOT = TRINKET0SLOT or "Trinket" -- :4313
|
||
TRINKET1SLOT = TRINKET1SLOT or "Trinket" -- :4314
|
||
MAINHANDSLOT = MAINHANDSLOT or "Main Hand" -- :2658
|
||
SECONDARYHANDSLOT = SECONDARYHANDSLOT or "Off Hand" -- :3400
|
||
RANGEDSLOT = RANGEDSLOT or "Ranged" -- :3291
|
||
AMMOSLOT = AMMOSLOT or "Ammo" -- :53
|
||
|
||
-- The font color codes/tables live in our Fonts.xml (the ref's own home for them, l.8-19 —
|
||
-- verified this session), loaded before every window.
|
||
|
||
-- ── This window's own constants (ref-PaperDollFrame.lua:1-4, Benilla-prefixed) ────────────
|
||
BENILLA_NUM_STATS = 5 -- NUM_STATS
|
||
BENILLA_NUM_RESISTANCE_TYPES = 5 -- NUM_RESISTANCE_TYPES
|
||
ATTACK_POWER_MAGIC_NUMBER = 14 -- ATTACK_POWER_MAGIC_NUMBER
|
||
-- MagicResFrame1..5's ref `id=` attrs (ref-PaperDollFrame.xml:654-759) — arcane/fire/nature/
|
||
-- frost/shadow; Holy(1) never rides the paper doll (only 5 of the 6 schools show here).
|
||
BENILLA_MAGICRES_IDS = { 6, 2, 3, 4, 5 }
|
||
-- The window's pages, named exactly as the reference names them
|
||
-- ("PaperDollFrame"/"PetPaperDollFrame"/"ReputationFrame"/"SkillFrame"/"HonorFrame"). 1:1
|
||
-- with the tab row below (index N is tab N's page) — decision 0437 phase 4 added the Skills
|
||
-- page, decision 1057 the Pet one, ReputationFrame.xml took the real client's own slot 3
|
||
-- (which put Skills at the real client's own 4), and HonorFrame.xml takes the 5.
|
||
-- THE ROSTER IS NOW THE REFERENCE'S, WHOLE: five pages, five tabs, no omission left and
|
||
-- nothing past the end. The 0138 merchant-tab precedent ("tabs arrive with their pages") is
|
||
-- what kept this list a prefix of the real one until now, rather than a row of dead tabs.
|
||
-- `character_tests.rs` pins each page's `id=` against its slot here, which is what kept the
|
||
-- two in step as the middle of the row filled in.
|
||
BENILLA_CHARACTERFRAME_SUBFRAMES = {
|
||
"PaperDollFrame", "PetPaperDollFrame", "ReputationFrame", "SkillFrame", "HonorFrame",
|
||
}
|
||
|
||
-- ── The window: toggle / tab dispatch (ref CharacterFrame.lua:1-48) ─────────────────────
|
||
-- Kept BARE (not Benilla-prefixed) — the addon-facing entry point, matching this codebase's
|
||
-- own ToggleQuestLog() precedent (QuestLogFrame.xml).
|
||
function CharacterFrame_ShowSubFrame(frameName)
|
||
for _, value in ipairs(BENILLA_CHARACTERFRAME_SUBFRAMES) do
|
||
-- Nil-guarded: a page's file may not be loaded (a test subset, a later
|
||
-- load-on-demand page) — a missing sibling must never break the switch.
|
||
local page = getglobal(value)
|
||
if page then
|
||
if value == frameName then page:Show() else page:Hide() end
|
||
end
|
||
end
|
||
end
|
||
|
||
function ToggleCharacter(tab)
|
||
local subFrame = getglobal(tab)
|
||
if not subFrame then return end
|
||
-- ref CharacterFrame.lua:4-6, the pet guard: asking for the pet page with no pet does
|
||
-- NOTHING — not even close an open window. The `not IsVisible()` half is what still
|
||
-- lets the page CLOSE itself when the pet vanishes underneath it (the pet page's own
|
||
-- OnEvent calls straight back in here to do exactly that). Hoisted below the getglobal
|
||
-- (the ref tests it above) purely so the visibility read has a frame to ask.
|
||
if tab == "PetPaperDollFrame" and not HasPetUI() and not subFrame:IsVisible() then
|
||
return
|
||
end
|
||
local frame = getglobal("CharacterFrame")
|
||
-- ref CharacterFrame.lua:11, and the line whose absence desynced this window: the tab
|
||
-- row is selected HERE, from the page's own id, on EVERY path — including the one that
|
||
-- closes the window. Having it only on the tab-button OnClick meant a KEYBIND
|
||
-- (`C`/`SHIFT-P`, which call straight in here) switched the page and left the row
|
||
-- selecting the old tab; clicking that old tab then took the "already visible" branch
|
||
-- and shut the window instead of switching back (director, 2026-08-06). The id is the
|
||
-- page's own `id=` attribute — the loader really does apply it (loader/geometry.rs
|
||
-- SetID) — and `character_tests.rs` pins every page's id against its slot in
|
||
-- BENILLA_CHARACTERFRAME_SUBFRAMES, which is what keeps the two in step the day
|
||
-- Reputation lands between them.
|
||
PanelTemplates_SetTab(frame, subFrame:GetID())
|
||
if frame:IsVisible() then
|
||
if subFrame:IsVisible() then
|
||
HideUIPanel(frame)
|
||
else
|
||
PlaySound("igCharacterInfoTab")
|
||
CharacterFrame_ShowSubFrame(tab)
|
||
end
|
||
else
|
||
ShowUIPanel(frame)
|
||
CharacterFrame_ShowSubFrame(tab)
|
||
end
|
||
end
|
||
|
||
-- The tab row's own OnClick (ref CharacterFrameTab_OnClick, l.35-48), now id-based (decision
|
||
-- 0437 phase 4 grows the row to 2) — the MerchantFrame.xml Merchant/Buyback pair's own shape
|
||
-- for a >1-tab window: `id` indexes BOTH the tab button and BENILLA_CHARACTERFRAME_SUBFRAMES
|
||
-- 1:1. It does NOT select the tab itself — the ref's own tab OnClick doesn't either, because
|
||
-- ToggleCharacter is the single place that does it (above), so the click path and the
|
||
-- keybind path cannot disagree. l.47's trailing PlaySound is the ref's OWN redundant second
|
||
-- igCharacterInfoTab — ToggleCharacter already plays it on the "switch to this tab" path, so
|
||
-- this second call only matters when the window is ALREADY open on this same tab, i.e. the
|
||
-- HideUIPanel branch — kept rather than "fixed" since it's the ref's own
|
||
-- behavior, not a bug of ours.
|
||
function BenillaCharacterFrameTab_OnClick(id)
|
||
ToggleCharacter(BENILLA_CHARACTERFRAME_SUBFRAMES[id])
|
||
PlaySound("igCharacterInfoTab")
|
||
end
|
||
|
||
function CharacterFrame_OnLoad()
|
||
local frame = this
|
||
-- GetID()/SetID() DO exist (landed with slice 2's BagFrame, which relies on them for
|
||
-- its own per-window bag id) — the STALE claim this comment used to make is corrected
|
||
-- here (0208 phase 1b touched this function anyway). All 5 tabs ship with the Honor
|
||
-- page (Character + Pet + Reputation + Skills + Honor — the reference's own five); the
|
||
-- window opens on tab 1 by default, matching the real client. Tab 2 raises and hides
|
||
-- itself with the pet — PetTab_Update, which the pet page runs at its own OnLoad and on
|
||
-- every pet transition — so the COUNT here is the full row, not the currently-visible
|
||
-- one, which is why this number reaches the ref's own SetNumTabs(5) rather than
|
||
-- tracking what is on screen.
|
||
PanelTemplates_SetNumTabs(frame, 5)
|
||
PanelTemplates_SetTab(frame, 1)
|
||
-- The reference LABELS its numerals here (CharacterFrame_OnLoad l.55-57: "Health" on
|
||
-- the player's health bar, "XP" on the XP bar, with the power bar's following the
|
||
-- resource in UnitFrames.xml). Shipped in 1146 and cut the same day on the director's
|
||
-- call — bare numbers read better on our bars (decision 1147). The mechanism is
|
||
-- untouched and live: SetTextStatusBarTextPrefix works, and restoring any one of the
|
||
-- three is the one line the reference has. If it is ever restored, note the ordering
|
||
-- it depends on — a prefix only sticks on a bar that already has its TextString, and
|
||
-- this file's seat works only because the manifest runs UnitFrames (52) and ActionBar
|
||
-- (76) well ahead of it (149), exactly as FrameXML runs PlayerFrame (44) and
|
||
-- MainMenuBar (34) ahead of CharacterFrame (53).
|
||
end
|
||
|
||
-- ref CharacterFrame_OnShow (l.82-93). The Show*TextStatusBarText calls are LIVE as of
|
||
-- decision 1146 — the note that used to sit here ("no unit-frame bar-text-mode toggle
|
||
-- exists in this engine") was true when it was written and stopped being true when the
|
||
-- numerals landed (1143). Opening the character sheet reveals your own and your pet's
|
||
-- numbers for as long as it is open, whatever Status Bar Text says, through the same
|
||
-- lockShow refcount the hover uses — so a hover inside an open sheet still balances.
|
||
-- ShowWatchedReputationBarText is LIVE too, since the Reputation tab landed and with it a
|
||
-- driven watch bar (ActionBar.xml owns both, its own placement note says why): opening the
|
||
-- sheet reveals the watched faction's numbers for as long as it is open, exactly like the
|
||
-- five bars above. Guarded on existence like its neighbours — the engine's per-window
|
||
-- harnesses load this file without ActionBar.xml.
|
||
-- UnitPVPName -> plain UnitName (this file's header comment: PVP rank is a named deferral).
|
||
function CharacterFrame_OnShow()
|
||
if UpdateMicroButtons then UpdateMicroButtons() end
|
||
PlaySound("igCharacterInfoOpen")
|
||
SetPortraitTexture(getglobal("CharacterFramePortrait"), "player")
|
||
getglobal("CharacterNameText"):SetText(UnitName("player"))
|
||
if ShowTextStatusBarText then -- engine tests load file subsets
|
||
ShowTextStatusBarText(PlayerFrameHealthBar)
|
||
ShowTextStatusBarText(PlayerFrameManaBar)
|
||
ShowTextStatusBarText(MainMenuExpBar)
|
||
ShowTextStatusBarText(PetFrameHealthBar)
|
||
ShowTextStatusBarText(PetFrameManaBar)
|
||
end
|
||
if ShowWatchedReputationBarText then
|
||
ShowWatchedReputationBarText()
|
||
end
|
||
end
|
||
|
||
-- ref CharacterFrame_OnHide (l.95-104): everything past the PlaySound is the OnShow list's
|
||
-- Hide-twin — UpdateMicroButtons live (MicroMenu.xml), the bar-text calls live too (1146),
|
||
-- and the reputation one live since the watch bar started being driven. The subframe hide-loop is OUR OWN addition
|
||
-- (decision 0437 phase 4): PaperDollFrame is a true engine child of this frame (its
|
||
-- own header comment) so it hides for free on the parent's Hide-cascade, but
|
||
-- SkillFrame is a SEPARATE top-level file — this engine has no cross-file `parent=`
|
||
-- attachment (grepped `benilla-ui/src/loader`: the XML `parent=` attribute is read nowhere,
|
||
-- unlike `relativeTo`, which resolves by name regardless of tree position — see
|
||
-- SkillFrame.xml's own header comment) — so nothing else would hide it when the WHOLE
|
||
-- character window closes (ESC, the close X, or another left-slot window bumping it via
|
||
-- UIPanel exclusivity). Looping every BENILLA_CHARACTERFRAME_SUBFRAMES entry here, once, is
|
||
-- what carried that correctness through every non-nested tab that followed — Pet,
|
||
-- Reputation and now Honor, all four of the five pages that are separate files.
|
||
function CharacterFrame_OnHide()
|
||
if UpdateMicroButtons then UpdateMicroButtons() end
|
||
PlaySound("igCharacterInfoClose")
|
||
if HideTextStatusBarText then -- engine tests load file subsets
|
||
HideTextStatusBarText(PlayerFrameHealthBar)
|
||
HideTextStatusBarText(PlayerFrameManaBar)
|
||
HideTextStatusBarText(MainMenuExpBar)
|
||
HideTextStatusBarText(PetFrameHealthBar)
|
||
HideTextStatusBarText(PetFrameManaBar)
|
||
end
|
||
if HideWatchedReputationBarText then
|
||
HideWatchedReputationBarText()
|
||
end
|
||
for _, name in ipairs(BENILLA_CHARACTERFRAME_SUBFRAMES) do
|
||
local subFrame = getglobal(name)
|
||
if subFrame then subFrame:Hide() end
|
||
end
|
||
end
|
||
|
||
-- ── The paper-doll page (ref PaperDollFrame.lua) ────────────────────────────────────────
|
||
-- ref PaperDollFrame_OnLoad (l.6-29), the label lines (l.7-13) kept as the ref has them: the
|
||
-- labels live ONLY in the row template's $parentLabel (gold GameFontNormalSmall, LEFT) and
|
||
-- Lua fills them — never a re-declared region in an instance (the ref's instances carry no
|
||
-- <Layers> at all, and this engine's template expansion appends children, so a re-declared
|
||
-- $parentLabel creates a SECOND anchorless default-font FontString instead of merging — the
|
||
-- white/overlapping-label bug this line-set replaces). CHARACTER_POINTS_CHANGED/
|
||
-- UNIT_MODEL_CHANGED/PLAYER_DAMAGE_DONE_MODS/UNIT_RANGEDDAMAGE/PLAYER_GUILD_UPDATE/
|
||
-- SKILL_LINES_CHANGED are OMITTED (talents/guild/skills are out of this phase's event
|
||
-- contract; UNIT_RANGEDDAMAGE isn't in it either — UNIT_DAMAGE/UNIT_ATTACK_SPEED alone
|
||
-- trigger the ranged refresh below, same as the ref's own first branch already does).
|
||
function PaperDollFrame_OnLoad()
|
||
local frame = this
|
||
getglobal("CharacterAttackFrameLabel"):SetText(MELEE_ATTACK)
|
||
getglobal("CharacterDamageFrameLabel"):SetText(DAMAGE_COLON)
|
||
getglobal("CharacterAttackPowerFrameLabel"):SetText(ATTACK_POWER_COLON)
|
||
getglobal("CharacterRangedAttackFrameLabel"):SetText(RANGED_ATTACK)
|
||
getglobal("CharacterRangedDamageFrameLabel"):SetText(DAMAGE_COLON)
|
||
getglobal("CharacterRangedAttackPowerFrameLabel"):SetText(ATTACK_POWER_COLON)
|
||
getglobal("CharacterArmorFrameLabel"):SetText(ARMOR_COLON)
|
||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||
frame:RegisterEvent("UNIT_LEVEL")
|
||
frame:RegisterEvent("UNIT_RESISTANCES")
|
||
frame:RegisterEvent("UNIT_STATS")
|
||
frame:RegisterEvent("UNIT_DAMAGE")
|
||
frame:RegisterEvent("UNIT_ATTACK_SPEED")
|
||
frame:RegisterEvent("UNIT_ATTACK_POWER")
|
||
frame:RegisterEvent("UNIT_RANGED_ATTACK_POWER")
|
||
frame:RegisterEvent("UNIT_ATTACK")
|
||
end
|
||
|
||
-- Every row of the sheet, in the order a full repaint fills them. The order is load-bearing
|
||
-- at the ranged end: SetRangedAttack is what decides `PaperDollFrame.noRanged`, and the two
|
||
-- ranged rows after it read that flag rather than re-deciding it.
|
||
--
|
||
-- Rows are NAMED, not referenced. Resolving each through the global table at call time is
|
||
-- what the reference's own call-by-name got for free, and the paper-doll setters are prime
|
||
-- addon-hook territory: a table of captured function values would keep calling the setter an
|
||
-- addon replaced.
|
||
local paperDollRows = {
|
||
"PaperDollFrame_SetLevel",
|
||
"PaperDollFrame_SetStats",
|
||
"PaperDollFrame_SetResistances",
|
||
"PaperDollFrame_SetArmor",
|
||
"PaperDollFrame_SetDamage",
|
||
"PaperDollFrame_SetAttackPower",
|
||
"PaperDollFrame_SetAttackBothHands",
|
||
"PaperDollFrame_SetRangedAttack",
|
||
"PaperDollFrame_SetRangedDamage",
|
||
"PaperDollFrame_SetRangedAttackPower",
|
||
}
|
||
|
||
-- A weapon that changed how hard it hits and one that changed how often move the same four
|
||
-- rows, so the two events share a list rather than a copy of one.
|
||
local weaponRows = {
|
||
"PaperDollFrame_SetDamage",
|
||
"PaperDollFrame_SetRangedAttack",
|
||
"PaperDollFrame_SetRangedDamage",
|
||
"PaperDollFrame_SetAttackBothHands",
|
||
}
|
||
|
||
-- Which rows a single change moves, keyed by the event reporting it. The reference spells
|
||
-- this out as an if/elseif ladder and then keeps a second, hand-parallel copy of the row
|
||
-- order in OnShow; one table read two ways cannot drift the way two call lists do.
|
||
--
|
||
-- Only this file's registered subset appears (see PaperDollFrame_OnLoad's note on the
|
||
-- omitted events). PLAYER_ENTERING_WORLD is registered and deliberately absent: the ref's
|
||
-- one use for it is `CharacterModelFrame:SetUnit("player")`, and our CharacterModelFrame is
|
||
-- a booth-texture stand-in rather than a live model widget (this file's header) — there is
|
||
-- no SetUnit to call. It keeps its early return below rather than a row here, because the
|
||
-- reference returns on it before even the visibility check.
|
||
local rowsMovedBy = {
|
||
UNIT_LEVEL = { "PaperDollFrame_SetLevel" },
|
||
UNIT_STATS = { "PaperDollFrame_SetStats" },
|
||
UNIT_RESISTANCES = { "PaperDollFrame_SetResistances", "PaperDollFrame_SetArmor" },
|
||
UNIT_ATTACK = { "PaperDollFrame_SetAttackBothHands" },
|
||
UNIT_ATTACK_POWER = { "PaperDollFrame_SetAttackPower" },
|
||
UNIT_DAMAGE = weaponRows,
|
||
UNIT_ATTACK_SPEED = weaponRows,
|
||
UNIT_RANGED_ATTACK_POWER = {
|
||
"PaperDollFrame_SetRangedAttack", "PaperDollFrame_SetRangedAttackPower",
|
||
},
|
||
}
|
||
|
||
local function paintRows(rows)
|
||
for i = 1, table.getn(rows) do
|
||
getglobal(rows[i])()
|
||
end
|
||
end
|
||
|
||
-- `unit` is the DECLARED second parameter, not the `arg1` global: the XML passes `arg1` into
|
||
-- it exactly as the reference's own does (PaperDollFrame.xml), so an addon calling the 1.12
|
||
-- arity is read correctly rather than off a stale global. Only the player's own sheet is
|
||
-- driven from here (no pet/other-unit reuse in phase 1a), and only while it is on screen —
|
||
-- a hidden page is repainted wholesale by OnShow when it comes back.
|
||
function PaperDollFrame_OnEvent(event, unit)
|
||
if event == "PLAYER_ENTERING_WORLD" then
|
||
return
|
||
end
|
||
if not this:IsVisible() then return end
|
||
if unit ~= "player" then return end
|
||
local rows = rowsMovedBy[event]
|
||
if rows then
|
||
paintRows(rows)
|
||
end
|
||
end
|
||
|
||
-- ref PaperDollFrame_OnShow (l.568-585): SetGuild OMITTED (named deferral, this file's
|
||
-- header). The relic Hide/Show branch is DROPPED outright — UnitHasRelicSlot is
|
||
-- vanilla-always-false, so CharacterAmmoSlot simply never has a reason to hide; it ships
|
||
-- with no hidden="true" at all (see its own Button below).
|
||
function PaperDollFrame_OnShow()
|
||
paintRows(paperDollRows)
|
||
end
|
||
-- ref PaperDollFrame_OnHide (l.587-592) is entirely commented-out in the ref itself (the
|
||
-- ShoppingTooltip/compare-tooltip lines, OMIT) — nothing to transcribe, no OnHide wired.
|
||
|
||
-- UnitRace/UnitClass return nil,nil until the app's first player snapshot lands (unlike the
|
||
-- real client, whose race/class are synchronous local data, never network-raced) — "?" is a
|
||
-- harmless placeholder for that one-tick window, not a fidelity change (verified live: an
|
||
-- unguarded format() errors "string expected, got nil" the instant this fires before the
|
||
-- first snapshot).
|
||
function PaperDollFrame_SetLevel()
|
||
getglobal("CharacterLevelText"):SetText(
|
||
format(PLAYER_LEVEL, UnitLevel("player"), UnitRace("player") or "?", UnitClass("player") or "?"))
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetStats (l.131-174), including its per-refresh label SetText (l.140)
|
||
-- — the labels' one source of text (see PaperDollFrame_OnLoad's header comment).
|
||
function PaperDollFrame_SetStats()
|
||
for i = 1, BENILLA_NUM_STATS do
|
||
local label = getglobal("CharacterStatFrame" .. i .. "Label")
|
||
local text = getglobal("CharacterStatFrame" .. i .. "StatText")
|
||
local frame = getglobal("CharacterStatFrame" .. i)
|
||
local statName = getglobal("SPELL_STAT" .. (i - 1) .. "_NAME")
|
||
label:SetText(statName .. ":")
|
||
local stat, effectiveStat, posBuff, negBuff = UnitStat("player", i)
|
||
local tooltipText = HIGHLIGHT_FONT_COLOR_CODE .. statName .. " "
|
||
if posBuff == 0 and negBuff == 0 then
|
||
text:SetText(effectiveStat)
|
||
frame.tooltip = tooltipText .. effectiveStat .. FONT_COLOR_CODE_CLOSE
|
||
else
|
||
tooltipText = tooltipText .. effectiveStat
|
||
if posBuff > 0 or negBuff < 0 then
|
||
tooltipText = tooltipText .. " (" .. (stat - posBuff - negBuff) .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if posBuff > 0 then
|
||
tooltipText = tooltipText .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. posBuff .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if negBuff < 0 then
|
||
tooltipText = tooltipText .. RED_FONT_COLOR_CODE .. " " .. negBuff .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if posBuff > 0 or negBuff < 0 then
|
||
tooltipText = tooltipText .. HIGHLIGHT_FONT_COLOR_CODE .. ")" .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
frame.tooltip = tooltipText
|
||
if negBuff < 0 then
|
||
text:SetText(RED_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE)
|
||
else
|
||
text:SetText(GREEN_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- One word for how well a school is covered, from resistance-per-level. The bands descend,
|
||
-- so the first threshold cleared names it and a ratio of zero or less clears none of them.
|
||
-- (The reference leaves the answer in an implicit global; a pure function of the ratio is
|
||
-- both the honest shape and one less name in our sandboxed globals table.)
|
||
local function resistanceBand(ratio)
|
||
if ratio > 5 then return RESISTANCE_EXCELLENT end
|
||
if ratio > 3.75 then return RESISTANCE_VERYGOOD end
|
||
if ratio > 2.5 then return RESISTANCE_GOOD end
|
||
if ratio > 1.25 then return RESISTANCE_FAIR end
|
||
if ratio > 0 then return RESISTANCE_POOR end
|
||
return RESISTANCE_NONE
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetResistances (l.176-228).
|
||
function PaperDollFrame_SetResistances()
|
||
for i = 1, BENILLA_NUM_RESISTANCE_TYPES do
|
||
local resistId = BENILLA_MAGICRES_IDS[i]
|
||
local text = getglobal("MagicResText" .. i)
|
||
local frame = getglobal("MagicResFrame" .. i)
|
||
local base, resistance, positive, negative = UnitResistance("player", resistId)
|
||
local resistanceName = getglobal("RESISTANCE" .. resistId .. "_NAME")
|
||
frame.tooltip = resistanceName .. " " .. resistance
|
||
if math.abs(negative) > positive then
|
||
text:SetText(RED_FONT_COLOR_CODE .. resistance .. FONT_COLOR_CODE_CLOSE)
|
||
elseif math.abs(negative) == positive then
|
||
text:SetText(resistance)
|
||
else
|
||
text:SetText(GREEN_FONT_COLOR_CODE .. resistance .. FONT_COLOR_CODE_CLOSE)
|
||
end
|
||
if positive ~= 0 or negative ~= 0 then
|
||
frame.tooltip = frame.tooltip .. " ( " .. HIGHLIGHT_FONT_COLOR_CODE .. base
|
||
if positive > 0 then
|
||
frame.tooltip = frame.tooltip .. GREEN_FONT_COLOR_CODE .. " +" .. positive
|
||
end
|
||
if negative < 0 then
|
||
frame.tooltip = frame.tooltip .. " " .. RED_FONT_COLOR_CODE .. negative
|
||
end
|
||
frame.tooltip = frame.tooltip .. FONT_COLOR_CODE_CLOSE .. " )"
|
||
end
|
||
-- The divisor floors at 20 because the reference does (l.210-211: it reads the level,
|
||
-- then clamps on the NEXT line — an earlier note here cited l.210 alone and called
|
||
-- the floor ours). The `or 1` is the only difference: the ref would error on a nil
|
||
-- level, and nothing is gained by reproducing that.
|
||
local unitLevel = math.max(UnitLevel("player") or 1, 20)
|
||
frame.tooltipSubtext = format(RESISTANCE_TOOLTIP_SUBTEXT,
|
||
getglobal("RESISTANCE_TYPE" .. resistId), unitLevel,
|
||
resistanceBand(resistance / unitLevel))
|
||
end
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetArmor (l.230-250). NOTE the ref's own third UnitArmor return
|
||
-- (`armor`) is unused here too — PaperDollFormatStat gets `base`, not `armor`; the ref's
|
||
-- behavior kept, not "fixed".
|
||
function PaperDollFrame_SetArmor(unit, prefix)
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local base, effectiveArmor, armor, posBuff, negBuff = UnitArmor(unit)
|
||
local frame = getglobal(prefix .. "ArmorFrame")
|
||
local text = getglobal(prefix .. "ArmorFrameStatText")
|
||
PaperDollFormatStat(ARMOR, base, posBuff, negBuff, frame, text)
|
||
local playerLevel = UnitLevel(unit)
|
||
local armorReduction = effectiveArmor / ((85 * playerLevel) + 400)
|
||
armorReduction = 100 * (armorReduction / (armorReduction + 1))
|
||
frame.tooltipSubtext = format(ARMOR_TOOLTIP, playerLevel, armorReduction)
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetDefense (l.252-272). Shared like every setter around it, but the
|
||
-- CHARACTER sheet has no defense row — the real client's doesn't either, and this exists
|
||
-- solely for the pet page (decision 1057), which is why it arrives now and not in 0208.
|
||
-- `UnitDefense`'s second return is a single signed modifier, not the pos/neg pair the other
|
||
-- setters get, so the split into posBuff/negBuff happens here.
|
||
function PaperDollFrame_SetDefense(unit, prefix)
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local base, modifier = UnitDefense(unit)
|
||
local frame = getglobal(prefix .. "DefenseFrame")
|
||
local text = getglobal(prefix .. "DefenseFrameStatText")
|
||
-- The sign is all that decides which side of the pair the one modifier lands on, and a
|
||
-- modifier of zero lands on neither.
|
||
PaperDollFormatStat(DEFENSE_COLON, base, math.max(modifier, 0), math.min(modifier, 0),
|
||
frame, text)
|
||
end
|
||
|
||
-- ── Weapon swings: the arithmetic and the wording, once ────────────────────────────────────
|
||
-- Three rows read a swing — main hand, off hand, ranged — and it is the same calculation
|
||
-- with the same vocabulary each time, so it lives here instead of two and three times over.
|
||
|
||
-- The sheet's green and red for damage figures. Byte-identical to Fonts.xml's GREEN/RED
|
||
-- font-colour codes today, and kept separate on purpose: these are the damage row's own
|
||
-- colours, and reading them off the font palette would tie one to the other.
|
||
local DAMAGE_UP_COLOR = "|cff20ff20"
|
||
local DAMAGE_DOWN_COLOR = "|cffff2020"
|
||
|
||
-- What the weapon itself swings for. The numbers we are handed already have the flat
|
||
-- physical bonuses added and the percent multiplier applied; the row shows those, but the
|
||
-- tooltip breaks out where they came from, so the un-modified swing has to be recovered.
|
||
-- Returns that raw range, the modified average, and the gap the modifiers make between them.
|
||
local function unscaleSwing(minDamage, maxDamage, bonusPos, bonusNeg, percent)
|
||
local rawMin = (minDamage / percent) - bonusPos - bonusNeg
|
||
local rawMax = (maxDamage / percent) - bonusPos - bonusNeg
|
||
local baseDamage = (rawMin + rawMax) * 0.5
|
||
local fullDamage = (baseDamage + bonusPos + bonusNeg) * percent
|
||
return rawMin, rawMax, fullDamage, fullDamage - baseDamage
|
||
end
|
||
|
||
-- Both ends of a swing, rounded outwards and floored at 1 — a weapon swinging for a
|
||
-- fraction of a point still reads as a weapon.
|
||
local function swingBounds(minDamage, maxDamage)
|
||
return math.max(math.floor(minDamage), 1), math.max(math.ceil(maxDamage), 1)
|
||
end
|
||
|
||
-- The range as a tooltip writes it, always spaced.
|
||
local function damageRange(minDamage, maxDamage)
|
||
local low, high = swingBounds(minDamage, maxDamage)
|
||
return low .. " - " .. high
|
||
end
|
||
|
||
-- The range as the ROW writes it: spaced while both ends are two digits, tightened up once
|
||
-- either reaches three and the row starts running out of width.
|
||
local function damageFigure(minDamage, maxDamage)
|
||
local low, high = swingBounds(minDamage, maxDamage)
|
||
if low < 100 and high < 100 then
|
||
return low .. " - " .. high
|
||
end
|
||
return low .. "-" .. high
|
||
end
|
||
|
||
-- The tooltip's account of what modified the raw range: the flat bonus, then the multiplier,
|
||
-- each coloured by which way it went and left out entirely when it is not in play.
|
||
local function damageModifiers(tooltip, bonusPos, bonusNeg, percent)
|
||
if bonusPos > 0 then
|
||
tooltip = tooltip .. DAMAGE_UP_COLOR .. " +" .. bonusPos .. "|r"
|
||
end
|
||
if bonusNeg < 0 then
|
||
tooltip = tooltip .. DAMAGE_DOWN_COLOR .. " " .. bonusNeg .. "|r"
|
||
end
|
||
if percent > 1 then
|
||
tooltip = tooltip .. DAMAGE_UP_COLOR .. " x" .. math.floor(percent * 100 + 0.5) .. "%|r"
|
||
elseif percent < 1 then
|
||
tooltip = tooltip .. DAMAGE_DOWN_COLOR .. " x" .. math.floor(percent * 100 + 0.5) .. "%|r"
|
||
end
|
||
return tooltip
|
||
end
|
||
|
||
-- Which way a modified figure is tinted. Only asked once a caller knows something modified
|
||
-- it, so a zero bonus never reaches here and has no colour of its own.
|
||
local function damageColor(totalBonus)
|
||
if totalBonus > 0 then
|
||
return DAMAGE_UP_COLOR
|
||
end
|
||
return DAMAGE_DOWN_COLOR
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetDamage (l.274-372). The off hand is the same swing read twice: the
|
||
-- flat bonuses and the multiplier are the character's, not the weapon's, so both hands take
|
||
-- them, and only the speed and the raw range differ.
|
||
function PaperDollFrame_SetDamage(unit, prefix)
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local damageText = getglobal(prefix .. "DamageFrameStatText")
|
||
local damageFrame = getglobal(prefix .. "DamageFrame")
|
||
local speed, offhandSpeed = UnitAttackSpeed(unit)
|
||
local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent =
|
||
UnitDamage(unit)
|
||
local figure = damageFigure(minDamage, maxDamage)
|
||
local rawMin, rawMax, fullDamage, totalBonus =
|
||
unscaleSwing(minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent)
|
||
local damageTooltip = damageRange(rawMin, rawMax)
|
||
if totalBonus == 0 then
|
||
damageText:SetText(figure)
|
||
else
|
||
damageText:SetText(damageColor(totalBonus) .. figure .. "|r")
|
||
damageTooltip =
|
||
damageModifiers(damageTooltip, physicalBonusPos, physicalBonusNeg, percent)
|
||
end
|
||
damageFrame.damage = damageTooltip
|
||
damageFrame.attackSpeed = speed
|
||
damageFrame.dps = math.max(fullDamage, 1) / speed
|
||
if offhandSpeed then
|
||
local offMin, offMax, offhandFullDamage = unscaleSwing(
|
||
minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent)
|
||
-- The off hand gets its breakdown unconditionally: it has no row of its own to keep
|
||
-- plain, only the tooltip's second half.
|
||
damageFrame.offhandDamage = damageModifiers(damageRange(offMin, offMax),
|
||
physicalBonusPos, physicalBonusNeg, percent)
|
||
damageFrame.offhandAttackSpeed = offhandSpeed
|
||
damageFrame.offhandDps = math.max(offhandFullDamage, 1) / offhandSpeed
|
||
else
|
||
damageFrame.offhandAttackSpeed = nil
|
||
end
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetAttackPower (l.374-389).
|
||
function PaperDollFrame_SetAttackPower(unit, prefix)
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local base, posBuff, negBuff = UnitAttackPower(unit)
|
||
local frame = getglobal(prefix .. "AttackPowerFrame")
|
||
local text = getglobal(prefix .. "AttackPowerFrameStatText")
|
||
PaperDollFormatStat(MELEE_ATTACK_POWER, base, posBuff, negBuff, frame, text)
|
||
frame.tooltipSubtext = format(MELEE_ATTACK_POWER_TOOLTIP,
|
||
math.max(base + posBuff + negBuff, 0) / ATTACK_POWER_MAGIC_NUMBER)
|
||
end
|
||
|
||
-- An attack rating and whatever is moving it, on one row. Nothing moving it means the bare
|
||
-- number and no hover plate to explain; otherwise the row carries the modified TOTAL, tinted
|
||
-- by which way it went, and the plate carries the split that produced it. Both the melee row
|
||
-- and the ranged row read exactly this way.
|
||
local function setAttackRating(frame, text, base, modifier)
|
||
if modifier == 0 then
|
||
text:SetText(base)
|
||
frame.tooltip = nil
|
||
return
|
||
end
|
||
local color = RED_FONT_COLOR_CODE
|
||
local sign = " "
|
||
if modifier > 0 then
|
||
color = GREEN_FONT_COLOR_CODE
|
||
sign = " +"
|
||
end
|
||
frame.tooltip = base .. color .. sign .. modifier .. FONT_COLOR_CODE_CLOSE
|
||
text:SetText(color .. (base + modifier) .. FONT_COLOR_CODE_CLOSE)
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetAttackBothHands (l.391-417) — the weapon-skill line (decision 0208's
|
||
-- own "to confirm": the equipped-weapon subclass -> skill-id table is UnitAttackBothHands's
|
||
-- own concern, not this file's).
|
||
function PaperDollFrame_SetAttackBothHands(unit, prefix)
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local mainHandAttackBase, mainHandAttackMod = UnitAttackBothHands(unit)
|
||
setAttackRating(getglobal(prefix .. "AttackFrame"),
|
||
getglobal(prefix .. "AttackFrameStatText"), mainHandAttackBase, mainHandAttackMod)
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetRangedAttack (l.419-466). `hasRelic`/UnitHasRelicSlot DROPPED
|
||
-- outright (this file's header comment: vanilla-always-false, dead code in the ref itself).
|
||
-- The literal slot id 18 is the ref's OWN hardcoded value (l.435) — quoted verbatim; what
|
||
-- GetInventoryItemTexture resolves id 18 to is the parallel binding's call, not re-derived
|
||
-- here.
|
||
function PaperDollFrame_SetRangedAttack(unit, prefix)
|
||
if unit == "pet" then return end
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local frame = getglobal(prefix .. "RangedAttackFrame")
|
||
local text = getglobal(prefix .. "RangedAttackFrameStatText")
|
||
local paperDoll = getglobal("PaperDollFrame")
|
||
local rangedAttackBase, rangedAttackMod = UnitRangedAttack(unit)
|
||
local rangedTexture = GetInventoryItemTexture("player", 18)
|
||
local oldValue = paperDoll.noRanged
|
||
if rangedTexture then
|
||
paperDoll.noRanged = nil
|
||
else
|
||
text:SetText(NOT_APPLICABLE)
|
||
paperDoll.noRanged = true
|
||
frame.tooltip = nil
|
||
end
|
||
if oldValue ~= paperDoll.noRanged then
|
||
PaperDollFrame_SetRangedAttackPower()
|
||
PaperDollFrame_SetRangedDamage()
|
||
end
|
||
if not rangedTexture then return end
|
||
setAttackRating(frame, text, rangedAttackBase, rangedAttackMod)
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetRangedDamage (l.468-537).
|
||
function PaperDollFrame_SetRangedDamage(unit, prefix)
|
||
if unit == "pet" then return end
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local damageText = getglobal(prefix .. "RangedDamageFrameStatText")
|
||
local damageFrame = getglobal(prefix .. "RangedDamageFrame")
|
||
local paperDoll = getglobal("PaperDollFrame")
|
||
if paperDoll.noRanged then
|
||
damageText:SetText(NOT_APPLICABLE)
|
||
damageFrame.damage = nil
|
||
return
|
||
end
|
||
local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent =
|
||
UnitRangedDamage(unit)
|
||
local figure = damageFigure(minDamage, maxDamage)
|
||
local rawMin, rawMax, fullDamage, totalBonus =
|
||
unscaleSwing(minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent)
|
||
local damagePerSecond = math.max(fullDamage, 1) / rangedAttackSpeed
|
||
local tooltip = damageRange(rawMin, rawMax)
|
||
if totalBonus == 0 then
|
||
damageText:SetText(figure)
|
||
else
|
||
damageText:SetText(damageColor(totalBonus) .. figure .. "|r")
|
||
tooltip = damageModifiers(tooltip, physicalBonusPos, physicalBonusNeg, percent)
|
||
-- Only the modified case gets a hover plate here: an unmodified bow has nothing to
|
||
-- explain beyond the figure already on the row.
|
||
damageFrame.tooltip = tooltip .. " " .. format(DPS_TEMPLATE, damagePerSecond)
|
||
end
|
||
damageFrame.attackSpeed = rangedAttackSpeed
|
||
damageFrame.damage = tooltip
|
||
damageFrame.dps = damagePerSecond
|
||
end
|
||
|
||
-- ref PaperDollFrame_SetRangedAttackPower (l.539-566).
|
||
function PaperDollFrame_SetRangedAttackPower(unit, prefix)
|
||
if unit == "pet" then return end
|
||
unit = unit or "player"
|
||
prefix = prefix or "Character"
|
||
local frame = getglobal(prefix .. "RangedAttackPowerFrame")
|
||
local text = getglobal(prefix .. "RangedAttackPowerFrameStatText")
|
||
local paperDoll = getglobal("PaperDollFrame")
|
||
if paperDoll.noRanged then
|
||
text:SetText(NOT_APPLICABLE)
|
||
frame.tooltip = nil
|
||
return
|
||
end
|
||
if HasWandEquipped() then
|
||
text:SetText("--")
|
||
frame.tooltip = nil
|
||
return
|
||
end
|
||
local base, posBuff, negBuff = UnitRangedAttackPower(unit)
|
||
PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, frame, text)
|
||
frame.tooltipSubtext = format(RANGED_ATTACK_POWER_TOOLTIP,
|
||
math.max(base + posBuff + negBuff, 0) / ATTACK_POWER_MAGIC_NUMBER)
|
||
end
|
||
|
||
-- ref PaperDollFormatStat (l.804-833).
|
||
function PaperDollFormatStat(name, base, posBuff, negBuff, frame, textString)
|
||
local effective = math.max(0, base + posBuff + negBuff)
|
||
local text = HIGHLIGHT_FONT_COLOR_CODE .. name .. " " .. effective
|
||
if posBuff == 0 and negBuff == 0 then
|
||
text = text .. FONT_COLOR_CODE_CLOSE
|
||
textString:SetText(effective)
|
||
else
|
||
if posBuff > 0 or negBuff < 0 then
|
||
text = text .. " (" .. base .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if posBuff > 0 then
|
||
text = text .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. posBuff .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if negBuff < 0 then
|
||
text = text .. RED_FONT_COLOR_CODE .. " " .. negBuff .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if posBuff > 0 or negBuff < 0 then
|
||
text = text .. HIGHLIGHT_FONT_COLOR_CODE .. ")" .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
if negBuff < 0 then
|
||
textString:SetText(RED_FONT_COLOR_CODE .. effective .. FONT_COLOR_CODE_CLOSE)
|
||
else
|
||
textString:SetText(GREEN_FONT_COLOR_CODE .. effective .. FONT_COLOR_CODE_CLOSE)
|
||
end
|
||
end
|
||
frame.tooltip = text
|
||
end
|
||
|
||
-- ref PaperDollStatTooltip(unit, stat) (l.786-802), signature-exact: the button is the
|
||
-- ambient `this` the reference reads, NOT a leading parameter, and `unit` leads `stat`
|
||
-- exactly as the ref declares them (its pet rows pass "pet" — ref PetPaperDollFrame.xml:345;
|
||
-- ours likewise, decision 1057). A leading frame parameter here was a wrong SHAPE behind a
|
||
-- right name — 1199's failure mode — because an addon calls the 1.12 arity.
|
||
function PaperDollStatTooltip(unit, stat)
|
||
local button = this
|
||
-- classFileName nil until the first player snapshot lands (this file's SetLevel comment
|
||
-- on the same engine timing gap) — "" just misses every class lookup, falling through to
|
||
-- DEFAULT_*_TOOLTIP below exactly like an unrecognized class would. A pet has no class
|
||
-- either, so the pet rows land on the same DEFAULT_* fallback the ref gives them.
|
||
local _, classFileName = UnitClass(unit or "player")
|
||
classFileName = classFileName or ""
|
||
local classStatText = getglobal(strupper(classFileName) .. "_" .. stat .. "_TOOLTIP")
|
||
if not classStatText then
|
||
classStatText = getglobal("DEFAULT_" .. stat .. "_TOOLTIP")
|
||
end
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(button.tooltip)
|
||
GameTooltip:AddLine(classStatText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
-- ref CharacterDamageFrame_OnEnter (l.835-851).
|
||
function CharacterDamageFrame_OnEnter()
|
||
local button = this
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(ATTACK_SPEED_COLON, string.format("%.2f", button.attackSpeed),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_COLON, button.damage,
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_PER_SECOND, string.format("%.1f", button.dps),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
if button.offhandAttackSpeed then
|
||
GameTooltip:AddLine(" ")
|
||
GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(ATTACK_SPEED_COLON, string.format("%.2f", button.offhandAttackSpeed),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_COLON, button.offhandDamage,
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_PER_SECOND, string.format("%.1f", button.offhandDps),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
end
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
-- ref CharacterRangedDamageFrame_OnEnter (l.853-863).
|
||
function CharacterRangedDamageFrame_OnEnter()
|
||
local button = this
|
||
if not button.damage then return end
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(INVTYPE_RANGED, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(ATTACK_SPEED_COLON, string.format("%.2f", button.attackSpeed),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_COLON, button.damage,
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:AddDoubleLine(DAMAGE_PER_SECOND, string.format("%.1f", button.dps),
|
||
NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
-- ── The 19 equipment slots + ammo (ref PaperDollItemSlotButton_*, l.78-98/594-784) ──────
|
||
-- Cooldowns, the broken-red tint, and SHOW_COMPARE_TOOLTIP are still OMITTED this phase —
|
||
-- this file's header comment. What ships now (1b): the icon/count fill, the empty-slot
|
||
-- art, the hover tooltip, click-to-equip/-use (l.647-662, ctrl/shift named deferrals),
|
||
-- the drag trio, lock dimming, and the CURSOR_UPDATE ring highlight (emulated — header
|
||
-- comment).
|
||
function BenillaPaperDollSlot_OnLoad(button, slotName)
|
||
button:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
||
local id, texture, checkRelic = GetInventorySlotInfo(slotName)
|
||
button.invSlotId = id
|
||
button.slotName = slotName
|
||
button.emptyTexture = texture
|
||
button.checkRelic = checkRelic -- UnitHasRelicSlot is vanilla-always-false (header OMIT): never read
|
||
button.icon = getglobal(button:GetName() .. "IconTexture")
|
||
button.count = getglobal(button:GetName() .. "Count")
|
||
-- Equip interactions on the 19 named slots use the equip-swap wire (PickupInventoryItem
|
||
-- pick/place/swap). The ammo slot (id 0) is different: it LOADS ammo by entry via
|
||
-- CMSG_SET_AMMO (decision 0526; wow-re cursor-dragdrop-slots.md — the client's auto-equip
|
||
-- sender forks ammo-class → SET_AMMO), so it only wants click-to-place + drag-drop, both
|
||
-- routed to BenillaCharacterAmmoSlot_OnClick (its own Scripts block below). It carries no
|
||
-- ring, so the CURSOR_UPDATE highlight / ITEM_LOCK dim legs would no-op anyway, and there
|
||
-- is no drag-OUT (you can't pick the loaded ammo off the slot).
|
||
if slotName ~= "AmmoSlot" then
|
||
button:RegisterEvent("ITEM_LOCK_CHANGED")
|
||
button:RegisterEvent("CURSOR_UPDATE")
|
||
-- The shift-compare listener (ref PaperDollFrame.lua l.83): the ENGINE fires
|
||
-- SHOW_COMPARE_TOOLTIP(slot, n) for an equippable item hover while shift is held;
|
||
-- only the matching visible doll slot answers (the OnEvent branch below).
|
||
button:RegisterEvent("SHOW_COMPARE_TOOLTIP")
|
||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
-- The drag trio (decision 0216 §3): click-carry and drag are ONE code path in the
|
||
-- reference (PaperDollFrame.xml:20-25 routes OnDragStart/OnReceiveDrag to the same
|
||
-- OnClick("LeftButton", ignoreModifiers=1) the plain click uses) — see
|
||
-- BenillaPaperDollSlot_OnClick below for the identical routing, the bag slots' own
|
||
-- precedent (BagFrame.xml's BenillaBagSlot_OnClick).
|
||
button:RegisterForDrag("LeftButton")
|
||
else
|
||
button:RegisterForClicks("LeftButtonUp")
|
||
end
|
||
BenillaPaperDollSlot_Update(button)
|
||
end
|
||
|
||
-- Left: the reference's own modifier fork (ref l.647-660) — CTRL previews the worn
|
||
-- item in the dressing room (decision 1060), SHIFT posts its link into an open chat edit
|
||
-- box (decision 1059), and neither falls through to a pickup a real modified click would
|
||
-- never trigger. Plain click: PickupInventoryItem (pick up / place / swap / cancel,
|
||
-- ref l.656). Right: UseInventoryItem (ref l.659). `ignoreModifiers` is the drag-route
|
||
-- calls' own suppression, the bag slots' precedent.
|
||
function BenillaPaperDollSlot_OnClick(button, mouseButton, ignoreModifiers)
|
||
if mouseButton == "LeftButton" then
|
||
if IsControlKeyDown() and not ignoreModifiers then
|
||
DressUpItemLink(GetInventoryItemLink("player", button.invSlotId))
|
||
return
|
||
elseif IsShiftKeyDown() and not ignoreModifiers then
|
||
-- Both of the ref's guards (l.652: only when the edit box is up) plus our own
|
||
-- nil-link one live in the shared helper (UIParent.xml). A shift-click with chat
|
||
-- closed does nothing here — a worn item has no stack to split, unlike a bag slot.
|
||
BenillaChatEdit_InsertLink(GetInventoryItemLink("player", button.invSlotId))
|
||
return
|
||
end
|
||
PickupInventoryItem(button.invSlotId)
|
||
GameTooltip:Hide() -- the item just left the slot for the cursor
|
||
BenillaPaperDollSlot_Update(button)
|
||
elseif mouseButton == "RightButton" then
|
||
UseInventoryItem(button.invSlotId)
|
||
end
|
||
end
|
||
|
||
-- The ammo slot's own click/drop (decision 0526): ammo LOADS by entry (CMSG_SET_AMMO), it
|
||
-- doesn't swap into an equip slot, so it can't share BenillaPaperDollSlot_OnClick's
|
||
-- PickupInventoryItem path. Only an ammo payload fits (CursorCanGoInSlot(0) — ammo's
|
||
-- find_equip_slot is [0]); the drop funnels through AutoEquipCursorItem, whose app-side drain
|
||
-- resolves the held item's entry and forks to SET_AMMO — the reference's own shared auto-equip
|
||
-- sender (wow-re cursor-dragdrop-slots.md). An empty cursor or a non-ammo payload is inert
|
||
-- (nothing fits), and there is no unload-via-slot in 1.12.
|
||
function BenillaCharacterAmmoSlot_OnClick(button)
|
||
if CursorCanGoInSlot(button.invSlotId) then
|
||
AutoEquipCursorItem()
|
||
GameTooltip:Hide()
|
||
BenillaPaperDollSlot_Update(button)
|
||
end
|
||
end
|
||
|
||
function BenillaPaperDollSlot_Update(button)
|
||
local textureName = GetInventoryItemTexture("player", button.invSlotId)
|
||
if textureName then
|
||
button.icon:SetTexture(textureName)
|
||
local count = GetInventoryItemCount("player", button.invSlotId)
|
||
if (count or 0) > 1 then
|
||
button.count:SetText(count)
|
||
else
|
||
button.count:SetText("")
|
||
end
|
||
else
|
||
button.icon:SetTexture(button.emptyTexture)
|
||
button.count:SetText("")
|
||
end
|
||
-- A BROKEN item (durability 0) tints icon + slot ring red — ref
|
||
-- PaperDollItemSlotButton_Update (l.670-676: SetItemButtonTextureVertexColor +
|
||
-- SetItemButtonNormalTextureVertexColor, both 0.9, 0, 0). The bags carry no broken
|
||
-- tint in 1.12 (ContainerFrame.lua has none) — equipped only. Kept as a flag for
|
||
-- the cursor highlight's restore (Unlock below shares the ring).
|
||
button.broken = textureName and GetInventoryItemBroken("player", button.invSlotId)
|
||
-- A locked slot (its item is up on the cursor, or a send is still pending
|
||
-- server-side, decision 0216 §4/0218 §3) dims — the bag slots' own vertex-dim
|
||
-- convention (BagFrame.xml's BenillaBagSlot_Update), applied here instead of the
|
||
-- ref's separate SetItemButtonDesaturated call (no engine equivalent — header
|
||
-- comment). The transient drag-dim outranks the broken red on the icon.
|
||
if IsInventoryItemLocked(button.invSlotId) then
|
||
button.icon:SetVertexColor(0.4, 0.4, 0.4)
|
||
elseif button.broken then
|
||
button.icon:SetVertexColor(0.9, 0, 0)
|
||
else
|
||
button.icon:SetVertexColor(1, 1, 1)
|
||
end
|
||
BenillaPaperDollSlot_UnlockHighlight(button)
|
||
if GameTooltip:IsOwned(button) then
|
||
BenillaPaperDollSlot_OnEnter(button)
|
||
end
|
||
end
|
||
|
||
-- ref PaperDollItemSlotButton_OnEnter (l.739-748): the equipped hover is the INSTANCE
|
||
-- render — SetInventoryItem, never an id/template render. That carries the live
|
||
-- durability pair (an earlier SetItemById here read the template's full max/max), and
|
||
-- an instance hover never arms a shift-compare — the engine's SetInventoryItem doesn't
|
||
-- arm (a worn item compared with itself is no comparison; director-caught: shift over
|
||
-- the doll popped a "Currently Equipped" 0/XX beside a template-full main tooltip).
|
||
-- The ref's repair-mode branch (l.757-762) is INTERIM-omitted with the binding's
|
||
-- repairCost. checkRelic (l.744-746) is TBC-flagged dead weight in 1.12 — omitted.
|
||
function BenillaPaperDollSlot_OnEnter(button)
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
local hasItem = GameTooltip:SetInventoryItem("player", button.invSlotId)
|
||
if not hasItem then
|
||
-- Empty slot: the slot-name tooltip (ref strupper(strsub(name,10)) -> the matching
|
||
-- GlobalStrings key, e.g. "HeadSlot" -> HEADSLOT -> "Head").
|
||
GameTooltip:SetText(getglobal(strupper(button.slotName)) or button.slotName)
|
||
end
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
-- CURSOR_UPDATE's LockHighlight/UnlockHighlight emulation (this file's header comment: no
|
||
-- true forced-highlight affordance exists — no benilla-ui Button method shows a state
|
||
-- texture off real hover). A vertex tint on the slot's own Quickslot2 ring
|
||
-- (`NormalTexture`, the template below) stands in: green while `CursorCanGoInSlot` says
|
||
-- the held payload fits here, white otherwise.
|
||
-- Both legs no-op on a ringless slot (the ammo slot carries no NormalTexture).
|
||
function BenillaPaperDollSlot_LockHighlight(button)
|
||
local ring = button:GetNormalTexture()
|
||
if ring then
|
||
ring:SetVertexColor(0, 1, 0)
|
||
end
|
||
end
|
||
|
||
-- The restore leg: back to the ring's resting color — broken red (ref l.672) or white.
|
||
function BenillaPaperDollSlot_UnlockHighlight(button)
|
||
local ring = button:GetNormalTexture()
|
||
if not ring then
|
||
return
|
||
end
|
||
if button.broken then
|
||
ring:SetVertexColor(0.9, 0, 0)
|
||
else
|
||
ring:SetVertexColor(1, 1, 1)
|
||
end
|
||
end
|
||
|
||
function BenillaPaperDollSlot_OnEvent(button)
|
||
if event == "UNIT_INVENTORY_CHANGED" and arg1 == "player" then
|
||
BenillaPaperDollSlot_Update(button)
|
||
elseif event == "ITEM_LOCK_CHANGED" then
|
||
-- Ref PaperDollItemSlotButton_OnEvent (l.601-604): no arg filtering — every doll
|
||
-- slot just repaints on any lock transition (cheap, idempotent; it's this SLOT's
|
||
-- own dim that's actually changing, if anything is).
|
||
BenillaPaperDollSlot_Update(button)
|
||
elseif event == "CURSOR_UPDATE" then
|
||
if CursorCanGoInSlot(button.invSlotId) then
|
||
BenillaPaperDollSlot_LockHighlight(button)
|
||
else
|
||
BenillaPaperDollSlot_UnlockHighlight(button)
|
||
end
|
||
elseif event == "SHOW_COMPARE_TOOLTIP" then
|
||
-- ref PaperDollItemSlotButton_OnEvent (l.621-640, quoted; button.invSlotId for the
|
||
-- ref's this:GetID()): arg1 = the doll slot the hovered item would equip into,
|
||
-- arg2 = which shopping tooltip. Both anchor to THIS doll slot (1 to its right,
|
||
-- 2 hanging below-right) — so compares appear only with the character window
|
||
-- open, the 1.12 behavior.
|
||
if arg1 ~= button.invSlotId or not button:IsVisible() or arg2 > NUM_SHOPPING_TOOLTIPS then
|
||
return
|
||
end
|
||
local tooltip = getglobal("ShoppingTooltip" .. arg2)
|
||
local anchor = "ANCHOR_RIGHT"
|
||
if arg2 > 1 then
|
||
anchor = "ANCHOR_BOTTOMRIGHT"
|
||
end
|
||
tooltip:SetOwner(button, anchor)
|
||
local hasItem = tooltip:SetInventoryItem("player", button.invSlotId)
|
||
if not hasItem then
|
||
tooltip:Hide()
|
||
end
|
||
end
|
||
end
|
||
|
||
-- ref PaperDollItemSlotButton_OnUpdate (l.766-784), the un-throttled BagFrame-style
|
||
-- re-enter loop (BagFrame.xml's own comment on why this ships unthrottled).
|
||
function BenillaPaperDollSlot_OnUpdate(button)
|
||
if GameTooltip:IsOwned(button) then
|
||
BenillaPaperDollSlot_OnEnter(button)
|
||
end
|
||
end
|
||
|
||
-- ── The model pane (ref UIParent.lua:1420-1462) ─────────────────────────────────────────
|
||
-- This file's header comment: a booth-texture stand-in, not a live widget. `frame` here is
|
||
-- CharacterModelFrame; `frame.facing` stands in for the ref's `model.rotation`.
|
||
-- These four are the ref's SHARED Model_* helpers (UIParent.lua), and they are shared here
|
||
-- too: the pet page's pane (decision 1057) drives the very same code. The one thing that
|
||
-- differs per pane is WHERE the yaw goes — the engine has no `Model:SetFacing` widget
|
||
-- method, so each pane has its own booth-yaw binding — so the pane names its own in
|
||
-- `frame.setFacing` at OnLoad and these read it. (The inspect window still carries its own
|
||
-- copy of this quartet, predating the generalization; folding it in is a follow-up, not
|
||
-- this slice's to churn.)
|
||
function BenillaPaperDollModel_OnLoad(frame)
|
||
frame.facing = 0.61 -- ref UIParent.lua:1422, the literal default facing
|
||
frame.setFacing(frame.facing)
|
||
end
|
||
|
||
-- ref Model_RotateLeft/Right (UIParent.lua:1426-1442) — the ref's OWN left/right sign
|
||
-- convention is preserved verbatim (rotate-left SUBTRACTS, rotate-right ADDS); not
|
||
-- re-derived, just quoted.
|
||
function BenillaPaperDollModel_RotateLeft(frame)
|
||
frame.facing = frame.facing - 0.03
|
||
frame.setFacing(frame.facing)
|
||
PlaySound("igInventoryRotateCharacter")
|
||
end
|
||
|
||
function BenillaPaperDollModel_RotateRight(frame)
|
||
frame.facing = frame.facing + 0.03
|
||
frame.setFacing(frame.facing)
|
||
PlaySound("igInventoryRotateCharacter")
|
||
end
|
||
|
||
-- ref Model_OnUpdate (UIParent.lua:1444-1462) — the HELD-button continuous spin, which is
|
||
-- where a rotate button's actual feel lives: half a turn per second (ROTATIONS_PER_SECOND,
|
||
-- UIParent.lua:2), against which the 0.03 click nudge above is a ~1.7° tap. Every 1.12 model
|
||
-- pane wires it (PaperDollFrame l.222-224, DressUpFrame.xml:202-204, TabardFrame.xml:406-408).
|
||
-- It used to be omitted here for want of `GetButtonState` — that method now answers "PUSHED"
|
||
-- for a LIVE mouse-held button (decision 0288 P3), so the ref's own loop ships here.
|
||
-- That INCLUDES the ref's sign quirk: the held branches run OPPOSITE to the click helpers
|
||
-- (held-LEFT adds, held-RIGHT subtracts). Not a slip of ours — the ref's own, not re-derived.
|
||
function BenillaPaperDollModel_OnUpdate(frame, elapsed)
|
||
local step = elapsed * 2 * PI * ROTATIONS_PER_SECOND
|
||
if getglobal(frame:GetName() .. "RotateLeftButton"):GetButtonState() == "PUSHED" then
|
||
frame.facing = frame.facing + step
|
||
if frame.facing < 0 then
|
||
frame.facing = frame.facing + (2 * PI)
|
||
end
|
||
frame.setFacing(frame.facing)
|
||
end
|
||
if getglobal(frame:GetName() .. "RotateRightButton"):GetButtonState() == "PUSHED" then
|
||
frame.facing = frame.facing - step
|
||
if frame.facing > (2 * PI) then
|
||
frame.facing = frame.facing - (2 * PI)
|
||
end
|
||
frame.setFacing(frame.facing)
|
||
end
|
||
end
|
||
|
||
-- ref CharacterModelFrame_OnMouseUp (l.31-35): a plain left-click-up on the model pane
|
||
-- also auto-equips a held container item — the model pane doubles as a drop target even
|
||
-- without a drag, not just via OnReceiveDrag. AutoEquipCursorItem is already a no-op for
|
||
-- every non-fitting/non-container payload (cursor.rs's own contract), so no CursorHasItem
|
||
-- guard is needed here.
|
||
function BenillaPaperDollModel_OnMouseUp(frame, button)
|
||
if button == "LeftButton" then
|
||
AutoEquipCursorItem()
|
||
end
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
The shared equipment-slot button (ref PaperDollItemSlotButtonTemplate inherits
|
||
ItemButtonTemplate, ref-PaperDollFrame.xml:4-38 — ItemButtonTemplate's own XML isn't part of
|
||
this session's extraction, so its shape is taken from this codebase's own prior
|
||
reconstruction of it, BagFrame.xml's BenillaBagSlotTemplate: 37x37, a BACKGROUND icon fill,
|
||
an OVERLAY count, the 64x64 UI-Quickslot2 ring centered (0,-1), UI-Quickslot-Depress pushed,
|
||
ButtonHilight-Square ADD highlight — duplicated here rather than cross-file inherited so this
|
||
window's slot behavior (UNIT_INVENTORY_CHANGED refresh, tooltip) stays self-contained in one
|
||
file, the same posture Merchant's own item-row template takes vs. reusing Bag's).
|
||
Cooldown ($parentCooldown, CooldownFrameTemplate) OMITTED — no cooldown feed/engine
|
||
affordance exists yet. OnClick + the drag trio land THIS phase (1b) — the NormalTexture
|
||
ring below doubles as the CURSOR_UPDATE highlight's vertex-tint target (this file's header
|
||
comment: an emulation, no true LockHighlight/UnlockHighlight exists).
|
||
-->
|
||
<Button name="BenillaPaperDollItemSlotTemplate" virtual="true">
|
||
<Size><AbsDimension x="37" y="37"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentIconTexture"/>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-5" y="2"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="64" y="64"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
|
||
</Anchors>
|
||
</NormalTexture>
|
||
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>BenillaPaperDollSlot_OnClick(self, arg1)</OnClick>
|
||
<OnEnter>BenillaPaperDollSlot_OnEnter(self)</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
<OnEvent>BenillaPaperDollSlot_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaPaperDollSlot_OnUpdate(self)</OnUpdate>
|
||
<!-- The reference routes both drag entries to the plain click path with modifiers
|
||
suppressed (PaperDollFrame.xml:20-25 — PickupInventoryItem, ignoring
|
||
shift/ctrl) — the bag slots' own precedent (BagFrame.xml). -->
|
||
<OnDragStart>BenillaPaperDollSlot_OnClick(self, "LeftButton", true)</OnDragStart>
|
||
<OnReceiveDrag>BenillaPaperDollSlot_OnClick(self, "LeftButton", true)</OnReceiveDrag>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<!--
|
||
The ref defines TWO byte-identical templates for the attribute/stat rows — StatFrameTemplate
|
||
(ref-PaperDollFrame.xml:39-71) and AttributeFrameTemplate (l.72-105): same 104x13 size, same
|
||
Label(GameFontNormalSmall,LEFT) + $parentStat(30x13,RIGHT)/$parentText(GameFontHighlightSmall,
|
||
RIGHT) shape — a semantic-only distinction in the real client (armor/attack rows "are stats",
|
||
the 5 primaries "are attributes"). Collapsed to ONE template here (a legitimate reuse — no
|
||
behavior differs). `self:EnableMouse(true)` in OnLoad: a plain Frame isn't mouse-enabled by
|
||
construction in this engine (this file's header comment) — every instance below needs it to
|
||
receive its own OnEnter/OnLeave hover.
|
||
-->
|
||
<Frame name="BenillaStatRowTemplate" virtual="true">
|
||
<Size><AbsDimension x="104" y="13"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<FontString name="$parentLabel" inherits="GameFontNormalSmall">
|
||
<Anchors><Anchor point="LEFT"/></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<Frame name="$parentStat">
|
||
<Size><AbsDimension x="30" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<FontString name="$parentText" inherits="GameFontHighlightSmall" justifyH="RIGHT">
|
||
<Anchors><Anchor point="RIGHT"/></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
</Frames>
|
||
</Frame>
|
||
|
||
<!--
|
||
The magic-resistance icon frame (ref MagicResistanceFrameTemplate, ref-PaperDollFrame.xml:
|
||
106-123): 32x29, a generic tooltip OnEnter reading self.tooltip/self.tooltipSubtext (both
|
||
filled by PaperDollFrame_SetResistances) — no per-instance OnEnter override needed
|
||
(the ref's own MagicResFrame1-5 instances carry none either).
|
||
-->
|
||
<Frame name="BenillaMagicResistanceFrameTemplate" virtual="true">
|
||
<Size><AbsDimension x="32" y="29"/></Size>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>
|
||
if self.tooltip then
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(self.tooltip)
|
||
GameTooltip:AddLine(self.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
end
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<Frame name="CharacterFrame" hidden="true">
|
||
<!-- The real 384x512 window (ref-CharacterFrame.xml:5-7). No <Anchors> — ShowUIPanel/
|
||
SetLeftFrame SetPoints this to the left slot on open (UiPanels.xml's own convention). -->
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<!-- HitRectInsets: transcribed for fidelity; no loader wiring exists yet (this file's header
|
||
comment) — a harmless no-op today. -->
|
||
<HitRectInsets><AbsInset left="0" right="30" top="0" bottom="45"/></HitRectInsets>
|
||
<Layers>
|
||
<!-- Portrait 60x60 TOPLEFT (7,-6) (ref l.19-31). Set in OnShow via SetPortraitTexture
|
||
(the live model-bake binding, UnitFrames.xml's own precedent) — "player" is a fixed
|
||
token here (unlike a unit frame, this window only ever shows the local player). -->
|
||
<Layer level="ARTWORK">
|
||
<Texture name="CharacterFramePortrait">
|
||
<Size><AbsDimension x="60" y="60"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="7" y="-6"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Name: CENTER (6,232) wrapper, GameFontNormal 300x12 centered inside it, white (ref
|
||
l.35-64). UnitPVPName -> plain UnitName (this file's header comment: PVP rank is a
|
||
named deferral) — CharacterTitleText/CharacterGuildText (both PVP-rank/guild-driven)
|
||
are dropped with it. -->
|
||
<Frame name="CharacterNameFrame">
|
||
<Size><AbsDimension x="109" y="12"/></Size>
|
||
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="6" y="232"/></Offset></Anchor></Anchors>
|
||
<Layers>
|
||
<Layer>
|
||
<FontString name="CharacterNameText" inherits="GameFontNormal" text="NAME">
|
||
<Size><AbsDimension x="300" y="12"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Color r="1.0" g="1.0" b="1.0"/>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>self:SetFrameLevel(self:GetFrameLevel() + 1)</OnLoad>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Close: the ref's own UIPanelCloseButton position (CENTER of TOPRIGHT, -44,-25 — ref
|
||
l.65-78), on the minimize-button art this codebase's close buttons all use (no
|
||
UIPanelCloseButton template ships — Gossip/Bag/Merchant's own header comments).
|
||
OnLoad raises the frame level +1 (the same idiom CharacterNameFrame above uses,
|
||
the ref's own): the window's own art is PaperDollFrame's BACKGROUND
|
||
layer — a full-window sibling created AFTER this button — so at the shared default
|
||
level 0 the page's art paints over the button by creation order (order.rs). The ref's
|
||
close button rides the client's show-time bucket-tail re-insertion instead; benilla
|
||
proxies that with creation order, so the explicit raise is the faithful compensation. -->
|
||
<Button name="CharacterFrameCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-44" y="-25"/></Offset></Anchor></Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>self:SetFrameLevel(self:GetFrameLevel() + 1)</OnLoad>
|
||
<OnClick>HideUIPanel(getglobal("CharacterFrame"))</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
<!-- The tab row (ref l.79-168 — CENTER of BOTTOMLEFT +60,+62 — each tab chained off the
|
||
last, MerchantFrame.xml's own Merchant/Buyback LEFT-of-RIGHT -16 offset). ALL FIVE
|
||
of the real client's tabs, in ITS OWN ORDER and at ITS OWN NUMBERS:
|
||
Character/Pet/Reputation/Skills/Honor. Both deviations once flagged here are gone —
|
||
our Skills tab rendering 3rd where the reference's is 4th went with
|
||
ReputationFrame.xml, and the missing fifth went with HonorFrame.xml — so this row
|
||
carries no divergence from the reference at all.
|
||
Tab 2 starts HIDDEN — it is raised only for a unit with a pet UI, by the pet page's
|
||
PetTab_Update, which also re-anchors tab 3 onto tab 2's LEFT while it is
|
||
down so the row has no gap (ref PetPaperDollFrame.lua:189-198). That is now the
|
||
reference's own function on the reference's own tab, Reputation and all. Tab 3's
|
||
XML anchor is the WITH-pet one; the update owns it from load onward.
|
||
No hover tooltip (MicroButtonTooltipText/TOGGLECHARACTER0 have no engine surface,
|
||
and each tab's own visible label already says what it does — Merchant's own tab
|
||
pair carries no hover tooltip either). -->
|
||
<!-- The five labels are the ref's own GlobalStrings KEYS (l.79/97/114/…), not literals —
|
||
the loader resolves a key-shaped `text=` through the shipped strings, so the row is
|
||
localized like the reference's. (Tabs 1/4 carried the enUS literals from 0437;
|
||
same words either way in enUS, and now the same mechanism.) -->
|
||
<Button name="CharacterFrameTab1" inherits="CharacterFrameTabButtonTemplate" text="CHARACTER">
|
||
<Anchors><Anchor point="CENTER" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="60" y="62"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaCharacterFrameTab_OnClick(1)</OnClick></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFrameTab2" inherits="CharacterFrameTabButtonTemplate" text="PET" hidden="true">
|
||
<Anchors><Anchor point="LEFT" relativeTo="CharacterFrameTab1" relativePoint="RIGHT"><Offset><AbsDimension x="-16" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaCharacterFrameTab_OnClick(2)</OnClick></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFrameTab3" inherits="CharacterFrameTabButtonTemplate" text="REPUTATION">
|
||
<Anchors><Anchor point="LEFT" relativeTo="CharacterFrameTab2" relativePoint="RIGHT"><Offset><AbsDimension x="-16" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaCharacterFrameTab_OnClick(3)</OnClick></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFrameTab4" inherits="CharacterFrameTabButtonTemplate" text="SKILLS">
|
||
<Anchors><Anchor point="LEFT" relativeTo="CharacterFrameTab3" relativePoint="RIGHT"><Offset><AbsDimension x="-16" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaCharacterFrameTab_OnClick(4)</OnClick></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFrameTab5" inherits="CharacterFrameTabButtonTemplate" text="HONOR">
|
||
<Anchors><Anchor point="LEFT" relativeTo="CharacterFrameTab4" relativePoint="RIGHT"><Offset><AbsDimension x="-16" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaCharacterFrameTab_OnClick(5)</OnClick></Scripts>
|
||
</Button>
|
||
|
||
<!-- The paper-doll page (ref PaperDollFrame, ref-PaperDollFrame.xml:124-1059). Sized to
|
||
exactly fill the parent instead of the ref's setAllPoints="true" — the same effect
|
||
(see this file's header: frame-level setAllPoints was a no-op when this was written
|
||
and is wired now; the explicit size is equivalent, so it stays). -->
|
||
<Frame name="PaperDollFrame" id="1">
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<HitRectInsets><AbsInset left="0" right="30" top="0" bottom="45"/></HitRectInsets>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- The four quadrant slabs that ARE this page's art (ref l.129-173): 256-wide
|
||
left halves, 128-wide right halves, each 256 tall, pinned per corner. -->
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-CharacterTab-L1">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-CharacterTab-R1">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="0"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-CharacterTab-BottomLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="-256"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-CharacterTab-BottomRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="-256"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<!-- "Level %d %s %s" under the name (ref l.174-182). -->
|
||
<FontString name="CharacterLevelText" inherits="GameFontNormalSmall">
|
||
<Anchors>
|
||
<Anchor point="TOP" relativeTo="CharacterNameText" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="-6"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- The model pane (ref PlayerModel CharacterModelFrame, l.204-273): 233x224 at
|
||
TOPLEFT (65,-78). This file's header comment: a plain Frame sampling the
|
||
paper-doll booth bake, not a live <Model>/<PlayerModel> widget. -->
|
||
<Frame name="CharacterModelFrame">
|
||
<Size><AbsDimension x="233" y="224"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="65" y="-78"/></Offset></Anchor></Anchors>
|
||
<Layers>
|
||
<!-- BACKGROUND, not ARTWORK — the booth quad is an OPAQUE stand-in for a
|
||
widget the reference renders outside the layer batches, so it must
|
||
sit as low as a region goes or it swallows same-level siblings
|
||
(decision 1070; the pet page's diet icon is where that bit). -->
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentTexture">
|
||
<Size><AbsDimension x="233" y="224"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Rotate buttons (ref l.234-271): 35x35, left then right chained off its
|
||
TOPRIGHT, both at the model pane's own TOPLEFT.
|
||
`RegisterForClicks("LeftButtonDown","LeftButtonUp")` is the ref's own
|
||
(l.241-243/l.263-265): OnClick fires on BOTH edges, so one tap nudges
|
||
twice (2 × 0.03), and holding hands the spin to the pane's OnUpdate. -->
|
||
<Button name="CharacterModelFrameRotateLeftButton">
|
||
<Size><AbsDimension x="35" y="35"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-RotationLeft-Button-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-RotationLeft-Button-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Round" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>self:RegisterForClicks("LeftButtonDown", "LeftButtonUp")</OnLoad>
|
||
<OnClick>BenillaPaperDollModel_RotateLeft(getglobal("CharacterModelFrame"))</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
<Button name="CharacterModelFrameRotateRightButton">
|
||
<Size><AbsDimension x="35" y="35"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterModelFrameRotateLeftButton" relativePoint="TOPRIGHT"/></Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-RotationRight-Button-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-RotationRight-Button-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Round" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>self:RegisterForClicks("LeftButtonDown", "LeftButtonUp")</OnLoad>
|
||
<OnClick>BenillaPaperDollModel_RotateRight(getglobal("CharacterModelFrame"))</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>
|
||
-- A plain Frame isn't mouse-enabled by construction (this file's
|
||
-- header comment) — needed THIS phase (1b) so the pane hit-tests
|
||
-- as an OnMouseUp/OnReceiveDrag drop target (ref l.226-231).
|
||
self:EnableMouse(true)
|
||
self.setFacing = BenillaPaperDollModel_SetFacing
|
||
BenillaPaperDollModel_OnLoad(self)
|
||
BenillaSetBoothTexture(getglobal(self:GetName() .. "Texture"), "paperdoll")
|
||
</OnLoad>
|
||
<!-- ref l.221-224: the pane drives the held-button spin every frame. -->
|
||
<OnUpdate>BenillaPaperDollModel_OnUpdate(self, arg1)</OnUpdate>
|
||
<OnMouseUp>BenillaPaperDollModel_OnMouseUp(self, arg1)</OnMouseUp>
|
||
<OnReceiveDrag>AutoEquipCursorItem()</OnReceiveDrag>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!-- The attributes block (ref CharacterAttributesFrame, l.274-405): 230x78 at
|
||
TOPLEFT (67,-291), the 9-piece UI-Character-StatBackground plate (3 stacked
|
||
3-piece columns: player-stat / melee / ranged) behind the rows. -->
|
||
<Frame name="CharacterAttributesFrame">
|
||
<Size><AbsDimension x="230" y="78"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="67" y="-291"/></Offset></Anchor></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="PlayerStatBackgroundTop" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0" bottom="0.125"/>
|
||
</Texture>
|
||
<Texture name="PlayerStatBackgroundMiddle" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="53"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="PlayerStatBackgroundTop" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.125" bottom="0.1953125"/>
|
||
</Texture>
|
||
<Texture name="PlayerStatBackgroundBottom" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="PlayerStatBackgroundMiddle" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.484375" bottom="0.609375"/>
|
||
</Texture>
|
||
<Texture name="MeleeAttackBackgroundTop" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="115" y="0"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0" bottom="0.125"/>
|
||
</Texture>
|
||
<Texture name="MeleeAttackBackgroundMiddle" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="12"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="MeleeAttackBackgroundTop" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.125" bottom="0.1953125"/>
|
||
</Texture>
|
||
<Texture name="MeleeAttackBackgroundBottom" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="MeleeAttackBackgroundMiddle" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.484375" bottom="0.609375"/>
|
||
</Texture>
|
||
<Texture name="RangedAttackBackgroundTop" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="MeleeAttackBackgroundBottom" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="2"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0" bottom="0.125"/>
|
||
</Texture>
|
||
<Texture name="RangedAttackBackgroundMiddle" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="11"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="RangedAttackBackgroundTop" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.125" bottom="0.1953125"/>
|
||
</Texture>
|
||
<Texture name="RangedAttackBackgroundBottom" file="Interface\PaperDollInfoFrame\UI-Character-StatBackground">
|
||
<Size><AbsDimension x="115" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="RangedAttackBackgroundMiddle" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.8984375" top="0.484375" bottom="0.609375"/>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- The 5 primary attributes (ref l.407-491): TOPLEFT (6,-3), chained
|
||
BOTTOMLEFT-to-BOTTOMLEFT. Labels are the TEMPLATE's $parentLabel,
|
||
filled from Lua exactly like the ref (PaperDollFrame_OnLoad /
|
||
_SetStats — see the former's header comment); instances declare no
|
||
regions of their own, same as the ref's. -->
|
||
<Frame name="CharacterStatFrame1" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="6" y="-3"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>PaperDollStatTooltip("player", "STRENGTH")</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="CharacterStatFrame2" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterStatFrame1" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>PaperDollStatTooltip("player", "AGILITY")</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="CharacterStatFrame3" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterStatFrame2" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>PaperDollStatTooltip("player", "STAMINA")</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="CharacterStatFrame4" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterStatFrame3" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>PaperDollStatTooltip("player", "INTELLECT")</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="CharacterStatFrame5" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterStatFrame4" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>PaperDollStatTooltip("player", "SPIRIT")</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Armor (ref l.492-511), chained off Stat5's BOTTOMLEFT. -->
|
||
<Frame name="CharacterArmorFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterStatFrame5" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(self.tooltip)
|
||
GameTooltip:AddLine(self.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Melee attack rating (ref l.512-531), TOPLEFT of the attributes frame
|
||
itself (122,-2) — the second column's own chain root. -->
|
||
<Frame name="CharacterAttackFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterAttributesFrame" relativePoint="TOPLEFT"><Offset><AbsDimension x="122" y="-2"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(ATTACK_TOOLTIP)
|
||
GameTooltip:AddLine(ATTACK_TOOLTIP_SUBTEXT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Melee attack power (ref l.532-554), 99px-wide override (OnLoad). -->
|
||
<Frame name="CharacterAttackPowerFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterAttackFrame" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="5" y="1"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true); self:SetWidth(99)</OnLoad>
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(self.tooltip)
|
||
GameTooltip:AddLine(self.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Melee damage (ref l.555-574), 99px-wide override, dedicated OnEnter. -->
|
||
<Frame name="CharacterDamageFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterAttackPowerFrame" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true); self:SetWidth(99)</OnLoad>
|
||
<OnEnter>CharacterDamageFrame_OnEnter()</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Ranged attack rating (ref l.575-594). -->
|
||
<Frame name="CharacterRangedAttackFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterDamageFrame" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="-6"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true)</OnLoad>
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(RANGED_ATTACK_TOOLTIP)
|
||
GameTooltip:AddLine(ATTACK_TOOLTIP_SUBTEXT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Ranged attack power (ref l.595-619), 99px-wide, conditional tooltip
|
||
(the N/A / wand-equipped states leave self.tooltip nil). -->
|
||
<Frame name="CharacterRangedAttackPowerFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterRangedAttackFrame" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="5" y="1"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true); self:SetWidth(99)</OnLoad>
|
||
<OnEnter>
|
||
if self.tooltip then
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText(self.tooltip)
|
||
GameTooltip:AddLine(self.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
||
GameTooltip:Show()
|
||
end
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
<!-- Ranged damage (ref l.620-639), 99px-wide, dedicated OnEnter (no-ops
|
||
while self.damage is nil, e.g. no ranged weapon equipped). -->
|
||
<Frame name="CharacterRangedDamageFrame" inherits="BenillaStatRowTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterRangedAttackPowerFrame" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:EnableMouse(true); self:SetWidth(99)</OnLoad>
|
||
<OnEnter>CharacterRangedDamageFrame_OnEnter()</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
</Frame>
|
||
|
||
<!-- The 5 magic-resistance frames (ref CharacterResistanceFrame, l.642-760):
|
||
32x160 wrapper, TOPRIGHT of PaperDollFrame's own TOPLEFT (297,-77); each
|
||
32x29 icon TOP-chained off the previous, ids 6/2/3/4/5 (arcane/fire/nature/
|
||
frost/shadow — Holy(1) never rides the paper doll). -->
|
||
<Frame name="CharacterResistanceFrame">
|
||
<Size><AbsDimension x="32" y="160"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativeTo="PaperDollFrame" relativePoint="TOPLEFT"><Offset><AbsDimension x="297" y="-77"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Frames>
|
||
<Frame name="MagicResFrame1" inherits="BenillaMagicResistanceFrameTemplate">
|
||
<Anchors><Anchor point="TOP" relativeTo="CharacterResistanceFrame" relativePoint="TOP"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ResistanceIcons">
|
||
<TexCoords left="0" right="1.0" top="0.2265625" bottom="0.33984375"/>
|
||
</Texture>
|
||
<FontString name="MagicResText1" inherits="GameFontHighlightSmall" text="X">
|
||
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="MagicResFrame2" inherits="BenillaMagicResistanceFrameTemplate">
|
||
<Anchors><Anchor point="TOP" relativeTo="MagicResFrame1" relativePoint="BOTTOM"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ResistanceIcons">
|
||
<TexCoords left="0" right="1.0" top="0" bottom="0.11328125"/>
|
||
</Texture>
|
||
<FontString name="MagicResText2" inherits="GameFontHighlightSmall" text="X">
|
||
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="MagicResFrame3" inherits="BenillaMagicResistanceFrameTemplate">
|
||
<Anchors><Anchor point="TOP" relativeTo="MagicResFrame2" relativePoint="BOTTOM"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ResistanceIcons">
|
||
<TexCoords left="0" right="1.0" top="0.11328125" bottom="0.2265625"/>
|
||
</Texture>
|
||
<FontString name="MagicResText3" inherits="GameFontHighlightSmall" text="X">
|
||
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="MagicResFrame4" inherits="BenillaMagicResistanceFrameTemplate">
|
||
<Anchors><Anchor point="TOP" relativeTo="MagicResFrame3" relativePoint="BOTTOM"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ResistanceIcons">
|
||
<TexCoords left="0" right="1.0" top="0.33984375" bottom="0.453125"/>
|
||
</Texture>
|
||
<FontString name="MagicResText4" inherits="GameFontHighlightSmall" text="X">
|
||
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="MagicResFrame5" inherits="BenillaMagicResistanceFrameTemplate">
|
||
<Anchors><Anchor point="TOP" relativeTo="MagicResFrame4" relativePoint="BOTTOM"/></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ResistanceIcons">
|
||
<TexCoords left="0" right="1.0" top="0.453125" bottom="0.56640625"/>
|
||
</Texture>
|
||
<FontString name="MagicResText5" inherits="GameFontHighlightSmall" text="X">
|
||
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
</Frames>
|
||
</Frame>
|
||
|
||
<!-- The 19 equipment slots (ref l.761-931): left column TOPLEFT (21,-74) chained
|
||
BOTTOMLEFT -4, right column TOPLEFT (305,-74) chained the same way, the
|
||
weapon row off the page's own BOTTOMLEFT (122,127) then chained TOPRIGHT +5. -->
|
||
<Button name="CharacterHeadSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="21" y="-74"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "HeadSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterNeckSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterHeadSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "NeckSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterShoulderSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterNeckSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "ShoulderSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterBackSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterShoulderSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "BackSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterChestSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterBackSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "ChestSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterShirtSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterChestSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "ShirtSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterTabardSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterShirtSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "TabardSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterWristSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterTabardSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "WristSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterHandsSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="305" y="-74"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "HandsSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterWaistSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterHandsSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "WaistSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterLegsSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterWaistSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "LegsSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFeetSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterLegsSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "FeetSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFinger0Slot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterFeetSlot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "Finger0Slot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterFinger1Slot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterFinger0Slot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "Finger1Slot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterTrinket0Slot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterFinger1Slot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "Trinket0Slot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterTrinket1Slot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterTrinket0Slot" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "Trinket1Slot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterMainHandSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="122" y="127"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "MainHandSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterSecondaryHandSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterMainHandSlot" relativePoint="TOPRIGHT"><Offset><AbsDimension x="5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "SecondaryHandSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="CharacterRangedSlot" inherits="BenillaPaperDollItemSlotTemplate">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="CharacterSecondaryHandSlot" relativePoint="TOPRIGHT"><Offset><AbsDimension x="5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaPaperDollSlot_OnLoad(self, "RangedSlot")</OnLoad></Scripts>
|
||
</Button>
|
||
|
||
<!-- The ammo slot (ref CharacterAmmoSlot, l.932-1043): 27x27, LEFT of the ranged
|
||
slot's RIGHT (+15,0). NOT built from the shared slot template — its own
|
||
hand-authored art (a pouch background + a corner-accent overlay cut from the
|
||
same sheet, no Quickslot2 ring) — but reuses the SAME Lua as the 19 named
|
||
slots (this file's header comment: the ref shares PaperDollItemSlotButton_*
|
||
verbatim here too, keyed off "AmmoSlot"). $parentCount's hidden="true" (ref
|
||
default) is DROPPED — every other count fontstring in this codebase (Bag/
|
||
Merchant/this file's own template) uses the same "blank text = invisible"
|
||
idiom with no Show/Hide dance, applied here too for consistency.
|
||
$parentStock OMITTED (this file's header comment: no ref Lua populates it). -->
|
||
<Button name="CharacterAmmoSlot">
|
||
<Size><AbsDimension x="27" y="27"/></Size>
|
||
<Anchors>
|
||
<Anchor point="LEFT" relativeTo="CharacterRangedSlot" relativePoint="RIGHT"><Offset><AbsDimension x="15" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\PaperdollInfoFrame\UI-Character-AmmoSlot">
|
||
<Size><AbsDimension x="41" y="41"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<TexCoords left="0" right="0.640625" top="0" bottom="0.640625"/>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="BORDER">
|
||
<Texture name="$parentIconTexture"/>
|
||
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Anchors><Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-1" y="2"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<Texture file="Interface\PaperdollInfoFrame\UI-Character-AmmoSlot">
|
||
<Size><AbsDimension x="23" y="41"/></Size>
|
||
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="-22" y="0"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0.640625" right="1.0" top="0" bottom="0.640625"/>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaPaperDollSlot_OnLoad(self, "AmmoSlot")</OnLoad>
|
||
<OnEnter>BenillaPaperDollSlot_OnEnter(self)</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
<OnEvent>BenillaPaperDollSlot_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaPaperDollSlot_OnUpdate(self)</OnUpdate>
|
||
<!-- Ammo loads by SET_AMMO, not the equip-swap wire (decision 0526):
|
||
click-to-place and drag-drop both route to the ammo handler. -->
|
||
<OnClick>BenillaCharacterAmmoSlot_OnClick(self)</OnClick>
|
||
<OnReceiveDrag>BenillaCharacterAmmoSlot_OnClick(self)</OnReceiveDrag>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>PaperDollFrame_OnLoad()</OnLoad>
|
||
<OnEvent>PaperDollFrame_OnEvent(event, arg1)</OnEvent>
|
||
<OnShow>PaperDollFrame_OnShow()</OnShow>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>CharacterFrame_OnLoad()</OnLoad>
|
||
<OnShow>CharacterFrame_OnShow()</OnShow>
|
||
<OnHide>CharacterFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|