veloren_rtsim/rule/npc_ai/
dialogue.rs1use super::*;
2
3use std::sync::Arc;
4
5pub fn talk<S: State>(tgt: Actor) -> impl Action<S> + Clone {
6 just(move |ctx, _| ctx.controller.do_talk(tgt)).debug(|| "talking")
7}
8
9pub fn do_dialogue<S: State, A: Action<S>>(
10 tgt: Actor,
11 f: impl Fn(DialogueSession) -> A + Send + Sync + 'static,
12) -> impl Action<S> {
13 now(move |ctx, _| {
14 let session = ctx.controller.dialogue_start(tgt);
15 f(session)
16 .stop_if(move |ctx: &mut NpcCtx| {
18 let mut stop = false;
19 ctx.inbox.retain(|input| {
20 if let NpcInput::Dialogue(_, dialogue) = input
21 && dialogue.id == session.id
22 && let DialogueKind::End = dialogue.kind
23 {
24 stop = true;
25 false
26 } else {
27 true
28 }
29 });
30 stop
31 })
32 .then(just(move |ctx, _| {
33 ctx.controller.do_idle();
34 ctx.controller.dialogue_end(session);
35 }))
36 })
37}
38
39impl DialogueSession {
40 pub fn ask_question<S: State, T: Into<Option<(u16, U)>>, U: Into<Response>>(
45 self,
46 question: Content,
47 responses: impl IntoIterator<Item = T> + Clone + Send + Sync + 'static,
48 ) -> impl Action<S, Option<u16>> {
49 let responses = responses
50 .clone()
51 .into_iter()
52 .flat_map(Into::into)
53 .map(|(id, r)| (id, r.into()))
54 .collect::<Arc<[_]>>();
55
56 now(move |ctx, _| {
57 let q_tag = ctx.controller.dialogue_question(
58 self,
59 question.clone(),
60 responses.iter().cloned(),
61 );
62 let responses = responses.clone();
63 until(move |ctx, _| {
64 let mut id = None;
65 ctx.inbox.retain(|input| {
66 if let NpcInput::Dialogue(_, dialogue) = input
67 && dialogue.id == self.id
69 && let DialogueKind::Response { tag, response_id, response, .. } = &dialogue.kind
70 && *tag == q_tag
72 && responses.iter().any(|(r_id, r)| r_id == response_id && r == response)
74 {
75 id = Some(*response_id);
76 false
77 } else {
78 true
79 }
80 });
81 match id {
82 None => ControlFlow::Continue(talk(self.target)),
84 Some(response_id) => ControlFlow::Break(response_id),
85 }
86 })
87 })
88 .and_then(move |response_id| talk(self.target).repeat().stop_if(timeout(0.5)).map(move |_, _| response_id))
90 .stop_if(timeout(60.0))
93 }
94
95 pub fn say_statement<S: State>(self, stmt: Content) -> impl Action<S> {
96 now(move |ctx, _| {
97 ctx.controller.dialogue_statement(self, stmt.clone());
98 idle()
99 })
100 .then(talk(self.target)
101 .repeat()
102 .stop_if(timeout(2.5)))
104 .map(|_, _| ())
105 }
106}