veloren_rtsim/ai/
mod.rs

1pub mod predicate;
2
3use predicate::Predicate;
4
5use crate::{
6    RtState,
7    data::{
8        ReportId, Sentiments,
9        npc::{Controller, Npc, NpcId},
10    },
11};
12use common::{
13    comp,
14    resources::{Time, TimeOfDay},
15    rtsim::NpcInput,
16    shared_server_config::ServerConstants,
17    uid::IdMaps,
18    weather::WeatherGrid,
19};
20use hashbrown::HashSet;
21use itertools::Either;
22use rand_chacha::ChaChaRng;
23use specs::{Read, ReadExpect, ReadStorage, SystemData, shred};
24use std::{any::Any, collections::VecDeque, marker::PhantomData, ops::ControlFlow};
25use world::{IndexRef, World};
26
27pub trait State: Clone + Send + Sync + 'static {}
28
29impl<T: Clone + Send + Sync + 'static> State for T {}
30
31#[derive(Clone, Copy)]
32struct Resettable<T> {
33    original: T,
34    current: T,
35}
36
37impl<T: Clone> From<T> for Resettable<T> {
38    fn from(value: T) -> Self {
39        Self {
40            original: value.clone(),
41            current: value,
42        }
43    }
44}
45
46impl<T: Clone> Resettable<T> {
47    fn reset(&mut self) { self.current = self.original.clone(); }
48}
49
50impl<T> std::ops::Deref for Resettable<T> {
51    type Target = T;
52
53    fn deref(&self) -> &Self::Target { &self.current }
54}
55
56impl<T> std::ops::DerefMut for Resettable<T> {
57    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.current }
58}
59
60/// The context provided to an [`Action`] while it is being performed. It should
61/// be possible to access any and all important information about the game world
62/// through this struct.
63pub struct NpcCtx<'a, 'd> {
64    pub state: &'a RtState,
65    pub world: &'a World,
66    pub index: IndexRef<'a>,
67
68    pub time_of_day: TimeOfDay,
69    pub time: Time,
70
71    pub npc_id: NpcId,
72    pub npc: &'a Npc,
73    pub controller: &'a mut Controller,
74    pub inbox: &'a mut VecDeque<NpcInput>, // TODO: Allow more inbox items
75    pub sentiments: &'a mut Sentiments,
76    pub known_reports: &'a mut HashSet<ReportId>,
77
78    /// The delta time since this npcs ai was last ran.
79    pub dt: f32,
80    pub rng: ChaChaRng,
81    pub system_data: &'a NpcSystemData<'d>,
82}
83
84#[derive(SystemData)]
85pub struct NpcSystemData<'a> {
86    pub positions: ReadStorage<'a, comp::Pos>,
87    pub id_maps: Read<'a, IdMaps>,
88    pub server_constants: ReadExpect<'a, ServerConstants>,
89    pub weather_grid: ReadExpect<'a, WeatherGrid>,
90}
91
92/// A trait that describes 'actions': long-running tasks performed by rtsim
93/// NPCs. These can be as simple as walking in a straight line between two
94/// locations or as complex as taking part in an adventure with players or
95/// performing an entire daily work schedule.
96///
97/// Actions are built up from smaller sub-actions via the combinator methods
98/// defined on this trait, and with the standalone functions in this module.
99/// Using these combinators, in a similar manner to using the [`Iterator`] API,
100/// it is possible to construct arbitrarily complex actions including behaviour
101/// trees (see [`choose`] and [`watch`]) and other forms of moment-by-moment
102/// decision-making.
103///
104/// On completion, actions may produce a value, denoted by the type parameter
105/// `R`. For example, an action may communicate whether it was successful or
106/// unsuccessful through this completion value.
107///
108/// You should not need to implement this trait yourself when writing AI code.
109/// If you find yourself wanting to implement it, please discuss with the core
110/// dev team first.
111pub trait Action<S = (), R = ()>: Any + Send + Sync {
112    /// Returns `true` if the action should be considered the 'same' (i.e:
113    /// achieving the same objective) as another. In general, the AI system
114    /// will try to avoid switching (and therefore restarting) tasks when the
115    /// new task is the 'same' as the old one.
116    // TODO: Figure out a way to compare actions based on their 'intention': i.e:
117    // two pathing actions should be considered equivalent if their destination
118    // is the same regardless of the progress they've each made.
119    fn is_same(&self, other: &Self) -> bool
120    where
121        Self: Sized;
122
123    /// Like [`Action::is_same`], but allows for dynamic dispatch.
124    fn dyn_is_same_sized(&self, other: &dyn Action<S, R>) -> bool
125    where
126        Self: Sized,
127    {
128        match (other as &dyn Any).downcast_ref::<Self>() {
129            Some(other) => self.is_same(other),
130            None => false,
131        }
132    }
133
134    /// Like [`Action::is_same`], but allows for dynamic dispatch.
135    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool;
136
137    /// Generate a backtrace for the action. The action should recursively push
138    /// all of the tasks it is currently performing.
139    fn backtrace(&self, bt: &mut Vec<String>);
140
141    /// Reset the action to its initial state such that it can be repeated.
142    fn reset(&mut self);
143
144    /// Perform the action for the current tick.
145    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R>;
146
147    /// Create an action that chains together two sub-actions, one after the
148    /// other.
149    ///
150    /// # Example
151    ///
152    /// ```ignore
153    /// // Walk toward an enemy NPC and, once done, attack the enemy NPC
154    /// goto(enemy_npc).then(attack(enemy_npc))
155    /// ```
156    #[must_use]
157    fn then<A1: Action<S, R1>, R1>(self, other: A1) -> Then<Self, A1, R>
158    where
159        Self: Sized,
160    {
161        Then {
162            a0: self,
163            a0_finished: false,
164            a1: other,
165            phantom: PhantomData,
166        }
167    }
168
169    /// Like `Action::then`, except the second action may be configured by the
170    /// output of the first.
171    ///
172    /// # Example
173    ///
174    /// ```ignore
175    /// ask_question("Is it sunny?").and_then(|response| match response {
176    ///     true => say("Good, I like sunshine"),
177    ///     false => say("Shame, I'll get my coat"),
178    /// })
179    /// ```
180    #[must_use]
181    fn and_then<F, A1: Action<S, R1>, R1>(self, f: F) -> AndThen<Self, F, A1, R>
182    where
183        Self: Sized,
184    {
185        AndThen {
186            a0: self,
187            f,
188            a1: None,
189            phantom: PhantomData,
190        }
191    }
192
193    /// Create an action that repeats a sub-action indefinitely.
194    ///
195    /// # Example
196    ///
197    /// ```ignore
198    /// // Endlessly collect flax from the environment
199    /// find_and_collect(ChunkResource::Flax).repeat()
200    /// ```
201    #[must_use]
202    fn repeat(self) -> Repeat<Self, R>
203    where
204        Self: Sized,
205    {
206        Repeat(self, PhantomData)
207    }
208
209    /// Stop the sub-action suddenly if a condition is reached.
210    ///
211    /// # Example
212    ///
213    /// ```ignore
214    /// // Keep going on adventures until your 111th birthday
215    /// go_on_an_adventure().repeat().stop_if(|ctx| ctx.npc.age > 111.0)
216    /// ```
217    #[must_use]
218    fn stop_if<P: Predicate + Clone>(self, p: P) -> StopIf<Self, P>
219    where
220        Self: Sized,
221    {
222        StopIf(self, p.into())
223    }
224
225    /// Pause an action to possibly perform another action.
226    ///
227    /// # Example
228    ///
229    /// ```ignore
230    /// // Keep going on adventures until your 111th birthday
231    /// walk_to_the_shops()
232    ///     .interrupt_with(|ctx| if ctx.npc.is_hungry() {
233    ///         Some(eat_food())
234    ///     } else {
235    ///         None
236    ///     })
237    /// ```
238    #[must_use]
239    fn interrupt_with<
240        A1: Action<S, R1>,
241        R1,
242        F: Fn(&mut NpcCtx, &mut S) -> Option<A1> + Send + Sync + 'static,
243    >(
244        self,
245        f: F,
246    ) -> InterruptWith<Self, F, A1, R1>
247    where
248        Self: Sized,
249    {
250        InterruptWith {
251            a0: self,
252            f,
253            a1: None,
254            phantom: PhantomData,
255        }
256    }
257
258    /// Map the completion value of this action to something else.
259    #[must_use]
260    fn map<F: Fn(R, &mut S) -> R1, R1>(self, f: F) -> Map<Self, F, R>
261    where
262        Self: Sized,
263    {
264        Map(self, f, PhantomData)
265    }
266
267    /// Box the action. Often used to perform type erasure, such as when you
268    /// want to return one of many actions (each with different types) from
269    /// the same function.
270    ///
271    /// Note that [`Either`] can often be used to unify mismatched types without
272    /// the need for boxing.
273    ///
274    /// # Example
275    ///
276    /// ```ignore
277    /// // Error! Type mismatch between branches
278    /// if npc.is_too_tired() {
279    ///     goto(npc.home)
280    /// } else {
281    ///     go_on_an_adventure()
282    /// }
283    ///
284    /// // All fine
285    /// if npc.is_too_tired() {
286    ///     goto(npc.home).boxed()
287    /// } else {
288    ///     go_on_an_adventure().boxed()
289    /// }
290    /// ```
291    #[must_use]
292    fn boxed(self) -> Box<dyn Action<S, R>>
293    where
294        Self: Sized,
295    {
296        Box::new(self)
297    }
298
299    /// Set the state for child actions.
300    ///
301    /// Note that state is reset when repeated.
302    ///
303    /// # Example
304    ///
305    /// ```ignore
306    /// just(|_, state: &mut i32| *state += 2)
307    ///     // Outputs 5
308    ///     .then(just(|_, state: &mut i32| println!("{state}")))
309    ///     .with_state(3)
310    /// ```
311    #[must_use]
312    fn with_state<S0>(self, s: S) -> WithState<Self, S, S0>
313    where
314        Self: Sized,
315        S: Clone,
316    {
317        WithState(self, s.into(), PhantomData)
318    }
319
320    /// Map the current state for child actions, this map expects the return
321    /// value to have the same lifetime as the input state.
322    ///
323    /// # Example
324    ///
325    /// ```ignore
326    /// // Goes forward 5 steps
327    /// just(|_, state: &mut i32| go_forward(*state))
328    ///     .map_state(|state: &mut (i32, i32)| &mut state.1)
329    ///     .with_state((14, 5))
330    /// ```
331    #[must_use]
332    fn map_state<S0, F>(self, f: F) -> MapState<Self, F, S, S0>
333    where
334        F: Fn(&mut S0) -> &mut S,
335        Self: Sized,
336    {
337        MapState(self, f, PhantomData)
338    }
339
340    /// Add debugging information to the action that will be visible when using
341    /// the `/npc_info` command.
342    ///
343    /// # Example
344    ///
345    /// ```ignore
346    /// goto(npc.home).debug(|| "Going home")
347    /// ```
348    #[must_use]
349    fn debug<F, T>(self, mk_info: F) -> Debug<Self, F, T>
350    where
351        Self: Sized,
352    {
353        Debug(self, mk_info, PhantomData)
354    }
355
356    #[must_use]
357    fn l<Rhs>(self) -> Either<Self, Rhs>
358    where
359        Self: Sized,
360    {
361        Either::Left(self)
362    }
363
364    #[must_use]
365    fn r<Lhs>(self) -> Either<Lhs, Self>
366    where
367        Self: Sized,
368    {
369        Either::Right(self)
370    }
371}
372
373impl<S: State, R: 'static> Action<S, R> for Box<dyn Action<S, R>> {
374    fn is_same(&self, other: &Self) -> bool { (**self).dyn_is_same(other) }
375
376    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool {
377        match (other as &dyn Any).downcast_ref::<Self>() {
378            Some(other) => self.is_same(other),
379            None => false,
380        }
381    }
382
383    fn backtrace(&self, bt: &mut Vec<String>) { (**self).backtrace(bt) }
384
385    fn reset(&mut self) { (**self).reset(); }
386
387    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
388        (**self).tick(ctx, state)
389    }
390}
391
392impl<S: State, R: 'static, A: Action<S, R>, B: Action<S, R>> Action<S, R> for Either<A, B> {
393    fn is_same(&self, other: &Self) -> bool {
394        match (self, other) {
395            (Either::Left(x), Either::Left(y)) => x.is_same(y),
396            (Either::Right(x), Either::Right(y)) => x.is_same(y),
397            _ => false,
398        }
399    }
400
401    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool { self.dyn_is_same_sized(other) }
402
403    fn backtrace(&self, bt: &mut Vec<String>) {
404        match self {
405            Either::Left(x) => x.backtrace(bt),
406            Either::Right(x) => x.backtrace(bt),
407        }
408    }
409
410    fn reset(&mut self) {
411        match self {
412            Either::Left(x) => x.reset(),
413            Either::Right(x) => x.reset(),
414        }
415    }
416
417    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
418        match self {
419            Either::Left(x) => x.tick(ctx, state),
420            Either::Right(x) => x.tick(ctx, state),
421        }
422    }
423}
424
425// Now
426
427/// See [`now`].
428#[derive(Copy, Clone)]
429pub struct Now<F, A>(F, Option<A>);
430
431impl<
432    S: State,
433    R: Send + Sync + 'static,
434    F: Fn(&mut NpcCtx, &mut S) -> A + Send + Sync + 'static,
435    A: Action<S, R>,
436> Action<S, R> for Now<F, A>
437{
438    // TODO: This doesn't compare?!
439    fn is_same(&self, _other: &Self) -> bool { true }
440
441    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool { self.dyn_is_same_sized(other) }
442
443    fn backtrace(&self, bt: &mut Vec<String>) {
444        if let Some(action) = &self.1 {
445            action.backtrace(bt);
446        } else {
447            bt.push("<thinking>".to_string());
448        }
449    }
450
451    fn reset(&mut self) { self.1 = None; }
452
453    // TODO: Reset closure state?
454    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
455        (self.1.get_or_insert_with(|| (self.0)(ctx, state))).tick(ctx, state)
456    }
457}
458
459/// Start a new action based on the state of the world (`ctx`) at the moment the
460/// action is started.
461///
462/// If you're in a situation where you suddenly find yourself needing `ctx`, you
463/// probably want to use this.
464///
465/// # Example
466///
467/// ```ignore
468/// // An action that makes an NPC immediately travel to its *current* home
469/// now(|ctx| goto(ctx.npc.home))
470/// ```
471pub fn now<S, R, F, A: Action<S, R>>(f: F) -> Now<F, A>
472where
473    F: Fn(&mut NpcCtx, &mut S) -> A + Send + Sync + 'static,
474{
475    Now(f, None)
476}
477
478// Until
479
480/// See [`now`].
481#[derive(Copy, Clone)]
482pub struct Until<F, A, R, R1>(F, Option<A>, PhantomData<(R, R1)>);
483
484impl<
485    S: State,
486    R: Send + Sync + 'static,
487    F: Fn(&mut NpcCtx, &mut S) -> ControlFlow<R1, A> + Send + Sync + 'static,
488    A: Action<S, R>,
489    R1: Send + Sync + 'static,
490> Action<S, R1> for Until<F, A, R, R1>
491{
492    // TODO: This doesn't compare?!
493    fn is_same(&self, _other: &Self) -> bool { true }
494
495    fn dyn_is_same(&self, other: &dyn Action<S, R1>) -> bool { self.dyn_is_same_sized(other) }
496
497    fn backtrace(&self, bt: &mut Vec<String>) {
498        if let Some(action) = &self.1 {
499            action.backtrace(bt);
500        } else {
501            bt.push("<thinking>".to_string());
502        }
503    }
504
505    fn reset(&mut self) { self.1 = None; }
506
507    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R1> {
508        let action = match &mut self.1 {
509            Some(action) => action,
510            None => match (self.0)(ctx, state) {
511                ControlFlow::Continue(action) => self.1.insert(action),
512                ControlFlow::Break(b) => return ControlFlow::Break(b),
513            },
514        };
515
516        match action.tick(ctx, state) {
517            ControlFlow::Continue(()) => ControlFlow::Continue(()),
518            ControlFlow::Break(_) => {
519                self.1 = None;
520                ControlFlow::Continue(())
521            },
522        }
523    }
524}
525
526pub fn until<S, F, A: Action<S, R>, R, R1>(f: F) -> Until<F, A, R, R1>
527where
528    F: Fn(&mut NpcCtx, &mut S) -> ControlFlow<R1, A>,
529{
530    Until(f, None, PhantomData)
531}
532
533// Just
534
535/// See [`just`].
536#[derive(Copy, Clone)]
537pub struct Just<F, R = ()>(F, PhantomData<R>);
538
539impl<S: State, R: Send + Sync + 'static, F: Fn(&mut NpcCtx, &mut S) -> R + Send + Sync + 'static>
540    Action<S, R> for Just<F, R>
541{
542    fn is_same(&self, _other: &Self) -> bool { true }
543
544    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool { self.dyn_is_same_sized(other) }
545
546    fn backtrace(&self, _bt: &mut Vec<String>) {}
547
548    fn reset(&mut self) {}
549
550    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
551        ControlFlow::Break((self.0)(ctx, state))
552    }
553}
554
555/// An action that executes some code just once when performed.
556///
557/// If you want to execute this code on every tick, consider combining it with
558/// [`Action::repeat`].
559///
560/// # Example
561///
562/// ```ignore
563/// // Make the current NPC say 'Hello, world!' exactly once
564/// just(|ctx| ctx.controller.say("Hello, world!"))
565/// ```
566pub fn just<S: State, F, R: Send + Sync + 'static>(f: F) -> Just<F, R>
567where
568    F: Fn(&mut NpcCtx, &mut S) -> R + Send + Sync + 'static,
569{
570    Just(f, PhantomData)
571}
572
573// Finish
574
575/// See [`finish`].
576#[derive(Copy, Clone)]
577pub struct Finish;
578
579impl<S: State> Action<S, ()> for Finish {
580    fn is_same(&self, _other: &Self) -> bool { true }
581
582    fn dyn_is_same(&self, other: &dyn Action<S, ()>) -> bool { self.dyn_is_same_sized(other) }
583
584    fn backtrace(&self, _bt: &mut Vec<String>) {}
585
586    fn reset(&mut self) {}
587
588    fn tick(&mut self, _ctx: &mut NpcCtx, _state: &mut S) -> ControlFlow<()> {
589        ControlFlow::Break(())
590    }
591}
592
593/// An action that immediately finishes without doing anything.
594///
595/// This action is useless by itself, but becomes useful when combined with
596/// actions that make decisions.
597///
598/// # Example
599///
600/// ```ignore
601/// now(|ctx| {
602///     if ctx.npc.is_tired() {
603///         sleep().boxed() // If we're tired, sleep
604///     } else if ctx.npc.is_hungry() {
605///         eat().boxed() // If we're hungry, eat
606///     } else {
607///         finish().boxed() // Otherwise, do nothing
608///     }
609/// })
610/// ```
611#[must_use]
612pub fn finish() -> Finish { Finish }
613
614// Tree
615
616pub type Priority = usize;
617
618pub const URGENT: Priority = 0;
619pub const IMPORTANT: Priority = 1;
620pub const CASUAL: Priority = 2;
621
622pub struct Node<S, R>(Box<dyn Action<S, R>>, Priority);
623
624/// Perform an action with [`URGENT`] priority (see [`choose`]).
625#[must_use]
626pub fn urgent<S, A: Action<S, R>, R>(a: A) -> Node<S, R> { Node(Box::new(a), URGENT) }
627
628/// Perform an action with [`IMPORTANT`] priority (see [`choose`]).
629#[must_use]
630pub fn important<S, A: Action<S, R>, R>(a: A) -> Node<S, R> { Node(Box::new(a), IMPORTANT) }
631
632/// Perform an action with [`CASUAL`] priority (see [`choose`]).
633#[must_use]
634pub fn casual<S, A: Action<S, R>, R>(a: A) -> Node<S, R> { Node(Box::new(a), CASUAL) }
635
636/// See [`choose`] and [`watch`].
637pub struct Tree<S, F, R> {
638    next: F,
639    prev: Option<Node<S, R>>,
640    interrupt: bool,
641}
642
643impl<S: State, F: Fn(&mut NpcCtx, &mut S) -> Node<S, R> + Send + Sync + 'static, R: 'static>
644    Action<S, R> for Tree<S, F, R>
645{
646    fn is_same(&self, _other: &Self) -> bool { true }
647
648    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool { self.dyn_is_same_sized(other) }
649
650    fn backtrace(&self, bt: &mut Vec<String>) {
651        if let Some(prev) = &self.prev {
652            prev.0.backtrace(bt);
653        } else {
654            bt.push("<thinking>".to_string());
655        }
656    }
657
658    fn reset(&mut self) { self.prev = None; }
659
660    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
661        let new = (self.next)(ctx, state);
662
663        let prev = match &mut self.prev {
664            Some(prev) if prev.1 <= new.1 && (prev.0.dyn_is_same(&*new.0) || !self.interrupt) => {
665                prev
666            },
667            _ => self.prev.insert(new),
668        };
669
670        match prev.0.tick(ctx, state) {
671            ControlFlow::Continue(()) => ControlFlow::Continue(()),
672            ControlFlow::Break(r) => {
673                self.prev = None;
674                ControlFlow::Break(r)
675            },
676        }
677    }
678}
679
680/// An action that allows implementing a decision tree, with action
681/// prioritisation.
682///
683/// The inner function will be run every tick to decide on an action. When an
684/// action is chosen, it will be performed until completed *UNLESS* an action
685/// with a more urgent priority is chosen in a subsequent tick. [`choose`] tries
686/// to commit to actions when it can: only more urgent actions will interrupt an
687/// action that's currently being performed. If you want something that's more
688/// eager to switch actions, see [`watch`].
689///
690/// # Example
691///
692/// ```ignore
693/// choose(|ctx| {
694///     if ctx.npc.is_being_attacked() {
695///         urgent(combat()) // If we're in danger, do something!
696///     } else if ctx.npc.is_hungry() {
697///         important(eat()) // If we're hungry, eat
698///     } else {
699///         casual(idle()) // Otherwise, do nothing
700///     }
701/// })
702/// ```
703#[must_use]
704pub fn choose<S: State, R: 'static, F>(f: F) -> impl Action<S, R>
705where
706    F: Fn(&mut NpcCtx, &mut S) -> Node<S, R> + Send + Sync + 'static,
707{
708    Tree {
709        next: f,
710        prev: None,
711        interrupt: false,
712    }
713}
714
715/// An action that allows implementing a decision tree, with action
716/// prioritisation.
717///
718/// The inner function will be run every tick to decide on an action. When an
719/// action is chosen, it will be performed until completed unless a different
720/// action of the same or higher priority is chosen in a subsequent tick.
721/// [`watch`] is very unfocused and will happily switch between actions
722/// rapidly between ticks if conditions change. If you want something that
723/// tends to commit to actions until they are completed, see [`choose`].
724///
725/// # Example
726///
727/// ```ignore
728/// watch(|ctx| {
729///     if ctx.npc.is_being_attacked() {
730///         urgent(combat()) // If we're in danger, do something!
731///     } else if ctx.npc.is_hungry() {
732///         important(eat()) // If we're hungry, eat
733///     } else {
734///         casual(idle()) // Otherwise, do nothing
735///     }
736/// })
737/// ```
738#[must_use]
739pub fn watch<S: State, R: 'static, F>(f: F) -> impl Action<S, R>
740where
741    F: Fn(&mut NpcCtx, &mut S) -> Node<S, R> + Send + Sync + 'static,
742{
743    Tree {
744        next: f,
745        prev: None,
746        interrupt: true,
747    }
748}
749
750// Then
751
752/// See [`Action::then`].
753#[derive(Copy, Clone)]
754pub struct Then<A0, A1, R0> {
755    a0: A0,
756    a0_finished: bool,
757    a1: A1,
758    phantom: PhantomData<R0>,
759}
760
761impl<
762    S: State,
763    A0: Action<S, R0>,
764    A1: Action<S, R1>,
765    R0: Send + Sync + 'static,
766    R1: Send + Sync + 'static,
767> Action<S, R1> for Then<A0, A1, R0>
768{
769    fn is_same(&self, other: &Self) -> bool {
770        self.a0.is_same(&other.a0) && self.a1.is_same(&other.a1)
771    }
772
773    fn dyn_is_same(&self, other: &dyn Action<S, R1>) -> bool { self.dyn_is_same_sized(other) }
774
775    fn backtrace(&self, bt: &mut Vec<String>) {
776        if self.a0_finished {
777            self.a1.backtrace(bt);
778        } else {
779            self.a0.backtrace(bt);
780        }
781    }
782
783    fn reset(&mut self) {
784        self.a0.reset();
785        self.a0_finished = false;
786        self.a1.reset();
787    }
788
789    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R1> {
790        if !self.a0_finished {
791            match self.a0.tick(ctx, state) {
792                ControlFlow::Continue(()) => return ControlFlow::Continue(()),
793                ControlFlow::Break(_) => self.a0_finished = true,
794            }
795        }
796        self.a1.tick(ctx, state)
797    }
798}
799
800// AndThen
801
802/// See [`Action::and_then`].
803#[derive(Copy, Clone)]
804pub struct AndThen<A0, F, A1, R0> {
805    a0: A0,
806    f: F,
807    a1: Option<A1>,
808    phantom: PhantomData<R0>,
809}
810
811impl<
812    S: State,
813    A0: Action<S, R0>,
814    A1: Action<S, R1>,
815    R0: Send + Sync + 'static,
816    R1: Send + Sync + 'static,
817    F: Fn(R0) -> A1 + Send + Sync + 'static,
818> Action<S, R1> for AndThen<A0, F, A1, R0>
819{
820    fn is_same(&self, other: &Self) -> bool {
821        self.a0.is_same(&other.a0)
822            && match (&self.a1, &other.a1) {
823                (Some(a1_0), Some(a1_1)) => a1_0.is_same(a1_1),
824                _ => true,
825            }
826    }
827
828    fn dyn_is_same(&self, other: &dyn Action<S, R1>) -> bool { self.dyn_is_same_sized(other) }
829
830    fn backtrace(&self, bt: &mut Vec<String>) {
831        if let Some(a1) = &self.a1 {
832            a1.backtrace(bt);
833        } else {
834            self.a0.backtrace(bt);
835        }
836    }
837
838    fn reset(&mut self) {
839        self.a0.reset();
840        self.a1 = None;
841    }
842
843    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R1> {
844        let a1 = match &mut self.a1 {
845            None => match self.a0.tick(ctx, state) {
846                ControlFlow::Continue(()) => return ControlFlow::Continue(()),
847                ControlFlow::Break(r) => self.a1.insert((self.f)(r)),
848            },
849            Some(a1) => a1,
850        };
851        a1.tick(ctx, state)
852    }
853}
854
855// InterruptWith
856
857/// See [`Action::then`].
858#[derive(Copy, Clone)]
859pub struct InterruptWith<A0, F, A1, R1> {
860    a0: A0,
861    f: F,
862    a1: Option<A1>,
863    phantom: PhantomData<R1>,
864}
865
866impl<
867    S: State,
868    A0: Action<S, R0>,
869    A1: Action<S, R1>,
870    F: Fn(&mut NpcCtx, &mut S) -> Option<A1> + Send + Sync + 'static,
871    R0: Send + Sync + 'static,
872    R1: Send + Sync + 'static,
873> Action<S, R0> for InterruptWith<A0, F, A1, R1>
874{
875    fn is_same(&self, other: &Self) -> bool { self.a0.is_same(&other.a0) }
876
877    fn dyn_is_same(&self, other: &dyn Action<S, R0>) -> bool { self.dyn_is_same_sized(other) }
878
879    fn backtrace(&self, bt: &mut Vec<String>) {
880        if let Some(a1) = &self.a1 {
881            // TODO: Find a way to represent interrupts in backtraces
882            bt.push("<interrupted>".to_string());
883            a1.backtrace(bt);
884        } else {
885            self.a0.backtrace(bt);
886        }
887    }
888
889    fn reset(&mut self) {
890        self.a0.reset();
891        self.a1 = None;
892    }
893
894    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R0> {
895        if let Some(new_a1) = (self.f)(ctx, state) {
896            self.a1 = Some(new_a1);
897        }
898
899        if let Some(a1) = &mut self.a1 {
900            match a1.tick(ctx, state) {
901                ControlFlow::Continue(()) => return ControlFlow::Continue(()),
902                ControlFlow::Break(_) => self.a1 = None,
903            }
904        }
905
906        self.a0.tick(ctx, state)
907    }
908}
909
910// Repeat
911
912/// See [`Action::repeat`].
913#[derive(Copy, Clone)]
914pub struct Repeat<A, R = ()>(A, PhantomData<R>);
915
916impl<S: State, R: Send + Sync + 'static, A: Action<S, R>> Action<S, !> for Repeat<A, R> {
917    fn is_same(&self, other: &Self) -> bool { self.0.is_same(&other.0) }
918
919    fn dyn_is_same(&self, other: &dyn Action<S, !>) -> bool { self.dyn_is_same_sized(other) }
920
921    fn backtrace(&self, bt: &mut Vec<String>) { self.0.backtrace(bt); }
922
923    fn reset(&mut self) { self.0.reset(); }
924
925    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<!> {
926        match self.0.tick(ctx, state) {
927            ControlFlow::Continue(()) => ControlFlow::Continue(()),
928            ControlFlow::Break(_) => {
929                self.0.reset();
930                ControlFlow::Continue(())
931            },
932        }
933    }
934}
935
936// Sequence
937
938/// See [`seq`].
939#[derive(Copy, Clone)]
940pub struct Sequence<I, A, R = ()>(Resettable<I>, Option<A>, PhantomData<R>);
941
942impl<
943    S: State,
944    R: Send + Sync + 'static,
945    I: Iterator<Item = A> + Clone + Send + Sync + 'static,
946    A: Action<S, R>,
947> Action<S, ()> for Sequence<I, A, R>
948{
949    fn is_same(&self, _other: &Self) -> bool { true }
950
951    fn dyn_is_same(&self, other: &dyn Action<S, ()>) -> bool { self.dyn_is_same_sized(other) }
952
953    fn backtrace(&self, bt: &mut Vec<String>) {
954        if let Some(action) = &self.1 {
955            action.backtrace(bt);
956        } else {
957            bt.push("<thinking>".to_string());
958        }
959    }
960
961    fn reset(&mut self) {
962        self.0.reset();
963        self.1 = None;
964    }
965
966    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<()> {
967        let item = if let Some(prev) = &mut self.1 {
968            prev
969        } else {
970            match self.0.next() {
971                Some(next) => self.1.insert(next),
972                None => return ControlFlow::Break(()),
973            }
974        };
975
976        if let ControlFlow::Break(_) = item.tick(ctx, state) {
977            self.1 = None;
978        }
979
980        ControlFlow::Continue(())
981    }
982}
983
984/// An action that consumes and performs an iterator of actions in sequence, one
985/// after another.
986///
987/// # Example
988///
989/// ```ignore
990/// // A list of enemies we should attack in turn
991/// let enemies = vec![
992///     ugly_goblin,
993///     stinky_troll,
994///     rude_dwarf,
995/// ];
996///
997/// // Attack each enemy, one after another
998/// seq(enemies
999///     .into_iter()
1000///     .map(|enemy| attack(enemy)))
1001/// ```
1002#[must_use]
1003pub fn seq<S, I, A, R>(iter: I) -> Sequence<I, A, R>
1004where
1005    I: Iterator<Item = A> + Clone,
1006    A: Action<S, R>,
1007{
1008    Sequence(iter.into(), None, PhantomData)
1009}
1010
1011// StopIf
1012
1013/// See [`Action::stop_if`].
1014#[derive(Copy, Clone)]
1015pub struct StopIf<A, P>(A, Resettable<P>);
1016
1017impl<S: State, A: Action<S, R>, P: Predicate + Clone + Send + Sync + 'static, R>
1018    Action<S, Option<R>> for StopIf<A, P>
1019{
1020    fn is_same(&self, other: &Self) -> bool { self.0.is_same(&other.0) }
1021
1022    fn dyn_is_same(&self, other: &dyn Action<S, Option<R>>) -> bool {
1023        self.dyn_is_same_sized(other)
1024    }
1025
1026    fn backtrace(&self, bt: &mut Vec<String>) { self.0.backtrace(bt); }
1027
1028    fn reset(&mut self) {
1029        self.0.reset();
1030        self.1.reset();
1031    }
1032
1033    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<Option<R>> {
1034        if self.1.should(ctx) {
1035            ControlFlow::Break(None)
1036        } else {
1037            self.0.tick(ctx, state).map_break(Some)
1038        }
1039    }
1040}
1041
1042// Map
1043
1044/// See [`Action::map`].
1045#[derive(Copy, Clone)]
1046pub struct Map<A, F, R>(A, F, PhantomData<R>);
1047
1048impl<
1049    S: State,
1050    A: Action<S, R>,
1051    F: Fn(R, &mut S) -> R1 + Send + Sync + 'static,
1052    R: Send + Sync + 'static,
1053    R1,
1054> Action<S, R1> for Map<A, F, R>
1055{
1056    fn is_same(&self, other: &Self) -> bool { self.0.is_same(&other.0) }
1057
1058    fn dyn_is_same(&self, other: &dyn Action<S, R1>) -> bool { self.dyn_is_same_sized(other) }
1059
1060    fn backtrace(&self, bt: &mut Vec<String>) { self.0.backtrace(bt); }
1061
1062    fn reset(&mut self) { self.0.reset(); }
1063
1064    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R1> {
1065        self.0.tick(ctx, state).map_break(|t| (self.1)(t, state))
1066    }
1067}
1068
1069// Debug
1070
1071/// See [`Action::debug`].
1072#[derive(Copy, Clone)]
1073pub struct Debug<A, F, T>(A, F, PhantomData<T>);
1074
1075impl<
1076    S: 'static,
1077    A: Action<S, R>,
1078    F: Fn() -> T + Send + Sync + 'static,
1079    R: Send + Sync + 'static,
1080    T: Send + Sync + std::fmt::Display + 'static,
1081> Action<S, R> for Debug<A, F, T>
1082{
1083    fn is_same(&self, other: &Self) -> bool { self.0.is_same(&other.0) }
1084
1085    fn dyn_is_same(&self, other: &dyn Action<S, R>) -> bool { self.dyn_is_same_sized(other) }
1086
1087    fn backtrace(&self, bt: &mut Vec<String>) {
1088        bt.push((self.1)().to_string());
1089        self.0.backtrace(bt);
1090    }
1091
1092    fn reset(&mut self) { self.0.reset(); }
1093
1094    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S) -> ControlFlow<R> {
1095        self.0.tick(ctx, state)
1096    }
1097}
1098
1099#[derive(Copy, Clone)]
1100pub struct WithState<A, S, S0>(A, Resettable<S>, PhantomData<S0>);
1101
1102impl<S0: State, S: State, R, A: Action<S, R>> Action<S0, R> for WithState<A, S, S0> {
1103    fn is_same(&self, other: &Self) -> bool
1104    where
1105        Self: Sized,
1106    {
1107        self.0.is_same(&other.0)
1108    }
1109
1110    fn dyn_is_same(&self, other: &dyn Action<S0, R>) -> bool { self.dyn_is_same_sized(other) }
1111
1112    fn backtrace(&self, bt: &mut Vec<String>) { self.0.backtrace(bt) }
1113
1114    fn reset(&mut self) {
1115        self.0.reset();
1116        self.1.reset();
1117    }
1118
1119    fn tick(&mut self, ctx: &mut NpcCtx, _state: &mut S0) -> ControlFlow<R> {
1120        self.0.tick(ctx, &mut self.1.current)
1121    }
1122}
1123
1124#[derive(Copy, Clone)]
1125pub struct MapState<A, F, S, S0>(A, F, PhantomData<(S, S0)>);
1126
1127impl<S0: State, S: State, R, A: Action<S, R>, F: Fn(&mut S0) -> &mut S + Send + Sync + 'static>
1128    Action<S0, R> for MapState<A, F, S, S0>
1129{
1130    fn is_same(&self, other: &Self) -> bool
1131    where
1132        Self: Sized,
1133    {
1134        self.0.is_same(&other.0)
1135    }
1136
1137    fn dyn_is_same(&self, other: &dyn Action<S0, R>) -> bool { self.dyn_is_same_sized(other) }
1138
1139    fn backtrace(&self, bt: &mut Vec<String>) { self.0.backtrace(bt) }
1140
1141    fn reset(&mut self) { self.0.reset(); }
1142
1143    fn tick(&mut self, ctx: &mut NpcCtx, state: &mut S0) -> ControlFlow<R> {
1144        self.0.tick(ctx, (self.1)(state))
1145    }
1146}