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