From 6ef6eb751443421e5929295e0b04c8b31da9243c Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 7 Sep 2026 18:54:54 +0200 Subject: [PATCH] =?UTF-8?q?fix(vtank):=20slice=207=20round=20F=20item=204?= =?UTF-8?q?=20=E2=80=94=20recall=20combo=20at=20VTank's=20terse-caption=20?= =?UTF-8?q?shape?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resemblance re-check: "the recall combo's full spell names overflow the 120 px box on most of the 27 entries — VTank's cmbRecallType uses terse captions ('Primary', 'LS Sending', 'PtOIA', 'Fac. Hub'...): show those, keep the full name in the waypoint and .af." Round E's D-2 had widened the combo 120->300 to fit RecallDisplayName's full spell names; this reverts the widening and shows VTank's own cmbRecallType captions instead, restoring the box to VTank's real 120 width. Added RouteWaypoint.RecallShortCaption(RouteRecallKind) — VTank's 27 terse cmbRecallType strings transcribed from docs/research/vtank-kb/ 08-ui-views.md §1 (this worktree has no refs/vtank/ checkout to read mainView.xml directly; the KB doc is its own faithful transcription of that exact file, duplicate quirk included). The UI file's own caption list carries a genuine VTank authoring duplicate — "Fac. Hub" then "FacHub" again four slots later — that pushes every later caption one position past the 26 real castable recalls it captions; removing that duplicate restores an exact 1:1, in-order match onto RouteRecallKind's 26 real spells (confirmed by meaning, not just position — "Candeth" for Return to the Keep is Candeth Keep, the literal destination; the three "Soc. *" captions are the Society stronghold recalls). Marketplace was never a cmbRecallType option (VTank's one slash-only recall) and keeps its own literal caption since this combo still lists it. RouteRecallNames/SelectedRouteRecall/SelectRouteRecall now read/parse RecallShortCaption instead of RecallDisplayName — this is the ONLY thing that changed. AddRouteRecallCore/RecallLabel still write the full name (RecallDisplayName) onto the waypoint, the Route grid row, and the .af file, completely untouched by this commit. 27 captions used, in RouteRecallKind order: Primary, Secondary, LS, LS Sending, Portal, Aphus, Sanctuary, Caul, GW, Aerlinthe, Mt. Lethe, Ulgrim's, Bur, PtOIA, Graveyard, Colosseum, Fac. Hub, Gear K. Camp, Neftet, Candeth, Rynthid, VR Rocks, VR Tree, Soc. CH, Soc. RB, Soc. EW, Marketplace. Mutation shown to fail first: RouteRecallComboShowsVtanksTerseCaptionsButTheWaypointKeepsTheFullName replaces RouteRecallComboShowsVtankNamesNotEnumIdentifiers with the new expected terse-caption list. Verified by temporarily reverting RouteRecallNames/SelectedRouteRecall back to RecallDisplayName (a targeted mutation, then reverted) — the test failed with "Expected: [Primary, Secondary, LS, ...] Actual: [Primary Portal Recall, Secondary Portal Recall, Lifestone Recall, ...]" — then passed once RecallShortCaption was restored. MossTank suite 724/724 (one test replaced, net count unchanged); App markup/plugin filter 258/258 (unaffected — no App-side markup change). Co-Authored-By: Claude Fable 5.1 --- src/AcDream.Plugins.MossTank/MossTankPanel.cs | 28 ++++++--- src/AcDream.Plugins.MossTank/Navigation.cs | 60 +++++++++++++++++++ src/AcDream.Plugins.MossTank/mosstank.xml | 23 +++---- .../MossTankPanelTests.cs | 47 ++++++++------- 4 files changed, 118 insertions(+), 40 deletions(-) diff --git a/src/AcDream.Plugins.MossTank/MossTankPanel.cs b/src/AcDream.Plugins.MossTank/MossTankPanel.cs index a29e64f6..9ae0b7e3 100644 --- a/src/AcDream.Plugins.MossTank/MossTankPanel.cs +++ b/src/AcDream.Plugins.MossTank/MossTankPanel.cs @@ -1059,9 +1059,19 @@ internal sealed partial class MossTankPanel // "ParadoxTouchedOlthoiInfestedAreaRecall", ...) instead of VTank's // real recall names — RouteInsertModeNames/RouteModeNames above // already route their own display captions through a dedicated - // string, not the enum's own ToString(); this brings Recall in line + // string, not the enum's own ToString(); this brought Recall in line // via the same RecallDisplayName table AddRouteRecallCore/RecallLabel // already use. + // + // Round F item 4 (resemblance re-check: "the recall combo's full + // spell names overflow the 120 px box on most of the 27 entries — + // VTank's cmbRecallType uses terse captions"): the combo itself now + // shows VTank's OWN terse cmbRecallType captions + // (RecallShortCaption) instead of RecallDisplayName's full spell + // names — the full name still drives the waypoint text, the grid + // row, and the .af file untouched, through RecallDisplayName/ + // RecallLabel exactly as before; only this one combo's own display + // (and the string SelectRouteRecall parses back) changed. public IReadOnlyList RouteRecallNames { get @@ -1069,11 +1079,11 @@ internal sealed partial class MossTankPanel RouteRecallKind[] values = Enum.GetValues(); var names = new string[values.Length]; for (int i = 0; i < values.Length; i++) - names[i] = RouteWaypoint.RecallDisplayName(values[i]); + names[i] = RouteWaypoint.RecallShortCaption(values[i]); return names; } } - public string SelectedRouteRecall => RouteWaypoint.RecallDisplayName(_routeRecallKind); + public string SelectedRouteRecall => RouteWaypoint.RecallShortCaption(_routeRecallKind); public IReadOnlyList RouteProfileNames => _routeProfiles.AvailableNames; public string SelectedRouteProfile => _routeProfiles.Selected; @@ -1154,14 +1164,18 @@ internal sealed partial class MossTankPanel RefreshRouteEditor(); SaveRouteProfile(); }; - // D-2: parses the SAME display string RouteRecallNames/SelectedRouteRecall - // now show (Enum.TryParse against the bare C# identifier no longer - // matches what the combo actually sends back). + // D-2: parses the SAME string RouteRecallNames/SelectedRouteRecall now + // show (Enum.TryParse against the bare C# identifier no longer matches + // what the combo actually sends back). Round F item 4 switched that + // string from RecallDisplayName's full name to + // RecallShortCaption's terse VTank caption — only the parsed FORMAT + // changed; the waypoint/grid/.af still read the recall's full name + // through RecallDisplayName/RecallLabel, unaffected by this method. public Action SelectRouteRecall => value => { foreach (RouteRecallKind kind in Enum.GetValues()) { - if (RouteWaypoint.RecallDisplayName(kind).Equals(value, StringComparison.OrdinalIgnoreCase)) + if (RouteWaypoint.RecallShortCaption(kind).Equals(value, StringComparison.OrdinalIgnoreCase)) { _routeRecallKind = kind; return; diff --git a/src/AcDream.Plugins.MossTank/Navigation.cs b/src/AcDream.Plugins.MossTank/Navigation.cs index 5fde615c..907e57b5 100644 --- a/src/AcDream.Plugins.MossTank/Navigation.cs +++ b/src/AcDream.Plugins.MossTank/Navigation.cs @@ -240,6 +240,66 @@ internal sealed class RouteWaypoint _ => value.ToString(), }; + /// + /// VTank's own cmbRecallType combo CAPTION (docs/research/ + /// vtank-kb/08-ui-views.md §1's Route table, transcribed from + /// refs/vtank/uTank2.ViewXML.mainView.xml's 27-string Choice + /// list) for each — used ONLY by the + /// combo's own display/parse round-trip (MossTankPanel.RouteRecallNames/ + /// SelectedRouteRecall/SelectRouteRecall); the waypoint text, the + /// Route grid row, and the .af file keep showing 's full name via , + /// untouched by this method (round F item 4 — resemblance re-check: + /// "the recall combo's full spell names overflow the 120 px box... + /// VTank's cmbRecallType uses terse captions"). + /// + /// The UI file's own 27 caption strings carry a genuine VTank + /// authoring duplicate — "Fac. Hub" at position 17 and "FacHub" + /// again at position 21 (KB's own noted "authoring duplicate") — + /// which pushes every later caption one slot further than the 26 + /// real (unique) castable recalls it captions. Removing that + /// duplicate restores an exact 1:1, in-order match onto + /// 's 26 real spells: "Candeth" for + /// Return to the Keep (Candeth Keep IS the keep that spell returns + /// to), "Graveyard" for Call of the Mhoire Forge, and the three + /// "Soc. *" captions for the Society stronghold recalls. + /// was never a + /// cmbRecallType option at all (it is VTank's one slash-command-only + /// recall, per RecallDisplayName's own doc history) — it keeps its + /// own literal caption here since MossTank's combo still lists it. + /// + internal static string RecallShortCaption(RouteRecallKind value) => value switch + { + RouteRecallKind.PrimaryPortalRecall => "Primary", + RouteRecallKind.SecondaryPortalRecall => "Secondary", + RouteRecallKind.LifestoneRecall => "LS", + RouteRecallKind.LifestoneSending => "LS Sending", + RouteRecallKind.PortalRecall => "Portal", + RouteRecallKind.RecallAphusLassel => "Aphus", + RouteRecallKind.RecallTheSanctuary => "Sanctuary", + RouteRecallKind.RecallToTheSingularityCaul => "Caul", + RouteRecallKind.GlendenWoodRecall => "GW", + RouteRecallKind.AerlintheRecall => "Aerlinthe", + RouteRecallKind.MountLetheRecall => "Mt. Lethe", + RouteRecallKind.UlgrimsRecall => "Ulgrim's", + RouteRecallKind.BurRecall => "Bur", + RouteRecallKind.ParadoxTouchedOlthoiInfestedAreaRecall => "PtOIA", + RouteRecallKind.CallOfTheMhoireForge => "Graveyard", + RouteRecallKind.ColosseumRecall => "Colosseum", + RouteRecallKind.FacilityHubRecall => "Fac. Hub", + RouteRecallKind.GearKnightInvasionAreaCampRecall => "Gear K. Camp", + RouteRecallKind.LostCityOfNeftetRecall => "Neftet", + RouteRecallKind.ReturnToTheKeep => "Candeth", + RouteRecallKind.RynthidRecall => "Rynthid", + RouteRecallKind.ViridianRiseRecall => "VR Rocks", + RouteRecallKind.ViridianRiseGreatTreeRecall => "VR Tree", + RouteRecallKind.CelestialHandStrongholdRecall => "Soc. CH", + RouteRecallKind.RadiantBloodStrongholdRecall => "Soc. RB", + RouteRecallKind.EldrytchWebStrongholdRecall => "Soc. EW", + RouteRecallKind.Marketplace => "Marketplace", + _ => value.ToString(), + }; + /// /// The real retail spell id VTank casts for each recall (metaf's own /// NRecall table). has diff --git a/src/AcDream.Plugins.MossTank/mosstank.xml b/src/AcDream.Plugins.MossTank/mosstank.xml index b0bf0934..b31c8546 100644 --- a/src/AcDream.Plugins.MossTank/mosstank.xml +++ b/src/AcDream.Plugins.MossTank/mosstank.xml @@ -711,18 +711,19 @@ VTank's one slash-command entry) in VTank's own combo order — see RouteRecallKind's own doc comment for the deviation from the earlier 4-entry model. --> - - 300 widening + is reverted: RouteRecallNames/SelectedRouteRecall now read + RecallShortCaption (VTank's own terse cmbRecallType strings — + "LS", "Mt. Lethe", "PtOIA", "Fac. Hub", ...), so the box is back + at VTank's real 120 width; AddRouteRecallCore still writes the + FULL name (RecallDisplayName via RecallLabel) onto the waypoint, + the grid row, and the .af, untouched by this. --> + [Fact] - public void RouteRecallComboShowsVtankNamesNotEnumIdentifiers() + public void RouteRecallComboShowsVtanksTerseCaptionsButTheWaypointKeepsTheFullName() { var automation = new FakeAutomation { NavigationSnapshot = NavigationAt(0f) }; var panel = new MossTankPanel(new FakeHost(automation)); Assert.Equal( [ - "Primary Portal Recall", "Secondary Portal Recall", "Lifestone Recall", - "Lifestone Sending", "Portal Recall", "Recall Aphus Lassel", - "Recall the Sanctuary", "Recall to the Singularity Caul", - "Glenden Wood Recall", "Aerlinthe Recall", "Mount Lethe Recall", - "Ulgrim's Recall", "Bur Recall", - "Paradox-touched Olthoi Infested Area Recall", - "Call of the Mhoire Forge", "Colosseum Recall", "Facility Hub Recall", - "Gear Knight Invasion Area Camp Recall", "Lost City of Neftet Recall", - "Return to the Keep", "Rynthid Recall", "Viridian Rise Recall", - "Viridian Rise Great Tree Recall", "Celestial Hand Stronghold Recall", - "Radiant Blood Stronghold Recall", "Eldrytch Web Stronghold Recall", - "Marketplace Recall", + "Primary", "Secondary", "LS", "LS Sending", "Portal", "Aphus", + "Sanctuary", "Caul", "GW", "Aerlinthe", "Mt. Lethe", "Ulgrim's", + "Bur", "PtOIA", "Graveyard", "Colosseum", "Fac. Hub", + "Gear K. Camp", "Neftet", "Candeth", "Rynthid", "VR Rocks", + "VR Tree", "Soc. CH", "Soc. RB", "Soc. EW", "Marketplace", ], panel.RouteRecallNames); - // Default selection reads as a real name, not "PrimaryPortalRecall". - Assert.Equal("Primary Portal Recall", panel.SelectedRouteRecall); + // Default selection reads as a terse caption, not the full name + // or the bare enum identifier. + Assert.Equal("Primary", panel.SelectedRouteRecall); - panel.SelectRouteRecall("Lifestone Recall"); - Assert.Equal("Lifestone Recall", panel.SelectedRouteRecall); + panel.SelectRouteRecall("LS"); + Assert.Equal("LS", panel.SelectedRouteRecall); + // The full name still lands on the notice and the grid row even + // though selection went through the terse caption above. panel.AddRouteRecall(); Assert.Contains("Lifestone Recall", panel.RouteNotice, StringComparison.Ordinal); Assert.Contains("Lifestone Recall", Assert.Single(panel.RouteWaypointTextColumn));