summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc13
-rw-r--r--crawl-ref/source/beam.h4
-rw-r--r--crawl-ref/source/effects.cc59
-rw-r--r--crawl-ref/source/effects.h2
-rw-r--r--crawl-ref/source/fight.cc49
-rw-r--r--crawl-ref/source/fight.h13
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);