1 /**
2  * @file
3  * @brief Brand/ench/etc effects that might alter something in an
4  *             unexpected way.
5 **/
6 
7 #pragma once
8 
9 #include "beh-type.h"
10 #include "mon-util.h"
11 #include "mgen-data.h"
12 
13 struct bolt;
14 
15 class final_effect
16 {
17 public:
~final_effect()18     virtual ~final_effect() {}
19 
20     virtual bool mergeable(const final_effect &a) const = 0;
merge(const final_effect &)21     virtual void merge(const final_effect &)
22     {
23     }
24 
25     virtual void fire() = 0;
26 
27 protected:
28     static void schedule(final_effect *eff);
29 
30     mid_t att, def;
31     coord_def posn;
attacker()32     actor *attacker() const { return actor_by_mid(att); }
defender()33     actor *defender() const { return actor_by_mid(def); }
34 
final_effect(const actor * attack,const actor * defend,const coord_def & pos)35     final_effect(const actor *attack, const actor *defend, const coord_def &pos)
36         : att(attack ? attack->mid : 0),
37           def(defend ? defend->mid : 0),
38           posn(pos)
39     {
40     }
41 };
42 
43 class mirror_damage_fineff : public final_effect
44 {
45 public:
46     bool mergeable(const final_effect &a) const override;
47     void merge(const final_effect &a) override;
48     void fire() override;
49 
schedule(const actor * attack,const actor * defend,int dam)50     static void schedule(const actor *attack, const actor *defend, int dam)
51     {
52         final_effect::schedule(new mirror_damage_fineff(attack, defend, dam));
53     }
54 protected:
mirror_damage_fineff(const actor * attack,const actor * defend,int dam)55     mirror_damage_fineff(const actor *attack, const actor *defend, int dam)
56         : final_effect(attack, defend, coord_def()), damage(dam)
57     {
58     }
59     int damage;
60 };
61 
62 class ru_retribution_fineff : public final_effect
63 {
64 public:
65     bool mergeable(const final_effect &a) const override;
66     void merge(const final_effect &a) override;
67     void fire() override;
68 
schedule(const actor * attack,const actor * defend,int dam)69     static void schedule(const actor *attack, const actor *defend, int dam)
70     {
71         final_effect::schedule(new ru_retribution_fineff(attack, defend, dam));
72     }
73 protected:
ru_retribution_fineff(const actor * attack,const actor * defend,int dam)74     ru_retribution_fineff(const actor *attack, const actor *defend, int dam)
75         : final_effect(attack, defend, coord_def()), damage(dam)
76     {
77     }
78     int damage;
79 };
80 
81 class trample_follow_fineff : public final_effect
82 {
83 public:
84     bool mergeable(const final_effect &a) const override;
85     void fire() override;
86 
schedule(const actor * attack,const coord_def & pos)87     static void schedule(const actor *attack, const coord_def &pos)
88     {
89         final_effect::schedule(new trample_follow_fineff(attack, pos));
90     }
91 protected:
trample_follow_fineff(const actor * attack,const coord_def & pos)92     trample_follow_fineff(const actor *attack, const coord_def &pos)
93         : final_effect(attack, 0, pos)
94     {
95     }
96 };
97 
98 class blink_fineff : public final_effect
99 {
100 public:
101     bool mergeable(const final_effect &a) const override;
102     void fire() override;
103 
104     static void schedule(const actor *blinker, const actor *other = nullptr)
105     {
106         final_effect::schedule(new blink_fineff(blinker, other));
107     }
108 protected:
blink_fineff(const actor * blinker,const actor * o)109     blink_fineff(const actor *blinker, const actor *o)
110         : final_effect(o, blinker, coord_def())
111     {
112     }
113 };
114 
115 class teleport_fineff : public final_effect
116 {
117 public:
118     bool mergeable(const final_effect &a) const override;
119     void fire() override;
120 
schedule(const actor * defend)121     static void schedule(const actor *defend)
122     {
123         final_effect::schedule(new teleport_fineff(defend));
124     }
125 protected:
teleport_fineff(const actor * defend)126     teleport_fineff(const actor *defend)
127         : final_effect(0, defend, coord_def())
128     {
129     }
130 };
131 
132 class trj_spawn_fineff : public final_effect
133 {
134 public:
135     bool mergeable(const final_effect &a) const override;
136     void merge(const final_effect &a) override;
137     void fire() override;
138 
schedule(const actor * attack,const actor * defend,const coord_def & pos,int dam)139     static void schedule(const actor *attack, const actor *defend,
140                          const coord_def &pos, int dam)
141     {
142         final_effect::schedule(new trj_spawn_fineff(attack, defend, pos, dam));
143     }
144 protected:
trj_spawn_fineff(const actor * attack,const actor * defend,const coord_def & pos,int dam)145     trj_spawn_fineff(const actor *attack, const actor *defend,
146                      const coord_def &pos, int dam)
147         : final_effect(attack, defend, pos), damage(dam)
148     {
149     }
150     int damage;
151 };
152 
153 class blood_fineff : public final_effect
154 {
155 public:
156     bool mergeable(const final_effect &a) const override;
157     void fire() override;
158     void merge(const final_effect &a) override;
159 
schedule(const actor * defend,const coord_def & pos,int blood_amount)160     static void schedule(const actor *defend, const coord_def &pos,
161                          int blood_amount)
162     {
163         final_effect::schedule(new blood_fineff(defend, pos, blood_amount));
164     }
165 protected:
blood_fineff(const actor * defend,const coord_def & pos,int blood_amount)166     blood_fineff(const actor *defend, const coord_def &pos, int blood_amount)
167         : final_effect(0, 0, pos), mtype(defend->type), blood(blood_amount)
168     {
169     }
170     monster_type mtype;
171     int blood;
172 };
173 
174 class deferred_damage_fineff : public final_effect
175 {
176 public:
177     bool mergeable(const final_effect &a) const override;
178     void merge(const final_effect &a) override;
179     void fire() override;
180 
181     static void schedule(const actor *attack, const actor *defend,
182                          int dam, bool attacker_effects, bool fatal = true)
183     {
184         final_effect::schedule(
185             new deferred_damage_fineff(attack, defend, dam, attacker_effects,
186                                        fatal));
187     }
188 protected:
deferred_damage_fineff(const actor * attack,const actor * defend,int dam,bool _attacker_effects,bool _fatal)189     deferred_damage_fineff(const actor *attack, const actor *defend,
190                            int dam, bool _attacker_effects, bool _fatal)
191         : final_effect(attack, defend, coord_def()),
192           damage(dam), attacker_effects(_attacker_effects), fatal(_fatal)
193     {
194     }
195     int damage;
196     bool attacker_effects;
197     bool fatal;
198 };
199 
200 class starcursed_merge_fineff : public final_effect
201 {
202 public:
203     bool mergeable(const final_effect &a) const override;
204     void fire() override;
205 
schedule(const actor * merger)206     static void schedule(const actor *merger)
207     {
208         final_effect::schedule(new starcursed_merge_fineff(merger));
209     }
210 protected:
starcursed_merge_fineff(const actor * merger)211     starcursed_merge_fineff(const actor *merger)
212         : final_effect(0, merger, coord_def())
213     {
214     }
215 };
216 
217 class shock_serpent_discharge_fineff : public final_effect
218 {
219 public:
220     bool mergeable(const final_effect &a) const override;
221     void merge(const final_effect &a) override;
222     void fire() override;
223 
schedule(const actor * serpent,actor & oppressor,coord_def pos,int pow)224     static void schedule(const actor *serpent, actor &oppressor,
225                          coord_def pos, int pow)
226     {
227         final_effect::schedule(new shock_serpent_discharge_fineff(serpent,
228                                                                   oppressor,
229                                                                   pos, pow));
230     }
231 protected:
shock_serpent_discharge_fineff(const actor * serpent,actor & rudedude,coord_def pos,int pow)232     shock_serpent_discharge_fineff(const actor *serpent, actor &rudedude,
233                                    coord_def pos, int pow)
234         : final_effect(0, serpent, coord_def()), oppressor(rudedude),
235           position(pos), power(pow),
236         attitude(mons_attitude(*serpent->as_monster()))
237     {
238     }
239     actor &oppressor;
240     coord_def position;
241     int power;
242     mon_attitude_type attitude;
243 };
244 
245 class explosion_fineff : public final_effect
246 {
247 public:
248     // One explosion at a time, please.
mergeable(const final_effect &)249     bool mergeable(const final_effect &) const override { return false; }
250     void fire() override;
251 
schedule(bolt & beam,string boom,string sanct,bool inner_flame,const actor * flame_agent)252     static void schedule(bolt &beam, string boom, string sanct,
253                          bool inner_flame, const actor* flame_agent)
254     {
255         final_effect::schedule(new explosion_fineff(beam, boom, sanct,
256                                                     inner_flame, flame_agent));
257     }
258 protected:
explosion_fineff(const bolt & beem,string boom,string sanct,bool flame,const actor * agent)259     explosion_fineff(const bolt &beem, string boom, string sanct,
260                      bool flame, const actor* agent)
261         : final_effect(0, 0, coord_def()), beam(beem),
262           boom_message(boom), sanctuary_message(sanct),
263           inner_flame(flame), flame_agent(agent)
264     {
265     }
266     bolt beam;
267     string boom_message;
268     string sanctuary_message;
269     bool inner_flame;
270     const actor* flame_agent;
271 };
272 
273 // A fineff that triggers a daction; otherwise the daction
274 // occurs immediately (and then later) -- this might actually
275 // be too soon in some cases.
276 class delayed_action_fineff : public final_effect
277 {
278 public:
279     bool mergeable(const final_effect &a) const override;
280     virtual void fire() override;
281 
schedule(daction_type action,const string & final_msg)282     static void schedule(daction_type action, const string &final_msg)
283     {
284         final_effect::schedule(new delayed_action_fineff(action, final_msg));
285     }
286 protected:
delayed_action_fineff(daction_type _action,const string & _final_msg)287     delayed_action_fineff(daction_type _action, const string &_final_msg)
288         : final_effect(0, 0, coord_def()),
289           action(_action), final_msg(_final_msg)
290     {
291     }
292     daction_type action;
293     string final_msg;
294 };
295 
296 class kirke_death_fineff : public delayed_action_fineff
297 {
298 public:
299     void fire() override;
300 
schedule(const string & final_msg)301     static void schedule(const string &final_msg)
302     {
303         final_effect::schedule(new kirke_death_fineff(final_msg));
304     }
305 protected:
kirke_death_fineff(const string & _final_msg)306     kirke_death_fineff(const string & _final_msg)
307         : delayed_action_fineff(DACT_KIRKE_HOGS, _final_msg)
308     {
309     }
310 };
311 
312 class rakshasa_clone_fineff : public final_effect
313 {
314 public:
315     bool mergeable(const final_effect &a) const override;
316     void fire() override;
317 
schedule(const actor * defend,const coord_def & pos)318     static void schedule(const actor *defend, const coord_def &pos)
319     {
320         final_effect::schedule(new rakshasa_clone_fineff(defend, pos));
321     }
322 protected:
rakshasa_clone_fineff(const actor * defend,const coord_def & pos)323     rakshasa_clone_fineff(const actor *defend, const coord_def &pos)
324         : final_effect(0, defend, pos)
325     {
326     }
327     int damage;
328 };
329 
330 class bennu_revive_fineff : public final_effect
331 {
332 public:
333     // Each trigger is from the death of a different bennu---no merging.
mergeable(const final_effect &)334     bool mergeable(const final_effect &) const override { return false; }
335     void fire() override;
336 
schedule(coord_def pos,int revives,beh_type attitude,unsigned short foe)337     static void schedule(coord_def pos, int revives, beh_type attitude,
338                          unsigned short foe)
339     {
340         final_effect::schedule(new bennu_revive_fineff(pos, revives, attitude, foe));
341     }
342 protected:
bennu_revive_fineff(coord_def pos,int _revives,beh_type _att,unsigned short _foe)343     bennu_revive_fineff(coord_def pos, int _revives, beh_type _att,
344                         unsigned short _foe)
345         : final_effect(0, 0, pos), revives(_revives), attitude(_att), foe(_foe)
346     {
347     }
348     int revives;
349     beh_type attitude;
350     unsigned short foe;
351 };
352 
353 class infestation_death_fineff : public final_effect
354 {
355 public:
mergeable(const final_effect &)356     bool mergeable(const final_effect &) const override { return false; }
357     void fire() override;
358 
schedule(coord_def pos,const string & name)359     static void schedule(coord_def pos, const string &name)
360     {
361         final_effect::schedule(new infestation_death_fineff(pos, name));
362     }
363 protected:
infestation_death_fineff(coord_def pos,const string & _name)364     infestation_death_fineff(coord_def pos, const string &_name)
365         : final_effect(0, 0, pos), name(_name)
366     {
367     }
368     string name;
369 };
370 
371 class make_derived_undead_fineff : public final_effect
372 {
373 public:
mergeable(const final_effect &)374     bool mergeable(const final_effect &) const override { return false; }
375     void fire() override;
376 
schedule(coord_def pos,mgen_data mg,int xl,const string & agent,const string & msg)377     static void schedule(coord_def pos, mgen_data mg, int xl,
378                          const string &agent, const string &msg)
379     {
380         final_effect::schedule(new make_derived_undead_fineff(pos, mg, xl, agent, msg));
381     }
382 protected:
make_derived_undead_fineff(coord_def pos,mgen_data _mg,int _xl,const string & _agent,const string & _msg)383     make_derived_undead_fineff(coord_def pos, mgen_data _mg, int _xl,
384                                const string &_agent, const string &_msg)
385         : final_effect(0, 0, pos), mg(_mg), experience_level(_xl),
386           agent(_agent), message(_msg)
387     {
388     }
389     mgen_data mg;
390     int experience_level;
391     string agent;
392     string message;
393 };
394 
395 class mummy_death_curse_fineff : public final_effect
396 {
397 public:
mergeable(const final_effect &)398     bool mergeable(const final_effect &) const override { return false; }
399     void fire() override;
400 
schedule(const actor * attack,string name,killer_type killer,int pow)401     static void schedule(const actor * attack, string name, killer_type killer, int pow)
402     {
403         final_effect::schedule(new mummy_death_curse_fineff(attack, name, killer, pow));
404     }
405 protected:
mummy_death_curse_fineff(const actor * attack,string _name,killer_type _killer,int _pow)406     mummy_death_curse_fineff(const actor * attack, string _name, killer_type _killer, int _pow)
407         : final_effect(fixup_attacker(attack), 0, coord_def()), name(_name),
408           killer(_killer), pow(_pow)
409     {
410     }
411     const actor *fixup_attacker(const actor *a);
412 
413     string name;
414     killer_type killer;
415     int pow;
416 };
417 
418 class summon_dismissal_fineff : public final_effect
419 {
420 public:
421     bool mergeable(const final_effect &fe) const override;
422     void merge(const final_effect &) override;
423     void fire() override;
424 
schedule(const actor * _defender)425     static void schedule(const actor * _defender)
426     {
427         final_effect::schedule(new summon_dismissal_fineff(_defender));
428     }
429 protected:
summon_dismissal_fineff(const actor * _defender)430     summon_dismissal_fineff(const actor * _defender)
431         : final_effect(0, _defender, coord_def())
432     {
433     }
434 };
435 
436 class spectral_weapon_fineff : public final_effect
437 {
438 public:
mergeable(const final_effect &)439     bool mergeable(const final_effect &) const override { return false; };
440     void fire() override;
441 
schedule(const actor & attack,const actor & defend)442     static void schedule(const actor &attack, const actor &defend)
443     {
444         final_effect::schedule(new spectral_weapon_fineff(attack, defend));
445     }
446 protected:
spectral_weapon_fineff(const actor & attack,const actor & defend)447     spectral_weapon_fineff(const actor &attack, const actor &defend)
448         : final_effect(&attack, &defend, coord_def())
449     {
450     }
451 };
452 
453 void fire_final_effects();
454