acdream/tests/AcDream.UI.Abstractions.Tests/Panels/Settings/GameplaySettingsTests.cs
Erik b7165e5b17 feat(ui): Gameplay tab — 14 retail CharacterOption-derived toggles
Phase L.0 (cont.) — third tab on the Settings shell, in the Easy-wins
build order. Subset of retail's CharacterOption + CharacterOptions2
bitfield flags ported as bools (see acclient.h:3404+ enum). Local-
only this phase per the brainstorm — server sync deferred to a
later phase that will marshal the draft into the retail
CharacterOption packet.

GameplaySettings record exposes 14 named flags grouped by usage:

 · Combat: AutoTarget, AutoRepeatAttack, ToggleRun, AdvancedCombatUI,
   VividTargetingIndicator
 · Display: ShowTooltips, SideBySideVitals, CoordinatesOnRadar,
   SpellDuration, ShowHelm, ShowCloak
 · Interface: AllowGive, LockUI, UseMouseTurning

Retail names + bit values are documented in field-level comments so
the future server-sync phase has a 1:1 mapping. Defaults are
typical-user starting points (NOT bit-exact to retail's
0x50C4A54A / 0x948700 masks); class-level remarks call out that
defaults will be re-anchored to retail values once the wire-format
is the load-bearing source.

SettingsStore grows LoadGameplay / SaveGameplay using the existing
SaveSection generic helper (added in the audio commit). All three
non-keybind sections (display, audio, gameplay) now coexist in
settings.json with non-destructive cross-section saves — verified
by a new "all three sections coexist" round-trip test.

SettingsVM grows the parallel gameplay state machine
(gameplayPersisted / gameplayDraft / SetGameplay / onSaveGameplay).
HasUnsavedChanges, Save, Cancel, ResetAllToDefaults all cover
gameplay too. Constructor signature adds two more params; existing
call sites (App startup + tests) updated.

SettingsPanel.RenderGameplayTab replaces the L.0-shell placeholder —
14 Checkbox calls grouped under three Text+Separator headers, plus
a footer note explaining the local-only-this-phase scope. The
"Coming soon" placeholder test was retargeted from "Gameplay" to
"Chat" since Gameplay is no longer a placeholder.

GameWindow construction site loads gameplay on startup + writes via
the SettingsStore on Save. Server-sync packet wiring is left as a
TODO comment in the onSaveGameplay callback (next phase, after the
protocol round-trip is in place).

14 new tests:
 · GameplaySettings record (3) — defaults pinned, value equality,
   with-expressions
 · SettingsStore gameplay (4) — missing-file → defaults, round-trip,
   partial-file fallback, all-three-sections coexist
 · SettingsVM gameplay (5) — initial draft, SetGameplay marks dirty,
   Save invokes callback, Cancel reverts, ResetAllToDefaults covers
 · SettingsPanel gameplay tab (2) — 8 spot-checked Checkboxes render
   only when active

dotnet build green (0 warnings); dotnet test 1,276 / 1,276 green
(243 Core.Net + 360 UI.Abstractions + 673 Core).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 18:05:07 +02:00

54 lines
1.9 KiB
C#

using AcDream.UI.Abstractions.Panels.Settings;
namespace AcDream.UI.Abstractions.Tests.Panels.Settings;
/// <summary>
/// L.0: <see cref="GameplaySettings"/> default-pin tests + value-equality
/// guarantees. Defaults are intentionally NOT bit-exact to retail's
/// <c>0x50C4A54A</c> mask — see GameplaySettings remarks for rationale.
/// </summary>
public sealed class GameplaySettingsTests
{
[Fact]
public void Default_values_are_typical_user_friendly()
{
// These defaults are reviewed in the L.0 brainstorm — typical-user
// starting point, not retail-bitmask. A change to any of these
// should be a deliberate decision, not a drive-by.
var d = GameplaySettings.Default;
Assert.True(d.AutoTarget);
Assert.True(d.AutoRepeatAttack);
Assert.True(d.ToggleRun);
Assert.False(d.AdvancedCombatUI);
Assert.True(d.ShowTooltips);
Assert.False(d.VividTargetingIndicator);
Assert.False(d.SideBySideVitals);
Assert.False(d.CoordinatesOnRadar);
Assert.True(d.SpellDuration);
Assert.True(d.AllowGive);
Assert.True(d.ShowHelm);
Assert.True(d.ShowCloak);
Assert.False(d.LockUI);
Assert.False(d.UseMouseTurning);
}
[Fact]
public void Equality_is_value_based()
{
var a = GameplaySettings.Default;
var b = GameplaySettings.Default with { AutoTarget = false };
var c = GameplaySettings.Default with { AutoTarget = false };
Assert.NotEqual(a, b);
Assert.Equal(b, c);
}
[Fact]
public void With_expression_clones_one_field()
{
var d = GameplaySettings.Default with { LockUI = true };
Assert.True(d.LockUI);
// Other fields untouched.
Assert.Equal(GameplaySettings.Default.AutoTarget, d.AutoTarget);
Assert.Equal(GameplaySettings.Default.ShowHelm, d.ShowHelm);
}
}