diff options
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/debug.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/delay.cc | 73 | ||||
-rw-r--r-- | crawl-ref/source/effects.cc | 102 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/food.cc | 30 | ||||
-rw-r--r-- | crawl-ref/source/itemname.cc | 11 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 44 | ||||
-rw-r--r-- | crawl-ref/source/makeitem.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 212 | ||||
-rw-r--r-- | crawl-ref/source/misc.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 6 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 25 | ||||
-rw-r--r-- | crawl-ref/source/newgame.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/player.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/spells3.cc | 41 | ||||
-rw-r--r-- | crawl-ref/source/spells4.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/tile1.cc | 5 |
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 ) |