summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorabrahamwl <abrahamwl@gmail.com>2009-10-27 22:04:57 -0700
committerAdam Borowski <kilobyte@angband.pl>2009-10-28 14:54:38 +0100
commit1cd5f5996970da48788b3bdc615652ed66763b70 (patch)
tree29022993b49c92c1c5070b4f9ecc02331f3688c3 /crawl-ref/source
parent67ab2ff904da3b6a3f426ee6d6a6b8e4116f199a (diff)
downloadcrawl-ref-1cd5f5996970da48788b3bdc615652ed66763b70.tar.gz
crawl-ref-1cd5f5996970da48788b3bdc615652ed66763b70.zip
Electrocution discharge in water ala FR 1637214
Weapons of electrocution now discharge in water, if the target is touching the water and not rElec, hitting all adjacent water-touching non-rElec creatures for about half the normal electrocution damage. Particularly notable new code is the implementation of an area-of-effect callback for beams, as well as a function and structure for weapon effects that should only happen after the target would have died, if it was going to die, and therefore cannot safely make use of its data. Issues that still need to be decided: - How doe Xom feel about this? (eg. If creatures hurt themselves this way.) - Should it ask you if you want to attack when you know the discharge will hit yourself?
Diffstat (limited to 'crawl-ref/source')
-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);