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-03-13 23:05:12 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-03-13 23:05:12 +0000
commitf01463de3abf61a8c3057b7aa70841e000cf55f4 (patch)
treefdfd3e692097c5a6ce0531a33cd591bd7655367c /crawl-ref/source
parent2f4c72e5d1f2a84ddc6ac24b3b4628edc4e43dc3 (diff)
downloadcrawl-ref-f01463de3abf61a8c3057b7aa70841e000cf55f4.tar.gz
crawl-ref-f01463de3abf61a8c3057b7aa70841e000cf55f4.zip
Overhauled potions of blood and vampires.
1.) Vampires can only suck blood from creatures with M_COLD_BLOOD or M_WARM_BLOOD set (no insects anymore!) These restrictions are the same for blood spatter. Also, the monster's corpse must be of type contaminated (e.g. gnoll) or clean. Everything will be rejected. 2.) At xl 6 vampires gain the ability to create potions of blood from butchered corpses. The delay is the same as for butchering, and they also need a butchering tool (since I now think fangs don't really cut it); only the messaging is different, and the result, of course. If the monster doesn't meet the restrictions in (1), the corpse gets butchered instead (important when there are necromancers roaming about) and the resulting chunks don't get the THROWN flag set because vampires are unlikely to want to pick them up. 3.) Potions of blood can turn bad. They last about 1200 turns which is a rather long time, though of course not infinite. Potions created from corpses take the corpse age into account. From age 199 downwards potions of blood are described as "congealed blood". The effect when quaffing is entirely the same, it's just a warning that the potion will soon disappear. I've moved the potion descriptions over into item.plus, so that I could use item.special for the timer to allow for easy comparison in update_corpses() etc. Ideally each stack of potions of blood would have a props vector attached (similarly to decks) with the timeout turns stored in order oldest to newest, so that you'd always drink the oldest potion first, and if a potion was too old it (and it's time value) would just drop out of the stack. Since I haven't got this to work yet, instead the weighted average age of two substacks is calculated and used for the combined stack. Congealed (age < 200) and comparatively fresh (age >= 200) potions of blood will never stack. As suggested in FR 191314, !blood are a now an additional power source for Sublimation of Blood, and the used potion turns into decay. And speaking of decay, I've modified the mummy curse to only affect a substack if the to-be-decayed potions are blood because I think losing your food source that way would be the equivalent of spores destroying all your food at the same time. I think that's it; might still be buggy though I *did* test with some vampires, both wiz-mode and not, and because of the special -> plus change for potions, existing potions will now all look alike (clear potions). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3626 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-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 )