summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/debug.cc5
-rw-r--r--crawl-ref/source/delay.cc73
-rw-r--r--crawl-ref/source/effects.cc102
-rw-r--r--crawl-ref/source/fight.cc3
-rw-r--r--crawl-ref/source/food.cc30
-rw-r--r--crawl-ref/source/itemname.cc11
-rw-r--r--crawl-ref/source/items.cc44
-rw-r--r--crawl-ref/source/makeitem.cc13
-rw-r--r--crawl-ref/source/misc.cc212
-rw-r--r--crawl-ref/source/misc.h4
-rw-r--r--crawl-ref/source/mon-util.cc6
-rw-r--r--crawl-ref/source/mon-util.h1
-rw-r--r--crawl-ref/source/monstuff.cc25
-rw-r--r--crawl-ref/source/newgame.cc5
-rw-r--r--crawl-ref/source/player.cc5
-rw-r--r--crawl-ref/source/spells3.cc41
-rw-r--r--crawl-ref/source/spells4.cc3
-rw-r--r--crawl-ref/source/tile1.cc5
18 files changed, 423 insertions, 165 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 3fa9861253..ae71901a4b 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1235,9 +1235,12 @@ void create_spec_object()
mitm[thing_created].plus = 50;
break;
+ case OBJ_POTIONS:
+ if (mitm[thing_created].sub_type == POT_BLOOD)
+ mitm[thing_created].special = 1200;
+ // fall-through
case OBJ_FOOD:
case OBJ_SCROLLS:
- case OBJ_POTIONS:
mitm[thing_created].quantity = 12;
break;
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index 5448984ea0..dd621a1485 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -525,7 +525,9 @@ void handle_delay( void )
mpr("You start removing your armour.", MSGCH_MULTITURN_ACTION);
break;
case DELAY_BUTCHER:
- mpr("You start butchering the corpse.", MSGCH_MULTITURN_ACTION);
+ mprf(MSGCH_MULTITURN_ACTION, "You start %s the corpse.",
+ can_bottle_blood_from_corpse(mitm[delay.parm1].plus)?
+ "bottling blood from" : "butchering");
break;
case DELAY_MEMORISE:
mpr("You start memorising the spell.", MSGCH_MULTITURN_ACTION);
@@ -673,8 +675,9 @@ void handle_delay( void )
you.inv[delay.parm1].name(DESC_NOCAP_YOUR).c_str());
break;
case DELAY_BUTCHER:
- mpr("You continue butchering the corpse.",
- MSGCH_MULTITURN_ACTION);
+ mprf(MSGCH_MULTITURN_ACTION, "You continue %s the corpse.",
+ can_bottle_blood_from_corpse(mitm[delay.parm1].plus)?
+ "bottling blood from" : "butchering");
break;
case DELAY_MEMORISE:
mpr("You continue memorising.", MSGCH_MULTITURN_ACTION);
@@ -841,11 +844,12 @@ static void finish_delay(const delay_queue_item &delay)
const item_def &item = mitm[delay.parm1];
if (is_valid_item(item) && item.base_type == OBJ_CORPSES)
{
-
if (item.sub_type == CORPSE_SKELETON)
{
- mpr("The corpse rots away into a skeleton just before you "
- "finish butchering it!");
+ mprf("The corpse rots away into a skeleton just before you "
+ "finish %s!", can_bottle_blood_from_corpse(item.plus)
+ ? "bottling its blood"
+ : "butchering");
if (you.mutation[MUT_SAPROVOROUS] == 3)
xom_check_corpse_waste();
@@ -855,36 +859,45 @@ static void finish_delay(const delay_queue_item &delay)
break;
}
- mprf("You finish %s the corpse into pieces.",
- (you.has_usable_claws() || you.mutation[MUT_FANGS] == 3) ?
- "ripping" : "chopping");
-
- if (is_good_god(you.religion) && is_player_same_species(item.plus))
- simple_god_message(" expects more respect for your departed "
- "relatives.");
- else if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)
- simple_god_message(" expects more respect for this departed "
- "soul.");
-
- if (you.species == SP_VAMPIRE &&
- mons_corpse_effect(item.plus) != CE_HCL &&
- (!god_likes_butchery(you.religion) ||
- !you.duration[DUR_PRAYER]))
+ if (can_bottle_blood_from_corpse(item.plus))
{
- mpr("What a waste.");
- }
- turn_corpse_into_chunks( mitm[ delay.parm1 ] );
-
- if (you.duration[DUR_BERSERKER] &&
- you.berserk_penalty != NO_BERSERK_PENALTY)
+ turn_corpse_into_blood_potions( mitm[ delay.parm1 ] );
+ }
+ else
{
- mpr("You enjoyed that.");
- you.berserk_penalty = 0;
+ mprf("You finish %s the corpse into pieces.",
+ (you.has_usable_claws() || you.mutation[MUT_FANGS] == 3) ?
+ "ripping" : "chopping");
+
+ if (is_good_god(you.religion) && is_player_same_species(item.plus))
+ simple_god_message(" expects more respect for your departed "
+ "relatives.");
+ else if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)
+ simple_god_message(" expects more respect for this departed "
+ "soul.");
+
+ if (you.species == SP_VAMPIRE && you.experience_level < 6
+ && mons_has_blood(item.plus)
+ && (!god_likes_butchery(you.religion)
+ || !you.duration[DUR_PRAYER]))
+ {
+ mpr("What a waste.");
+ }
+ turn_corpse_into_chunks( mitm[ delay.parm1 ] );
+
+ if (you.duration[DUR_BERSERKER] &&
+ you.berserk_penalty != NO_BERSERK_PENALTY)
+ {
+ mpr("You enjoyed that.");
+ you.berserk_penalty = 0;
+ }
}
}
else
{
- mpr("You stop butchering the corpse.");
+ mprf("You stop %s.", can_bottle_blood_from_corpse(item.plus) ?
+ "bottling this corpse's blood"
+ : "butchering the corpse");
}
stashes.update_stash(); // Stash-track the generated item(s)
break;
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 3b3782c087..e0297f14cb 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1542,6 +1542,9 @@ bool acquirement(object_class_type class_wanted, int agent,
thing.quantity += 150;
else if (quant > 1)
thing.quantity = quant;
+
+ if (thing.base_type == OBJ_POTIONS && thing.sub_type == POT_BLOOD)
+ thing.special = 1200;
// remove curse flag from item
do_uncurse_item( thing );
@@ -2166,33 +2169,57 @@ static void hell_effects()
}
}
+static bool food_item_needs_time_check(item_def &item)
+{
+ if (!is_valid_item(item))
+ return false;
+
+ if (item.base_type != OBJ_CORPSES
+ && item.base_type != OBJ_FOOD
+ && item.base_type != OBJ_POTIONS)
+ {
+ return false;
+ }
+
+ if (item.base_type == OBJ_CORPSES
+ && item.sub_type > CORPSE_SKELETON)
+ {
+ return false;
+ }
+
+ if (item.base_type == OBJ_FOOD && item.sub_type != FOOD_CHUNK)
+ {
+ return false;
+ }
+
+ if (item.base_type == OBJ_POTIONS && item.sub_type != POT_BLOOD)
+ {
+ return false;
+ }
+
+ return true;
+}
+
static void rot_inventory_food(long time_delta)
{
// Update all of the corpses and food chunks in the player's
// inventory {should be moved elsewhere - dlb}
bool burden_changed_by_rot = false;
+ int blood_num, congealed_blood_num = 0;
std::vector<char> rotten_items;
for (int i = 0; i < ENDOFPACK; i++)
{
if (you.inv[i].quantity < 1)
continue;
- if (you.inv[i].base_type != OBJ_CORPSES && you.inv[i].base_type != OBJ_FOOD)
- continue;
-
- if (you.inv[i].base_type == OBJ_CORPSES
- && you.inv[i].sub_type > CORPSE_SKELETON)
- {
- continue;
- }
-
- if (you.inv[i].base_type == OBJ_FOOD && you.inv[i].sub_type != FOOD_CHUNK)
+ if (!food_item_needs_time_check(you.inv[i]))
continue;
-
+
if ((time_delta / 20) >= you.inv[i].special)
{
- if (you.inv[i].base_type == OBJ_FOOD)
+ if (you.inv[i].base_type == OBJ_FOOD
+ || you.inv[i].base_type == OBJ_POTIONS)
{
if (you.equip[EQ_WEAPON] == i)
unwield_item();
@@ -2225,8 +2252,17 @@ static void rot_inventory_food(long time_delta)
you.inv[i].special -= (time_delta / 20);
- if (you.inv[i].special < 100 &&
- (you.inv[i].special + (time_delta / 20) >=100 ))
+ if (you.inv[i].base_type == OBJ_POTIONS)
+ {
+ blood_num += you.inv[i].quantity;
+ if (you.inv[i].special < 200
+ && you.inv[i].special + (time_delta / 20) >= 200)
+ {
+ congealed_blood_num += you.inv[i].quantity;
+ }
+ }
+ else if (food_is_rotten(you.inv[i])
+ && (you.inv[i].special + (time_delta / 20) >= 100 ))
{
rotten_items.push_back(index_to_letter( i ));
}
@@ -2290,6 +2326,20 @@ static void rot_inventory_food(long time_delta)
learned_something_new(TUT_ROTTEN_FOOD);
}
+
+ if (congealed_blood_num)
+ {
+ std::string msg = "";
+ if (blood_num == 1)
+ mpr("Your potion of blood congeals.", MSGCH_ROTTEN_MEAT);
+ else if (congealed_blood_num == 1)
+ mpr("One of your potions of blood congeals.", MSGCH_ROTTEN_MEAT);
+ else if (congealed_blood_num < blood_num)
+ mpr("Some of your potions of blood congeal.", MSGCH_ROTTEN_MEAT);
+ else
+ mpr("Your potions of blood congeal.", MSGCH_ROTTEN_MEAT);
+ }
+
if (burden_changed_by_rot)
{
mpr("Your equipment suddenly weighs less.", MSGCH_ROTTEN_MEAT);
@@ -2532,7 +2582,7 @@ void handle_time( long time_delta )
you.put_to_sleep();
}
- // Update all of the corpses and food chunks on the floor
+ // Update all of the corpses, food chunks and potions of blood on the floor.
update_corpses(time_delta);
rot_inventory_food(time_delta);
@@ -2799,28 +2849,12 @@ void update_corpses(double elapsedTime)
{
item_def &it = mitm[c];
- if (!is_valid_item(it))
- continue;
-
- if (it.base_type != OBJ_CORPSES && it.base_type != OBJ_FOOD)
- {
- continue;
- }
-
- if (it.base_type == OBJ_CORPSES
- && it.sub_type > CORPSE_SKELETON)
- {
- continue;
- }
-
- if (it.base_type == OBJ_FOOD && it.sub_type != FOOD_CHUNK)
- {
+ if (!food_item_needs_time_check(it))
continue;
- }
-
+
if (rot_time >= it.special && !is_being_butchered(it))
{
- if (it.base_type == OBJ_FOOD)
+ if (it.base_type == OBJ_FOOD || it.base_type == OBJ_POTIONS)
{
destroy_item(c);
}
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index c9537034ff..99ca63105f 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -2035,7 +2035,8 @@ bool melee_attack::apply_damage_brand()
const int chunk_type = mons_corpse_effect( def->type );
// don't drink poisonous or mutagenic blood
- if (chunk_type == CE_CLEAN || chunk_type == CE_CONTAMINATED)
+ if (mons_has_blood(def->type)
+ && (chunk_type == CE_CLEAN || chunk_type == CE_CONTAMINATED))
{
mprf( "You draw %s's blood!",
def->name(DESC_NOCAP_THE, true).c_str() );
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index 92d8f42d84..d3bd27cc73 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -221,7 +221,10 @@ bool butchery(int which_corpse)
static_cast<transformation_type>(you.attribute[ATTR_TRANSFORMATION]);
// Xom probably likes this, occasionally
- bool teeth_butcher = (you.mutation[MUT_FANGS] == 3);
+ // Vampires fangs are optimised for biting, not for tearing flesh.
+ // Other species with this mutation still might benefit from this.
+ bool teeth_butcher = (you.mutation[MUT_FANGS] == 3
+ && you.species != SP_VAMPIRE);
bool barehand_butcher = (transform_can_butcher_barehanded(transform)
|| you.has_claws()) && you.equip[EQ_GLOVES] == -1;
@@ -287,7 +290,9 @@ bool butchery(int which_corpse)
// if there are several corpses on the square.
if ( num_corpses == 0 )
{
- mpr("There isn't anything to butcher here.");
+ mprf("There isn't anything to %s here.",
+ you.species == SP_VAMPIRE && you.experience_level > 5 ? "bottle"
+ : "butcher");
return false;
}
else if ( !prechosen
@@ -301,13 +306,17 @@ bool butchery(int which_corpse)
continue;
// offer the possibility of butchering
- mprf("Butcher %s? [y/n/q/c]", mitm[o].name(DESC_NOCAP_A).c_str());
+ mprf("%s %s? [y/n/q/c]", can_bottle_blood_from_corpse(mitm[o].plus)?
+ "Bottle" : "Butcher",
+ mitm[o].name(DESC_NOCAP_A).c_str());
+
// possible results:
// 0 - cancel all butchery (quit)
// 1 - say no to this butchery, continue prompting
// 2 - OK this butchery
// Yes, this is a hack because it's too annoying to adapt
// yesnoquit() to this purpose.
+
int result = 100;
while (result == 100)
{
@@ -443,7 +452,9 @@ bool butchery(int which_corpse)
if (canceled_butcher)
canned_msg(MSG_OK);
else
- mpr("There isn't anything else to butcher here.");
+ mprf("There isn't anything else to %s here.",
+ you.species == SP_VAMPIRE && you.experience_level >= 6 ?
+ "bottle" : "butcher");
return false;
} // end butchery()
@@ -1433,6 +1444,7 @@ bool can_ingest(int what_isit, int kindof_thing, bool suppress_msg, bool reqid,
case OBJ_POTIONS: // called by lua
if (get_ident_type(OBJ_POTIONS, kindof_thing) != ID_KNOWN_TYPE)
return true;
+
switch (kindof_thing)
{
case POT_BLOOD:
@@ -1613,18 +1625,20 @@ static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk)
return (this_chunk_effect);
} // end determine_chunk_effect()
-static bool vampire_consume_corpse(const int mons_type, int max_chunks,
+static bool vampire_consume_corpse(const int mons_type, const int max_chunks,
const int chunk_type, const bool rotten)
{
- if (chunk_type == CE_HCL)
+ if (!mons_has_blood(mons_type))
{
mpr( "There is no blood in this body!" );
return false;
}
// This is the exact formula of corpse nutrition for chunk lovers
- max_chunks = 1 + random2(max_chunks);
- int mass = CHUNK_BASE_NUTRITION * max_chunks;
+ int chunk_amount = 1 + random2(max_chunks);
+ chunk_amount = stepdown_value( chunk_amount, 4, 4, 12, 12 );
+ int mass = CHUNK_BASE_NUTRITION * chunk_amount;
+
int food_value = 0, hp_amt = 0, mp_amt = 0;
if (rotten)
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 93a016f00b..0c252260cc 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -1288,12 +1288,17 @@ std::string item_def::name_aux( description_level_type desc,
}
if (know_type)
{
- buff << "potion of " << potion_type_name(item_typ);
+ buff << "potion of ";
+
+ if (this->sub_type == POT_BLOOD && this->special < 200)
+ buff << "congealed ";
+
+ buff << potion_type_name(item_typ);
}
else
{
- const int pqual = PQUAL(this->special);
- const int pcolour = PCOLOUR(this->special);
+ const int pqual = PQUAL(this->plus);
+ const int pcolour = PCOLOUR(this->plus);
static const char *potion_qualifiers[] = {
"", "bubbling ", "fuming ", "fizzy ", "viscous ", "lumpy ",
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 8e31a5e8ff..8afba9f8b8 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -1302,7 +1302,9 @@ bool items_stack( const item_def &item1, const item_def &item2,
// both items must be stackable
if (!force_merge
&& (!is_stackable_item( item1 ) || !is_stackable_item( item2 )))
+ {
return (false);
+ }
// base and sub-types must always be the same to stack
if (item1.base_type != item2.base_type || item1.sub_type != item2.sub_type)
@@ -1336,19 +1338,30 @@ bool items_stack( const item_def &item1, const item_def &item2,
ISFLAG_DROPPED | ISFLAG_THROWN | \
ISFLAG_NOTED_ID | ISFLAG_NOTED_GET | \
ISFLAG_BEEN_IN_INV)
- if ((item1.flags & NON_IDENT_FLAGS) !=
- (item2.flags & NON_IDENT_FLAGS))
+
+ if ((item1.flags & NON_IDENT_FLAGS) != (item2.flags & NON_IDENT_FLAGS))
{
return false;
}
- // Thanks to mummy cursing, we can have potions of decay
- // that don't look alike... so we don't stack potions
- // if either isn't identified and they look different. -- bwr
- if (item1.base_type == OBJ_POTIONS && item1.special != item2.special &&
- (!item_type_known(item1) || !item_type_known(item2)))
+ if (item1.base_type == OBJ_POTIONS)
{
- return false;
+ // Thanks to mummy cursing, we can have potions of decay
+ // that don't look alike... so we don't stack potions
+ // if either isn't identified and they look different. -- bwr
+ if (item1.plus != item2.plus
+ && (!item_type_known(item1) || !item_type_known(item2)))
+ {
+ return false;
+ }
+
+ // Don't stack congealed potions of blood with non-congealed ones.
+ if (item1.sub_type == POT_BLOOD
+ && (item1.special < 200 && item2.special >= 200
+ || item2.special < 200 && item1.special >= 200))
+ {
+ return false;
+ }
}
// The inscriptions can differ if one of them is blank, but if they
@@ -1524,6 +1537,14 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
you.inv[m].inscription = mitm[obj].inscription;
}
+ if (mitm[obj].base_type == OBJ_POTIONS
+ && mitm[obj].sub_type == POT_BLOOD)
+ {
+ // use average age
+ int age = you.inv[m].special * you.inv[m].quantity
+ + mitm[obj].special * quant_got;
+ you.inv[m].special = age / (you.inv[m].quantity + quant_got);
+ }
inc_inv_item_quantity( m, quant_got );
dec_mitm_item_quantity( obj, quant_got );
burden_change();
@@ -1726,6 +1747,13 @@ bool copy_item_to_grid( const item_def &item, int x_plos, int y_plos,
{
if (items_stack( item, mitm[i] ))
{
+ if (item.base_type == OBJ_POTIONS && item.sub_type == POT_BLOOD)
+ {
+ // calculate average age
+ int age = mitm[i].special * mitm[i].quantity
+ + item.special * quant_drop;
+ mitm[i].special = age / (mitm[i].quantity + quant_drop);
+ }
inc_mitm_item_quantity( i, quant_drop );
// If the items on the floor already have a nonzero slot,
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index ff1af54244..4fc9f2b377 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -490,9 +490,9 @@ void item_colour( item_def &item )
break;
case OBJ_POTIONS:
- item.special = you.item_description[IDESC_POTIONS][item.sub_type];
+ item.plus = you.item_description[IDESC_POTIONS][item.sub_type];
- switch (item.special % 14)
+ switch (item.plus % 14)
{
case 0: //"clear potion"
default:
@@ -2313,14 +2313,19 @@ static void generate_potion_item(item_def& item, int force_type,
} while ( (stype == POT_POISON && item_level < 1) ||
(stype == POT_STRONG_POISON && item_level < 11) ||
(stype == POT_SLOWING && item_level < 7) );
+
if ( stype == POT_GAIN_STRENGTH || stype == POT_GAIN_DEXTERITY ||
stype == POT_GAIN_INTELLIGENCE || stype == POT_EXPERIENCE ||
stype == POT_MAGIC || stype == POT_RESTORE_ABILITIES )
+ {
item.quantity = 1;
+ }
item.sub_type = stype;
}
-
- item.plus = 0;
+ if (item.sub_type == POT_BLOOD)
+ item.special = 1200;
+ else
+ item.special = 0;
}
static void generate_scroll_item(item_def& item, int force_type,
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index ad5f84db63..80636c4bdb 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -80,8 +80,59 @@
#include "view.h"
#include "xom.h"
-// void place_chunks(int mcls, unsigned char rot_status, unsigned char chx,
-// unsigned char chy, unsigned char ch_col)
+static void create_monster_hide(int mons_class)
+{
+ int o = get_item_slot( 100 + random2(200) );
+ if (o == NON_ITEM)
+ return;
+
+ mitm[o].quantity = 1;
+
+ // these values are common to all: {dlb}
+ mitm[o].base_type = OBJ_ARMOUR;
+ mitm[o].plus = 0;
+ mitm[o].plus2 = 0;
+ mitm[o].special = 0;
+ mitm[o].flags = 0;
+ mitm[o].colour = mons_class_colour( mons_class );
+
+ // these values cannot be set by a reasonable formula: {dlb}
+ switch (mons_class)
+ {
+ case MONS_DRAGON:
+ mitm[o].sub_type = ARM_DRAGON_HIDE;
+ break;
+ case MONS_TROLL:
+ mitm[o].sub_type = ARM_TROLL_HIDE;
+ break;
+ case MONS_ICE_DRAGON:
+ mitm[o].sub_type = ARM_ICE_DRAGON_HIDE;
+ break;
+ case MONS_STEAM_DRAGON:
+ mitm[o].sub_type = ARM_STEAM_DRAGON_HIDE;
+ break;
+ case MONS_MOTTLED_DRAGON:
+ mitm[o].sub_type = ARM_MOTTLED_DRAGON_HIDE;
+ break;
+ case MONS_STORM_DRAGON:
+ mitm[o].sub_type = ARM_STORM_DRAGON_HIDE;
+ break;
+ case MONS_GOLDEN_DRAGON:
+ mitm[o].sub_type = ARM_GOLD_DRAGON_HIDE;
+ break;
+ case MONS_SWAMP_DRAGON:
+ mitm[o].sub_type = ARM_SWAMP_DRAGON_HIDE;
+ break;
+ case MONS_SHEEP:
+ case MONS_YAK:
+ default:
+ mitm[o].sub_type = ARM_ANIMAL_SKIN;
+ break;
+ }
+
+ move_item_to_grid( &o, you.x_pos, you.y_pos );
+}
+
void turn_corpse_into_chunks( item_def &item )
{
ASSERT( item.base_type == OBJ_CORPSES );
@@ -90,74 +141,130 @@ void turn_corpse_into_chunks( item_def &item )
const int max_chunks = mons_weight( mons_class ) / 150;
// only fresh corpses bleed enough to colour the ground
- if (item.special >= 100)
+ if (!food_is_rotten(item))
bleed_onto_floor(you.x_pos, you.y_pos, mons_class, max_chunks, true);
item.base_type = OBJ_FOOD;
item.sub_type = FOOD_CHUNK;
item.quantity = 1 + random2( max_chunks );
- item.flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
-
item.quantity = stepdown_value( item.quantity, 4, 4, 12, 12 );
- // seems to me that this should come about only
- // after the corpse has been butchered ... {dlb}
+ if (you.species != SP_VAMPIRE)
+ item.flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
+
+ // happens after the corpse has been butchered
if (monster_descriptor(mons_class, MDSC_LEAVES_HIDE) && !one_chance_in(3))
+ create_monster_hide(mons_class);
+}
+
+bool can_bottle_blood_from_corpse(int mons_type)
+{
+ if (you.species != SP_VAMPIRE || you.experience_level < 6
+ || !mons_has_blood(mons_type))
{
- int o = get_item_slot( 100 + random2(200) );
- if (o == NON_ITEM)
- return;
+ return (false);
+ }
+
+ int chunk_type = mons_corpse_effect( mons_type );
+ if (chunk_type == CE_CLEAN || chunk_type == CE_CONTAMINATED)
+ return (true);
+
+ return (false);
+}
+
+void turn_corpse_into_blood_potions( item_def &item )
+{
+ ASSERT( item.base_type == OBJ_CORPSES );
+ ASSERT( !food_is_rotten(item) );
- mitm[o].quantity = 1;
+ const int mons_class = item.plus;
+ ASSERT( can_bottle_blood_from_corpse(mons_class) );
- // these values are common to all: {dlb}
- mitm[o].base_type = OBJ_ARMOUR;
- mitm[o].plus = 0;
- mitm[o].plus2 = 0;
- mitm[o].special = 0;
- mitm[o].flags = 0;
- mitm[o].colour = mons_class_colour( mons_class );
+ item.base_type = OBJ_POTIONS;
+ item.sub_type = POT_BLOOD;
+ item.colour = RED;
+ item.special = (item.special - 80) * 10; // potion's age
+
+ // max. amount is about one third of the max. amount for chunks
+ const int max_chunks = mons_weight( mons_class ) / 150;
+ item.quantity = 1 + random2( max_chunks/3 );
+ item.quantity = stepdown_value( item.quantity, 2, 2, 6, 6 );
- // these values cannot be set by a reasonable formula: {dlb}
- switch (mons_class)
+ item.flags &= ~(ISFLAG_THROWN | ISFLAG_DROPPED);
+
+ // happens after the blood has been bottled
+ if (monster_descriptor(mons_class, MDSC_LEAVES_HIDE) && !one_chance_in(3))
+ create_monster_hide(mons_class);
+}
+
+// A variation of the mummy curse: for potions of blood (vital for Vampires!)
+// split the stack and only turn part of it into POT_DECAY.
+void split_blood_potions_into_decay( int obj, int amount )
+{
+ ASSERT(obj != -1);
+ item_def potion = you.inv[obj];
+
+ ASSERT(is_valid_item(potion));
+ ASSERT(potion.base_type == OBJ_POTIONS && potion.sub_type == POT_BLOOD);
+ ASSERT(amount <= potion.quantity);
+
+ if (amount <= 0)
+ amount = random2(potion.quantity) + 1;
+
+ // if entire stack affected just change subtype
+ if (amount == potion.quantity)
+ {
+ you.inv[obj].sub_type = POT_DECAY;
+ return;
+ }
+
+ // try to merge into existing stacks of decayed potions
+ for (int m = 0; m < ENDOFPACK; m++)
+ {
+ if (you.inv[m].base_type == OBJ_POTIONS
+ && you.inv[m].sub_type == POT_DECAY)
+ {
+ inc_inv_item_quantity( m, amount );
+ dec_inv_item_quantity( obj, amount);
+
+ return;
+ }
+ }
+
+ // only bother creating a distinct stack of potions
+ // if it won't get destroyed right away
+ if (!grid_destroys_items(grd[you.x_pos][you.y_pos]))
+ {
+ item_def potion2;
+ potion2.base_type = OBJ_POTIONS;
+ potion2.sub_type = POT_DECAY;
+ potion2.plus = potion.plus; // are these even needed?
+ potion2.plus2 = potion.plus2;
+ potion2.flags = potion.flags;
+ potion2.quantity = amount;
+ potion2.special = 0;
+
+ switch (random2(4))
{
- case MONS_DRAGON:
- mitm[o].sub_type = ARM_DRAGON_HIDE;
- break;
- case MONS_TROLL:
- mitm[o].sub_type = ARM_TROLL_HIDE;
+ case 0:
+ potion2.colour = RED;
break;
- case MONS_ICE_DRAGON:
- mitm[o].sub_type = ARM_ICE_DRAGON_HIDE;
+ case 1:
+ potion2.colour = BROWN;
break;
- case MONS_STEAM_DRAGON:
- mitm[o].sub_type = ARM_STEAM_DRAGON_HIDE;
+ case 2:
+ potion2.colour = GREEN;
break;
- case MONS_MOTTLED_DRAGON:
- mitm[o].sub_type = ARM_MOTTLED_DRAGON_HIDE;
- break;
- case MONS_STORM_DRAGON:
- mitm[o].sub_type = ARM_STORM_DRAGON_HIDE;
- break;
- case MONS_GOLDEN_DRAGON:
- mitm[o].sub_type = ARM_GOLD_DRAGON_HIDE;
- break;
- case MONS_SWAMP_DRAGON:
- mitm[o].sub_type = ARM_SWAMP_DRAGON_HIDE;
- break;
- case MONS_SHEEP:
- case MONS_YAK:
- mitm[o].sub_type = ARM_ANIMAL_SKIN;
- break;
- default:
- // future implementation {dlb}
- mitm[o].sub_type = ARM_ANIMAL_SKIN;
+ case 3:
+ potion2.colour = LIGHTRED;
break;
}
- move_item_to_grid( &o, item.x, item.y );
- }
-} // end place_chunks()
+ copy_item_to_grid( potion2, you.x_pos, you.y_pos );
+ }
+ // is decreased even if the decay stack goes splat
+ dec_inv_item_quantity(obj, amount);
+}
// checks whether the player or a monster is capable of bleeding
static bool victim_can_bleed(int montype)
@@ -181,8 +288,7 @@ static bool victim_can_bleed(int montype)
}
// now check monsters
- return (mons_class_flag(montype, M_COLD_BLOOD)
- || mons_class_flag(montype, M_WARM_BLOOD));
+ return (mons_has_blood(montype));
}
static bool allow_bleeding_on_square(int x, int y)
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 31e92ee619..b967684ac4 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -71,6 +71,10 @@ void trackers_init_new_level(bool transit);
* *********************************************************************** */
void turn_corpse_into_chunks( item_def &item );
+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 );
+
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 edbb7de93a..3154102d56 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -407,6 +407,12 @@ bool mons_is_insubstantial(int mc)
return mons_class_flag(mc, M_INSUBSTANTIAL);
}
+bool mons_has_blood(int mc)
+{
+ return (mons_class_flag(mc, M_COLD_BLOOD)
+ || mons_class_flag(mc, M_WARM_BLOOD));
+}
+
bool mons_behaviour_perceptible(const monsters *mon)
{
return (!mons_class_flag(mon->type, M_NO_EXP_GAIN)
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 2aad04d707..739bb8c26f 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -651,6 +651,7 @@ bool mons_class_is_slowable(int mc);
bool mons_is_stationary(const monsters *mon);
bool mons_is_wall_shielded(int mc);
bool mons_is_insubstantial(int mc);
+bool mons_has_blood(int mc);
bool mons_is_submerged( const monsters *mon );
bool invalid_monster(const monsters *mon);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 8a4ffc4942..ced682c33f 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -243,12 +243,27 @@ bool curse_an_item( bool decay_potions )
/* don't change you.inv_special (just for fun) */
if (you.inv[item].base_type == OBJ_POTIONS)
{
- // Xom is amused by useful potions being ruined.
- if (item_value(you.inv[item], true) / you.inv[item].quantity > 2)
- xom_is_stimulated(32 * you.inv[item].quantity);
+ // Potions of blood are vital to vampires, so make an exception for
+ // for them. (Come to think of it, this would work nicely for all
+ // other potion types as well.)
+ if (you.inv[item].sub_type == POT_BLOOD)
+ {
+ int amount = random2(you.inv[item].quantity) + 1;
+ split_blood_potions_into_decay(item, amount);
+
+ // Xom is amused if this happens to thirsty vampires
+ if (you.species == SP_VAMPIRE && you.hunger_state <= HS_HUNGRY)
+ xom_is_stimulated(32 * amount);
+ }
+ else
+ {
+ // Xom is amused by useful potions being ruined.
+ if (item_value(you.inv[item], true) / you.inv[item].quantity > 2)
+ xom_is_stimulated(32 * you.inv[item].quantity);
- you.inv[item].sub_type = POT_DECAY;
- unset_ident_flags( you.inv[item], ISFLAG_IDENT_MASK ); // all different
+ you.inv[item].sub_type = POT_DECAY;
+ unset_ident_flags( you.inv[item], ISFLAG_IDENT_MASK ); // all different
+ }
}
else
do_curse_item( you.inv[item] );
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 244e4720cc..f24ab8173b 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -829,12 +829,13 @@ static void give_starting_food()
if ( you.species == SP_SPRIGGAN )
{
item.base_type = OBJ_POTIONS;
- item.sub_type = POT_PORRIDGE;
+ item.sub_type = POT_PORRIDGE;
}
else if (you.species == SP_VAMPIRE)
{
item.base_type = OBJ_POTIONS;
- item.sub_type = POT_BLOOD;
+ item.sub_type = POT_BLOOD;
+ item.special = 1200;
}
else
{
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 854e600352..4efee38c60 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -3018,6 +3018,11 @@ void level_change(bool skip_ability_increase)
MSGCH_INTRINSIC_GAIN );
}
}
+ else if (you.experience_level == 6)
+ {
+ mpr("You can now bottle potions of blood from chopped up "
+ "corpses.");
+ }
else if (you.experience_level == 13)
{
mprf( MSGCH_INTRINSIC_GAIN,
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 681d5cb0eb..588795ee8d 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -310,9 +310,35 @@ void sublimation(int power)
{
unsigned char loopy = 0; // general purpose loop variable {dlb}
- if (you.equip[EQ_WEAPON] == -1
- || you.inv[you.equip[EQ_WEAPON]].base_type != OBJ_FOOD
- || you.inv[you.equip[EQ_WEAPON]].sub_type != FOOD_CHUNK)
+ int wielded = you.equip[EQ_WEAPON];
+ if (wielded != -1)
+ {
+ if (you.inv[wielded].base_type == OBJ_FOOD
+ && you.inv[wielded].sub_type == FOOD_CHUNK)
+ {
+ mpr("The chunk of flesh you are holding crumbles to dust.");
+ mpr("A flood of magical energy pours into your mind!");
+
+ inc_mp( 7 + random2(7), false );
+
+ dec_inv_item_quantity( wielded, 1 );
+ }
+ else if (you.inv[wielded].base_type == OBJ_POTIONS
+ && you.inv[wielded].sub_type == POT_BLOOD)
+ {
+ mprf("The blood within %s frothes and boils.",
+ you.inv[wielded].quantity == 1 ? "the flask you are holding"
+ : "one of your flasks");
+ split_blood_potions_into_decay( wielded, 1 );
+
+ mpr("A flood of magical energy pours into your mind!");
+ inc_mp( 7 + random2(7), false );
+ }
+ else // no appropriate item wielded
+ wielded = -1;
+ }
+
+ if (wielded == -1)
{
if (you.duration[DUR_DEATHS_DOOR])
{
@@ -343,15 +369,6 @@ void sublimation(int power)
}
}
}
- else
- {
- mpr("The chunk of flesh you are holding crumbles to dust.");
- mpr("A flood of magical energy pours into your mind!");
-
- inc_mp( 7 + random2(7), false );
-
- dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
- }
return;
} // end sublimation()
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index c1fcacad94..462aa582d9 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1775,8 +1775,7 @@ void cast_fulsome_distillation( int powc )
switch (mons_corpse_effect( mitm[corpse].plus ))
{
case CE_CLEAN:
- pot_type = (power_up ? POT_CONFUSION :
- one_chance_in(30)? POT_BLOOD : POT_WATER);
+ pot_type = (power_up ? POT_CONFUSION : POT_WATER);
break;
case CE_CONTAMINATED:
diff --git a/crawl-ref/source/tile1.cc b/crawl-ref/source/tile1.cc
index 0b76f5fcea..99e1e6fd67 100644
--- a/crawl-ref/source/tile1.cc
+++ b/crawl-ref/source/tile1.cc
@@ -1608,7 +1608,7 @@ int tileidx_item(const item_def &item)
}
else
{
- return TILE_POTION_OFFSET + special % 14;
+ return TILE_POTION_OFFSET + item.plus % 14;
}
case OBJ_BOOKS:
@@ -4229,7 +4229,8 @@ void finish_inven_data(int n, int *tiles, int *num, int *idx, int *iflag)
{
q = itm->quantity;
}
- if (q==1) q = -1;
+ if (q == 1)
+ q = -1;
if ( type == OBJ_WANDS
&& (!(itm->flags & ISFLAG_KNOW_PLUSES )