summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorStefan O'Rear <stefanor@cox.net>2009-11-04 02:24:58 -0800
committerStefan O'Rear <stefanor@cox.net>2009-11-04 02:25:24 -0800
commit30387f6a8372b62160a6c2a4441a1b5909538055 (patch)
treec742100bf2aadfddd53e496e9798acce4f7879b7 /crawl-ref/source
parentb6bb6178f82fc4227a63414e4bec9d2916e2a9b0 (diff)
downloadcrawl-ref-30387f6a8372b62160a6c2a4441a1b5909538055.tar.gz
crawl-ref-30387f6a8372b62160a6c2a4441a1b5909538055.zip
Disintegration can be very messy.
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/beam.cc9
-rw-r--r--crawl-ref/source/enum.h3
-rw-r--r--crawl-ref/source/misc.cc33
-rw-r--r--crawl-ref/source/misc.h1
-rw-r--r--crawl-ref/source/monster.cc9
-rw-r--r--crawl-ref/source/monstuff.cc94
-rw-r--r--crawl-ref/source/monstuff.h2
-rw-r--r--crawl-ref/source/player.cc6
-rw-r--r--crawl-ref/source/spells4.cc55
9 files changed, 195 insertions, 17 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 96b139da86..77d9c19741 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -3837,7 +3837,14 @@ void bolt::affect_player_enchantment()
if (aux_source.empty())
aux_source = "a disintegration bolt";
- internal_ouch(damage.roll());
+ {
+ int amt = damage.roll();
+ internal_ouch(amt);
+
+ if (you.can_bleed())
+ blood_spray(you.pos(), MONS_PLAYER, amt / 5);
+ }
+
obvious_effect = true;
break;
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index a0b94c81c5..02ad706fb2 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2188,7 +2188,8 @@ enum monster_flag_type
// name.
MF_NAME_MASK = 0x30000,
MF_GOD_GIFT = 0x40000, // Is a god gift.
- MF_FLEEING_FROM_SANCTUARY = 0x80000 // Is running away from player sanctuary
+ MF_FLEEING_FROM_SANCTUARY = 0x80000, // Is running away from player sanctuary
+ MF_EXPLODE_KILL = 0x100000 // Is being killed with disintegration
};
// Adding slots breaks saves. YHBW.
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 94566c96e4..94603039d3 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1147,6 +1147,39 @@ void bleed_onto_floor(const coord_def& where, monster_type montype,
_maybe_bloodify_square(where, damage, spatter, smell_alert);
}
+void blood_spray(const coord_def& origin, monster_type montype, int level)
+{
+ los_def ld(origin, opc_solid);
+
+ ld.update();
+
+ int tries = 0;
+ for (int i = 0; i < level; ++i)
+ {
+ // Blood drops are small and light and suffer a lot of wind
+ // resistance.
+ int range = random2(8) + 1;
+
+ while (tries < 5000)
+ {
+ ++tries;
+
+ coord_def bloody = origin;
+ bloody.x += random_range(-range, range);
+ bloody.y += random_range(-range, range);
+
+ if (in_bounds(bloody) && ld.see_cell(bloody))
+ {
+ if (feat_is_solid(grd(bloody)) && coinflip())
+ continue;
+
+ bleed_onto_floor(bloody, montype, 99);
+ break;
+ }
+ }
+ }
+}
+
static void _spatter_neighbours(const coord_def& where, int chance)
{
for (adjacent_iterator ai(where, false); ai; ++ai)
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index c9c0e2eaee..83d6791d62 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -39,6 +39,7 @@ void turn_corpse_into_blood_potions (item_def &item);
void turn_corpse_into_skeleton_and_blood_potions(item_def &item);
void split_potions_into_decay(int obj, int amount, bool need_msg = true);
+void blood_spray(const coord_def& where, monster_type mon, int level);
void bleed_onto_floor(const coord_def& where, monster_type mon, int damage,
bool spatter = false, bool smell_alert = true);
void generate_random_blood_spatter_on_level();
diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc
index 319e256d5a..1ad06936d4 100644
--- a/crawl-ref/source/monster.cc
+++ b/crawl-ref/source/monster.cc
@@ -3267,6 +3267,15 @@ int monsters::hurt(const actor *agent, int amount, beam_type flavour,
hit_points = max_hit_points;
}
+ if (flavour == BEAM_NUKE || flavour == BEAM_DISINTEGRATION)
+ {
+ if (can_bleed())
+ blood_spray(pos(), id(), amount / 5);
+
+ if (!alive())
+ flags |= MF_EXPLODE_KILL;
+ }
+
// Allow the victim to exhibit passive damage behaviour (royal
// jelly).
kill_category whose = (agent == NULL) ? KC_OTHER :
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index e7f5ff2c9e..7eaf3133bb 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -23,6 +23,7 @@
#include "dgnevent.h"
#include "directn.h"
#include "files.h"
+#include "food.h"
#include "godabil.h"
#include "items.h"
#include "kills.h"
@@ -336,6 +337,78 @@ monster_type fill_out_corpse(const monsters* monster, item_def& corpse,
return (corpse_class);
}
+bool explode_corpse(item_def& corpse, const coord_def& where)
+{
+ los_def ld(where, opc_solid);
+
+ if (monster_descriptor(corpse.plus, MDSC_LEAVES_HIDE)
+ && mons_genus(corpse.plus) == MONS_DRAGON)
+ {
+ // Uh... dragon hide is tough stuff and it keeps the monster in
+ // one piece? More importantly, it prevents a flavor feature
+ // from becoming a trap for the unwary.
+
+ return (false);
+ }
+
+ ld.update();
+
+ int nchunks = 1 + random2(mons_weight(corpse.plus) / 150);
+ nchunks = stepdown_value(nchunks, 4, 4, 12, 12);
+
+ int ntries = 0;
+
+ corpse.base_type = OBJ_FOOD;
+ corpse.sub_type = FOOD_CHUNK;
+
+ blood_spray(where, static_cast<monster_type>(corpse.plus), nchunks * 3);
+
+ while (nchunks > 0 && ntries < 10000)
+ {
+ ++ntries;
+
+ coord_def cp = where;
+ cp.x += random_range(-LOS_RADIUS, LOS_RADIUS);
+ cp.y += random_range(-LOS_RADIUS, LOS_RADIUS);
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Trying to scatter chunk to %d, %d...",
+ cp.x, cp.y);
+#endif
+
+ if (! in_bounds(cp))
+ continue;
+
+ if (! ld.see_cell(cp))
+ continue;
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Cell is visible...");
+#endif
+
+ if (feat_is_solid(grd(cp)))
+ continue;
+
+ --nchunks;
+
+ if (feat_destroys_items(grd(cp)))
+ {
+ if (!silenced(cp))
+ mprf(MSGCH_SOUND, feat_item_destruction_message(grd(cp)));
+
+ continue;
+ }
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "Success");
+#endif
+
+ copy_item_to_grid(corpse, cp);
+ }
+
+ return (true);
+}
+
// Returns the item slot of a generated corpse, or -1 if no corpse.
int place_monster_corpse(const monsters *monster, bool silent,
bool force)
@@ -363,19 +436,32 @@ int place_monster_corpse(const monsters *monster, bool silent,
if (corpse_class == MONS_NO_MONSTER || (!force && coinflip()))
return (-1);
- if (feat_destroys_items(grd(monster->pos())))
+ int o = get_item_slot();
+ if (o == NON_ITEM)
{
item_was_destroyed(corpse);
return (-1);
}
- int o = get_item_slot();
- if (o == NON_ITEM)
- return (-1);
mitm[o] = corpse;
origin_set_monster(mitm[o], monster);
+ if ((monster->flags & MF_EXPLODE_KILL)
+ && explode_corpse(corpse, monster->pos()))
+ {
+ // We already have a spray of chunks
+ destroy_item(o);
+ return (-1);
+ }
+
+ if (feat_destroys_items(grd(monster->pos())))
+ {
+ item_was_destroyed(corpse);
+ destroy_item(o);
+ return (-1);
+ }
+
// Don't care if 'o' is changed, and it shouldn't be (corpses don't
// stack).
move_item_to_grid(&o, monster->pos());
diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h
index c8df0edde0..6b1de15f19 100644
--- a/crawl-ref/source/monstuff.h
+++ b/crawl-ref/source/monstuff.h
@@ -80,6 +80,8 @@ int monster_die(monsters *monster, killer_type killer,
monster_type fill_out_corpse(const monsters* monster, item_def& corpse,
bool allow_weightless = false);
+bool explode_corpse(item_def& corpse, const coord_def& where);
+
int place_monster_corpse(const monsters *monster, bool silent,
bool force = false);
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 0ec66b2678..d3dd1d6829 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -6957,6 +6957,12 @@ int player::hurt(const actor *agent, int amount, beam_type flavour,
ASSERT(false);
ouch(amount, NON_MONSTER, KILLED_BY_SOMETHING);
}
+
+ if ((flavour == BEAM_NUKE || flavour == BEAM_DISINTEGRATION) && can_bleed())
+ {
+ blood_spray(pos(), id(), amount / 5);
+ }
+
return (amount);
}
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 08620200b8..39f1be7c52 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -64,11 +64,12 @@ enum DEBRIS // jmf: add for shatter, dig, and Giants to throw
// Just to avoid typing this over and over.
// Returns true if monster died. -- bwr
-static bool _player_hurt_monster(monsters& m, int damage)
+static bool _player_hurt_monster(monsters& m, int damage,
+ beam_type flavour = BEAM_MISSILE)
{
if (damage > 0)
{
- m.hurt(&you, damage, BEAM_MISSILE, false);
+ m.hurt(&you, damage, flavour, false);
if (m.alive())
{
@@ -1422,7 +1423,8 @@ bool cast_fragmentation(int pow, const dist& spd)
// fizzle (since we don't actually explode wood golems). -- bwr
explode = false;
beam.damage.num = 2;
- _player_hurt_monster(*mon, beam.damage.roll());
+ _player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION);
break;
case MONS_IRON_GOLEM:
@@ -1431,7 +1433,8 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.name = "blast of metal fragments";
beam.colour = CYAN;
beam.damage.num = 4;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION))
beam.damage.num += 2;
break;
@@ -1444,7 +1447,8 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.name = "blast of rock fragments";
beam.colour = BROWN;
beam.damage.num = 3;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION))
beam.damage.num++;
break;
@@ -1470,7 +1474,8 @@ bool cast_fragmentation(int pow, const dist& spd)
if (pow >= 50 && one_chance_in(10))
statue_damage = mon->hit_points;
- if (_player_hurt_monster(*mon, statue_damage))
+ if (_player_hurt_monster(*mon, statue_damage,
+ BEAM_DISINTEGRATION))
beam.damage.num += 2;
}
break;
@@ -1481,7 +1486,8 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.name = "blast of crystal shards";
beam.colour = WHITE;
beam.damage.num = 4;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION))
beam.damage.num += 2;
break;
@@ -1493,7 +1499,8 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.colour = WHITE;
beam.damage.num = 2;
beam.flavour = BEAM_ICE;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll()),
+ BEAM_DISINTEGRATION);
beam.damage.num++;
break;
}
@@ -1515,7 +1522,8 @@ bool cast_fragmentation(int pow, const dist& spd)
else
{
beam.damage.num = 2;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION))
beam.damage.num += 2;
}
goto all_done; // i.e., no "Foo Explodes!"
@@ -1533,7 +1541,8 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.name = "blast of petrified fragments";
beam.colour = mons_class_colour(mon->type);
beam.damage.num = petrifying ? 2 : 3;
- if (_player_hurt_monster(*mon, beam.damage.roll()))
+ if (_player_hurt_monster(*mon, beam.damage.roll(),
+ BEAM_DISINTEGRATION))
beam.damage.num++;
break;
}
@@ -1544,7 +1553,8 @@ bool cast_fragmentation(int pow, const dist& spd)
// Yes, this spell does lousy damage if the monster
// isn't susceptible. -- bwr
- _player_hurt_monster(*mon, roll_dice(1, 5 + pow / 25));
+ _player_hurt_monster(*mon, roll_dice(1, 5 + pow / 25),
+ BEAM_DISINTEGRATION);
goto do_terrain;
}
@@ -1552,6 +1562,29 @@ bool cast_fragmentation(int pow, const dist& spd)
goto all_done;
}
+ for (stack_iterator si(spd.target); si; ++si)
+ {
+ if (si->base_type == OBJ_CORPSES)
+ {
+ std::string nm = si->name(DESC_CAP_THE);
+ if (si->sub_type == CORPSE_BODY)
+ {
+ if (!explode_corpse(*si, spd.target))
+ {
+ mprf("%s seems to be exceptionally well connected.",
+ nm.c_str());
+
+ goto all_done;
+ }
+ }
+
+ mprf("%s explodes!", nm.c_str());
+ destroy_item(si.link());
+ // si invalid now!
+ goto all_done;
+ }
+ }
+
if (env.markers.property_at(spd.target, MAT_ANY,
"veto_fragmentation") == "veto")
{