1 /**
2  * @file
3  * @brief Functions for handling multi-turn actions.
4 **/
5 
6 #pragma once
7 
8 #include <vector>
9 
10 #include "activity-interrupt-type.h"
11 #include "command-type.h"
12 #include "enum.h"
13 #include "item-prop-enum.h"
14 #include "mpr.h"
15 #include "operation-types.h"
16 #include "seen-context-type.h"
17 
18 using std::vector;
19 
20 class interrupt_block
21 {
22 public:
23     interrupt_block(bool block = true) {
24         m_block = block;
25         if (block)
26             ++interrupts_blocked;
27     }
~interrupt_block()28     ~interrupt_block() {
29         if (m_block)
30             --interrupts_blocked;
31     }
32 
blocked()33     static bool blocked() { return interrupts_blocked > 0; }
34 private:
35     bool m_block;
36     static int interrupts_blocked;
37 };
38 
39 class monster;
40 struct ait_hp_loss;
41 
42 enum class ai_payload // activity interrupt payloads
43 {
44     none,
45     int_payload,
46     string_payload,
47     monster,
48     hp_loss,
49 };
50 
51 struct activity_interrupt_data
52 {
53     ai_payload apt;
54     union
55     {
56         const char* string_data;
57         const int*  int_data;
58         const ait_hp_loss* ait_hp_loss_data;
59         monster* mons_data;
60         nullptr_t no_data;
61     };
62 
63     seen_context_type context;
64 
activity_interrupt_dataactivity_interrupt_data65     activity_interrupt_data()
66         : apt(ai_payload::none), no_data(nullptr), context(SC_NONE)
67     {
68     }
activity_interrupt_dataactivity_interrupt_data69     activity_interrupt_data(const int *i)
70         : apt(ai_payload::int_payload), int_data(i), context(SC_NONE)
71     {
72     }
activity_interrupt_dataactivity_interrupt_data73     activity_interrupt_data(const char *s)
74         : apt(ai_payload::string_payload), string_data(s), context(SC_NONE)
75     {
76     }
activity_interrupt_dataactivity_interrupt_data77     activity_interrupt_data(const string &s)
78         : apt(ai_payload::string_payload), string_data(s.c_str()),
79           context(SC_NONE)
80     {
81     }
82     activity_interrupt_data(monster* m, seen_context_type ctx = SC_NONE)
aptactivity_interrupt_data83         : apt(ai_payload::monster), mons_data(m), context(ctx)
84     {
85     }
activity_interrupt_dataactivity_interrupt_data86     activity_interrupt_data(const ait_hp_loss *ahl)
87         : apt(ai_payload::hp_loss), ait_hp_loss_data(ahl), context(SC_NONE)
88     {
89     }
90 };
91 
92 struct ait_hp_loss
93 {
94     int hp;
95     int hurt_type;  // KILLED_BY_POISON, etc.
96 
ait_hp_lossait_hp_loss97     ait_hp_loss(int _hp, int _ht) : hp(_hp), hurt_type(_ht) { }
98 };
99 
100 class Delay
101 {
102     /**
103      * This is run if `started` is not yet true.
104      */
start()105     virtual void start()
106     { }
107 
108     /**
109      * This is run before tick(); if it returns true, the delay is popped off
110      * the queue and handle() returns early.
111      */
invalidated()112     virtual bool invalidated()
113     {
114         return false;
115     }
116 
117     /**
118      * This is run once each turn of the delay, including the first, but not if
119      * it has finished.
120      */
tick()121     virtual void tick()
122     { }
123 
124     /**
125      * If the delay has finished, this is run instead. It should contain the payload of
126      * the delay.
127      */
finish()128     virtual void finish()
129     {
130         mpr("You finish doing something buggy.");
131     }
132 protected:
133     bool started = false;
134 public:
135     int duration;
136 
Delay(int dur)137     Delay(int dur) : duration{dur}
138     { }
139 
140     virtual ~Delay() = default;
141 
142     /**
143      * @return whether this is a running delay (run, rest, travel), which
144      * involves moving/resting each turn until completed, rather than depending
145      * on `duration` itself.
146      */
is_run()147     virtual bool is_run() const
148     {
149         return false;
150     }
151 
152     /**
153      * @return whether this is a stair travel delay, which are generally
154      * uninterruptible but are interrupted by teleport. Note that no stairs
155      * are necessarily involved.
156      */
is_stair_travel()157     virtual bool is_stair_travel() const
158     {
159         return is_stairs();
160     }
161 
162     /**
163      * @return whether this involves going up or down stairs.
164      */
is_stairs()165     virtual bool is_stairs() const
166     {
167         return false;
168     }
169 
is_resting()170     virtual bool is_resting() const
171     {
172         return false;
173     }
174 
175     /**
176      * @return whether it's OK to start eating during this delay if hungry.
177      */
want_autoeat()178     virtual bool want_autoeat() const
179     {
180         return false;
181     }
182 
is_macro()183     virtual bool is_macro() const
184     {
185         return false;
186     }
187 
188     /**
189      * @return true if this delay can act as a parent to other delays, i.e. if
190      * other delays can be spawned while this delay is running. If is_parent
191      * returns true, new delays will be pushed immediately to the front of the
192      * delay in question, rather than at the end of the queue.
193      */
is_parent()194     virtual bool is_parent() const
195     {
196         return false;
197     }
198 
199     /**
200      * This is called exactly each turn that the delay is active.
201      */
202     virtual void handle();
203 
204     /**
205      * This is called on the front of the delay queue when stop_delay is called.
206      * If the player needs to be notified, it should also print a message.
207      * @return whether to pop the delay.
208      */
try_interrupt()209     virtual bool try_interrupt()
210     {
211         // The default is for delays to be uninterruptible once started.
212         return false;
213     }
214 
215     /**
216      *@return true if the delay involves using the item in this way (and
217      * therefore the item should not be messed with).
218      */
is_being_used(const item_def &)219     virtual bool is_being_used(const item_def& /*item*/) const
220     {
221         return false;
222     }
223 
224     /**
225      * @return the delay's name; used in debugging and for the interrupt_ option family.
226      */
227     virtual const char* name() const = 0;
228 };
229 
230 class EquipOnDelay : public Delay
231 {
232     item_def& equip;
233     bool was_prompted = false;
234 
235     void start() override;
236 
tick()237     void tick() override
238     {
239         mprf(MSGCH_MULTITURN_ACTION, "You continue putting on %s.",
240              equip.name(DESC_YOUR).c_str());
241     }
242 
243     void finish() override;
244 public:
EquipOnDelay(int dur,item_def & item)245     EquipOnDelay(int dur, item_def& item) :
246                  Delay(dur), equip(item)
247     { }
248 
249     bool try_interrupt() override;
250 
name()251     const char* name() const override
252     {
253         return "armour_on";
254     }
255 
is_being_used(const item_def & item)256     bool is_being_used(const item_def& item) const override
257     {
258         return &item == &equip;
259     }
260 };
261 
262 class EquipOffDelay : public Delay
263 {
264     const item_def& equip;
265     bool was_prompted = false;
266 
267     void start() override;
268 
tick()269     void tick() override
270     {
271         mprf(MSGCH_MULTITURN_ACTION, "You continue taking off %s.",
272              equip.name(DESC_YOUR).c_str());
273     }
274 
275     bool invalidated() override;
276 
277     void finish() override;
278 public:
EquipOffDelay(int dur,const item_def & item)279     EquipOffDelay(int dur, const item_def& item) :
280                    Delay(dur), equip(item)
281     { }
282 
283     bool try_interrupt() override;
284 
name()285     const char* name() const override
286     {
287         return "armour_off";
288     }
289 
is_being_used(const item_def & item)290     bool is_being_used(const item_def& item) const override
291     {
292         return &item == &equip;
293     }
294 };
295 
296 class JewelleryOnDelay : public Delay
297 {
298     item_def& jewellery;
299 
300     void tick() override;
301 
302     void finish() override;
303 public:
JewelleryOnDelay(int dur,item_def & item)304     JewelleryOnDelay(int dur, item_def& item) :
305                      Delay(dur), jewellery(item)
306     { }
307 
name()308     const char* name() const override
309     {
310         return "jewellery_on";
311     }
312 
is_being_used(const item_def & item)313     bool is_being_used(const item_def& item) const override
314     {
315         return &item == &jewellery;
316     }
317 };
318 
319 class MemoriseDelay : public Delay
320 {
321     void start() override;
322 
tick()323     void tick() override
324     {
325         mprf(MSGCH_MULTITURN_ACTION, "You continue memorising.");
326     }
327 
328     void finish() override;
329 public:
330     spell_type spell;
331 
MemoriseDelay(int dur,spell_type sp)332     MemoriseDelay(int dur, spell_type sp) :
333                   Delay(dur), spell{sp}
334     { }
335 
336     bool try_interrupt() override;
337 
name()338     const char* name() const override
339     {
340         return "memorise";
341     }
342 };
343 
344 class PasswallDelay : public Delay
345 {
346     coord_def dest;
347     void start() override;
348 
tick()349     void tick() override
350     {
351         mprf(MSGCH_MULTITURN_ACTION, "You continue meditating on the rock.");
352     }
353 
354     void finish() override;
355 public:
PasswallDelay(int dur,coord_def pos)356     PasswallDelay(int dur, coord_def pos) :
357                   Delay(dur), dest{pos}
358     { }
359 
360     bool try_interrupt() override;
361 
name()362     const char* name() const override
363     {
364         return "passwall";
365     }
366 };
367 
368 class DropItemDelay : public Delay
369 {
370     item_def& item;
371 
372     void tick() override;
373 
374     void finish() override;
375 public:
DropItemDelay(int dur,item_def & it)376     DropItemDelay(int dur, item_def& it) :
377                   Delay(dur), item(it)
378     { }
379 
name()380     const char* name() const override
381     {
382         return "drop_item";
383     }
384 
is_being_used(const item_def & item_)385     bool is_being_used(const item_def& item_) const override
386     {
387         return &item_ == &item;
388     }
389 };
390 
391 struct SelItem;
392 class MultidropDelay : public Delay
393 {
394     vector<SelItem>& items;
395 
396     bool invalidated() override;
397     void tick() override;
398 public:
MultidropDelay(int dur,vector<SelItem> & vec)399     MultidropDelay(int dur, vector<SelItem>& vec) :
400                   Delay(dur), items(vec)
401     { }
402 
403     bool try_interrupt() override;
404 
name()405     const char* name() const override
406     {
407         return "multidrop";
408     }
409 
is_parent()410     bool is_parent() const override
411     {
412         // Can spawn delay_drop_item
413         return true;
414     }
415 };
416 
417 class AscendingStairsDelay : public Delay
418 {
419     void finish() override;
420 public:
AscendingStairsDelay(int dur)421     AscendingStairsDelay(int dur) : Delay(dur)
422     { }
423 
424     bool try_interrupt() override;
425 
is_stairs()426     bool is_stairs() const override
427     {
428         return true;
429     }
430 
name()431     const char* name() const override
432     {
433         return "ascending_stairs";
434     }
435 };
436 
437 class DescendingStairsDelay : public Delay
438 {
439     void finish() override;
440 public:
DescendingStairsDelay(int dur)441     DescendingStairsDelay(int dur) : Delay(dur)
442     { }
443 
444     bool try_interrupt() override;
445 
is_stairs()446     bool is_stairs() const override
447     {
448         return true;
449     }
450 
name()451     const char* name() const override
452     {
453         return "descending_stairs";
454     }
455 };
456 
457 // The run delays (run, travel, rest) have some common code that does not apply
458 // to any other ones.
459 class BaseRunDelay : public Delay
460 {
461     void handle() override;
462 
463     virtual bool want_move() const = 0;
464     virtual bool want_clear_messages() const = 0;
465     virtual command_type move_cmd() const = 0;
466 
467 protected:
468     bool unsafe_once = false;
469 
470 public:
is_run()471     bool is_run() const override
472     {
473         return true;
474     }
475 
is_parent()476     bool is_parent() const override
477     {
478         // Interlevel travel can do upstairs/downstairs delays.
479         // Additionally, travel/rest can do autoeat.
480         return true;
481     }
482 
483     bool try_interrupt() override;
484 
BaseRunDelay()485     BaseRunDelay() : Delay(1)
486     { }
487 };
488 
489 class RunDelay : public BaseRunDelay
490 {
want_move()491     bool want_move() const override
492     {
493         return true;
494     }
495 
want_clear_messages()496     bool want_clear_messages() const override
497     {
498         return true;
499     }
500 
501     command_type move_cmd() const override;
502 public:
RunDelay()503     RunDelay() : BaseRunDelay()
504     { }
505 
name()506     const char* name() const override
507     {
508         return "run";
509     }
510 };
511 
512 class RestDelay : public BaseRunDelay
513 {
want_move()514     bool want_move() const override
515     {
516         return false;
517     }
518 
want_autoeat()519     bool want_autoeat() const override
520     {
521         return true;
522     }
523 
want_clear_messages()524     bool want_clear_messages() const override
525     {
526         return false;
527     }
528 
529     command_type move_cmd() const override;
530 public:
RestDelay()531     RestDelay() : BaseRunDelay()
532     { }
533 
is_resting()534     bool is_resting() const override
535     {
536         return true;
537     }
538 
name()539     const char* name() const override
540     {
541         return "rest";
542     }
543 };
544 
545 class TravelDelay : public BaseRunDelay
546 {
want_move()547     bool want_move() const override
548     {
549         return true;
550     }
551 
want_autoeat()552     bool want_autoeat() const override
553     {
554         return true;
555     }
556 
want_clear_messages()557     bool want_clear_messages() const override
558     {
559         return true;
560     }
561 
562     command_type move_cmd() const override;
563 public:
TravelDelay(bool unsafe)564     TravelDelay(bool unsafe) : BaseRunDelay()
565     {
566         unsafe_once = unsafe;
567     }
568 
name()569     const char* name() const override
570     {
571         return "travel";
572     }
573 };
574 
575 class MacroDelay : public Delay
576 {
577     void handle() override;
578 public:
MacroDelay()579     MacroDelay() : Delay(1)
580     { }
581 
582     bool try_interrupt() override;
583 
is_parent()584     bool is_parent() const override
585     {
586         // Lua macros can in theory perform any of the other delays,
587         // including travel; in practise travel still assumes there can be
588         // no parent delay.
589         return true;
590     }
591 
is_macro()592     bool is_macro() const override
593     {
594         return true;
595     }
596 
name()597     const char* name() const override
598     {
599         //XXX: this is compared to in _userdef_interrupt_activity
600         return "macro";
601     }
602 };
603 
604 class MacroProcessKeyDelay : public Delay
605 {
606 public:
MacroProcessKeyDelay()607     MacroProcessKeyDelay() : Delay(1)
608     { }
609 
handle()610     void handle() override
611     {
612         // If a Lua macro wanted Crawl to process a key normally, early exit.
613         return;
614     }
615 
name()616     const char* name() const override
617     {
618         return "macro_process_key";
619     }
620 };
621 
622 class ShaftSelfDelay : public Delay
623 {
624     void start() override;
625 
tick()626     void tick() override
627     {
628         mprf(MSGCH_MULTITURN_ACTION, "You continue digging a shaft.");
629     }
630 
631     void finish() override;
632 public:
ShaftSelfDelay(int dur)633     ShaftSelfDelay(int dur) : Delay(dur)
634     { }
635 
636     bool try_interrupt() override;
637 
is_stair_travel()638     bool is_stair_travel() const override
639     {
640         return true;
641     }
642 
name()643     const char* name() const override
644     {
645         return "shaft_self";
646     }
647 };
648 
649 class ExsanguinateDelay : public Delay
650 {
651     bool was_prompted = false;
652 
653     void start() override;
654 
tick()655     void tick() override
656     {
657         mprf(MSGCH_MULTITURN_ACTION, "You continue bloodletting.");
658     }
659 
660     void finish() override;
661 public:
ExsanguinateDelay(int dur)662     ExsanguinateDelay(int dur) : Delay(dur)
663     { }
664 
665     bool try_interrupt() override;
666 
name()667     const char* name() const override
668     {
669         return "exsanguinate";
670     }
671 };
672 
673 class RevivifyDelay : public Delay
674 {
675     bool was_prompted = false;
676 
677     void start() override;
678 
tick()679     void tick() override
680     {
681         mprf(MSGCH_MULTITURN_ACTION, "You continue your ritual.");
682     }
683 
684     void finish() override;
685 public:
RevivifyDelay(int dur)686     RevivifyDelay(int dur) : Delay(dur)
687     { }
688 
689     bool try_interrupt() override;
690 
name()691     const char* name() const override
692     {
693         return "revivify";
694     }
695 };
696 
697 void push_delay(shared_ptr<Delay> delay);
698 
699 template<typename T, typename... Args>
start_delay(Args &&...args)700 shared_ptr<Delay> start_delay(Args&&... args)
701 {
702     auto delay = make_shared<T>(forward<Args>(args)...);
703     push_delay(delay);
704     return delay;
705 }
706 
707 void stop_delay(bool stop_stair_travel = false);
708 bool you_are_delayed();
709 shared_ptr<Delay> current_delay();
710 void handle_delay();
711 
712 bool player_stair_delay();
713 bool already_learning_spell(int spell = -1);
714 
715 void clear_macro_process_key_delay();
716 
717 activity_interrupt get_activity_interrupt(const string &);
718 
719 void run_macro(const char *macroname = nullptr);
720 
721 void autotoggle_autopickup(bool off);
722 bool interrupt_activity(activity_interrupt ai,
723                         const activity_interrupt_data &a
724                             = activity_interrupt_data(),
725                         vector<string>* msgs_buf = nullptr);
726