summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc71
-rw-r--r--crawl-ref/source/misc.cc6
-rw-r--r--crawl-ref/source/mon-data.h20
-rw-r--r--crawl-ref/source/mon-util.cc13
-rw-r--r--crawl-ref/source/mon-util.h2
-rw-r--r--crawl-ref/source/monstuff.cc18
-rw-r--r--crawl-ref/source/view.cc102
-rw-r--r--crawl-ref/source/view.h1
8 files changed, 187 insertions, 46 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index a1116db1f6..bbbf6ce749 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -1610,15 +1610,14 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
{
case BEAM_FIRE:
case BEAM_STEAM:
- hurted =
- resist_adjust_damage(
+ hurted
+ = resist_adjust_damage(
monster,
pbolt.flavour,
- pbolt.flavour == BEAM_FIRE
- ? monster->res_fire()
- : monster->res_steam(),
- hurted,
- true);
+ (pbolt.flavour == BEAM_FIRE) ? monster->res_fire()
+ : monster->res_steam(),
+ hurted, true);
+
if (!hurted)
{
if (doFlavouredEffects)
@@ -1728,9 +1727,8 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
}
}
else if (doFlavouredEffects)
- {
poison_monster( monster, _whose_kill(pbolt), 4 );
- }
+
break;
case BEAM_NEG:
@@ -1761,7 +1759,7 @@ int mons_adjust_flavoured( monsters *monster, bolt &pbolt,
}
monster->max_hit_points -= 2 + random2(3);
- monster->hit_points -= 2 + random2(3);
+ monster->hit_points -= 2 + random2(3);
if (monster->hit_points >= monster->max_hit_points)
monster->hit_points = monster->max_hit_points;
@@ -2298,10 +2296,10 @@ void fire_tracer(const monsters *monster, bolt &pbolt)
pbolt.is_tracer = true;
pbolt.source_x = monster->x; // always safe to do.
pbolt.source_y = monster->y;
- pbolt.beam_source = monster_index(monster);
+ pbolt.beam_source = monster_index(monster);
pbolt.can_see_invis = (mons_see_invis(monster) != 0);
- pbolt.smart_monster = (mons_intel(monster->type) == I_HIGH ||
- mons_intel(monster->type) == I_NORMAL);
+ pbolt.smart_monster = (mons_intel(monster->type) == I_HIGH
+ || mons_intel(monster->type) == I_NORMAL);
pbolt.attitude = mons_attitude(monster);
// init tracer variables
@@ -3485,10 +3483,11 @@ static int _affect_player( bolt &beam )
const bool engulfs = (beam.is_explosion || beam.is_big_cloud);
mprf( "The %s %s you!",
- beam.name.c_str(), (engulfs) ? "engulfs" : "hits" );
+ beam.name.c_str(), (engulfs) ? "engulfs" : "hits" );
int hurted = 0;
- int burn_power = (beam.is_explosion) ? 5 : ((beam.is_beam) ? 3 : 2);
+ int burn_power = (beam.is_explosion) ? 5 :
+ (beam.is_beam) ? 3 : 2;
// Roll the damage
hurted += roll_dice( beam.damage );
@@ -3529,6 +3528,18 @@ static int _affect_player( bolt &beam )
if (hurted < 0)
hurted = 0;
+ // if the beam is an actual missile or of the MMISSILE type (Earth magic)
+ // might bleed on the floor
+ if (!engulfs
+ && (beam.flavour == BEAM_MISSILE || beam.flavour == BEAM_MMISSILE))
+ {
+ int blood = hurted/2; // assumes DVORP_PIERCING, factor: 0.5
+ if (blood > you.hp)
+ blood = you.hp;
+
+ bleed_onto_floor(you.x_pos, you.y_pos, -1, blood, true);
+ }
+
hurted = check_your_resists( hurted, beam.flavour );
if (beam.flavour == BEAM_MIASMA && hurted > 0)
@@ -3856,8 +3867,10 @@ static int _affect_monster(bolt &beam, monsters *mon)
if (beam.flavour == BEAM_ELECTRICITY)
{
if (see_grid(mon->x, mon->y))
+ {
mprf("The %s arcs harmlessly into the water.",
beam.name.c_str());
+ }
return (BEAM_STOP);
}
@@ -4006,6 +4019,7 @@ static int _affect_monster(bolt &beam, monsters *mon)
mprf("%s blocks the %s.",
mon->name(DESC_CAP_THE).c_str(),
beam.name.c_str());
+
mon->shield_block_succeeded();
return (BEAM_STOP);
}
@@ -4022,17 +4036,18 @@ static int _affect_monster(bolt &beam, monsters *mon)
mprf("The %s %s %s.",
beam.name.c_str(),
engulfs? "engulfs" : "hits",
- player_monster_visible(&menv[tid])?
- mon->name(DESC_NOCAP_THE).c_str()
- : "something");
+ player_monster_visible(&menv[tid]) ?
+ mon->name(DESC_NOCAP_THE).c_str() : "something");
}
else
{
// the player might hear something,
// if _they_ fired a missile (not beam)
if (!silenced(you.x_pos, you.y_pos) && beam.flavour == BEAM_MISSILE
- && YOU_KILL(beam.thrower))
+ && YOU_KILL(beam.thrower))
+ {
mprf(MSGCH_SOUND, "The %s hits something.", beam.name.c_str());
+ }
}
if (beam.name.find("throwing net") != std::string::npos)
@@ -4043,9 +4058,22 @@ static int _affect_monster(bolt &beam, monsters *mon)
// doFlavouredEffects = false above)
hurt_final = mons_adjust_flavoured(mon, beam, raw_damage);
+ // if the beam is an actual missile or of the MMISSILE type (Earth magic)
+ // might bleed on the floor
+ if (!engulfs
+ && (beam.flavour == BEAM_MISSILE || beam.flavour == BEAM_MMISSILE))
+ {
+ // using raw_damage instead of the flavoured one!
+ int blood = raw_damage/2; // assumes DVORP_PIERCING, factor: 0.5
+ if (blood > mon->hit_points)
+ blood = mon->hit_points;
+
+ bleed_onto_floor(mon->x, mon->y, mon->type, blood, true);
+ }
+
// now hurt monster
hurt_monster( mon, hurt_final );
-
+
if (mon->hit_points < 1)
{
_monster_die(mon, beam);
@@ -4069,8 +4097,7 @@ static int _affect_monster(bolt &beam, monsters *mon)
}
- /* looks for missiles which aren't poison but
- are poison*ed* */
+ /* looks for missiles which aren't poison but are poison*ed* */
if (beam.name.find("poisoned") != std::string::npos
&& beam.flavour != BEAM_POISON
&& beam.flavour != BEAM_POISON_ARROW)
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 0f8ec8a42b..f676640646 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -341,6 +341,12 @@ static void maybe_bloodify_square(int x, int y, int amount, bool spatter = false
#endif
if (allow_bleeding_on_square(x,y))
env.map[x][y].property = FPROP_BLOODY;
+
+ // if old or new blood on square, the smell reaches further
+ if (env.map[x][y].property == FPROP_BLOODY)
+ blood_smell(12, x, y);
+ else // still allow a lingering smell
+ blood_smell(7, x, y);
if (spatter)
{
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 460bf14772..92baf40a27 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -674,7 +674,7 @@
// hounds ('h')
{
MONS_JACKAL, 'h', BROWN, "jackal",
- M_WARM_BLOOD,
+ M_WARM_BLOOD | M_BLOOD_SCENT,
MR_NO_FLAGS,
200, 10, MONS_HOUND, MONS_JACKAL, MH_NATURAL, -1,
{ {AT_BITE, AF_PLAIN, 3}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -685,7 +685,7 @@
{
MONS_HOUND, 'h', YELLOW, "hound",
- M_SENSE_INVIS | M_WARM_BLOOD,
+ M_SENSE_INVIS | M_WARM_BLOOD | M_BLOOD_SCENT,
MR_NO_FLAGS,
300, 10, MONS_HOUND, MONS_HOUND, MH_NATURAL, -3,
{ {AT_BITE, AF_PLAIN, 6}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -696,7 +696,7 @@
{
MONS_WARG, 'h', WHITE, "warg",
- M_SENSE_INVIS | M_WARM_BLOOD,
+ M_SENSE_INVIS | M_WARM_BLOOD | M_BLOOD_SCENT,
MR_RES_POISON,
600, 12, MONS_HOUND, MONS_WARG, MH_NATURAL, -6,
{ {AT_BITE, AF_PLAIN, 12}, {AT_CLAW, AF_PLAIN, 3}, {AT_CLAW, AF_PLAIN, 3}, AT_NO_ATK },
@@ -707,7 +707,7 @@
{
MONS_WOLF, 'h', LIGHTGREY, "wolf",
- M_WARM_BLOOD | M_SENSE_INVIS,
+ M_WARM_BLOOD | M_SENSE_INVIS | M_BLOOD_SCENT,
MR_NO_FLAGS,
450, 10, MONS_HOUND, MONS_WOLF, MH_NATURAL, -3,
{ {AT_BITE, AF_PLAIN, 8}, {AT_CLAW, AF_PLAIN, 2}, {AT_CLAW, AF_PLAIN, 2}, AT_NO_ATK },
@@ -718,7 +718,7 @@
{
MONS_WAR_DOG, 'h', CYAN, "war dog",
- M_SENSE_INVIS | M_WARM_BLOOD,
+ M_SENSE_INVIS | M_WARM_BLOOD | M_BLOOD_SCENT,
MR_NO_FLAGS,
350, 10, MONS_HOUND, MONS_WAR_DOG, MH_NATURAL, -3,
{ {AT_BITE, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -740,7 +740,7 @@
{
MONS_HELL_HOUND, 'h', LIGHTCYAN, "hell hound",
- M_SENSE_INVIS | M_EVIL | M_SPECIAL_ABILITY,
+ M_SENSE_INVIS | M_EVIL | M_SPECIAL_ABILITY | M_BLOOD_SCENT,
MR_RES_POISON | MR_RES_HELLFIRE | MR_VUL_COLD,
0, 10, MONS_HOUND, MONS_HELL_HOUND, MH_DEMONIC, -3,
{ {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -1452,7 +1452,7 @@
{
MONS_GIANT_MOSQUITO, 'y', WHITE, "giant mosquito",
- M_FLIES,
+ M_FLIES | M_BLOOD_SCENT,
MR_VUL_POISON,
100, 10, MONS_GIANT_MOSQUITO, MONS_GIANT_MOSQUITO, MH_NATURAL, -3,
{ {AT_BITE, AF_DISEASE, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -2601,7 +2601,7 @@
// vampires ('V')
{
MONS_VAMPIRE, 'V', RED, "vampire",
- M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS,
+ M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS | M_BLOOD_SCENT,
MR_RES_POISON | MR_RES_COLD,
0, 11, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
{ {AT_BITE, AF_VAMPIRIC, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -2612,7 +2612,7 @@
{
MONS_VAMPIRE_KNIGHT, 'V', CYAN, "vampire knight",
- M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS,
+ M_FIGHTER | M_SPELLCASTER | M_SEE_INVIS | M_EVIL | M_SPEAKS | M_BLOOD_SCENT,
MR_RES_POISON | MR_RES_COLD,
0, 13, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
{ {AT_HIT, AF_PLAIN, 33}, {AT_BITE, AF_VAMPIRIC, 15}, AT_NO_ATK, AT_NO_ATK },
@@ -2623,7 +2623,7 @@
{
MONS_VAMPIRE_MAGE, 'V', MAGENTA, "vampire mage",
- M_SPELLCASTER | M_SEE_INVIS | M_FLIES | M_EVIL | M_SPEAKS,
+ M_SPELLCASTER | M_SEE_INVIS | M_FLIES | M_EVIL | M_SPEAKS | M_BLOOD_SCENT,
MR_RES_POISON | MR_RES_COLD,
0, 15, MONS_VAMPIRE, MONS_VAMPIRE, MH_UNDEAD, -6,
{ {AT_BITE, AF_VAMPIRIC, 22}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 44949915ae..757c31c663 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -3737,9 +3737,10 @@ void monsters::rot(actor *agent, int rotlevel, int immed_rot)
if (damage > 0)
{
if (mons_near(this) && player_monster_visible(this))
- mprf("%s %s!",
- name(DESC_CAP_THE).c_str(),
+ {
+ mprf("%s %s!", name(DESC_CAP_THE).c_str(),
rotlevel == 0? "looks less resilient" : "rots");
+ }
hurt(agent, damage);
if (alive())
{
@@ -4102,8 +4103,10 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
case ENCH_SUBMERGED:
if (type == MONS_AIR_ELEMENTAL && mons_near(this) && !quiet)
+ {
mprf("%s merges itself into the air.",
name(DESC_CAP_A, true).c_str() );
+ }
break;
case ENCH_CHARM:
@@ -4189,7 +4192,7 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
if (mons_class_flag(type, M_INVIS))
add_ench( mon_enchant(ENCH_INVIS) );
else if (mons_near(this) && !player_see_invis()
- && !has_ench( ENCH_SUBMERGED ))
+ && !has_ench( ENCH_SUBMERGED ))
{
if (!quiet)
mprf("%s appears!", name(DESC_CAP_A, true).c_str() );
@@ -4222,8 +4225,10 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
if (player_monster_visible(this))
simple_monster_message(this, " stops glowing.");
else if (has_ench(ENCH_INVIS) && mons_near(this))
+ {
mprf("%s stops glowing and disappears.",
name(DESC_CAP_THE, true).c_str());
+ }
}
break;
@@ -5118,8 +5123,10 @@ bool monsters::do_shaft()
if (mons_near(this))
{
if (player_monster_visible(this))
+ {
mprf("A shaft briefly opens up underneath %s!",
name(DESC_NOCAP_THE).c_str());
+ }
else
mpr("A shaft briefly opens up in the floor!");
}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 277fb85d86..ae69af7e15 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -104,7 +104,7 @@ enum mons_class_flags
M_SPLITS = (1<<12), // monster can split
M_AMPHIBIOUS = (1<<13), // monster can swim in water,
M_THICK_SKIN = (1<<14), // monster has more effective AC,
- M_RESERVED = (1<<15), // currently UNUSED
+ M_BLOOD_SCENT = (1<<15), // monster can smell blood
M_COLD_BLOOD = (1<<16), // susceptible to cold
M_WARM_BLOOD = (1<<17), // no effect currently
M_REGEN = (1<<18), // regenerates quickly
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index c67df32f00..e76070df59 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -654,8 +654,8 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
update_beholders(monster, true);
const int monster_killed = monster_index(monster);
- bool death_message =
- !silent && mons_near(monster) && player_monster_visible(monster);
+ bool death_message
+ = !silent && mons_near(monster) && player_monster_visible(monster);
bool in_transit = false;
const bool hard_reset = testbits(monster->flags, MF_HARD_RESET);
bool drop_items = !hard_reset;
@@ -1452,7 +1452,7 @@ bool monster_polymorph( monsters *monster, monster_type targetc,
// If old monster is visible to the player, and is interesting,
// then note why the interesting monster went away.
if (player_monster_visible(monster) && mons_near(monster)
- && MONST_INTERESTING(monster))
+ && MONST_INTERESTING(monster))
{
take_note(Note(NOTE_POLY_MONSTER, monster->type, 0,
monster->name(DESC_CAP_A, true).c_str()));
@@ -1964,9 +1964,11 @@ void behaviour_event( monsters *mon, int event, int src,
// will alert monster to <src> and turn them
// against them, unless they have a current foe.
// it won't turn friends hostile either.
- if (mon->behaviour != BEH_CORNERED && mon->behaviour != BEH_PANIC &&
- mon->behaviour != BEH_FLEE)
+ if (mon->behaviour != BEH_CORNERED && mon->behaviour != BEH_PANIC
+ && mon->behaviour != BEH_FLEE)
+ {
mon->behaviour = BEH_SEEK;
+ }
if (mon->foe == MHITNOT)
mon->foe = src;
@@ -3516,8 +3518,8 @@ static bool _handle_wand(monsters *monster, bolt &beem)
{
bool niceWand = false;
bool zap = false;
- bool was_visible =
- mons_near(monster) && player_monster_visible(monster);
+ bool was_visible
+ = mons_near(monster) && player_monster_visible(monster);
item_def &wand(mitm[monster->inv[MSLOT_WAND]]);
@@ -3936,7 +3938,7 @@ static bool _enemies_around(const monsters *monster)
static bool _handle_spell( monsters *monster, bolt & beem )
{
bool monsterNearby = mons_near(monster);
- bool finalAnswer = false; // as in: "Is that your...?" {dlb}
+ bool finalAnswer = false; // as in: "Is that your...?" {dlb}
const spell_type draco_breath = _get_draconian_breath_spell(monster);
// yes, there is a logic to this ordering {dlb}:
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 0dc5492496..3acbe87da6 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -1488,7 +1488,6 @@ void cloud_grid(void)
// Returns true if the PC heard the noise.
bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
{
- int p;
struct monsters *monster = 0; // NULL {dlb}
bool ret = false;
@@ -1520,7 +1519,7 @@ bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
ret = true;
}
- for (p = 0; p < MAX_MONSTERS; p++)
+ for (int p = 0; p < MAX_MONSTERS; p++)
{
monster = &menv[p];
@@ -1542,6 +1541,105 @@ bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
return (ret);
} // end noisy()
+static const char* _player_vampire_smells_blood(int dist)
+{
+ // non-hungry vampires get no clear indication of how close the smell is
+ if (you.hunger_state > HS_HUNGRY)
+ return "";
+
+ if (dist < 16) // 4*4
+ return " near-by";
+
+ if (you.hunger_state <= HS_NEAR_STARVING && dist > 64) // 8*8
+ return " in the distance";
+
+ return "";
+}
+
+void blood_smell( int strength, int blood_x, int blood_y )
+{
+ struct monsters *monster = 0; // NULL {dlb}
+
+ const int range = strength * strength;
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS,
+ "blood stain at (%d, %d), range of smell = %d",
+ blood_x, blood_y, range);
+#endif
+
+ // of the player species, only vampires can smell blood
+ if (you.species == SP_VAMPIRE)
+ {
+ // whether they actually do so, depends on their hunger state
+ int vamp_strength = strength - 2 * (you.hunger_state - 1);
+ if (vamp_strength > 0)
+ {
+ int vamp_range = vamp_strength * vamp_strength;
+
+ const int player_distance
+ = distance( you.x_pos, you.y_pos, blood_x, blood_y );
+
+ if (player_distance <= vamp_range)
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS,
+ "Player smells blood, pos: (%d, %d), dist = %d)",
+ you.x_pos, you.y_pos, player_distance);
+#endif
+ you.check_awaken(range - player_distance);
+ // don't message if you can see the square
+ if (!see_grid(blood_x, blood_y))
+ {
+ mprf("You smell fresh blood%s.",
+ _player_vampire_smells_blood(player_distance));
+ }
+ }
+ }
+ }
+
+ for (int p = 0; p < MAX_MONSTERS; p++)
+ {
+ monster = &menv[p];
+
+ if (monster->type < 0)
+ continue;
+
+ if (!mons_class_flag(monster->type, M_BLOOD_SCENT))
+ continue;
+
+ if (distance(monster->x, monster->y, blood_x, blood_y) <= range)
+ {
+ // let sleeping hounds lie
+ if (mons_is_sleeping(monster)
+ && mons_species(monster->type) != MONS_VAMPIRE)
+ {
+ // 33% chance of sleeping on
+ // 33% of being disturbed (start BEH_WANDER)
+ // 33% of being alerted (start BEH_SEEK)
+ if (!one_chance_in(3))
+ {
+ if (coinflip())
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "disturbing %s (%d, %d)",
+ monster->name(DESC_PLAIN).c_str(),
+ monster->x, monster->y);
+#endif
+ behaviour_event( monster, ME_DISTURB, MHITNOT,
+ blood_x, blood_y );
+ }
+ continue;
+ }
+ }
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "alerting %s (%d, %d)",
+ monster->name(DESC_PLAIN).c_str(), monster->x, monster->y);
+#endif
+ behaviour_event( monster, ME_ALERT, MHITNOT, blood_x, blood_y );
+ }
+ }
+} // end blood_smell()
+
/* The LOS code now uses raycasting -- haranp */
#define LONGSIZE (sizeof(unsigned long)*8)
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 3bad8ec7c5..93d0c9f746 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -114,6 +114,7 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg,
* spells - spells3 - spells4
* *********************************************************************** */
bool noisy( int loudness, int nois_x, int nois_y, const char *msg = NULL );
+void blood_smell( int strength, int blood_x, int blood_y);
void handle_monster_shouts(monsters* monster, bool force = false);
// last updated 12may2000 {dlb}