diff options
-rw-r--r-- | crawl-ref/source/beam.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/beam.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 59 | ||||
-rw-r--r-- | crawl-ref/source/effects.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 49 | ||||
-rw-r--r-- | crawl-ref/source/fight.h | 13 |
6 files changed, 131 insertions, 9 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 89b038d6dd..9e2153d18c 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -5661,8 +5661,15 @@ void bolt::determine_affected_cells(explosion_map& m, const coord_def& delta, if (feat_is_solid(dngn_feat) && !feat_is_wall(dngn_feat) && stop_at_statues) return; - // Hmm, I think we're OK. - m(delta + centre) = std::min(count, m(delta + centre)); + // Check if it passes the callback functions. + bool hits = true; + for (unsigned int i = 0; i < aoe_funcs.size(); ++i) + hits = (*aoe_funcs[i])(*this, loc) && hits; + + if (hits) { + // Hmm, I think we're OK. + m(delta + centre) = std::min(count, m(delta + centre)); + } // Now recurse in every direction. for (int i = 0; i < 8; ++i) @@ -5785,7 +5792,7 @@ bolt::bolt() : range(-2), type('*'), is_explosion(false), is_big_cloud(false), aimed_at_spot(false), aux_source(), affects_nothing(false), affects_items(true), effect_known(true), draw_delay(15), special_explosion(NULL), - range_funcs(), damage_funcs(), hit_funcs(), + range_funcs(), damage_funcs(), hit_funcs(), aoe_funcs(), obvious_effect(false), seen(false), path_taken(), range_used(0), is_tracer(false), aimed_at_feet(false), msg_generated(false), passed_target(false), in_explosion_phase(false), diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h index 41f410c8ac..281641cf90 100644 --- a/crawl-ref/source/beam.h +++ b/crawl-ref/source/beam.h @@ -56,6 +56,7 @@ typedef bool (*beam_damage_func)(bolt& beam, actor* victim, int &dmg, std::string &dmg_msg); typedef bool (*beam_hit_func)(bolt& beam, actor* victim, int dmg, int corpse); +typedef bool (*explosion_aoe_func)(bolt& beam, const coord_def& target); struct bolt { @@ -103,6 +104,9 @@ struct bolt std::vector<range_used_func> range_funcs; std::vector<beam_damage_func> damage_funcs; std::vector<beam_hit_func> hit_funcs; + std::vector<explosion_aoe_func> aoe_funcs; // Function for if the + // explosion only affects + // certain grid positions. // OUTPUT parameters (tracing, ID) bool obvious_effect; // did an 'obvious' effect happen? diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index a73b69d800..6dc8b2dbcf 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -382,6 +382,65 @@ void immolation(int pow, int caster, coord_def where, bool known, beam.explode(); } +static bool _conduct_electricity_hit(bolt& beam, actor* victim, int dmg, int corpse) +{ + if (!victim->alive() || victim->res_elec() > 0 || victim->airborne()) + return (false); + + return (true); +} + +static bool _conduct_electricity_damage(bolt &beam, actor* victim, + int &dmg, std::string &dmg_msg) +{ + dmg = (10 + random2(15)) / 2; + + return false; +} + +static bool _conduct_electricity_aoe(bolt& beam, const coord_def& target) +{ + if (feat_is_water(grd(target))) + return true; + + return false; +} + +void conduct_electricity(coord_def where, actor *attacker) +{ + const char *aux = "arcing electricity"; + + bolt beam; + + beam.flavour = BEAM_ELECTRICITY; + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def(1, 15); + beam.target = where; + beam.name = "electric current"; + beam.colour = LIGHTCYAN; + beam.aux_source = aux; + beam.ex_size = 1; + beam.is_explosion = true; + beam.effect_known = true; + beam.affects_items = false; + beam.aoe_funcs.push_back(_conduct_electricity_aoe); + beam.hit_funcs.push_back(_conduct_electricity_hit); + beam.damage_funcs.push_back(_conduct_electricity_damage); + + if (attacker == &you) + { + beam.thrower = KILL_YOU; + beam.beam_source = NON_MONSTER; + } + else + { + beam.thrower = KILL_MON; + beam.beam_source = attacker->mindex(); + } + + beam.explode(false, true); +} + void cleansing_flame(int pow, int caster, coord_def where, actor *attacker) { diff --git a/crawl-ref/source/effects.h b/crawl-ref/source/effects.h index 9cc9be9072..0dcf371f89 100644 --- a/crawl-ref/source/effects.h +++ b/crawl-ref/source/effects.h @@ -144,6 +144,8 @@ int torment_monsters(coord_def where, int pow, int caster, void immolation(int pow, int caster, coord_def where, bool known = false, actor *attacker = NULL); +void conduct_electricity(coord_def where, actor *attacker); + void cleansing_flame(int pow, int caster, coord_def where, actor *attacker = NULL); diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 522ad3dbe5..9606b308ac 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -353,7 +353,7 @@ melee_attack::melee_attack(actor *attk, actor *defn, shield(NULL), defender_shield(NULL), heavy_armour_penalty(0), can_do_unarmed(false), water_attack(false), miscast_level(-1), miscast_type(SPTYP_NONE), - miscast_target(NULL) + miscast_target(NULL), final_effects() { init_attack(); } @@ -1887,6 +1887,29 @@ void melee_attack::player_check_weapon_effects() } } +// Effects that occur after all other effects, even if the monster is dead. +// For example, explosions that would hit other creatures, but we want +// to deal with only one creature at a time, so that's handled last. +// You probably want to call player_monattk_hit_effects instead, as that +// function calls this one. +// Returns true if the combat round should end here. +bool melee_attack::player_monattk_final_hit_effects(bool mondied) +{ + for (unsigned int i = 0; i < final_effects.size(); ++i) + { + switch (final_effects[i].flavor) + { + case FINEFF_LIGHTNING_DISCHARGE: + if (see_cell(final_effects[i].location)) + mpr("Electricity arcs through the water!"); + conduct_electricity(final_effects[i].location, attacker); + break; + } + } + + return mondied; +} + // Returns true if the combat round should end here. bool melee_attack::player_monattk_hit_effects(bool mondied) { @@ -1932,7 +1955,7 @@ bool melee_attack::player_monattk_hit_effects(bool mondied) } if (mondied) - return (true); + return player_monattk_final_hit_effects(true); // These effects apply only to monsters that are still alive: @@ -1943,14 +1966,14 @@ bool melee_attack::player_monattk_hit_effects(bool mondied) // Also returns true if the hydra's last head was cut off, in which // case nothing more should be done to the hydra. if (decapitate_hydra(damage_done)) - return (!defender->alive()); + return player_monattk_final_hit_effects(!defender->alive()); // These two (staff damage and damage brand) are mutually exclusive! player_apply_staff_damage(); // Returns true if the monster croaked. if (!special_damage && apply_damage_brand()) - return (true); + return player_monattk_final_hit_effects(true); if (!no_damage_message.empty()) { @@ -1984,10 +2007,10 @@ bool melee_attack::player_monattk_hit_effects(bool mondied) { _monster_die(defender_as_monster(), KILL_YOU, NON_MONSTER); - return (true); + return player_monattk_final_hit_effects(true); } - return (false); + return player_monattk_final_hit_effects(false); } void melee_attack::_monster_die(monsters* monster, killer_type killer, @@ -3073,7 +3096,21 @@ bool melee_attack::apply_damage_brand() "You are electrocuted!" : "There is a sudden explosion of sparks!"; special_damage = 10 + random2(15); + + // Check for arcing in water, and add the final effect. + const coord_def& pos = defender->pos(); + + // We know the defender is neither airborne nor electricity + // resistant, from above, but is it on water? + if (feat_is_water(grd(pos))) + { + attack_final_effect effect; + effect.flavor = FINEFF_LIGHTNING_DISCHARGE; + effect.location = pos; + final_effects.push_back(effect); + } } + break; case SPWPN_ORC_SLAYING: diff --git a/crawl-ref/source/fight.h b/crawl-ref/source/fight.h index ec1102c80a..98bbe75346 100644 --- a/crawl-ref/source/fight.h +++ b/crawl-ref/source/fight.h @@ -37,6 +37,16 @@ enum unchivalric_attack_type UCAT_SLEEPING }; +enum attack_final_effect_flavor +{ + FINEFF_LIGHTNING_DISCHARGE +}; +struct attack_final_effect +{ + attack_final_effect_flavor flavor; + coord_def location; +}; + struct mon_attack_def; int effective_stat_bonus( int wepType = -1 ); @@ -197,6 +207,8 @@ private: int random_chaos_brand(); void do_miscast(); + std::vector<attack_final_effect> final_effects; + private: // Monster-attack specific stuff bool mons_attack_you(); @@ -248,6 +260,7 @@ private: int player_calc_base_unarmed_damage(); bool player_hurt_monster(); void player_exercise_combat_skills(); + bool player_monattk_final_hit_effects(bool mondied); bool player_monattk_hit_effects(bool mondied); void player_sustain_passive_damage(); int player_staff_damage(int skill); |