1 /**
2  * @file
3  * @brief General dungeon events.
4 **/
5 
6 #pragma once
7 
8 #include <list>
9 
10 #include "player.h"
11 
12 // Keep event names in l-dgnevt.cc in sync.
13 enum dgn_event_type
14 {
15     DET_NONE            = 0x0000,
16 
17     DET_TURN_ELAPSED    = 0x0001,
18     DET_MONSTER_MOVED   = 0x0002,
19     DET_PLAYER_MOVED    = 0x0004,
20     DET_LEAVING_LEVEL   = 0x0008,
21     DET_ENTERING_LEVEL  = 0x0010,
22     DET_ENTERED_LEVEL   = 0x0020,
23     DET_PLAYER_IN_LOS   = 0x0040,   // Player just entered LOS.
24     DET_PLAYER_CLIMBS   = 0x0080,   // Player climbing stairs.
25     DET_MONSTER_DIED    = 0x0100,
26     DET_ITEM_PICKUP     = 0x0200,
27     DET_ITEM_MOVED      = 0x0400,
28     DET_FEAT_CHANGE     = 0x0800,
29     DET_UNUSED          = 0x1000,   // open for grabs
30     DET_DOOR_OPENED     = 0x2000,
31     DET_DOOR_CLOSED     = 0x4000,
32     DET_HP_WARNING      = 0x8000,
33     DET_PRESSURE_PLATE  = 0x10000,
34 
35     DET_GLOBAL_MASK     = DET_TURN_ELAPSED | DET_LEAVING_LEVEL
36                         | DET_ENTERING_LEVEL | DET_ENTERED_LEVEL
37                         | DET_MONSTER_DIED | DET_HP_WARNING,
38 
39     DET_POSITION_MASK   = DET_MONSTER_MOVED | DET_PLAYER_MOVED
40                         | DET_PLAYER_IN_LOS | DET_ITEM_PICKUP
41                         | DET_ITEM_MOVED | DET_FEAT_CHANGE
42                         | DET_DOOR_OPENED | DET_DOOR_CLOSED
43                         | DET_PRESSURE_PLATE,
44 };
45 
46 class dgn_event
47 {
48 public:
49     dgn_event_type type;
50     coord_def      place;
51     int            elapsed_ticks;
52     int            arg1, arg2;
53     coord_def      dest;
54 
55 public:
56     dgn_event(dgn_event_type t, const coord_def &p = coord_def(),
57               int ticks = you.time_taken, int a1 = 0, int a2 = 0,
58               const coord_def &d = coord_def())
type(t)59         : type(t), place(p), elapsed_ticks(ticks), arg1(a1),
60           arg2(a2), dest(d)
61     {
62     }
63 };
64 
65 class dgn_event_listener
66 {
67 public:
68     virtual ~dgn_event_listener();
69     // For vetoable events, return false to veto.
70     virtual bool notify_dgn_event(const dgn_event &e) = 0;
71 };
72 
73 // Alarm goes off when something enters this square.
74 struct dgn_square_alarm
75 {
dgn_square_alarmdgn_square_alarm76     dgn_square_alarm() : eventmask(0), listeners() { }
77 
78     unsigned eventmask;
79     list<dgn_event_listener*> listeners;
80 };
81 
82 struct dgn_listener_def
83 {
dgn_listener_defdgn_listener_def84     dgn_listener_def(unsigned mask, dgn_event_listener *l)
85         : eventmask(mask), listener(l)
86     {
87     }
88 
89     unsigned eventmask;
90     dgn_event_listener *listener;
91 };
92 
93 // Listeners are not saved here. Map markers have their own
94 // persistence and activation mechanisms. Other listeners must make
95 // their own persistence arrangements.
96 class dgn_event_dispatcher
97 {
98 public:
dgn_event_dispatcher()99     dgn_event_dispatcher() : global_event_mask(0), grid_triggers()
100     {
101     }
102 
103     void clear();
104     void clear_listeners_at(const coord_def &pos);
105     bool has_listeners_at(const coord_def &pos) const;
106     void move_listeners(const coord_def &from, const coord_def &to);
107 
108     // Returns false if the event is vetoed.
109     bool fire_vetoable_position_event(const dgn_event &e,
110                                       const coord_def &pos);
111 
112     bool fire_vetoable_position_event(dgn_event_type et,
113                                       const coord_def &pos);
114 
115     void fire_position_event(dgn_event_type et, const coord_def &pos);
116     void fire_position_event(const dgn_event &e, const coord_def &pos);
117     void fire_event(dgn_event_type et);
118     void fire_event(const dgn_event &e);
119 
120     void register_listener(unsigned evmask, dgn_event_listener *,
121                            const coord_def &pos = coord_def());
122     void remove_listener(dgn_event_listener *,
123                          const coord_def &pos = coord_def());
124 private:
125     void register_listener_at(unsigned mask, const coord_def &pos,
126                               dgn_event_listener *l);
127     void remove_listener_at(const coord_def &pos, dgn_event_listener *l);
128 
129 private:
130     unsigned global_event_mask;
131     unique_ptr<dgn_square_alarm> grid_triggers[GXM][GYM];
132     list<dgn_listener_def> listeners;
133 };
134 
135 extern dgn_event_dispatcher dungeon_events;
136