diff --git a/src/AcDream.App/UI/Testing/RetailUiAutomationProbe.cs b/src/AcDream.App/UI/Testing/RetailUiAutomationProbe.cs
index d3ab64c1..069f6d26 100644
--- a/src/AcDream.App/UI/Testing/RetailUiAutomationProbe.cs
+++ b/src/AcDream.App/UI/Testing/RetailUiAutomationProbe.cs
@@ -131,6 +131,22 @@ public sealed class RetailUiAutomationProbe
return true;
}
+ ///
+ /// Raw synthetic click at canvas coordinates (vitals retail-modes round,
+ /// 2026-08-17): the Options panel's Character-tab rows are template
+ /// instances sharing ONE dat element id per control
+ /// (0x10000218/0x10000219 for every toggle row), so
+ /// element-id addressing cannot reach a SPECIFIC row's checkbox — a
+ /// drive script instead reads the row's rect from
+ /// and clicks its center. Same synthetic route as
+ /// — never the OS cursor.
+ ///
+ public bool ClickAtPoint(int x, int y)
+ {
+ ClickAt(x, y);
+ return true;
+ }
+
///
/// 2026-08-17 morning gate: synthetic pointer HOVER (no click) at an
/// element's center, for rollover/tooltip verification. Deliberately
diff --git a/src/AcDream.App/UI/Testing/RetailUiAutomationScriptRunner.cs b/src/AcDream.App/UI/Testing/RetailUiAutomationScriptRunner.cs
index 46d0ec37..7a0c9c7c 100644
--- a/src/AcDream.App/UI/Testing/RetailUiAutomationScriptRunner.cs
+++ b/src/AcDream.App/UI/Testing/RetailUiAutomationScriptRunner.cs
@@ -219,7 +219,7 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
private bool DoClick(ScriptCommand command)
{
var p = command.Parts;
- if (p.Length < 3) return Stop(command, "usage: click element | click item [source]");
+ if (p.Length < 3) return Stop(command, "usage: click element | click item [source] | click at ");
string target = p[1].ToLowerInvariant();
if (target == "element")
{
@@ -231,7 +231,19 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
if (!TryParseUInt(p[2], out uint itemGuid)) return Stop(command, $"bad item guid '{p[2]}'");
return _probe.ClickItem(itemGuid, ParseSource(p, 3)) || Stop(command, "click item failed");
}
- return Stop(command, "usage: click element | click item [source]");
+ if (target == "at")
+ {
+ // `click at ` — raw synthetic click in canvas coordinates
+ // (see RetailUiAutomationProbe.ClickAtPoint: template-instanced
+ // controls share one dat id, so a specific row is addressed by
+ // the rect its own `dump` line reports).
+ if (p.Length < 4
+ || !TryParseInt(p[2], out int x)
+ || !TryParseInt(p[3], out int y))
+ return Stop(command, "usage: click at ");
+ return _probe.ClickAtPoint(x, y) || Stop(command, "click at failed");
+ }
+ return Stop(command, "usage: click element | click item [source] | click at ");
}
/// 2026-08-17 morning gate: `hover element <datId>` — a