diff --git a/Cargo.lock b/Cargo.lock index 0c72824c..5981928e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -592,6 +592,7 @@ dependencies = [ "benilla-formats", "benilla-protocol", "benilla-ui", + "benilla-wmo", "bevy", "bevy_egui", "bytemuck", diff --git a/crates/benilla-app/Cargo.toml b/crates/benilla-app/Cargo.toml index b43c8112..335e99c2 100644 --- a/crates/benilla-app/Cargo.toml +++ b/crates/benilla-app/Cargo.toml @@ -82,6 +82,12 @@ mint = "0.5" # source. Pinned to 0.8: the version `benilla-srp` already depends on, so this adds no crate. rand = "0.8" +[dev-dependencies] +# The WMO portal-cull audit's raw-face instruments (`WOW_PIN_COL`): the pin probe compares the +# filtered walking-collision set against the group file's FULL face list with per-face MOPY flags, +# which only the raw parser exposes — benilla-formats' gathers are exactly the filtered views. +benilla-wmo = { path = "../benilla-wmo" } + # Linux/BSD: the Wayland clipboard (decision 0702). We build with bevy's `wayland` feature, so on a # Wayland session winit gives us a native Wayland window and `arboard` — X11-only without its # non-default `wayland-data-control` feature — finds no X11 CLIPBOARD owner and every paste fails. diff --git a/crates/benilla-app/assets/ui/ActionBar.xml b/crates/benilla-app/assets/ui/ActionBar.xml index 5567011d..a09af17c 100644 --- a/crates/benilla-app/assets/ui/ActionBar.xml +++ b/crates/benilla-app/assets/ui/ActionBar.xml @@ -648,13 +648,54 @@ BenillaExhaustionTick.timer = nil end + -- ── The max-level rail (ref-ReputationFrame.lua, the max-level slice) ───────────────── + -- ref l.14: the constant lives in ReputationFrame.lua, which isn't built yet — it moves + -- there with the reputation system. + MAX_PLAYER_LEVEL = 60 + + function BenillaMaxLevelBar_OnLoad(bar) + bar:RegisterEvent("PLAYER_ENTERING_WORLD") + bar:RegisterEvent("PLAYER_LEVEL_UP") + end + + -- ref ReputationWatchBar_Update's else arm (ref-ReputationFrame.lua l.161-166 + + -- l.236-244), the no-watched-faction branch only — the reputation branches wait for the + -- reputation system: at MAX_PLAYER_LEVEL the XP strip gives way to the rail and the + -- tick goes with it. Login seam: the ref initializes off UPDATE_FACTION (its OnEvent's + -- else arm; the faction list lands at every login), an event benilla doesn't carry yet, + -- so the rail listens to PLAYER_ENTERING_WORLD instead — same moment, same values. + function BenillaMaxLevelBar_Update(newLevel) + if not newLevel then + newLevel = UnitLevel("player") + end + if newLevel == MAX_PLAYER_LEVEL then + BenillaExpBar:Hide() + BenillaMaxLevelBar:Show() + BenillaExhaustionTick:Hide() + else + BenillaExpBar:Show() + BenillaMaxLevelBar:Hide() + end + end + + -- The ref's event fan (ref-ReputationFrame.xml l.1002-1016): PLAYER_LEVEL_UP passes + -- arg1 (the new level — the level FIELD may not have landed yet), everything else + -- re-reads UnitLevel. + function BenillaMaxLevelBar_OnEvent() + if event == "PLAYER_LEVEL_UP" then + BenillaMaxLevelBar_Update(arg1) + else + BenillaMaxLevelBar_Update() + end + end + -- ── The exhaustion tick (ref-MainMenuBar.lua ExhaustionTick_*) ──────────────────────── -- The round marker riding the XP bar at the point where rested XP runs out, plus the - -- pale fill between the bar's value and that point. Two transcription cuts, named: - -- the ref's MainMenuBarMaxLevelBar / ReputationWatchBar guards reference max-level bar - -- art and the faction watch bar, neither built — each is its own slice, and until then - -- the guards' frames can't be shown, so the cuts are unreachable-code cuts, not behavior - -- cuts. (A level-60 body simply keeps its inert XP bar for now.) + -- pale fill between the bar's value and that point. One transcription cut left, named: + -- the ref's two ReputationWatchBar guards (the max-level+rep tick hide, l.51-54, and + -- the rep-bar-replaced-the-xp-bar hide, l.69-71) reference the faction watch bar, not + -- built — its frame can't be shown, so the cut is an unreachable-code cut, not a + -- behavior cut. The MainMenuBarMaxLevelBar guard is live since 1094 (the rail below). function BenillaExhaustionTick_OnLoad(tick) tick:RegisterEvent("PLAYER_ENTERING_WORLD") tick:RegisterEvent("PLAYER_XP_UPDATE") @@ -683,7 +724,8 @@ local exhaustionTickSet = max(((playerCurrXP + exhaustionThreshold) / playerMaxXP) * BenillaExpBar:GetWidth(), 0) tick:ClearAllPoints() - if exhaustionTickSet > BenillaExpBar:GetWidth() then + if exhaustionTickSet > BenillaExpBar:GetWidth() + or BenillaMaxLevelBar:IsShown() then tick:Hide() BenillaExhaustionLevelFillBar:Hide() else @@ -1049,6 +1091,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BenillaMaxLevelBar_OnLoad(self) + BenillaMaxLevelBar_OnEvent() + + + + OnShow resets it to the skull and swaps a fishing loot to FishingLoot-Icon + (decision 1086), exactly as the ref's OnShow does (l.133-140). --> diff --git a/crates/benilla-app/assets/ui/SkillFrame.xml b/crates/benilla-app/assets/ui/SkillFrame.xml index c60ca7ff..65d32dd7 100644 --- a/crates/benilla-app/assets/ui/SkillFrame.xml +++ b/crates/benilla-app/assets/ui/SkillFrame.xml @@ -111,19 +111,52 @@ function BenillaSkillFrame_PaintBar(bar, skillName, skillRank, skillModifier, skillMaxRank) local nameText = getglobal(bar:GetName() .. "SkillName") local rankText = getglobal(bar:GetName() .. "SkillRank") + -- The trough behind the fill (ref `$parentBackground`), recoloured per branch alongside + -- the fill itself — ref SkillFrame.lua:158 (normal) and :167 (proficiency), and the + -- detail pane's identical pair at :356/:376. The ref sets the normal-skill pair BEFORE + -- its `skillMaxRank` gate and lets the proficiency arm overwrite it; setting each arm's + -- own pair here is the same result with no dead write. The ref's THIRD writer of this + -- texture — the `skillCostType == 1/2/3` green/yellow/red block at :96-111, and the + -- `stepCost` "Learn " gray at :126 — is unreachable for us and would be + -- overwritten here even if it weren't: `stepCost`/`rankCost` are always nil and + -- `numTempPoints` always 0 (skills.rs's module doc — dead 1.12 data, deviation 1/5), so + -- every entry row takes the ref's own `else -- Normal skill` arm. + local bgTexture = getglobal(bar:GetName() .. "Background") nameText:SetText(skillName) nameText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) rankText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) - if skillMaxRank == 0 then - -- A 1.12 proficiency line the app reports as 0/0 (SkillEntry's own doc) — barless - -- plain text, deviation-free reading of the ref's own "skillMaxRank == 1" gray-bar - -- intent, adapted to our app's 0/0 shape (this file's header comment, no-fillbar note). + if skillMaxRank == 1 then + -- ref SkillFrame.lua:161-167 verbatim: "If max rank in a skill is 1 assume that + -- its a proficiency" — a FULL gray bar and NO rank text. Two kinds of line land + -- here, and the ref can't tell them apart because it doesn't need to: the armor + -- proficiencies, which the server really does report as 1/1, and the single-rank + -- lines (class skills, Dual Wield, racials, the per-mount riding lines) whose + -- `skillMaxRank` the engine already overrode to 1 off + -- `SkillRaceClassInfo.flags & 0x400` (skills.rs's `SkillEntry::mono`) — which is + -- why a hunter's `Beast Mastery 300/300` draws gray and numberless here, exactly + -- as it does in the real client. + bar:SetMinMaxValues(0, 1) + bar:SetValue(1) + bar:SetStatusBarColor(0.5, 0.5, 0.5) + rankText:SetText("") + bgTexture:SetVertexColor(1.0, 1.0, 1.0, 0.5) + elseif skillMaxRank == 0 then + -- Not reachable off a live server (a line the player HAS always carries a max ≥ 1) + -- and the ref leaves this case to fall through its own if/elseif untouched — + -- which, on a recycled row, would leave the PREVIOUS skill's bar and rank text + -- sitting there. We blank instead: a stale-state hole is a quirk, not behaviour. bar:SetMinMaxValues(0, 1) bar:SetValue(0) bar:SetStatusBarColor(0, 0, 0, 0) rankText:SetText("") + -- back to the template's own declared base, so a recycled row shows a neutral empty + -- trough rather than the previous skill's blue or white. The base lives in the + -- TEXEL (the template's ``), so restoring it means an IDENTITY + -- vertex colour — writing 0.2 here would multiply it to 0.04 (decision 1101). + bgTexture:SetVertexColor(1.0, 1.0, 1.0, 1.0) else bar:SetStatusBarColor(0.0, 0.0, 1.0, 0.5) + bgTexture:SetVertexColor(0.0, 0.0, 0.75, 0.5) bar:SetMinMaxValues(0, skillMaxRank) bar:SetValue(skillRank) -- ref SkillFrame.lua:178-186, transcribed byte-exact (this file's header comment, diff --git a/crates/benilla-app/assets/ui/UnitFrames.xml b/crates/benilla-app/assets/ui/UnitFrames.xml index cfaef29f..50f1b9e7 100644 --- a/crates/benilla-app/assets/ui/UnitFrames.xml +++ b/crates/benilla-app/assets/ui/UnitFrames.xml @@ -946,6 +946,28 @@ + + + + + + + + + + + + + + - - - - - - - - - - - -