using System.Collections.Generic;
using AcDream.Core.Chat;
using AcDream.UI.Abstractions.Panels.Settings;
namespace AcDream.App.UI.Layout;
///
/// Pure port of gmConfigUI::SetMouseTurningDefaults @0x0049E8F0 — the
/// Gameplay tab's "Use Mouse Turning Settings" button
/// (docs/research/2026-08-10-keyboard-config-and-gameplay-tab.md §4.4).
/// A one-shot "apply the recommended mouse-turning values" macro over six
/// options: five CLIENT-LOCAL preferences
/// () plus one server-synced bit
/// (PlayerOption.UseMouseTurning, NOT modeled here — the caller
/// threads the current/target value in and reads
/// back out to decide whether to
/// send SetSingleCharacterOption (0x0005)).
///
///
/// Byte-verified per-value conditions (research doc §4.4, the MSVC
/// fcomp/fnstsw/jnp idiom — the body runs when the
/// CURRENT value differs from the macro's target, exact float equality, no
/// epsilon): Stiffness → 0.95 iff ≠ 0.95; AdjustmentSpeed → 50.0 iff
/// ≠ 50.0; MouseLookSensitivity → 0.7 iff ≠ 0.7; AlignToSlope
/// → off iff currently on; InvertMouseLookYAxis → on iff currently off;
/// UseMouseTurning → on iff currently off. Retail's directional bool
/// conditions (== 1 / == 0) are behaviourally identical to a
/// plain inequality against the fixed target for a two-state bool, so this
/// port uses != uniformly.
///
///
///
/// Retail emits one retail-verbatim chat line PER CHANGED value (never for
/// an already-at-target value) and finishes with
/// SaveCurrentValues() (the caller's job — the macro's target page is
/// the Config tab's own , which this class does not
/// know about).
///
///
public static class MouseTurningSettingsMacro
{
public readonly record struct Result(
CameraTurningSettings Updated,
bool UseMouseTurningChanged,
IReadOnlyList ChatLines);
///
/// Computes the macro's outcome. Pure — no I/O, no side effects; the
/// caller applies (persist + live apply),
/// sends the wire bit if ,
/// and emits through the interface-text
/// seam, in that order (retail's own call order at
/// 0x0049E924-0x0049EB57).
///
public static Result Compute(CameraTurningSettings current, bool useMouseTurningCurrent)
{
CameraTurningSettings target = CameraTurningSettings.MouseTurningTarget;
var lines = new List();
float stiffness = current.Stiffness;
if (stiffness != target.Stiffness)
{
lines.Add(OptionsPanelText.CameraStiffnessChanged(stiffness, target.Stiffness));
stiffness = target.Stiffness;
}
float adjustmentSpeed = current.AdjustmentSpeed;
if (adjustmentSpeed != target.AdjustmentSpeed)
{
lines.Add(OptionsPanelText.CameraAdjustmentChanged(adjustmentSpeed, target.AdjustmentSpeed));
adjustmentSpeed = target.AdjustmentSpeed;
}
float sensitivity = current.MouseLookSensitivity;
if (sensitivity != target.MouseLookSensitivity)
{
lines.Add(OptionsPanelText.MouseSensitivityChanged(sensitivity, target.MouseLookSensitivity));
sensitivity = target.MouseLookSensitivity;
}
bool alignToSlope = current.AlignToSlope;
if (alignToSlope != target.AlignToSlope)
{
lines.Add(OptionsPanelText.AlignToSlopeChanged);
alignToSlope = target.AlignToSlope;
}
bool invertY = current.InvertMouseLookYAxis;
if (invertY != target.InvertMouseLookYAxis)
{
lines.Add(OptionsPanelText.InvertMouseLookAxesChanged);
invertY = target.InvertMouseLookYAxis;
}
// UseMouseTurning's target is always ON (true) — retail's
// `== 0` condition ("currently off").
bool useMouseTurningChanged = useMouseTurningCurrent != true;
if (useMouseTurningChanged)
lines.Add(OptionsPanelText.TurnToFaceCameraChanged);
return new Result(
new CameraTurningSettings(stiffness, adjustmentSpeed, sensitivity, alignToSlope, invertY),
useMouseTurningChanged,
lines);
}
}