feat(vtank): slice 7 fix round B item 9 — Advanced Options gets clVal, lFilterList, and a real description readout
VTank's own AdvancedOptionsView (docs/research/vtank-kb/08-ui-views.md §1's
secondary-view table): lOptionList is clOpt(180)+clVal(62) two columns, not
a name-only list; lFilterList (268,4,120,180) is a category checklist
(check+text columns) filtering it; txtInfo (4,188,384,80) is a description
readout.
- lOptionList is now a real 2-column <list><column> grid: name (clOpt,
PITCH 187) + live value (clVal, PITCH 69, AdvancedOptionValueColumn via
the existing GetMetaOption/.ToDisplayString() pipeline).
- lFilterList genuinely filters lOptionList: VtankDefaultSettingsDatabase
now parses VTank's own SettingsCategories table (136 rows straight from
the embedded .usd, 2 columns: Setting name + Categories bitmask) into
VtankOptionCatalog.CategoryBits (9 distinct bits, 0x01-0x100). A setting
with no recorded bitmask always shows regardless of filter state. This
worktree has no refs/vtank/ checkout, so VTank's own category NAME
strings for those 9 bits aren't available anywhere in this repo — the
checklist honestly labels each by its raw bit value ("0x04" etc.)
instead of a guessed name.
- AdvancedOptionDescription surfaces VTank's own real Settings.Description
column (93 of 137 rows non-empty, genuine retail help text — e.g.
DoHelp's own wording about fellowship healing) prefixed with the option
name, filling the exact 384x80 readout and replacing the old bare
name-only label.
- SelectAdvancedOption/AdvancedOptionName now resolve through the FILTERED
list (not the raw 137-row catalog) so selection stays correct as the
filter narrows/widens it.
- Apply/Back move beside each other below the two lists to make room;
popup height grows 392 -> 476 for the taller lists + description block,
pushing item 8's "MossTank Extras" section further down (unchanged
internally).
New tests: AdvancedOptionCategoryFilterHidesNonMatchingSettings (unchecking
every category but EnableLooting's own 0x100 hides EnableNav but keeps
EnableLooting; re-checking restores the full list),
AdvancedOptionDescriptionSurfacesRealRetailHelpText,
AdvancedOptionValueColumnMirrorsTheLiveSettingValue. All three mutation-
checked: disabling FilteredAdvancedOptionNames's filter predicate, the
description's name-prefix, and the value column's GetMetaOption call each
turned their test red; restoring each turns it green.
tests/AcDream.Plugins.MossTank.Tests: 671/671 (was 668/668, +3).
tests/AcDream.App.Tests --filter Markup|Plugin|UiMenu|Slider: 276/3 skipped/279 (unchanged).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
95c93858a1
commit
328faea995
6 changed files with 266 additions and 42 deletions
|
|
@ -188,6 +188,11 @@ internal sealed partial class MossTankPanel
|
|||
private bool _lootEditorVisible;
|
||||
private bool _advancedOptionsVisible;
|
||||
private int _selectedAdvancedOption;
|
||||
// Fix round B item 9: one enabled flag per VtankOptionCatalog.CategoryBits
|
||||
// entry, all true by default (no filter narrows the list until the user
|
||||
// unchecks something).
|
||||
private readonly bool[] _advancedOptionCategoryEnabled =
|
||||
Enumerable.Repeat(true, VtankOptionCatalog.CategoryBits.Length).ToArray();
|
||||
private string _advancedOptionValueDraft = string.Empty;
|
||||
private string _advancedOptionNotice =
|
||||
"All VTank settings are available here.";
|
||||
|
|
@ -398,15 +403,65 @@ internal sealed partial class MossTankPanel
|
|||
public bool MetaVisible => MetaSelected;
|
||||
public bool LootEditorVisible => _lootEditorVisible;
|
||||
public bool AdvancedOptionsVisible => _advancedOptionsVisible;
|
||||
public IReadOnlyList<string> AdvancedOptionNames => VtankOptionCatalog.Names;
|
||||
// Fix round B item 9: VTank's own AdvancedOptionsView (docs/research/
|
||||
// vtank-kb/08-ui-views.md §1) pairs lOptionList's clOpt name column
|
||||
// with a clVal VALUE column, and filters both through lFilterList — a
|
||||
// category checklist keyed by SettingsCategories' own per-setting
|
||||
// bitmask (VtankDefaultSettingsDatabase.SettingCategoryBitmasks, 136
|
||||
// rows straight from the embedded .usd). This worktree has no
|
||||
// refs/vtank/ checkout, so VTank's own category NAME strings aren't
|
||||
// available anywhere in this repo — the filter groups are labeled by
|
||||
// their raw bit value ("0x04" etc.) instead of a guessed name; a
|
||||
// setting with no recorded bitmask always shows regardless of filter
|
||||
// state (never silently hidden by a filter that doesn't apply to it).
|
||||
public IReadOnlyList<string> AdvancedOptionNames => FilteredAdvancedOptionNames();
|
||||
public IReadOnlyList<string> AdvancedOptionValueColumn => FilteredAdvancedOptionNames()
|
||||
.Select(name => GetMetaOption(name).ToDisplayString())
|
||||
.ToArray();
|
||||
public IReadOnlyList<string> AdvancedOptionCategoryNames { get; } =
|
||||
VtankOptionCatalog.CategoryBits.Select(bit => $"0x{bit:X}").ToArray();
|
||||
public IReadOnlyList<bool> AdvancedOptionCategoryEnabled => _advancedOptionCategoryEnabled;
|
||||
public Action<int> ToggleAdvancedOptionCategoryAt => index =>
|
||||
{
|
||||
if ((uint)index >= (uint)_advancedOptionCategoryEnabled.Length)
|
||||
return;
|
||||
_advancedOptionCategoryEnabled[index] = !_advancedOptionCategoryEnabled[index];
|
||||
_selectedAdvancedOption = ClampRow(_selectedAdvancedOption, AdvancedOptionNames.Count);
|
||||
LoadAdvancedOptionDraft();
|
||||
};
|
||||
public int SelectedAdvancedOptionIndex => _selectedAdvancedOption;
|
||||
public string AdvancedOptionName => VtankOptionCatalog.Names[
|
||||
Math.Clamp(
|
||||
_selectedAdvancedOption,
|
||||
0,
|
||||
VtankOptionCatalog.Names.Length - 1)];
|
||||
public string AdvancedOptionName
|
||||
{
|
||||
get
|
||||
{
|
||||
IReadOnlyList<string> names = FilteredAdvancedOptionNames();
|
||||
return names.Count == 0
|
||||
? string.Empty
|
||||
: names[Math.Clamp(_selectedAdvancedOption, 0, names.Count - 1)];
|
||||
}
|
||||
}
|
||||
public string AdvancedOptionValueDraft => _advancedOptionValueDraft;
|
||||
// Fix round B item 9: VTank's own Settings.Description column (93 of
|
||||
// 137 rows non-empty, real retail help text) — fills the 384x80
|
||||
// txtInfo readout.
|
||||
public string AdvancedOptionDescription =>
|
||||
VtankDefaultSettingsDatabase.SettingDescriptions.TryGetValue(AdvancedOptionName, out string? text)
|
||||
? $"{AdvancedOptionName}: {text}"
|
||||
: AdvancedOptionName;
|
||||
public string AdvancedOptionNotice => _advancedOptionNotice;
|
||||
|
||||
private IReadOnlyList<string> FilteredAdvancedOptionNames()
|
||||
{
|
||||
int enabledMask = 0;
|
||||
for (int i = 0; i < VtankOptionCatalog.CategoryBits.Length; i++)
|
||||
if (_advancedOptionCategoryEnabled[i])
|
||||
enabledMask |= VtankOptionCatalog.CategoryBits[i];
|
||||
|
||||
return VtankOptionCatalog.Names.Where(name =>
|
||||
!VtankDefaultSettingsDatabase.SettingCategoryBitmasks.TryGetValue(name, out int mask)
|
||||
|| mask == 0
|
||||
|| (mask & enabledMask) != 0).ToArray();
|
||||
}
|
||||
public Action ShowAdvancedOptions => () =>
|
||||
{
|
||||
_advancedOptionsVisible = true;
|
||||
|
|
@ -429,10 +484,7 @@ internal sealed partial class MossTankPanel
|
|||
};
|
||||
public Action<int> SelectAdvancedOption => index =>
|
||||
{
|
||||
_selectedAdvancedOption = Math.Clamp(
|
||||
index,
|
||||
0,
|
||||
VtankOptionCatalog.Names.Length - 1);
|
||||
_selectedAdvancedOption = ClampRow(index, FilteredAdvancedOptionNames().Count);
|
||||
LoadAdvancedOptionDraft();
|
||||
};
|
||||
public Action<string> SetAdvancedOptionValueDraft => value =>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ internal static class VtankDefaultSettingsDatabase
|
|||
private const string ResourceSuffix = ".VtankDefaultSettings.usd";
|
||||
private static readonly Lazy<string> RawText = new(LoadText);
|
||||
private static readonly Lazy<RechargeHandlerRow[]> DefaultRows = new(LoadDefaultRows);
|
||||
private static readonly Lazy<IReadOnlyDictionary<string, int>> CategoryBitmasksByName =
|
||||
new(LoadCategoryBitmasks);
|
||||
private static readonly Lazy<IReadOnlyDictionary<string, string>> DescriptionsByName =
|
||||
new(LoadDescriptions);
|
||||
|
||||
/// <summary>A fresh, independently mutable parse of the embedded document — every call gets its own object graph.</summary>
|
||||
public static VtankDatabase Parse() => VtankDatabase.Parse(RawText.Value);
|
||||
|
|
@ -29,6 +33,63 @@ internal static class VtankDefaultSettingsDatabase
|
|||
/// <summary>VTank's own shipped <c>RechargeHandlerSet</c> rows (26, in file order).</summary>
|
||||
public static IReadOnlyList<RechargeHandlerRow> DefaultRechargeHandlerRows => DefaultRows.Value;
|
||||
|
||||
/// <summary>
|
||||
/// VTank's own <c>SettingsCategories</c> table (2 columns, 136 rows:
|
||||
/// <c>Setting</c> name, <c>Categories</c> bitmask) — the data
|
||||
/// <c>lFilterList</c> (docs/research/vtank-kb/08-ui-views.md §1's
|
||||
/// AdvancedOptionsView table) filters <c>lOptionList</c> by. This
|
||||
/// worktree has no access to VTank's own category NAME strings (no
|
||||
/// <c>refs/vtank/</c> checkout here — see fix round B item 9's own
|
||||
/// binding-site comment); only the raw per-setting bitmask is real
|
||||
/// data we can port from the embedded .usd.
|
||||
/// </summary>
|
||||
public static IReadOnlyDictionary<string, int> SettingCategoryBitmasks => CategoryBitmasksByName.Value;
|
||||
|
||||
/// <summary>
|
||||
/// VTank's own <c>Settings</c> table <c>Description</c> column (93 of
|
||||
/// 137 rows non-empty) — real retail help text, e.g. "DoHelp" =>
|
||||
/// "If true, allies are healed/restamed/given mana. The fellowship
|
||||
/// window must be open to help fellows." Powers fix round B item 9's
|
||||
/// <c>txtInfo</c> readout.
|
||||
/// </summary>
|
||||
public static IReadOnlyDictionary<string, string> SettingDescriptions => DescriptionsByName.Value;
|
||||
|
||||
private static IReadOnlyDictionary<string, string> LoadDescriptions()
|
||||
{
|
||||
VtankDatabase database = VtankDatabase.Parse(RawText.Value);
|
||||
VtankTable? settings = database.Find("Settings");
|
||||
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (settings is null)
|
||||
return map;
|
||||
int nameColumn = settings.ColumnIndex("Setting");
|
||||
int descriptionColumn = settings.ColumnIndex("Description");
|
||||
if (nameColumn < 0 || descriptionColumn < 0)
|
||||
return map;
|
||||
foreach (VtankRow row in settings.Rows)
|
||||
{
|
||||
string description = row.Cells[descriptionColumn].AsString();
|
||||
if (!string.IsNullOrWhiteSpace(description))
|
||||
map[row.Cells[nameColumn].AsString()] = description;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, int> LoadCategoryBitmasks()
|
||||
{
|
||||
VtankDatabase database = VtankDatabase.Parse(RawText.Value);
|
||||
VtankTable? categories = database.Find("SettingsCategories");
|
||||
var map = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
if (categories is null)
|
||||
return map;
|
||||
int nameColumn = categories.ColumnIndex("Setting");
|
||||
int bitsColumn = categories.ColumnIndex("Categories");
|
||||
if (nameColumn < 0 || bitsColumn < 0)
|
||||
return map;
|
||||
foreach (VtankRow row in categories.Rows)
|
||||
map[row.Cells[nameColumn].AsString()] = row.Cells[bitsColumn].AsInt();
|
||||
return map;
|
||||
}
|
||||
|
||||
private static string LoadText()
|
||||
{
|
||||
Assembly assembly = typeof(VtankDefaultSettingsDatabase).Assembly;
|
||||
|
|
|
|||
|
|
@ -389,4 +389,25 @@ internal static class VtankOptionCatalog
|
|||
DeclaredTypes.TryGetValue(name, out VtankSettingValueType type)
|
||||
? type
|
||||
: VtankSettingValueType.Double;
|
||||
|
||||
/// <summary>
|
||||
/// Every individual bit (power of two) actually used across
|
||||
/// <see cref="VtankDefaultSettingsDatabase.SettingCategoryBitmasks"/>'s
|
||||
/// values, ascending — the real filter groups fix round B item 9's
|
||||
/// <c>lFilterList</c> checklist offers, since a row's own mask can be a
|
||||
/// sum of several category bits (e.g. 12 = 4+8).
|
||||
/// </summary>
|
||||
internal static readonly int[] CategoryBits = VtankDefaultSettingsDatabase
|
||||
.SettingCategoryBitmasks.Values
|
||||
.SelectMany(DecomposeBits)
|
||||
.Distinct()
|
||||
.Order()
|
||||
.ToArray();
|
||||
|
||||
private static IEnumerable<int> DecomposeBits(int mask)
|
||||
{
|
||||
for (int bit = 1; bit != 0 && bit <= mask; bit <<= 1)
|
||||
if ((mask & bit) != 0)
|
||||
yield return bit;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,45 +45,73 @@
|
|||
stepper (a real duplicate of Options' own editable
|
||||
FollowNavMinimumValueText field — kept for symmetry with the other
|
||||
extras, not deleted, since both write the same
|
||||
NavigationSettings.MinimumDistanceMeters). Panel height grows 300->392
|
||||
to fit this section without touching the retail editor above it; item 9
|
||||
is expected to reshuffle the retail portion further (clVal column,
|
||||
lFilterList checklist, description readout) without moving this section.
|
||||
Bold text isn't representable in the plain retail UI font (0x40000000
|
||||
has no bold face) — the section header uses the same bright caption
|
||||
color other headers use instead. -->
|
||||
<panel x="253" y="405" w="392" h="392" title="MossTank Advanced Options"
|
||||
NavigationSettings.MinimumDistanceMeters).
|
||||
|
||||
Fix round B item 9 reshuffled the retail portion to match
|
||||
AdvancedOptionsView's own geometry (docs/research/vtank-kb/
|
||||
08-ui-views.md §1's secondary-view table) instead of the single-column
|
||||
name-only list item 8 left in place: lOptionList is now a real 2-column
|
||||
grid (clOpt name + clVal live value, PITCH 180+7=187 / 62+7=69) sitting
|
||||
beside lFilterList (268,4,120,180), a real category checklist
|
||||
(check + text columns) that filters lOptionList by VTank's own
|
||||
SettingsCategories bitmask (VtankDefaultSettingsDatabase — 136 rows
|
||||
straight from the embedded .usd, 9 distinct bits). This worktree has NO
|
||||
refs/vtank/ checkout, so VTank's own category NAME strings for those 9
|
||||
bits aren't available anywhere in this repo; the checklist labels each
|
||||
by its raw bit value ("0x04" etc.) rather than a guessed name — a
|
||||
documented, honest gap, not silently dropped. The description readout
|
||||
(AdvancedOptionDescription) fills VTank's exact 384x80 txtInfo and now
|
||||
surfaces VTank's own real per-setting help text (Settings.Description,
|
||||
93 of 137 rows non-empty, e.g. DoHelp's own retail wording) prefixed
|
||||
with the option's name — replacing the old bare name-only label, which
|
||||
is dropped as redundant. Apply/Back move beside each other under the
|
||||
two lists (VTank's own popup has neither; acdream keeps them for the
|
||||
draft-then-submit editing flow the plain key-value grammar needs).
|
||||
Panel height grows 392->476 for the taller two-list row plus the
|
||||
description block; the "MossTank Extras" section (item 8) shifts down
|
||||
to keep sitting below everything the retail portion now needs. Bold
|
||||
text isn't representable in the plain retail UI font (0x40000000 has no
|
||||
bold face) — the section header uses the same bright caption color
|
||||
other headers use instead. -->
|
||||
<panel x="253" y="405" w="392" h="476" title="MossTank Advanced Options"
|
||||
visible="{AdvancedOptionsVisible}" resize="none">
|
||||
<list x="4" y="22" w="260" h="160" rowheight="17"
|
||||
items="{AdvancedOptionNames}" selected="{SelectedAdvancedOptionIndex}"
|
||||
onchange="{SelectAdvancedOption}"
|
||||
tooltip="Select one of Virindi Tank's 137 advanced options." />
|
||||
<label x="272" y="22" w="116" h="16" text="{AdvancedOptionName}" color="#FFE8DEC3" />
|
||||
<button x="272" y="42" w="116" h="23" text="Apply"
|
||||
onclick="{ApplyAdvancedOption}" />
|
||||
<button x="272" y="70" w="116" h="23" text="Back"
|
||||
onclick="{HideAdvancedOptions}" />
|
||||
<field x="4" y="188" w="260" h="23" text="{AdvancedOptionValueDraft}"
|
||||
<list x="4" y="4" w="256" h="160" rowheight="17"
|
||||
selected="{SelectedAdvancedOptionIndex}" onchange="{SelectAdvancedOption}"
|
||||
tooltip="Select one of Virindi Tank's 137 advanced options.">
|
||||
<column type="text" width="187" items="{AdvancedOptionNames}" onclick="{SelectAdvancedOption}" />
|
||||
<column type="text" width="69" items="{AdvancedOptionValueColumn}" onclick="{SelectAdvancedOption}" />
|
||||
</list>
|
||||
<list x="268" y="4" w="120" h="180" rowheight="18"
|
||||
tooltip="Uncheck a category to hide its settings from the list on the left.">
|
||||
<column type="check" width="20" values="{AdvancedOptionCategoryEnabled}" onchange="{ToggleAdvancedOptionCategoryAt}" />
|
||||
<column type="text" width="*" items="{AdvancedOptionCategoryNames}" onclick="{ToggleAdvancedOptionCategoryAt}" />
|
||||
</list>
|
||||
<field x="4" y="168" w="260" h="16" text="{AdvancedOptionValueDraft}"
|
||||
onchange="{SetAdvancedOptionValueDraft}" onsubmit="{SubmitAdvancedOption}"
|
||||
maxlength="160" clearonsubmit="false" background="#E6000000"
|
||||
tooltip="Edit the selected advanced-option value and press Enter or Apply." />
|
||||
<label x="4" y="216" w="384" h="16" text="{AdvancedOptionNotice}" color="#FFC7B98F" />
|
||||
<label x="4" y="188" w="384" h="80" text="{AdvancedOptionDescription}" color="#FFE8DEC3" />
|
||||
<button x="4" y="272" w="116" h="23" text="Apply"
|
||||
onclick="{ApplyAdvancedOption}" />
|
||||
<button x="128" y="272" w="116" h="23" text="Back"
|
||||
onclick="{HideAdvancedOptions}" />
|
||||
<label x="4" y="298" w="384" h="16" text="{AdvancedOptionNotice}" color="#FFC7B98F" />
|
||||
|
||||
<label x="4" y="236" w="200" h="16" text="MossTank Extras" color="#FFE8DEC3" />
|
||||
<button x="4" y="254" w="90" h="18" text="Checkpoint" onclick="{AddRouteCheckpoint}" />
|
||||
<button x="100" y="254" w="90" h="18" text="Jump" onclick="{AddRouteJump}" />
|
||||
<button x="4" y="276" w="90" h="18" text="Remove" onclick="{RemoveRouteWaypoint}" />
|
||||
<button x="100" y="276" w="140" h="18" text="Set Follow Target" onclick="{SetFollowTarget}" />
|
||||
<label x="4" y="298" w="376" h="16" text="{RouteFollowTargetText}" color="#FFC7B98F" />
|
||||
<toggle x="4" y="318" w="140" h="18" text="Follow Corners"
|
||||
<label x="4" y="320" w="200" h="16" text="MossTank Extras" color="#FFE8DEC3" />
|
||||
<button x="4" y="338" w="90" h="18" text="Checkpoint" onclick="{AddRouteCheckpoint}" />
|
||||
<button x="100" y="338" w="90" h="18" text="Jump" onclick="{AddRouteJump}" />
|
||||
<button x="4" y="360" w="90" h="18" text="Remove" onclick="{RemoveRouteWaypoint}" />
|
||||
<button x="100" y="360" w="140" h="18" text="Set Follow Target" onclick="{SetFollowTarget}" />
|
||||
<label x="4" y="382" w="376" h="16" text="{RouteFollowTargetText}" color="#FFC7B98F" />
|
||||
<toggle x="4" y="402" w="140" h="18" text="Follow Corners"
|
||||
checked="{FollowAroundCornersEnabled}" onclick="{ToggleFollowAroundCorners}" />
|
||||
<toggle x="200" y="318" w="140" h="18" text="Open Doors"
|
||||
<toggle x="200" y="402" w="140" h="18" text="Open Doors"
|
||||
checked="{OpenDoorsEnabled}" onclick="{ToggleOpenDoors}" />
|
||||
<toggle x="4" y="340" w="140" h="18" text="Nav Priority"
|
||||
<toggle x="4" y="424" w="140" h="18" text="Nav Priority"
|
||||
checked="{NavigationPriorityEnabled}" onclick="{ToggleNavigationPriority}" />
|
||||
<label x="4" y="362" w="180" h="16" text="{RouteMinimumDistanceText}" color="#FFC7B98F" />
|
||||
<button x="190" y="362" w="24" h="18" text="-"
|
||||
<label x="4" y="446" w="180" h="16" text="{RouteMinimumDistanceText}" color="#FFC7B98F" />
|
||||
<button x="190" y="446" w="24" h="18" text="-"
|
||||
onclick="{RouteMinimumDistanceDown}" tooltip="Decrease the route arrival distance." />
|
||||
<button x="218" y="362" w="24" h="18" text="+"
|
||||
<button x="218" y="446" w="24" h="18" text="+"
|
||||
onclick="{RouteMinimumDistanceUp}" tooltip="Increase the route arrival distance." />
|
||||
</panel>
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ public sealed class MossTankMarkupContractTests
|
|||
/// give the main panel, now split across three files instead of one.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData("mosstank-advanced.xml", 392f, 392f)]
|
||||
[InlineData("mosstank-advanced.xml", 392f, 476f)]
|
||||
[InlineData("mosstank-loot-editor.xml", 268f, 300f)]
|
||||
[InlineData("mosstank-buffpicker.xml", 268f, 236f)]
|
||||
[InlineData("mosstank-metaeditor.xml", 630f, 160f)]
|
||||
|
|
|
|||
|
|
@ -1185,6 +1185,68 @@ public sealed class MossTankPanelTests
|
|||
Assert.False(panel.LootEditorVisible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdvancedOptionCategoryFilterHidesNonMatchingSettings()
|
||||
{
|
||||
// Fix round B item 9: lFilterList (docs/research/vtank-kb/
|
||||
// 08-ui-views.md §1's AdvancedOptionsView table) is a real category
|
||||
// checklist filtering lOptionList by VTank's own SettingsCategories
|
||||
// bitmask. "EnableLooting" carries ONLY bit 0x100 (256) in the
|
||||
// embedded .usd; "EnableNav" carries only bit 0x20 (32) — disabling
|
||||
// every category except 0x100 must hide EnableNav but keep
|
||||
// EnableLooting visible.
|
||||
var panel = new MossTankPanel(new FakeHost(new FakeAutomation()));
|
||||
Assert.Contains("EnableLooting", panel.AdvancedOptionNames);
|
||||
Assert.Contains("EnableNav", panel.AdvancedOptionNames);
|
||||
|
||||
for (int i = 0; i < panel.AdvancedOptionCategoryEnabled.Count; i++)
|
||||
if (VtankOptionCatalog.CategoryBits[i] != 0x100)
|
||||
panel.ToggleAdvancedOptionCategoryAt(i);
|
||||
|
||||
Assert.Contains("EnableLooting", panel.AdvancedOptionNames);
|
||||
Assert.DoesNotContain("EnableNav", panel.AdvancedOptionNames);
|
||||
|
||||
// Re-enabling everything restores the full list.
|
||||
for (int i = 0; i < panel.AdvancedOptionCategoryEnabled.Count; i++)
|
||||
if (!panel.AdvancedOptionCategoryEnabled[i])
|
||||
panel.ToggleAdvancedOptionCategoryAt(i);
|
||||
Assert.Contains("EnableNav", panel.AdvancedOptionNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdvancedOptionDescriptionSurfacesRealRetailHelpText()
|
||||
{
|
||||
// Fix round B item 9: txtInfo (384x80) now shows VTank's own real
|
||||
// Settings.Description text (93 of 137 rows non-empty) instead of a
|
||||
// bare name-only label.
|
||||
var panel = new MossTankPanel(new FakeHost(new FakeAutomation()));
|
||||
int index = panel.AdvancedOptionNames.ToList().IndexOf("DoHelp");
|
||||
Assert.True(index >= 0);
|
||||
|
||||
panel.SelectAdvancedOption(index);
|
||||
|
||||
Assert.StartsWith("DoHelp:", panel.AdvancedOptionDescription, StringComparison.Ordinal);
|
||||
Assert.Contains("fellowship", panel.AdvancedOptionDescription, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdvancedOptionValueColumnMirrorsTheLiveSettingValue()
|
||||
{
|
||||
// Fix round B item 9: lOptionList gained a real clVal value column
|
||||
// (AdvancedOptionValueColumn) alongside the name column.
|
||||
var panel = new MossTankPanel(new FakeHost(new FakeAutomation()));
|
||||
int index = panel.AdvancedOptionNames.ToList().IndexOf("EnableCombat");
|
||||
Assert.True(index >= 0);
|
||||
string before = panel.AdvancedOptionValueColumn[index];
|
||||
Assert.Equal(panel.CombatEnabled ? "True" : "False", before);
|
||||
|
||||
panel.ToggleCombatEnabled();
|
||||
|
||||
string after = panel.AdvancedOptionValueColumn[index];
|
||||
Assert.NotEqual(before, after);
|
||||
Assert.Equal(panel.CombatEnabled ? "True" : "False", after);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign VT slice 7 S7.2: VTank's cOn (Options tab, "Run Macro") is a
|
||||
/// Checkbox with a STATIC caption whose checked state reflects whether
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue