summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-04-15 07:53:58 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-04-15 07:53:58 +0000
commitb3878ade17db57b348d950892108b77ace2aa8f0 (patch)
treedf25e90759a2e74b9b331f4dc5c781250a500dc5 /crawl-ref/source
parentcb371dc5d4f25044434fe5b632a769abf5b949ad (diff)
downloadcrawl-ref-b3878ade17db57b348d950892108b77ace2aa8f0.tar.gz
crawl-ref-b3878ade17db57b348d950892108b77ace2aa8f0.zip
Disallow monster vampires to drain monsters (and the player) if they
have no blood - and yes, this means that using the right Transformation can help you avoid this. Also, never drain player vampires. Occasionally equip monster vampires with potions of blood, which they drink in times of emergency with a healing effect between !healing and !heal wounds. Don't allow the player to use the Bat Form transformation (or end said transformation) if doing so would result in death by stat loss. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@4236 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/abl-show.cc111
-rw-r--r--crawl-ref/source/describe.cc4
-rw-r--r--crawl-ref/source/fight.cc199
-rw-r--r--crawl-ref/source/makeitem.cc10
-rw-r--r--crawl-ref/source/misc.cc2
-rw-r--r--crawl-ref/source/misc.h1
-rw-r--r--crawl-ref/source/mon-util.cc6
-rw-r--r--crawl-ref/source/monstuff.cc42
8 files changed, 219 insertions, 156 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 0fa31e07e5..5647cde72c 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -78,7 +78,7 @@
enum ability_flag_type
{
ABFLAG_NONE = 0x00000000,
- ABFLAG_BREATH = 0x00000001, // ability uses DUR_BREATH_WEAPON
+ ABFLAG_BREATH = 0x00000001, // ability uses DUR_BREATH_WEAPON
ABFLAG_DELAY = 0x00000002, // ability has its own delay (ie recite)
ABFLAG_PAIN = 0x00000004, // ability must hurt player (ie torment)
ABFLAG_EXHAUSTION = 0x00000008, // fails if you.exhausted
@@ -165,7 +165,7 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] =
// The description screen was way out of date with the actual costs.
// This table puts all the information in one place... -- bwr
-//
+//
// The four numerical fields are: MP, HP, food, and piety.
// Note: food_cost = val + random2avg( val, 2 )
// piety_cost = val + random2( (val + 1) / 2 + 1 );
@@ -186,7 +186,7 @@ static const ability_def Ability_List[] =
{ ABIL_BREATHE_POWER, "Breathe Power", 0, 0, 125, 0, ABFLAG_BREATH },
{ ABIL_BREATHE_STICKY_FLAME, "Breathe Sticky Flame", 0, 0, 125, 0, ABFLAG_BREATH },
{ ABIL_BREATHE_STEAM, "Breathe Steam", 0, 0, 75, 0, ABFLAG_BREATH },
- { ABIL_TRAN_BAT, "Bat Form", 2, 0, 25, 0, ABFLAG_NONE },
+ { ABIL_TRAN_BAT, "Bat Form", 2, 0, 0, 0, ABFLAG_NONE },
{ ABIL_SPIT_ACID, "Spit Acid", 0, 0, 125, 0, ABFLAG_NONE },
@@ -210,12 +210,12 @@ static const ability_def Ability_List[] =
{ ABIL_MUMMY_RESTORATION, "Restoration", 1, 0, 0, 0, ABFLAG_PERMANENT_MP },
// EVOKE abilities use Evocations and come from items:
- // Mapping, Teleportation, and Blink can also come from mutations
- // so we have to distinguish them (see above). The off items
+ // Mapping, Teleportation, and Blink can also come from mutations
+ // so we have to distinguish them (see above). The off items
// below are labeled EVOKE because they only work now if the
// player has an item with the evocable power (not just because
- // you used a wand, potion, or miscast effect). I didn't see
- // any reason to label them as "Evoke" in the text, they don't
+ // you used a wand, potion, or miscast effect). I didn't see
+ // any reason to label them as "Evoke" in the text, they don't
// use or train Evocations (the others do). -- bwr
{ ABIL_EVOKE_MAPPING, "Evoke Sense Surroundings", 0, 0, 30, 0, ABFLAG_NONE },
{ ABIL_EVOKE_TELEPORTATION, "Evoke Teleportation", 3, 0, 200, 0, ABFLAG_NONE },
@@ -325,7 +325,7 @@ const struct ability_def & get_ability_def( ability_type abil )
/****************************************************/
{
for (unsigned int i = 0;
- i < sizeof(Ability_List) / sizeof(Ability_List[0]); i++)
+ i < sizeof(Ability_List) / sizeof(Ability_List[0]); i++)
{
if (Ability_List[i].ability == abil)
return (Ability_List[i]);
@@ -354,7 +354,7 @@ std::string print_abilities()
return text;
}
-
+
const std::string make_cost_description( ability_type ability )
{
const ability_def& abil = get_ability_def(ability);
@@ -399,7 +399,7 @@ const std::string make_cost_description( ability_type ability )
if (!ret.str().empty())
ret << ", ";
- ret << "Breath";
+ ret << "Breath";
}
if (abil.flags & ABFLAG_DELAY)
@@ -462,14 +462,14 @@ static talent _get_talent(ability_type ability, bool check_confused)
}
}
- // Look through the table to see if there's a preference, else
+ // Look through the table to see if there's a preference, else
// find a new empty slot for this ability. -- bwr
const int index = _find_ability_slot( ability );
if ( index != -1 )
result.hotkey = index_to_letter(index);
else
result.hotkey = 0; // means 'find later on'
-
+
switch (ability)
{
// begin spell abilities
@@ -482,12 +482,12 @@ static talent _get_talent(ability_type ability, bool check_confused)
// begin species abilities - some are mutagenic, too {dlb}
case ABIL_SPIT_POISON:
failure = ((you.species == SP_NAGA) ? 20 : 40)
- - 10 * you.mutation[MUT_SPIT_POISON]
+ - 10 * you.mutation[MUT_SPIT_POISON]
- you.experience_level;
break;
case ABIL_EVOKE_MAPPING:
- failure = 30 - you.skills[SK_EVOCATIONS];
+ failure = 30 - you.skills[SK_EVOCATIONS];
break;
case ABIL_MAPPING:
@@ -576,7 +576,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
break;
case ABIL_TELEPORTATION:
- failure = ((you.mutation[MUT_TELEPORT_AT_WILL] > 1) ? 30 : 50)
+ failure = ((you.mutation[MUT_TELEPORT_AT_WILL] > 1) ? 30 : 50)
- you.experience_level;
break;
// end demonic powers {dlb}
@@ -614,7 +614,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
if (you.species == SP_TROLL)
failure -= 30;
- else if (player_genus(GENPC_DWARVEN) || you.species == SP_HILL_ORC
+ else if (player_genus(GENPC_DWARVEN) || you.species == SP_HILL_ORC
|| you.species == SP_OGRE)
{
failure -= 10;
@@ -637,7 +637,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
invoc = true;
failure = 30 - (you.piety / 20) - (6 * you.skills[SK_INVOCATIONS]);
break;
-
+
// destroying stuff doesn't train anything
case ABIL_ELYVILON_DESTROY_WEAPONS:
invoc = true;
@@ -648,7 +648,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
invoc = true;
failure = 0;
break;
-
+
// These three are Trog abilities... Invocations means nothing -- bwr
case ABIL_TROG_BERSERK: // piety >= 30
invoc = true;
@@ -728,7 +728,7 @@ static talent _get_talent(ability_type ability, bool check_confused)
invoc = true;
failure = 80 - (you.piety / 25) - (4 * you.skills[SK_EVOCATIONS]);
break;
-
+
case ABIL_NEMELEX_MARK_FOUR:
invoc = true;
failure = 70 - (you.piety * 2 / 45)
@@ -823,11 +823,11 @@ bool activate_ability()
mpr("Sorry, you're too full to transform right now.");
else
mpr("Sorry, you're not good enough to have a special ability.");
-
+
crawl_state.zero_turns_taken();
return false;
}
-
+
if ( you.duration[DUR_CONF] )
{
talents = your_talents(true);
@@ -859,7 +859,7 @@ bool activate_ability()
else if (keyin == ESCAPE || keyin == ' ' ||
keyin == '\r' || keyin == '\n')
{
- canned_msg( MSG_OK );
+ canned_msg( MSG_OK );
return (false);
}
else if ( isalpha(keyin) )
@@ -889,6 +889,23 @@ bool activate_ability()
static bool _activate_talent(const talent& tal)
{
+ // Doing these would outright kill the player due to stat drain.
+ if (tal.which == ABIL_TRAN_BAT && you.strength <= 5)
+ {
+ mpr("You lack the strength for this transformation.");
+ crawl_state.zero_turns_taken();
+ return (false);
+ }
+ else if (tal.which == ABIL_END_TRANSFORMATION
+ && you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT
+ && you.dex <= 5)
+ {
+ mpr("Turning back with such low dexterity would be fatal!");
+ more();
+ crawl_state.zero_turns_taken();
+ return (false);
+ }
+
// some abilities don't need a hunger check
bool hungerCheck = true;
switch (tal.which)
@@ -927,14 +944,14 @@ static bool _activate_talent(const talent& tal)
crawl_state.zero_turns_taken();
return (false);
}
-
+
if (tal.which == ABIL_ZIN_SANCTUARY && env.sanctuary_time)
{
mpr("There's already a sanctuary in place on this level.");
crawl_state.zero_turns_taken();
return (false);
}
-
+
if ((tal.which == ABIL_EVOKE_BERSERK || tal.which == ABIL_TROG_BERSERK)
&& !you.can_go_berserk(true))
{
@@ -982,7 +999,7 @@ static bool _do_ability(const ability_def& abil)
struct bolt beam;
struct dist spd;
- // Note: the costs will not be applied until after this switch
+ // Note: the costs will not be applied until after this switch
// statement... it's assumed that only failures have returned! -- bwr
switch (abil.ability)
{
@@ -1009,7 +1026,7 @@ static bool _do_ability(const ability_def& abil)
case ABIL_DELAYED_FIREBALL:
if ( !spell_direction(spd, beam, DIR_NONE, TARG_ENEMY) )
return (false);
-
+
// Note: power level of ball calculated at release -- bwr
fireball( calc_spell_power( SPELL_DELAYED_FIREBALL, true ), beam );
@@ -1032,7 +1049,7 @@ static bool _do_ability(const ability_def& abil)
mpr("You spit poison.");
zapping( ZAP_SPIT_POISON,
- you.experience_level
+ you.experience_level
+ you.mutation[MUT_SPIT_POISON] * 5
+ (you.species == SP_NAGA) * 10,
beam );
@@ -1065,7 +1082,7 @@ static bool _do_ability(const ability_def& abil)
mpr("You feel momentarily disoriented.");
if (abil.ability == ABIL_EVOKE_MAPPING)
- exercise( SK_EVOCATIONS, 1 );
+ exercise( SK_EVOCATIONS, 1 );
break;
case ABIL_EVOKE_TELEPORTATION: // ring of teleportation
@@ -1198,9 +1215,9 @@ static bool _do_ability(const ability_def& abil)
if (you.experience_level > 14)
mpr("You feel very comfortable in the air.");
break;
-
+
// Fly (Draconians, or anything else with wings)
- case ABIL_FLY_II:
+ case ABIL_FLY_II:
if (you.duration[DUR_EXHAUSTED])
{
mpr("You're too exhausted to fly.");
@@ -1229,7 +1246,7 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_HELLFIRE:
- if (your_spells(SPELL_HELLFIRE,
+ if (your_spells(SPELL_HELLFIRE,
20 + you.experience_level, false) == SPRET_ABORT)
return (false);
break;
@@ -1343,7 +1360,7 @@ static bool _do_ability(const ability_def& abil)
// up to (60 + 40)/2 = 50
const int pow = ( 2*skill_bump(SK_INVOCATIONS) + you.piety / 5 ) / 2;
start_delay(DELAY_RECITE, 3, pow, you.hp);
-
+
exercise( SK_INVOCATIONS, 2 );
break;
}
@@ -1448,7 +1465,7 @@ static bool _do_ability(const ability_def& abil)
case ABIL_YRED_ANIMATE_CORPSE:
mpr("You call on the dead to walk for you...");
- animate_a_corpse( you.x_pos, you.y_pos, BEH_FRIENDLY,
+ animate_a_corpse( you.x_pos, you.y_pos, BEH_FRIENDLY,
you.pet_target, CORPSE_BODY );
exercise(SK_INVOCATIONS, 2 + random2(4));
@@ -1588,7 +1605,7 @@ static bool _do_ability(const ability_def& abil)
break;
case ABIL_TROG_BERSERK:
- // Trog abilities don't use or train invocations.
+ // Trog abilities don't use or train invocations.
if (you.hunger_state < HS_SATIATED)
{
mpr("You're too hungry to berserk.");
@@ -1669,7 +1686,7 @@ static bool _do_ability(const ability_def& abil)
// Paranoia.
if (you.hp_max < 1)
you.hp_max = 1;
-
+
// Deflate HP
set_hp( 1 + random2(you.hp), false );
@@ -1695,7 +1712,7 @@ static bool _do_ability(const ability_def& abil)
return (false);
}
zapping( ZAP_BANISHMENT, 16 + you.skills[SK_INVOCATIONS] * 8, beam );
- exercise(SK_INVOCATIONS, 3 + random2(5));
+ exercise(SK_INVOCATIONS, 3 + random2(5));
break;
case ABIL_LUGONU_CORRUPT:
@@ -1785,7 +1802,7 @@ static bool _do_ability(const ability_def& abil)
return (false);
}
- if (your_spells( SPELL_HELLFIRE,
+ if (your_spells( SPELL_HELLFIRE,
20 + you.experience_level, false ) == SPRET_ABORT)
return (false);
@@ -1895,7 +1912,7 @@ int choose_ability_menu(const std::vector<talent>& talents)
abil_menu.add_entry(me);
}
}
-
+
if ( found_invocations )
{
abil_menu.add_entry(new MenuEntry(" Invocations - ", MEL_SUBTITLE));
@@ -2001,7 +2018,7 @@ std::vector<talent> your_talents( bool check_confused )
{
_add_talent(talents, ABIL_TRAN_BAT, check_confused );
}
-
+
if (!player_is_airborne())
{
// kenku can fly, but only from the ground
@@ -2053,7 +2070,7 @@ std::vector<talent> your_talents( bool check_confused )
if (you.duration[DUR_TRANSFORMATION])
_add_talent(talents, ABIL_END_TRANSFORMATION, check_confused );
- if (you.mutation[MUT_BLINK])
+ if (you.mutation[MUT_BLINK])
_add_talent(talents, ABIL_BLINK, check_confused );
if (you.mutation[MUT_TELEPORT_AT_WILL])
@@ -2133,7 +2150,7 @@ std::vector<talent> your_talents( bool check_confused )
|| scan_randarts( RAP_LEVITATE ))
{
// Now you can only turn levitation off if you have an
- // activatable item. Potions and miscast effects will
+ // activatable item. Potions and miscast effects will
// have to time out (this makes the miscast effect actually
// a bit annoying). -- bwr
_add_talent(talents, you.duration[DUR_LEVITATION] ?
@@ -2180,15 +2197,15 @@ std::vector<talent> your_talents( bool check_confused )
// In theory, we could be left with an unreachable ability
// here (if you have 53 or more abilities simultaneously.)
}
-
+
return talents;
}
// Note: we're trying for a behaviour where the player gets
// to keep their assigned invocation slots if they get excommunicated
-// and then rejoin (but if they spend time with another god we consider
-// the old invocation slots void and erase them). We also try to
-// protect any bindings the character might have made into the
+// and then rejoin (but if they spend time with another god we consider
+// the old invocation slots void and erase them). We also try to
+// protect any bindings the character might have made into the
// traditional invocation slots (A-E and X). -- bwr
static void _set_god_ability_helper( ability_type abil, char letter )
{
@@ -2298,7 +2315,7 @@ static int _lugonu_warp_monster(int x, int y, int pow, int)
if (!mons_friendly(&mon))
behaviour_event( &mon, ME_ANNOY, MHITYOU );
-
+
if (check_mons_resist_magic(&mon, pow * 2))
{
mprf("%s %s.",
@@ -2337,7 +2354,7 @@ static void _lugonu_bends_space()
_lugonu_warp_area(pow);
random_blink(false, true);
-
+
const int damage = roll_dice(1, 4);
ouch(damage, 0, KILLED_BY_WILD_MAGIC, "a spatial distortion");
}
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 2f487034f4..9f9d44e634 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -1646,7 +1646,6 @@ std::string get_item_description( const item_def &item, bool verbose,
break;
case OBJ_POTIONS:
-#ifdef DEBUG_BLOOD_POTIONS
// list content of timer vector for blood potions
if (item.sub_type == POT_BLOOD
|| item.sub_type == POT_BLOOD_COAGULATED)
@@ -1663,7 +1662,8 @@ std::string get_item_description( const item_def &item, bool verbose,
for (int i = 0; i < timer.size(); i++)
description << (timer[i].get_long()) << " ";
}
-#endif
+ break;
+
case OBJ_SCROLLS:
case OBJ_ORBS:
case OBJ_CORPSES:
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 760a274a25..38d5ae0717 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -127,13 +127,13 @@ bool test_melee_hit(int to_hit, int ev)
miss = 100.0 - MIN_HIT_MISS_PERCENTAGE / 2.0;
else
{
- miss = MIN_HIT_MISS_PERCENTAGE / 2.0 +
+ miss = MIN_HIT_MISS_PERCENTAGE / 2.0 +
((100.0 - MIN_HIT_MISS_PERCENTAGE) * ev) / to_hit;
}
mprf( MSGCH_DIAGNOSTICS,
"to hit: %d; ev: %d; miss: %0.2f%%; roll: %d; result: %s%s (%d)",
- to_hit, ev, miss, roll, (margin >= 0) ? "hit" : "miss",
+ to_hit, ev, miss, roll, (margin >= 0) ? "hit" : "miss",
(roll == -1) ? "!!!" : "", margin );
#endif
@@ -451,7 +451,7 @@ void melee_attack::check_special_wield_effects()
// miscast_effect to operate on any actor.
if (one_chance_in(9) && attacker->atype() == ACT_PLAYER)
{
- miscast_effect( SPTYP_DIVINATION, random2(9), random2(70), 100,
+ miscast_effect( SPTYP_DIVINATION, random2(9), random2(70), 100,
"the Staff of Wucad Mu" );
}
break;
@@ -623,10 +623,10 @@ static bool _player_vampire_draws_blood(const int mons, const int damage,
ASSERT(mons != -1);
const monsters *mon = &menv[mons];
-
+
if (!_vamp_wants_blood_from_monster(mon))
return (false);
-
+
const int chunk_type = mons_corpse_effect( mon->type );
// now print message, need biting unless already done (never for bat form!)
@@ -690,7 +690,7 @@ bool melee_attack::player_attack()
return (false);
coord_def where = defender->pos();
-
+
if (player_hits_monster())
{
did_hit = true;
@@ -773,7 +773,7 @@ bool melee_attack::player_attack()
return (true);
const bool did_primary_hit = did_hit;
-
+
if (unarmed_ok && where == defender->pos() && player_aux_unarmed())
return (true);
@@ -797,7 +797,7 @@ bool melee_attack::player_aux_unarmed()
if (can_do_unarmed)
{
- if (you.species == SP_NAGA)
+ if (you.species == SP_NAGA)
uattack = UNAT_HEADBUTT;
else
uattack = (coinflip() ? UNAT_HEADBUTT : UNAT_KICK);
@@ -807,7 +807,7 @@ bool melee_attack::player_aux_unarmed()
{
uattack = UNAT_BITE;
}
-
+
if ((you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
|| player_genus(GENPC_DRACONIAN)
|| (you.species == SP_MERFOLK && player_is_swimming())
@@ -819,7 +819,7 @@ bool melee_attack::player_aux_unarmed()
if (coinflip())
uattack = UNAT_PUNCH;
-
+
if (you.species == SP_VAMPIRE && !one_chance_in(3))
uattack = UNAT_BITE;
}
@@ -864,7 +864,7 @@ bool melee_attack::player_aux_unarmed()
}
else
unarmed_attack = "kick";
-
+
aux_damage = (you.mutation[MUT_HOOVES] ? 10
: clawed_kick ? 8 : 5);
break;
@@ -893,7 +893,7 @@ bool melee_attack::player_aux_unarmed()
(you.species == SP_KENKU) ? "peck" : "headbutt";
aux_damage = 5 + you.mutation[MUT_HORNS] * 3;
-
+
// minotaurs used to get +5 damage here, now they get
// +6 because of the horns.
@@ -946,7 +946,7 @@ bool melee_attack::player_aux_unarmed()
// maybe add this to player messaging {dlb}
//
// STINGER mutation doesn't give extra damage here... that
- // would probably be a bit much, we'll still get the
+ // would probably be a bit much, we'll still get the
// poison bonus so it's still somewhat good.
if (you.species == SP_GREY_DRACONIAN && you.experience_level >= 7)
aux_damage = 12;
@@ -969,7 +969,7 @@ bool melee_attack::player_aux_unarmed()
if (shield || coinflip()
|| (weapon
&& hands == HANDS_TWO
- && weapon->base_type != OBJ_STAVES
+ && weapon->base_type != OBJ_STAVES
&& weapon->sub_type != WPN_QUARTERSTAFF) )
{
continue;
@@ -1028,7 +1028,7 @@ bool melee_attack::player_aux_unarmed()
else if (!one_chance_in(3)) // monster not interesting bloodwise
continue;
}
-
+
break;
/* To add more, add to while part of loop below as well */
@@ -1039,14 +1039,14 @@ bool melee_attack::player_aux_unarmed()
// unified to-hit calculation
to_hit = random2( calc_your_to_hit_unarmed(uattack,
damage_brand == SPWPN_VAMPIRICISM) );
-
+
make_hungry(2, true);
alert_nearby_monsters();
// XXX We're clobbering did_hit
did_hit = false;
-
+
bool ely_block = false;
if (you.religion != GOD_ELYVILON && you.penance[GOD_ELYVILON]
&& to_hit >= def->ev && one_chance_in(20))
@@ -1054,7 +1054,7 @@ bool melee_attack::player_aux_unarmed()
simple_god_message(" blocks your attack.", GOD_ELYVILON);
ely_block = true;
}
-
+
if (!ely_block && (to_hit >= def->ev || one_chance_in(30)))
{
if (attack_shield_blocked(true))
@@ -1072,7 +1072,7 @@ bool melee_attack::player_aux_unarmed()
miss_verb.empty()? unarmed_attack.c_str()
: miss_verb.c_str(),
defender->name(DESC_NOCAP_THE).c_str());
-
+
if (ely_block)
dec_penance(GOD_ELYVILON, 1 + random2(to_hit - def->ev));
}
@@ -1134,7 +1134,7 @@ bool melee_attack::player_apply_aux_unarmed()
player_monster_visible(def)?
", but do no damage" : "");
}
-
+
if (def->hit_points < 1)
{
monster_die(def, KILL_YOU, 0);
@@ -1184,7 +1184,7 @@ void melee_attack::player_announce_hit()
{
if (!verb_degree.empty() && verb_degree[0] != ' ')
verb_degree = " " + verb_degree;
-
+
msg::stream << "You " << attack_verb << ' '
<< def->name(DESC_NOCAP_THE)
<< verb_degree << debug_damage_number()
@@ -1231,12 +1231,12 @@ int melee_attack::player_stat_modify_damage(int damage)
{
int dammod = 78;
const int dam_stat_val = calc_stat_to_dam_base();
-
+
if (dam_stat_val > 11)
dammod += (random2(dam_stat_val - 11) * 2);
else if (dam_stat_val < 9)
dammod -= (random2(9 - dam_stat_val) * 3);
-
+
damage *= dammod;
damage /= 78;
@@ -1247,12 +1247,12 @@ int melee_attack::player_aux_stat_modify_damage(int damage)
{
int dammod = 10;
const int dam_stat_val = calc_stat_to_dam_base();
-
+
if (dam_stat_val > 11)
dammod += random2(dam_stat_val - 11) / 3;
if (dam_stat_val < 9)
dammod -= random2(9 - dam_stat_val) / 2;
-
+
damage *= dammod;
damage /= 10;
@@ -1290,7 +1290,7 @@ int melee_attack::player_apply_weapon_skill(int damage)
int melee_attack::player_apply_fighting_skill(int damage, bool aux)
{
const int base = aux? 40 : 30;
-
+
damage *= base + (random2(you.skills[SK_FIGHTING] + 1));
damage /= base;
@@ -1301,7 +1301,7 @@ int melee_attack::player_apply_misc_modifiers(int damage)
{
if (you.duration[DUR_MIGHT] > 1)
damage += 1 + random2(10);
-
+
if (you.hunger_state <= HS_STARVING && you.species != SP_VAMPIRE)
damage -= random2(5);
@@ -1313,7 +1313,7 @@ int melee_attack::player_apply_weapon_bonuses(int damage)
if (weapon && weapon->base_type == OBJ_WEAPONS)
{
int wpn_damage_plus = weapon->plus2;
-
+
damage += (wpn_damage_plus > -1) ? (random2(1 + wpn_damage_plus))
: -(1 + random2(-wpn_damage_plus));
@@ -1321,13 +1321,13 @@ int melee_attack::player_apply_weapon_bonuses(int damage)
// already included in the damage stat for the weapon -- bwr
if (hand_half_bonus)
damage += random2(3);
-
+
if (get_equip_race(*weapon) == ISFLAG_DWARVEN
&& player_genus(GENPC_DWARVEN))
{
damage += random2(3);
}
-
+
if (get_equip_race(*weapon) == ISFLAG_ORCISH
&& you.species == SP_HILL_ORC)
{
@@ -1490,7 +1490,7 @@ int melee_attack::player_weapon_type_modify(int damage)
else if (weapon->base_type == OBJ_WEAPONS)
weap_type = weapon->sub_type;
- // All weak hits look the same, except for when the player
+ // All weak hits look the same, except for when the player
// has a non-weapon in hand. -- bwr
// Exception: vampire bats only _bite_ to allow for drawing blood
if (damage < HIT_WEAK && (you.species != SP_VAMPIRE
@@ -1505,7 +1505,7 @@ int melee_attack::player_weapon_type_modify(int damage)
}
// take transformations into account, if no weapon is wielded
- if (weap_type == WPN_UNARMED
+ if (weap_type == WPN_UNARMED
&& you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE)
{
switch (you.attribute[ATTR_TRANSFORMATION])
@@ -1646,10 +1646,10 @@ bool melee_attack::player_hurt_monster()
void melee_attack::player_exercise_combat_skills()
{
const bool helpless = defender->cannot_fight();
-
+
if (!helpless || you.skills[ wpn_skill ] < 2)
exercise( wpn_skill, 1 );
-
+
if ((!helpless || you.skills[SK_FIGHTING] < 2)
&& one_chance_in(3))
{
@@ -1759,7 +1759,7 @@ bool melee_attack::player_monattk_hit_effects(bool mondied)
attack_verb.c_str(),
defender->name(DESC_NOCAP_THE).c_str());
}
-
+
if (needs_message && !special_damage_message.empty())
mprf("%s", special_damage_message.c_str());
@@ -1808,7 +1808,7 @@ static inline int get_resistible_fraction(beam_type flavour)
// FIXME: Does not (yet) handle life draining, player acid damage
// (does handle monster acid damage), miasma, and other exotic
// attacks.
-//
+//
// beam_type is just use to determine the damage flavour, it does not
// necessarily imply that the attack is a beam attack.
int resist_adjust_damage(actor *defender, beam_type flavour,
@@ -1816,9 +1816,9 @@ int resist_adjust_damage(actor *defender, beam_type flavour,
{
if (!res)
return (rawdamage);
-
+
const bool monster = defender->atype() == ACT_MONSTER;
-
+
// Check if this is a resist that pretends to be boolean for
// damage purposes - only electricity at the moment, raw poison
// damage uses the normal formula.
@@ -1827,7 +1827,7 @@ int resist_adjust_damage(actor *defender, beam_type flavour,
int resistible = rawdamage * resistible_fraction / 100;
const int irresistible = rawdamage - resistible;
-
+
if (res > 0)
{
if (monster && res >= 3)
@@ -1903,7 +1903,7 @@ void melee_attack::drain_monster()
atk_name(DESC_CAP_THE).c_str(),
attacker->conj_verb("drain").c_str(),
def_name(DESC_NOCAP_THE).c_str());
-
+
if (one_chance_in(5))
{
def->hit_dice--;
@@ -1915,10 +1915,10 @@ void melee_attack::drain_monster()
if (def->hit_points >= def->max_hit_points)
def->hit_points = def->max_hit_points;
-
+
if (def->hit_dice < 1)
def->hit_points = 0;
-
+
special_damage = 1 + (random2(damage_done) / 2);
attacker->god_conduct(DID_NECROMANCY, 2);
}
@@ -1938,12 +1938,12 @@ bool melee_attack::distortion_affects_defender()
make_stringf("%s %s in the translocular energy.",
def_name(DESC_CAP_THE).c_str(),
defender->conj_verb("bask").c_str());
-
+
defender->heal(1 + random2avg(7, 2), true); // heh heh
}
return (false);
}
-
+
if (one_chance_in(3))
{
if (defender_visible)
@@ -2121,14 +2121,14 @@ bool melee_attack::apply_damage_brand()
{
obvious_effect = true;
}
-
+
}
break;
case SPWPN_DRAINING:
drain_defender();
break;
-
+
/* 9 = speed - done before */
case SPWPN_VORPAL:
special_damage = 1 + random2(damage_done) / 2;
@@ -2145,7 +2145,7 @@ bool melee_attack::apply_damage_brand()
_player_vampire_draws_blood(monster_index(def), damage_done);
break;
}
-
+
if (defender->holiness() != MH_NATURAL || !weapon
|| defender->res_negative_energy() > 0
|| damage_done < 1 || attacker->stat_hp() == attacker->stat_maxhp()
@@ -2221,7 +2221,7 @@ bool melee_attack::apply_damage_brand()
// here. Generalise.
const int hdcheck =
(defender->holiness() == MH_NATURAL? random2(30) : random2(22));
-
+
if (mons_class_is_confusable(def->type) &&
hdcheck >= defender->get_experience_level())
{
@@ -2239,7 +2239,7 @@ bool melee_attack::apply_damage_brand()
if (attacker->atype() == ACT_PLAYER)
{
you.duration[DUR_CONFUSING_TOUCH] -= roll_dice(3, 5);
-
+
if (you.duration[DUR_CONFUSING_TOUCH] < 1)
you.duration[DUR_CONFUSING_TOUCH] = 1;
}
@@ -2267,7 +2267,7 @@ bool melee_attack::chop_hydra_head( int dam,
// chop-check to prevent runaway head inflation.
if (attacker->atype() == ACT_MONSTER && !one_chance_in(4))
return (false);
-
+
if ((dam_type == DVORP_SLICING || dam_type == DVORP_CHOPPING
|| dam_type == DVORP_CLAWING)
&& dam > 0
@@ -2372,7 +2372,7 @@ void melee_attack::emit_nodmg_hit_message()
void melee_attack::player_apply_staff_damage()
{
special_damage = 0;
-
+
if (!weapon || !item_is_staff(*weapon))
return;
@@ -2382,7 +2382,7 @@ void melee_attack::player_apply_staff_damage()
{
return;
}
-
+
switch (weapon->sub_type)
{
case STAFF_AIR:
@@ -2394,12 +2394,12 @@ void melee_attack::player_apply_staff_damage()
BEAM_ELECTRICITY,
defender->res_elec(),
player_staff_damage(SK_AIR_MAGIC));
-
+
if (special_damage)
special_damage_message =
make_stringf("%s is jolted!",
defender->name(DESC_CAP_THE).c_str());
-
+
break;
case STAFF_COLD:
@@ -2421,7 +2421,7 @@ void melee_attack::player_apply_staff_damage()
case STAFF_EARTH:
special_damage = player_staff_damage(SK_EARTH_MAGIC);
- if (special_damage)
+ if (special_damage)
{
special_damage_message =
make_stringf(
@@ -2588,7 +2588,7 @@ int melee_attack::player_to_hit(bool random_factor)
#ifdef DEBUG_DIAGNOSTICS
const int base_to_hit = your_to_hit;
#endif
-
+
if (water_attack)
your_to_hit += 5;
@@ -2642,7 +2642,7 @@ int melee_attack::player_to_hit(bool random_factor)
{
your_to_hit++;
}
-
+
}
else if (item_is_staff( *weapon ))
{
@@ -2829,7 +2829,7 @@ void melee_attack::player_apply_attack_delay()
#if DEBUG_DIAGNOSTICS
mprf( MSGCH_DIAGNOSTICS,
- "Weapon speed: %d; min: %d; attack time: %d",
+ "Weapon speed: %d; min: %d; attack time: %d",
final_attack_delay, min_delay, you.time_taken );
#endif
}
@@ -2837,46 +2837,46 @@ void melee_attack::player_apply_attack_delay()
int melee_attack::player_weapon_speed()
{
int attack_delay = 0;
-
+
if (weapon && (weapon->base_type == OBJ_WEAPONS
|| item_is_staff( *weapon )))
{
attack_delay = property( *weapon, PWPN_SPEED );
attack_delay -= you.skills[ wpn_skill ] / 2;
-
+
min_delay = property( *weapon, PWPN_SPEED ) / 2;
// Short blades can get up to at least unarmed speed.
if (wpn_skill == SK_SHORT_BLADES && min_delay > 5)
min_delay = 5;
-
+
// Using both hands can get a weapon up to speed 7
if ((hands == HANDS_TWO || hand_half_bonus)
&& min_delay > 7)
{
min_delay = 7;
}
-
+
// never go faster than speed 3 (ie 3 attacks per round)
if (min_delay < 3)
min_delay = 3;
-
+
// Hand and a half bonus only helps speed up to a point, any more
// than speed 10 must come from skill and the weapon
if (hand_half_bonus && attack_delay > 10)
attack_delay--;
-
+
// apply minimum to weapon skill modification
if (attack_delay < min_delay)
attack_delay = min_delay;
-
+
if (weapon->base_type == OBJ_WEAPONS
&& damage_brand == SPWPN_SPEED)
{
attack_delay = (attack_delay + 1) / 2;
}
}
-
+
return (attack_delay);
}
@@ -2885,16 +2885,16 @@ int melee_attack::player_unarmed_speed()
int unarmed_delay = 10;
min_delay = 5;
-
+
// Unarmed speed
if (you.burden_state == BS_UNENCUMBERED
&& one_chance_in(heavy_armour_penalty + 1))
{
if (you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT)
unarmed_delay = 10 - you.skills[SK_UNARMED_COMBAT] / 3;
- else
+ else
unarmed_delay = 10 - you.skills[SK_UNARMED_COMBAT] / 5;
-
+
/* this shouldn't happen anyway...sanity */
if (unarmed_delay < min_delay)
unarmed_delay = min_delay;
@@ -2913,7 +2913,7 @@ int melee_attack::player_apply_shield_delay(int attack_delay)
if (you.skills[SK_SHIELDS] <= 10 + random2(17))
attack_delay++;
// [dshaligram] Fall-through
-
+
case ARM_SHIELD:
if (you.skills[SK_SHIELDS] <= 3 + random2(17))
attack_delay++;
@@ -2987,7 +2987,7 @@ int melee_attack::player_calc_base_unarmed_damage()
int melee_attack::player_calc_base_weapon_damage()
{
int damage = 0;
-
+
if (weapon->base_type == OBJ_WEAPONS
|| item_is_staff( *weapon ))
{
@@ -3083,7 +3083,7 @@ bool melee_attack::attack_shield_blocked(bool verbose)
if (attacker->invisible() && !defender->can_see_invisible())
pro_block /= 3;
-
+
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Defender: %s, Pro-block: %d, Con-block: %d",
def_name(DESC_PLAIN).c_str(), pro_block, con_block);
@@ -3142,13 +3142,13 @@ int melee_attack::mons_calc_damage(const mon_attack_def &attk)
else if (atk->has_ench(ENCH_BATTLE_FRENZY))
{
const mon_enchant ench = atk->get_ench(ENCH_BATTLE_FRENZY);
-
+
#ifdef DEBUG_DIAGNOSTICS
const int orig_damage = damage;
#endif
-
+
damage = damage * (115 + ench.degree * 15) / 100;
-
+
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "%s frenzy damage: %d->%d",
attacker->name(DESC_PLAIN).c_str(), orig_damage, damage);
@@ -3200,7 +3200,7 @@ int melee_attack::mons_apply_defender_ac(int damage, int damage_max)
if (damage < 1)
damage = 0;
-
+
return damage;
}
@@ -3245,7 +3245,7 @@ std::string melee_attack::mons_attack_verb(const mon_attack_def &attk)
// spore
"hit",
-
+
"touch",
"engulf",
"claw",
@@ -3329,7 +3329,7 @@ void melee_attack::check_defender_train_armour()
{
if (defender->wearing_light_armour())
return;
-
+
const item_def *arm = defender->slot_item(EQ_BODY_ARMOUR);
if (arm && coinflip() && random2(1000) <= item_mass(*arm))
defender->exercise(SK_ARMOUR, coinflip()? 2 : 1);
@@ -3345,7 +3345,7 @@ void melee_attack::mons_do_poison(const mon_attack_def &attk)
{
if (defender->res_poison() > 0)
return;
-
+
if (attk.flavour == AF_POISON_NASTY
|| one_chance_in( 15 + 5 * (attk.flavour == AF_POISON) )
|| (damage_done > 1
@@ -3419,7 +3419,7 @@ void melee_attack::splash_defender_with_acid(int strength)
void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
{
// Most of this is from BWR 4.1.2.
-
+
int res = 0;
switch (attk.flavour)
{
@@ -3430,7 +3430,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
if (one_chance_in(4))
defender->mutate();
break;
-
+
case AF_POISON:
case AF_POISON_NASTY:
case AF_POISON_MEDIUM:
@@ -3512,6 +3512,15 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
break;
case AF_VAMPIRIC:
+ // only may bite non-vampiric monsters (players) capable of bleeding
+ if (defender->atype() == ACT_PLAYER
+ && (you.species == SP_VAMPIRE || !victim_can_bleed(-1))
+ || defender->atype() == ACT_MONSTER
+ && !victim_can_bleed(def->type))
+ {
+ break;
+ }
+
if (defender->res_negative_energy() > random2(3))
break;
@@ -3604,7 +3613,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
{
drain_defender();
}
-
+
break;
case AF_PARALYSE:
@@ -3625,7 +3634,7 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_RAGE:
if (!one_chance_in(3) || !defender->can_go_berserk())
break;
-
+
if (needs_message)
mprf("%s %s %s!",
atk_name(DESC_CAP_THE).c_str(),
@@ -3654,7 +3663,7 @@ void melee_attack::mons_perform_attack_rounds()
// Monsters hitting themselves get just one round.
if (attack_number > 0 && attacker == defender)
break;
-
+
const mon_attack_def attk = mons_attack_spec(atk, attack_number);
if (attk.type == AT_NONE)
{
@@ -3732,7 +3741,7 @@ void melee_attack::mons_perform_attack_rounds()
= _modify_blood_amount(damage_done, attacker->damage_type());
if (blood > defender->stat_hp())
blood = defender->stat_hp();
-
+
bleed_onto_floor(pos.x, pos.y, type, blood, true);
if (decapitate_hydra(damage_done,
@@ -3740,7 +3749,7 @@ void melee_attack::mons_perform_attack_rounds()
{
continue;
}
-
+
special_damage = 0;
special_damage_message.clear();
@@ -3748,12 +3757,12 @@ void melee_attack::mons_perform_attack_rounds()
// message sequences look too weird.
if (attacker != defender)
mons_apply_attack_flavour(attk);
-
+
if (!special_damage_message.empty())
mprf("%s", special_damage_message.c_str());
-
+
defender->hurt(attacker, damage_done + special_damage);
-
+
if (!defender->alive() || attacker == defender)
return;
@@ -3782,7 +3791,7 @@ bool melee_attack::mons_perform_attack()
}
mons_perform_attack_rounds();
-
+
return (did_hit);
}
@@ -3794,7 +3803,7 @@ void melee_attack::mons_check_attack_perceived()
if (defender->atype() == ACT_PLAYER)
{
interrupt_activity(AI_MONSTER_ATTACKS, atk);
-
+
// if a friend wants to help, they can attack <monster_attacking>
if (you.pet_target == MHITNOT)
you.pet_target = monster_index(atk);
@@ -3816,7 +3825,7 @@ int melee_attack::mons_to_hit()
#ifdef DEBUG_DIAGNOSTICS
const int base_hit = mhit;
#endif
-
+
if (water_attack)
mhit += 5;
@@ -3841,7 +3850,7 @@ int melee_attack::mons_to_hit()
attacker->name(DESC_PLAIN).c_str(),
base_hit, mhit);
#endif
-
+
return (mhit);
}
@@ -3864,7 +3873,7 @@ static void wielded_weapon_check(const item_def *weapon)
bool you_attack(int monster_attacked, bool unarmed_attacks)
{
monsters *defender = &menv[monster_attacked];
-
+
melee_attack attk(&you, defender, unarmed_attacks);
// We're trying to hit a monster, break out of travel/explore now.
@@ -4099,7 +4108,7 @@ static void stab_message( monsters *defender, int stab_bonus )
}
break;
case 1:
- mprf( "%s fails to defend %s.",
+ mprf( "%s fails to defend %s.",
defender->name(DESC_CAP_THE).c_str(),
defender->pronoun(PRONOUN_REFLEXIVE).c_str() );
break;
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 53000eed75..fb51386cf2 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -2920,6 +2920,16 @@ static void give_wand(monsters *mon, int level)
static void give_potion(monsters *mon, int level)
{
//mv - give potion
+ if (mons_species( mon->type ) == MONS_VAMPIRE && one_chance_in(5))
+ {
+ const int thing_created =
+ items(0, OBJ_POTIONS, POT_BLOOD, true, level, 0);
+ if (thing_created == NON_ITEM)
+ return;
+
+ mitm[thing_created].flags = 0;
+ give_monster_item(mon, thing_created);
+ }
if (mons_is_unique( mon->type ) && one_chance_in(3))
{
const int thing_created =
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index a069b76a34..bb1cba82f7 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1028,7 +1028,7 @@ void split_blood_potions_into_decay( int obj, int amount )
}
// checks whether the player or a monster is capable of bleeding
-static bool victim_can_bleed(int montype)
+bool victim_can_bleed(int montype)
{
if (montype == -1) // player
{
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 4c588fc42c..9e71adead8 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -81,6 +81,7 @@ bool can_bottle_blood_from_corpse( int mons_type );
void turn_corpse_into_blood_potions ( item_def &item );
void split_blood_potions_into_decay( int obj, int amount = -1 );
+bool victim_can_bleed(int montype);
void bleed_onto_floor(int x, int y, int mon, int damage, bool spatter = false);
// last updated 12may2000 {dlb}
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index a7b062381e..c5487f9386 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2090,9 +2090,11 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
break;
case SPELL_INVISIBILITY:
- if (mon->has_ench(ENCH_INVIS) ||
- (mons_friendly(mon) && !player_see_invis(false)))
+ if (mon->has_ench(ENCH_INVIS)
+ || (mons_friendly(mon) && !player_see_invis(false)))
+ {
ret = true;
+ }
break;
case SPELL_LESSER_HEALING:
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 035bc36f73..0ed96ff2d3 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -3375,14 +3375,37 @@ static bool _handle_potion(monsters *monster, bolt & beem)
}
break;
+ case POT_BLOOD:
+ case POT_BLOOD_COAGULATED:
+ if (mons_species(monster->type) == MONS_VAMPIRE
+ && monster->hit_points <= monster->max_hit_points / 2)
+ {
+ simple_monster_message(monster, " drinks a potion.");
+
+ if (heal_monster(monster, 10 + random2avg(28, 3), false))
+ {
+ simple_monster_message(monster, " is healed!");
+ ident = ID_MON_TRIED_TYPE;
+ }
+
+ imbibed = true;
+ }
+ break;
+
case POT_SPEED:
// notice that these are the same odd colours used in
// mons_ench_f2() {dlb}
+ if (monster->has_ench(ENCH_HASTE))
+ break;
+
beem.colour = BLUE;
// intentional fall through
case POT_INVISIBILITY:
if (mitm[monster->inv[MSLOT_POTION]].sub_type == POT_INVISIBILITY)
{
+ if (monster->has_ench(ENCH_INVIS))
+ break;
+
beem.colour = MAGENTA;
// Friendly monsters won't go invisible if the player
// can't see invisible. We're being nice.
@@ -3390,15 +3413,10 @@ static bool _handle_potion(monsters *monster, bolt & beem)
break;
}
- // why only drink these if not near player? {dlb}
- if (!mons_near(monster))
- {
- simple_monster_message(monster, " drinks a potion.");
-
- mons_ench_f2(monster, beem);
-
- imbibed = true;
- }
+ // allow monsters to drink these when player in sight (jpeg)
+ simple_monster_message(monster, " drinks a potion.");
+ mons_ench_f2(monster, beem);
+ imbibed = true;
ident = ID_KNOWN_TYPE;
break;
}
@@ -3407,6 +3425,12 @@ static bool _handle_potion(monsters *monster, bolt & beem)
{
if (dec_mitm_item_quantity( monster->inv[MSLOT_POTION], 1 ))
monster->inv[MSLOT_POTION] = NON_ITEM;
+ else if (mitm[monster->inv[MSLOT_POTION]].sub_type == POT_BLOOD
+ || mitm[monster->inv[MSLOT_POTION]].sub_type
+ == POT_BLOOD_COAGULATED)
+ {
+ remove_oldest_blood_potion(mitm[monster->inv[MSLOT_POTION]]);
+ }
if (ident != ID_UNKNOWN_TYPE && was_visible)
set_ident_type(OBJ_POTIONS, potion_type, ident);