summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/Interaction.fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop/Interaction.fs')
-rw-r--r--src/LivingVillage.Desktop/Interaction.fs65
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 ]