Mount authored gmCombatUI, share one press/hold/release request state machine across DAT buttons and keybindings, and recover the exact 1.0s/0.8s power timing from matching retail x86. The same timer fixes jump charge, while ready-stance, response queueing, auto-repeat, layout binding, migration, and conformance coverage keep behavior architectural rather than panel-local. Co-Authored-By: Codex <codex@openai.com>
106 lines
3.8 KiB
C#
106 lines
3.8 KiB
C#
using AcDream.App.Combat;
|
|
using AcDream.App.UI;
|
|
using AcDream.App.UI.Layout;
|
|
using AcDream.Core.Combat;
|
|
|
|
namespace AcDream.App.Tests.UI.Layout;
|
|
|
|
public sealed class CombatUiControllerTests
|
|
{
|
|
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
|
|
|
[Fact]
|
|
public void CombatMode_ShowsOnlyTargetedModes_AndSelectsMediumByDefault()
|
|
{
|
|
double now = 0d;
|
|
var combat = new CombatState();
|
|
using var attacks = CreateAttacks(combat, () => now, []);
|
|
var (layout, _, _, power, high, medium, low) = BuildLayout();
|
|
var visibility = new List<bool>();
|
|
using var controller = CombatUiController.Bind(
|
|
layout, combat, attacks, visibility.Add)!;
|
|
|
|
controller.SyncVisibility();
|
|
combat.SetCombatMode(CombatMode.Melee);
|
|
combat.SetCombatMode(CombatMode.Magic);
|
|
|
|
Assert.Equal([false, true, false], visibility);
|
|
Assert.False(high.Selected);
|
|
Assert.True(medium.Selected);
|
|
Assert.False(low.Selected);
|
|
Assert.Equal(CombatAttackController.InitialDesiredPower, power.ScalarPosition);
|
|
}
|
|
|
|
[Fact]
|
|
public void AuthoredHeightButton_PressChargesAndReleaseSendsThroughSharedController()
|
|
{
|
|
double now = 4d;
|
|
var sent = new List<(AttackHeight Height, float Power)>();
|
|
var combat = new CombatState();
|
|
using var attacks = CreateAttacks(combat, () => now, sent);
|
|
var (layout, basic, advanced, power, high, _, _) = BuildLayout();
|
|
using var controller = CombatUiController.Bind(
|
|
layout, combat, attacks, _ => { })!;
|
|
combat.SetCombatMode(CombatMode.Melee);
|
|
|
|
high.OnEvent(new UiEvent(0, high, UiEventType.MouseDown, Data1: 2, Data2: 2));
|
|
now = 4.5d;
|
|
Assert.Equal(0.5f, power.ScalarFill()!.Value, 3);
|
|
high.OnEvent(new UiEvent(0, high, UiEventType.MouseUp, Data1: 2, Data2: 2));
|
|
|
|
var attack = Assert.Single(sent);
|
|
Assert.Equal(AttackHeight.High, attack.Height);
|
|
Assert.Equal(0.5f, attack.Power, 3);
|
|
Assert.True(basic.Visible);
|
|
Assert.False(advanced.Visible);
|
|
}
|
|
|
|
private static CombatAttackController CreateAttacks(
|
|
CombatState combat,
|
|
Func<double> now,
|
|
List<(AttackHeight Height, float Power)> sent)
|
|
=> new(
|
|
combat,
|
|
() => true,
|
|
(height, power) =>
|
|
{
|
|
sent.Add((height, power));
|
|
return true;
|
|
},
|
|
autoRepeatAttack: () => false,
|
|
now: now);
|
|
|
|
private static (
|
|
ImportedLayout Layout,
|
|
UiElement Basic,
|
|
UiElement Advanced,
|
|
UiScrollbar Power,
|
|
UiButton High,
|
|
UiButton Medium,
|
|
UiButton Low) BuildLayout()
|
|
{
|
|
var root = new UiPanel { Width = 610, Height = 90 };
|
|
var basic = new UiPanel();
|
|
var advanced = new UiPanel();
|
|
var power = new UiScrollbar { Width = 507, Height = 14, Horizontal = true };
|
|
UiButton Button(uint id) => new(
|
|
new ElementInfo { Id = id, Type = 1, Width = 72, Height = 19 }, NoTex)
|
|
{
|
|
Width = 72,
|
|
Height = 19,
|
|
};
|
|
var high = Button(CombatUiController.HighButtonId);
|
|
var medium = Button(CombatUiController.MediumButtonId);
|
|
var low = Button(CombatUiController.LowButtonId);
|
|
var byId = new Dictionary<uint, UiElement>
|
|
{
|
|
[CombatUiController.BasicPanelId] = basic,
|
|
[CombatUiController.AdvancedPanelId] = advanced,
|
|
[CombatUiController.PowerControlId] = power,
|
|
[CombatUiController.HighButtonId] = high,
|
|
[CombatUiController.MediumButtonId] = medium,
|
|
[CombatUiController.LowButtonId] = low,
|
|
};
|
|
return (new ImportedLayout(root, byId), basic, advanced, power, high, medium, low);
|
|
}
|
|
}
|