summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop.Tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 12:37:05 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 12:37:05 +0800
commiteaedd532c7d93dec9cca5d361685ed32c85aeebb (patch)
tree15b0ac0769bd8add372fa010fdcf5d0504b0f979 /src/LivingVillage.Desktop.Tests
parent1401000ed8626a6eeb30d6b9f0d70224bd869b0a (diff)
downloadliving-village-eaedd532c7d93dec9cca5d361685ed32c85aeebb.tar.gz
fix(desktop): 目标选择纯距离优先与 id 平局
情境提示目标选择改为距离最近优先(不再按门/人类型特权),平局按实体 id 升序确定唯一目标;新增门/人两侧距离优先对照、精确等距 tie、NPC 数组快照不变(resolve 与 refreshPrompt 均不突变 Npcs)回归测试;透墙与超距判定沿用既有 实现,已有边界/竞争/切换用例保持全绿。
Diffstat (limited to 'src/LivingVillage.Desktop.Tests')
-rw-r--r--src/LivingVillage.Desktop.Tests/PrototypeTests.fs35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
index 77d2530..af34802 100644
--- a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
+++ b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
@@ -595,6 +595,41 @@ type PrototypeTests () =
Assert.IsTrue(M5Interaction.resolveAction blockedWorld Outside |> Option.isNone)
[<TestMethod>]
+ member _.TargetSelectionUsesPureDistancePriorityWithIdTiebreak () =
+ let doorPixel : PixelPosition =
+ { X = float32 (31 * Sim.tilePixels + Sim.tilePixels / 2)
+ Y = float32 (23 * Sim.tilePixels + Sim.tilePixels / 2) }
+ let avatar : Vec2 = { X = doorPixel.X - 32.0f; Y = doorPixel.Y }
+ let world = Sim.initialWorldN 42UL 2
+
+ // Door nearer than the villager: door wins by pure distance (no kind privilege).
+ let doorNearer =
+ { world with
+ Avatar = { world.Avatar with Pos = avatar }
+ Npcs = [| { world.Npcs.[0] with Pos = { X = avatar.X + 40.0f; Y = avatar.Y } } |] }
+ Assert.AreEqual<InteractionAction option>(Some(EnterHome(HomeId 1)), InteractionResolver.resolve doorNearer Outside |> Option.map (fun candidate -> candidate.Action))
+
+ // NPC nearer than the door: villager wins.
+ let npcNearerWorld = { doorNearer with Npcs = [| { world.Npcs.[0] with Pos = { X = avatar.X + 4.0f; Y = avatar.Y } } |] }
+ Assert.AreEqual<InteractionAction option>(Some(TalkTo(NpcId 0)), InteractionResolver.resolve npcNearerWorld Outside |> Option.map (fun candidate -> candidate.Action))
+
+ // Exact distance tie between two villagers: lower entity id wins deterministically.
+ let tieAvatar : Vec2 = { X = 1600.0f; Y = 800.0f }
+ let tieWorld =
+ { world with
+ Avatar = { world.Avatar with Pos = tieAvatar }
+ Npcs = [| { world.Npcs.[0] with Pos = { X = tieAvatar.X + 64.0f; Y = tieAvatar.Y } }
+ { world.Npcs.[1] with Pos = { X = tieAvatar.X - 64.0f; Y = tieAvatar.Y } } |] }
+ Assert.AreEqual<InteractionAction option>(Some(TalkTo(NpcId 0)), InteractionResolver.resolve tieWorld Outside |> Option.map (fun candidate -> candidate.Action))
+
+ // Array snapshot immutability: neither resolve nor refreshPrompt may mutate Npcs.
+ let snapshot = Array.copy tieWorld.Npcs
+ let resolvedIgnore = InteractionResolver.resolve tieWorld Outside
+ CollectionAssert.AreEqual(snapshot, tieWorld.Npcs)
+ let view = M5Interaction.refreshPrompt tieWorld M5Interaction.initial
+ CollectionAssert.AreEqual(snapshot, tieWorld.Npcs)
+
+ [<TestMethod>]
member _.WorldPanelDoesNotRenderA永久KeyList () =
let world = Sim.initialWorldN 42UL 0
let lines = M5Interaction.panelLines world M5Interaction.initial