diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 23:03:16 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 23:03:16 +0800 |
| commit | 6ce29c5e87d32e49dfe92b398fe45ef0b9de6cdf (patch) | |
| tree | 859a902d27e069e0e087579b6ea38dec76dc4bf3 /src/LivingVillage.Kernel.Tests/DailyTaskTests.fs | |
| parent | 11a2a1d8786a660d0f370a46f5ee0c69c108f823 (diff) | |
| parent | 50875bb65cc4cdba92f6745d2430a92d85474872 (diff) | |
| download | living-village-6ce29c5e87d32e49dfe92b398fe45ef0b9de6cdf.tar.gz | |
merge: P15 职业玩法收口——开局职业选择/货郎书生模板/CJK补字/全链路回归(独立复验全绿)
Diffstat (limited to 'src/LivingVillage.Kernel.Tests/DailyTaskTests.fs')
| -rw-r--r-- | src/LivingVillage.Kernel.Tests/DailyTaskTests.fs | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/src/LivingVillage.Kernel.Tests/DailyTaskTests.fs b/src/LivingVillage.Kernel.Tests/DailyTaskTests.fs index e784d83..0800ff8 100644 --- a/src/LivingVillage.Kernel.Tests/DailyTaskTests.fs +++ b/src/LivingVillage.Kernel.Tests/DailyTaskTests.fs @@ -50,20 +50,24 @@ type DailyTaskTests () = Assert.AreEqual<uint64>(0x02D114B7ABDD7A1FUL, Occupation.taskHash 4242UL 99UL 0L) [<TestMethod>] - member _.FarmerAndFisherPoolsAreThreeTemplatesEach () = + member _.EveryOccupationPoolIsNonEmptyAndFarmFisherKeepThree () = Assert.AreEqual( [ Occupation.DeliverGrain; Occupation.HelpWork; Occupation.TillSoil ], Occupation.taskPoolOf Occupation.Farmer) Assert.AreEqual( [ Occupation.NightCatch; Occupation.SellFish; Occupation.MarketInquiry ], Occupation.taskPoolOf Occupation.Fisher) - Assert.AreEqual<int>(0, Occupation.taskPoolOf Occupation.Peddler |> List.length) - Assert.AreEqual<int>(0, Occupation.taskPoolOf Occupation.Scholar |> List.length) + Assert.AreEqual( + [ Occupation.BuyGoods; Occupation.Resell ], + Occupation.taskPoolOf Occupation.Peddler) + Assert.AreEqual( + [ Occupation.ObserveNotes; Occupation.ReasonDebate ], + Occupation.taskPoolOf Occupation.Scholar) [<TestMethod>] member _.GeneratedTasksStayInPoolAndRepeatDeterministically () = for seed, occ in [ (42UL, 7UL); (7UL, 42UL); (123456789UL, 555UL) ] do - for kind in [ Occupation.Farmer; Occupation.Fisher ] do + for kind in Occupation.all do let pool = Occupation.taskPoolOf kind for day in 0L .. 299L do let task = (Occupation.dailyTaskOf seed occ day kind).Value @@ -77,9 +81,17 @@ type DailyTaskTests () = Assert.IsTrue(distinct.Count >= 2, "300 days must not pin a single template") [<TestMethod>] - member _.PeddlerAndScholarHaveNoDailyTaskYet () = - Assert.AreEqual<Occupation.DailyTask option>(None, Occupation.dailyTaskOf 42UL 7UL 0L Occupation.Peddler) - Assert.AreEqual<Occupation.DailyTask option>(None, Occupation.dailyTaskOf 42UL 7UL 0L Occupation.Scholar) + member _.PeddlerAndScholarGenerateTheirOwnDailyTasks () = + for kind in [ Occupation.Peddler; Occupation.Scholar ] do + for day in 0L .. 59L do + let task = (Occupation.dailyTaskOf 42UL 7UL day kind).Value + Assert.IsTrue(Occupation.taskPoolOf kind |> List.contains task.TemplateId) + Assert.AreEqual<Occupation.TaskTemplateId>( + Occupation.BuyGoods, + (Occupation.dailyTaskOf 42UL 7UL 0L Occupation.Peddler).Value.TemplateId) + Assert.AreEqual<Occupation.TaskTemplateId>( + Occupation.ObserveNotes, + (Occupation.dailyTaskOf 42UL 7UL 0L Occupation.Scholar).Value.TemplateId) [<TestMethod>] member _.TaskWindowCoversExactlyOneDayStartingOffered () = @@ -98,6 +110,10 @@ type DailyTaskTests () = Assert.AreEqual<string>("夜捕", Occupation.taskNameOf Occupation.NightCatch) Assert.AreEqual<string>("卖渔", Occupation.taskNameOf Occupation.SellFish) Assert.AreEqual<string>("询价", Occupation.taskNameOf Occupation.MarketInquiry) + Assert.AreEqual<string>("收货", Occupation.taskNameOf Occupation.BuyGoods) + Assert.AreEqual<string>("转卖", Occupation.taskNameOf Occupation.Resell) + Assert.AreEqual<string>("观察记事", Occupation.taskNameOf Occupation.ObserveNotes) + Assert.AreEqual<string>("论理", Occupation.taskNameOf Occupation.ReasonDebate) // ---- §3 状态机 Offered|Active|Done|Failed ---- @@ -298,3 +314,73 @@ type DailyTaskTests () = let state = { (Occupation.stateOf Occupation.Farmer) with Today = Some(DailyTaskHarness.taskForDay 9L) } WorldSave.saveWith (Some state) world Assert.AreEqual<string>(build (), build ()) + + // ---- P15:货郎/书生模板完成信号、事件通道桥、当日刷新 ---- + + [<TestMethod>] + member _.PeddlerAndScholarTemplatesCompleteOnTheirSignals () = + let buy = DailyTaskHarness.accepted Occupation.BuyGoods + Assert.AreEqual<Occupation.TaskState>(Occupation.Done, (Occupation.applySignal (Occupation.Purchased(Food, 2)) buy).State) + Assert.AreEqual<Occupation.TaskState>(Occupation.Active, (Occupation.applySignal (Occupation.Purchased(Food, 0)) buy).State) + Assert.AreEqual<Occupation.TaskState>(Occupation.Active, (Occupation.applySignal (Occupation.Dialogued(NpcId 0)) buy).State) + let resell = DailyTaskHarness.accepted Occupation.Resell + Assert.AreEqual<Occupation.TaskState>(Occupation.Done, (Occupation.applySignal (Occupation.Traded(playerId, Spice, 1)) resell).State) + Assert.AreEqual<Occupation.TaskState>(Occupation.Active, (Occupation.applySignal (Occupation.Traded(NpcId 2, Spice, 1)) resell).State) + let observe = DailyTaskHarness.accepted Occupation.ObserveNotes + Assert.AreEqual<Occupation.TaskState>(Occupation.Done, (Occupation.applySignal Occupation.Observed observe).State) + Assert.AreEqual<Occupation.TaskState>(Occupation.Active, (Occupation.applySignal (Occupation.Dialogued(NpcId 0)) observe).State) + let reason = DailyTaskHarness.accepted Occupation.ReasonDebate + Assert.AreEqual<Occupation.TaskState>(Occupation.Done, (Occupation.applySignal (Occupation.Dialogued(NpcId 3)) reason).State) + Assert.AreEqual<Occupation.TaskState>(Occupation.Active, (Occupation.applySignal Occupation.Observed reason).State) + + [<TestMethod>] + member _.SignalBridgeIgnoresNpcInitiatedEvents () = + let npcDialogue = + { Tick = 5L + Kind = DialogueEvent { Tick = 5L; Actor = NpcId 1; Target = NpcId 2; Intent = SmallTalk; Response = Friendly; Valence = 0.3f } } + Assert.AreEqual<Occupation.TaskSignal option>(None, Occupation.signalOfInteraction npcDialogue) + let npcTrade = { Tick = 5L; Kind = TradeEvent(NpcId 1, NpcId 2, Food, 1, 1.0f) } + Assert.AreEqual<Occupation.TaskSignal option>(None, Occupation.signalOfInteraction npcTrade) + let playerBuy = { Tick = 6L; Kind = TradeEvent(playerId, NpcId 2, Spice, 3, 2.0f) } + Assert.AreEqual<Occupation.TaskSignal option>(Some(Occupation.Purchased(Spice, 3)), Occupation.signalOfInteraction playerBuy) + let playerSell = { Tick = 7L; Kind = TradeEvent(NpcId 2, playerId, Fish, 4, 2.0f) } + Assert.AreEqual<Occupation.TaskSignal option>(Some(Occupation.Traded(playerId, Fish, 4)), Occupation.signalOfInteraction playerSell) + + [<TestMethod>] + member _.PlayerDialogueEventThroughExistingChannelCompletesTheDaysTask () = + let world = Sim.initialWorldN 7UL 4 + let nearFirst = { world with Avatar = { world.Avatar with Pos = world.Npcs.[0].Pos } } + match Sim.chooseDialogue (NpcId 0) SmallTalk nearFirst with + | DialogueRejected (failure, _) -> Assert.Fail($"dialogue rejected: {failure}") + | DialogueSucceeded (outcome, afterDialogue) -> + let event = afterDialogue.Events |> List.last + Assert.AreEqual<Sim.NpcId>(playerId, outcome.Actor) + Assert.AreEqual<Occupation.TaskSignal option>(Some(Occupation.Dialogued(NpcId 0)), Occupation.signalOfInteraction event) + let day = + [ 0L .. 60L ] + |> List.find (fun day -> + (Occupation.dailyTaskOf 42UL 7UL day Occupation.Farmer).Value.TemplateId = Occupation.HelpWork) + let offered = (Occupation.dailyTaskOf 42UL 7UL day Occupation.Farmer).Value + let notAccepted = Occupation.advanceTask event { (Occupation.stateOf Occupation.Farmer) with Today = Some offered } + Assert.AreEqual<Occupation.TaskState>(Occupation.Offered, notAccepted.Today.Value.State) + let active = notAccepted.Today |> Option.map Occupation.acceptTask + let completed = Occupation.advanceTask event { notAccepted with Today = active } + Assert.AreEqual<Occupation.TaskState>(Occupation.Done, completed.Today.Value.State) + + [<TestMethod>] + member _.RefreshTodayKeepsSameDayFinalsAndRegeneratesOnDayChange () = + let day0 = (Occupation.dailyTaskOf 42UL 7UL 0L Occupation.Farmer).Value + Assert.AreEqual<Occupation.DailyTask option>( + Some day0, + Occupation.refreshToday 42UL 7UL Occupation.Farmer (Sim.ticksPerDay - 1L) (Some day0)) + let day1 = (Occupation.dailyTaskOf 42UL 7UL 1L Occupation.Farmer).Value + Assert.AreEqual<Occupation.DailyTask option>( + Some day1, + Occupation.refreshToday 42UL 7UL Occupation.Farmer Sim.ticksPerDay (Some day0)) + let finished = { day0 with State = Occupation.Done } + Assert.AreEqual<Occupation.DailyTask option>( + Some finished, + Occupation.refreshToday 42UL 7UL Occupation.Farmer 10L (Some finished)) + Assert.AreEqual<Occupation.DailyTask option>( + Some day1, + Occupation.refreshToday 42UL 7UL Occupation.Farmer Sim.ticksPerDay None) |
