diff options
Diffstat (limited to 'src/LivingVillage.Desktop/Interaction.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Interaction.fs | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/src/LivingVillage.Desktop/Interaction.fs b/src/LivingVillage.Desktop/Interaction.fs index 58ebdd4..91e09ae 100644 --- a/src/LivingVillage.Desktop/Interaction.fs +++ b/src/LivingVillage.Desktop/Interaction.fs @@ -43,6 +43,7 @@ type M5View = Observations: Observation list Chronicle: string Status: string + StatusTick: int64 option HomeMode: HomeMode Prompt: string option } @@ -162,6 +163,7 @@ module M5Interaction = Observations = [] Chronicle = "" Status = "ready" + StatusTick = None HomeMode = Outside Prompt = None } @@ -234,6 +236,10 @@ module M5Interaction = let private npcNumber (NpcId id) = id + let menuNpcNumber (menu: DialogueMenu) : int = npcNumber menu.Target + + let intentLine (intent: DialogueIntent) : string = intentName intent + let private chooseIntent (index: int) (world: World) (view: M5View) : World * M5View = match view.Menu with | None -> world, { view with Status = "no dialogue menu; press E near an NPC" } @@ -245,15 +251,36 @@ module M5Interaction = | DialogueSucceeded(outcome, next) -> next, { view with - Panel = DialoguePanel + Panel = WorldPanel Menu = None Chronicle = Sim.annalText next Prompt = None - Status = sprintf "dialogue intent=%A response=%A" outcome.Intent outcome.Response } + Status = sprintf "dialogue intent=%A response=%A" outcome.Intent outcome.Response + StatusTick = Some next.Tick } | DialogueRejected(failure, next) -> - next, { view with Status = sprintf "dialogue rejected: %s" (dialogueFailureName failure) } + next, + { view with + Panel = WorldPanel + Menu = None + Prompt = None + Status = sprintf "dialogue rejected: %s" (dialogueFailureName failure) + StatusTick = Some next.Tick } - let apply (command: M5Command) (world: World) (view: M5View) : World * M5View = + let private commandAllowed (command: M5Command) (view: M5View) : bool = + match command with + | ClosePanel -> true + | Interact -> view.Panel = WorldPanel + | Intent1 + | Intent2 + | Intent3 + | Intent4 + | Intent5 + | Intent6 -> view.Panel = DialoguePanel + | Observe + | ToggleNeeds + | ShowChronicle -> view.Panel <> DialoguePanel + + let private applyAllowed (command: M5Command) (world: World) (view: M5View) : World * M5View = match command with | Interact -> match InteractionResolver.resolve world view.HomeMode with @@ -325,6 +352,20 @@ module M5Interaction = Status = sprintf "chronicle entries=%d" world.Annals.Length } | ClosePanel -> world, refreshPrompt world { view with Panel = WorldPanel; Menu = None; Status = "panel closed" } + let apply (command: M5Command) (world: World) (view: M5View) : World * M5View = + if commandAllowed command view then + let nextWorld, nextView = applyAllowed command world view + let stamped = + if nextView.Status <> view.Status && Option.isNone nextView.StatusTick then + { nextView with StatusTick = Some nextWorld.Tick } + else + nextView + nextWorld, stamped + else + world, view + + let statusDisplayDurationTicks = 150L + let tradeResultText (request: TradeRequest) (quote: float32 option) (result: TradeResult) : string = match result with | TradeSucceeded _ -> @@ -384,6 +425,15 @@ module M5Interaction = | value when value.StartsWith("no nearby") -> "附近没有可互动目标" | _ -> "状态已更新" + let statusText (view: M5View) : string = + if String.IsNullOrWhiteSpace view.Status then "准备就绪" else statusLabel view.Status + + let transientStatusLine (nowTick: int64) (view: M5View) : string option = + match view.StatusTick with + | Some tick when view.Panel = WorldPanel && nowTick - tick < statusDisplayDurationTicks -> + Some(statusText view) + | _ -> None + let private annalLine (entry: AnnalEntry) : string = match entry.Kind with | DialogueAnnal outcome -> @@ -415,12 +465,11 @@ module M5Interaction = |> List.map annalLine let panelLines (world: World) (view: M5View) : string list = - let status = if String.IsNullOrWhiteSpace view.Status then "准备就绪" else statusLabel view.Status + let status = statusText view match view.Panel with | WorldPanel -> - [ "村庄" ] - @ (view.Prompt |> Option.toList) - @ [ status ] + (view.Prompt |> Option.toList) + @ (transientStatusLine world.Tick view |> Option.toList) | NeedsPanel -> match view.Needs with | None -> [ "需求"; "暂无数据"; status ] |
