diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 12:37:05 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 12:37:05 +0800 |
| commit | eaedd532c7d93dec9cca5d361685ed32c85aeebb (patch) | |
| tree | 15b0ac0769bd8add372fa010fdcf5d0504b0f979 /src | |
| parent | 1401000ed8626a6eeb30d6b9f0d70224bd869b0a (diff) | |
| download | living-village-eaedd532c7d93dec9cca5d361685ed32c85aeebb.tar.gz | |
fix(desktop): 目标选择纯距离优先与 id 平局
情境提示目标选择改为距离最近优先(不再按门/人类型特权),平局按实体 id 升序确定唯一目标;新增门/人两侧距离优先对照、精确等距 tie、NPC 数组快照不变(resolve 与 refreshPrompt 均不突变 Npcs)回归测试;透墙与超距判定沿用既有 实现,已有边界/竞争/切换用例保持全绿。
Diffstat (limited to 'src')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/PrototypeTests.fs | 35 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Interaction.fs | 7 |
2 files changed, 36 insertions, 6 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 diff --git a/src/LivingVillage.Desktop/Interaction.fs b/src/LivingVillage.Desktop/Interaction.fs index 20ffa17..916544c 100644 --- a/src/LivingVillage.Desktop/Interaction.fs +++ b/src/LivingVillage.Desktop/Interaction.fs @@ -139,17 +139,12 @@ module InteractionResolver = candidates |> List.sortBy (fun candidate -> - let priority = - match candidate.Action with - | EnterHome _ - | ExitHome _ -> 0 - | TalkTo _ -> 1 let stableId = match candidate.Action with | TalkTo id -> npcNumber id | EnterHome(HomeId id) | ExitHome(HomeId id) -> id - priority, candidate.DistanceSquared, stableId) + candidate.DistanceSquared, stableId) |> List.tryHead let resolveAction = resolve |
