/* * File: transform.cc * Summary: Misc function related to player transformations. * Written by: Linley Henzell */ #include "AppHdr.h" #include "transform.h" #include #include #include "externs.h" #include "artefact.h" #include "delay.h" #include "invent.h" #include "it_use2.h" #include "item_use.h" #include "itemprop.h" #include "items.h" #include "output.h" #include "player.h" #include "random.h" #include "skills2.h" #include "state.h" #include "stuff.h" #include "traps.h" #include "xom.h" static void _extra_hp(int amount_extra); bool transformation_can_wield(transformation_type trans) { return (trans == TRAN_NONE || trans == TRAN_STATUE || trans == TRAN_LICH); } bool transform_allows_wearing_item(const item_def& item) { return ( transform_allows_wearing_item(item, static_cast( you.attribute[ATTR_TRANSFORMATION]))); } bool transform_allows_wearing_item(const item_def& item, transformation_type transform) { bool rc = true; if (item.base_type == OBJ_JEWELLERY) { // Everything but bats can wear all jewellery; bats and pigs can // only wear amulets. if ((transform == TRAN_BAT || transform == TRAN_PIG) && !jewellery_is_amulet(item)) { rc = false; } } else { // It's not jewellery, and it's worn, so it must be armour. const equipment_type eqslot = get_armour_slot(item); const bool is_soft_helmet = is_helmet(item) && !is_hard_helmet(item); switch (transform) { // Some forms can wear everything. case TRAN_NONE: case TRAN_LICH: rc = true; break; // Some can't wear anything. case TRAN_DRAGON: case TRAN_BAT: case TRAN_PIG: rc = false; break; // And some need more complicated logic. case TRAN_SPIDER: rc = is_soft_helmet; break; case TRAN_BLADE_HANDS: rc = (eqslot != EQ_SHIELD && eqslot != EQ_GLOVES); break; case TRAN_STATUE: rc = (eqslot == EQ_CLOAK || eqslot == EQ_HELMET); break; case TRAN_ICE_BEAST: rc = (eqslot == EQ_CLOAK || is_soft_helmet); break; default: // Bug-catcher. mprf(MSGCH_ERROR, "Unknown transformation type %d in " "transform_allows_wearing_item", you.attribute[ATTR_TRANSFORMATION]); break; } } return (rc); } static std::set _init_equipment_removal(transformation_type trans) { std::set result; if (!transformation_can_wield(trans) && you.weapon()) result.insert(EQ_WEAPON); // Liches can't wield holy weapons. if (trans == TRAN_LICH && you.weapon() && get_weapon_brand(*you.weapon()) == SPWPN_HOLY_WRATH) { result.insert(EQ_WEAPON); } for (int i = EQ_WEAPON + 1; i < NUM_EQUIP; ++i) { const equipment_type eq = static_cast(i); const item_def *pitem = you.slot_item(eq); if (pitem && !transform_allows_wearing_item(*pitem, trans)) result.insert(eq); } return (result); } static void _unwear_equipment_slot(equipment_type eqslot) { const int slot = you.equip[eqslot]; item_def *item = you.slot_item(eqslot); if (item == NULL) return; if (eqslot == EQ_WEAPON) { unwield_item(!you.berserk()); canned_msg(MSG_EMPTY_HANDED); you.attribute[ATTR_WEAPON_SWAP_INTERRUPTED] = slot + 1; } else if (item->base_type == OBJ_JEWELLERY) jewellery_remove_effects(*item, false); else unwear_armour(slot); } static void _remove_equipment(const std::set& removed, bool meld = true, bool mutation = false) { // Meld items into you in (reverse) order. (std::set is a sorted container) std::set::const_iterator iter; for (iter = removed.begin(); iter != removed.end(); ++iter) { const equipment_type e = *iter; item_def *equip = you.slot_item(e); if (equip == NULL) continue; bool unequip = (e == EQ_WEAPON || !meld); mprf("%s %s%s %s", equip->name(DESC_CAP_YOUR).c_str(), unequip ? "fall" : "meld", equip->quantity > 1 ? "" : "s", unequip ? "away!" : "into your body."); _unwear_equipment_slot(e); if (unequip) { you.equip[e] = -1; if (mutation) { // A mutation made us not only lose an equipment slot // but actually removed a worn item: Funny! xom_is_stimulated(is_artefact(*equip) ? 255 : 128); } } } } // FIXME: merge this with you_can_wear(), can_wear_armour(), etc. bool _mutations_prevent_wearing(const item_def& item) { const equipment_type eqslot = get_armour_slot(item); if (is_hard_helmet(item) && (player_mutation_level(MUT_HORNS) || player_mutation_level(MUT_BEAK))) { return (true); } // Barding is excepted here. if (item.sub_type == ARM_BOOTS && (player_mutation_level(MUT_HOOVES) || player_mutation_level(MUT_TALONS))) { return (true); } if (eqslot == EQ_GLOVES && player_mutation_level(MUT_CLAWS) >= 3) return (true); return (false); } static void _rewear_equipment_slot(equipment_type e) { if (e == EQ_WEAPON) // shouldn't happen return; if (you.equip[e] == -1) return; item_def& item = you.inv[you.equip[e]]; if (item.base_type == OBJ_JEWELLERY) jewellery_wear_effects(item); else { // In case the player was mutated during the transformation, // check whether the equipment is still wearable. bool force_remove = _mutations_prevent_wearing(item); // If you switched weapons during the transformation, make // sure you can still wear your shield. // (This is only possible with Statue Form.) if (e == EQ_SHIELD && you.weapon() && is_shield_incompatible(*you.weapon(), &item)) { force_remove = true; } if (force_remove) { mprf("%s is pushed off your body!", item.name(DESC_CAP_YOUR).c_str()); you.equip[e] = -1; } else armour_wear_effects(you.equip[e]); } } static void _unmeld_equipment(const std::set& melded) { // Unmeld items in order. std::set::const_iterator iter; for (iter = melded.begin(); iter != melded.end(); ++iter) { const equipment_type e = *iter; if (e == EQ_WEAPON || you.equip[e] == -1) continue; _rewear_equipment_slot(e); } } void unmeld_one_equip(equipment_type eq) { std::set e; e.insert(eq); _unmeld_equipment(e); } void remove_one_equip(equipment_type eq, bool meld, bool mutation) { std::set r; r.insert(eq); _remove_equipment(r, meld, mutation); } static bool _tran_may_meld_cursed(int transformation) { switch (transformation) { case TRAN_BAT: // Vampires of sufficient level may transform into bats even // with cursed gear. if (you.species == SP_VAMPIRE && you.experience_level >= 10) return (true); // intentional fall-through case TRAN_SPIDER: return (false); default: return (true); } } // Returns true if any piece of equipment that has to be removed is cursed. // Useful for keeping low level transformations from being too useful. static bool _check_for_cursed_equipment(const std::set &remove, const int trans, bool quiet = false) { std::set::const_iterator iter; for (iter = remove.begin(); iter != remove.end(); ++iter) { const equipment_type e = *iter; if (you.equip[e] == -1) continue; const item_def& item = you.inv[ you.equip[e] ]; if (item.cursed()) { if (e != EQ_WEAPON && _tran_may_meld_cursed(trans)) continue; // Wielding a cursed non-weapon/non-staff won't hinder // transformations. if (e == EQ_WEAPON && item.base_type != OBJ_WEAPONS && item.base_type != OBJ_STAVES) { continue; } if (!quiet) { mpr( "Your cursed equipment won't allow you to complete the " "transformation." ); } return (true); } } return (false); } // Count the stat boosts yielded by all items to be removed, and count // future losses (caused by the transformation) like a current stat boost, // as well. If the sum of all boosts of a stat is equal to or greater than // the current stat, give a message and return true. bool check_transformation_stat_loss(const std::set &remove, bool quiet, int str_loss, int dex_loss, int int_loss) { // Initialise with additional losses, if any. int prop_str = str_loss; int prop_dex = dex_loss; int prop_int = int_loss; // Might is very much temporary and might run out at any point during // your transformation, possibly resulting in stat loss caused by a // combination of an unequipping (and/or stat lowering) transformation // and Might running out at an inopportune moment. if (you.duration[DUR_MIGHT]) prop_str += 5; if (you.duration[DUR_BRILLIANCE]) prop_int += 5; if (you.duration[DUR_AGILITY]) prop_dex += 5; if (prop_str >= you.strength || prop_int >= you.intel || prop_dex >= you.dex) { if (!quiet) { mpr("This transformation would result in fatal stat loss!", MSGCH_WARN); } return (true); } // Check over all items to be removed or melded. std::set::const_iterator iter; for (iter = remove.begin(); iter != remove.end(); ++iter) { equipment_type e = *iter; if (you.equip[e] == -1) continue; const item_def& item = you.inv[you.equip[e]]; // There are no stat-boosting non-weapons/non-staves. if (e == EQ_WEAPON && item.base_type != OBJ_WEAPONS && item.base_type != OBJ_STAVES) { continue; } // Currently, the only non-artefacts which have stat-changing // effects are rings. if (item.base_type == OBJ_JEWELLERY) { if (!item_ident(item, ISFLAG_KNOW_PLUSES)) continue; switch (item.sub_type) { case RING_STRENGTH: prop_str += item.plus; break; case RING_DEXTERITY: prop_dex += item.plus; break; case RING_INTELLIGENCE: prop_int += item.plus; break; default: break; } } else if (item.base_type == OBJ_ARMOUR) { switch (get_armour_ego_type( item )) { case SPARM_STRENGTH: prop_str += 3; break; case SPARM_DEXTERITY: prop_dex += 3; break; case SPARM_INTELLIGENCE: prop_int += 3; break; default: break; } } if (is_artefact(item)) { prop_str += artefact_known_wpn_property(item, ARTP_STRENGTH); prop_int += artefact_known_wpn_property(item, ARTP_INTELLIGENCE); prop_dex += artefact_known_wpn_property(item, ARTP_DEXTERITY); } // Since there might be multiple items whose effects cancel each other // out while worn, if at any point in the order of checking this list // (which is the same order as when removing items) one of your stats // would reach 0, return true. if (prop_str >= you.strength || prop_int >= you.intel || prop_dex >= you.dex) { if (!quiet) { mpr("This transformation would result in fatal stat loss!", MSGCH_WARN); } return (true); } } return (false); } // Returns true if the player got prompted by an inscription warning and // chose to opt out. bool _check_transformation_inscription_warning( const std::set &remove) { // Check over all items to be removed or melded. std::set::const_iterator iter; for (iter = remove.begin(); iter != remove.end(); ++iter) { equipment_type e = *iter; if (you.equip[e] == -1) continue; const item_def& item = you.inv[you.equip[e]]; operation_types op = OPER_WEAR; if (e == EQ_WEAPON) op = OPER_WIELD; else if (item.base_type == OBJ_JEWELLERY) op = OPER_PUTON; if (!check_old_item_warning(item, op)) return (true); } return (false); } // FIXME: Switch to 4.1 transforms handling. size_type transform_size(int psize) { return you.transform_size(psize); } size_type player::transform_size(int psize) const { const int transform = attribute[ATTR_TRANSFORMATION]; switch (transform) { case TRAN_SPIDER: case TRAN_BAT: return SIZE_TINY; case TRAN_PIG: return SIZE_SMALL; case TRAN_ICE_BEAST: return SIZE_LARGE; case TRAN_DRAGON: return SIZE_HUGE; default: return SIZE_CHARACTER; } } void transformation_expiration_warning() { if (you.duration[DUR_TRANSFORMATION] <= get_expiration_threshold(DUR_TRANSFORMATION)) { mpr("You have a feeling this form won't last long."); } } static bool _abort_or_fizzle(bool just_check) { if (!just_check && you.turn_is_over) { canned_msg(MSG_SPELL_FIZZLES); return (true); // pay the necessary costs } return (false); // SPRET_ABORT } // Transforms you into the specified form. If force is true, checks for // inscription warnings are skipped, and the transformation fails silently // (if it fails). If just_check is true the transformation doesn't actually // happen, but the method returns whether it would be successful. bool transform(int pow, transformation_type which_trans, bool force, bool just_check) { if (!force && crawl_state.is_god_acting()) force = true; if (!force && you.transform_uncancellable) { // Jiyva's wrath-induced transformation is blocking the attempt. // May need to be updated if transform_uncancellable is used for // other uses. return (false); } if (you.species == SP_MERFOLK && you.swimming() && which_trans != TRAN_DRAGON && which_trans != TRAN_BAT) { // This might be overkill, but it's okay because obviously // whatever magical ability that lets them walk on land is // removed when they're in water (in this case, their natural // form is completely over-riding any other... goes well with // the forced transform when entering water)... but merfolk can // transform into flying forms. if (!force) mpr("You cannot transform out of your normal form while in water."); return (false); } // This must occur before the untransform() and the is_undead check. if (you.attribute[ATTR_TRANSFORMATION] == static_cast(which_trans)) { if (you.duration[DUR_TRANSFORMATION] < 100 * BASELINE_DELAY) { if (just_check) return (true); if (which_trans==TRAN_PIG) mpr("You feel you'll be a pig longer."); else mpr("You extend your transformation's duration."); you.increase_duration(DUR_TRANSFORMATION, random2(pow), 100); return (true); } else { if (!force && which_trans!=TRAN_PIG) mpr("You cannot extend your transformation any further!"); return (false); } } // The actual transformation may still fail later (e.g. due to cursed // equipment). Ideally, untransforming should cost a turn but nothing // else (as does the "End Transformation" ability). As it is, you // pay with mana and hunger if you already untransformed. if (!just_check && you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE) { bool skip_wielding = false; switch (which_trans) { case TRAN_STATUE: case TRAN_LICH: break; default: skip_wielding = true; break; } // Skip wielding weapon if it gets unwielded again right away. untransform(skip_wielding); } // Catch some conditions which prevent transformation. if (you.is_undead && (you.species != SP_VAMPIRE || which_trans != TRAN_BAT && you.hunger_state <= HS_SATIATED)) { if (!force) mpr("Your unliving flesh cannot be transformed in this way."); return (_abort_or_fizzle(just_check)); } if (which_trans == TRAN_LICH && you.duration[DUR_DEATHS_DOOR]) { if (!force) { mpr("The transformation conflicts with an enchantment " "already in effect."); } return (_abort_or_fizzle(just_check)); } std::set rem_stuff = _init_equipment_removal(which_trans); if (which_trans != TRAN_PIG && _check_for_cursed_equipment(rem_stuff, which_trans, force)) { return (_abort_or_fizzle(just_check)); } int str = 0, dex = 0, symbol = '@', colour = LIGHTGREY, xhp = 0, dur = 0; const char* tran_name = "buggy"; const char* msg = "You transform into something buggy!"; switch (which_trans) { case TRAN_SPIDER: tran_name = "spider"; dex = 5; symbol = 's'; colour = BROWN; dur = std::min(10 + random2(pow) + random2(pow), 60); msg = "You turn into a venomous arachnid creature."; break; case TRAN_BLADE_HANDS: tran_name = "Blade Hands"; dur = std::min(10 + random2(pow), 100); msg = "Your hands turn into razor-sharp scythe blades."; break; case TRAN_STATUE: tran_name = "statue"; str = 2; dex = -2; xhp = 15; symbol = '8'; colour = LIGHTGREY; dur = std::min(20 + random2(pow) + random2(pow), 100); if (player_genus(GENPC_DWARVEN) && one_chance_in(10)) msg = "You inwardly fear your resemblance to a lawn ornament."; else msg = "You turn into a living statue of rough stone."; break; case TRAN_ICE_BEAST: tran_name = "ice beast"; xhp = 12; symbol = 'I'; colour = WHITE; dur = std::min(30 + random2(pow) + random2(pow), 100); msg = "You turn into a creature of crystalline ice."; break; case TRAN_DRAGON: tran_name = "dragon"; str = 10; xhp = 16; symbol = 'D'; colour = GREEN; dur = std::min(20 + random2(pow) + random2(pow), 100); if (you.species == SP_MERFOLK && you.swimming()) { msg = "You fly out of the water as you turn into " "a fearsome dragon!"; } else msg = "You turn into a fearsome dragon!"; break; case TRAN_LICH: tran_name = "lich"; str = 3; symbol = 'L'; colour = LIGHTGREY; dur = std::min(20 + random2(pow) + random2(pow), 100); msg = "Your body is suffused with negative energy!"; break; case TRAN_BAT: tran_name = "bat"; str = -5; dex = 5; symbol = 'b'; colour = (you.species == SP_VAMPIRE ? DARKGREY : LIGHTGREY); dur = std::min(20 + random2(pow) + random2(pow), 100); if (you.species == SP_VAMPIRE) msg = "You turn into a vampire bat."; else msg = "You turn into a bat."; break; case TRAN_PIG: tran_name = "pig"; symbol = 'h'; colour = RED; dur = pow; msg = "You have been turned into a pig!"; you.transform_uncancellable = true; break; case TRAN_NONE: case NUM_TRANSFORMATIONS: break; } if (check_transformation_stat_loss(rem_stuff, force || which_trans == TRAN_PIG, std::max(-str, 0), std::max(-dex,0))) { // would have died to stat loss if (which_trans == TRAN_PIG) { // no easy way around this! mpr("A dreadful feeling locks you in place!"); if (you.duration[DUR_PARALYSIS]<10 * BASELINE_DELAY) you.duration[DUR_PARALYSIS]=10 * BASELINE_DELAY; } return (_abort_or_fizzle(just_check)); } // If we're just pretending return now. if (just_check) return (true); if (!force && _check_transformation_inscription_warning(rem_stuff)) return (_abort_or_fizzle(just_check)); // All checks done, transformation will take place now. you.redraw_evasion = true; you.redraw_armour_class = true; you.wield_change = true; // Most transformations conflict with stone skin. if (which_trans != TRAN_NONE && which_trans != TRAN_BLADE_HANDS && which_trans != TRAN_STATUE) { you.duration[DUR_STONESKIN] = 0; } // Give the transformation message. mpr(msg); _remove_equipment(rem_stuff); // Update your status. you.attribute[ATTR_TRANSFORMATION] = which_trans; you.set_duration(DUR_TRANSFORMATION, dur); you.symbol = symbol; you.colour = colour; burden_change(); if (str) { modify_stat(STAT_STRENGTH, str, true, make_stringf("gaining the %s transformation", tran_name).c_str()); } if (dex) { modify_stat(STAT_DEXTERITY, dex, true, make_stringf("gaining the %s transformation", tran_name).c_str()); } if (xhp) _extra_hp(xhp); // Extra effects switch (which_trans) { case TRAN_STATUE: if (you.duration[DUR_STONEMAIL] || you.duration[DUR_STONESKIN]) mpr("Your new body merges with your stone armour."); break; case TRAN_ICE_BEAST: if (you.duration[DUR_ICY_ARMOUR]) mpr("Your new body merges with your icy armour."); break; case TRAN_DRAGON: if (you.attribute[ATTR_HELD]) { mpr("The net rips apart!"); you.attribute[ATTR_HELD] = 0; int net = get_trapping_net(you.pos()); if (net != NON_ITEM) destroy_item(net); } break; case TRAN_LICH: // undead cannot regenerate -- bwr if (you.duration[DUR_REGENERATION]) { mpr("You stop regenerating.", MSGCH_DURATION); you.duration[DUR_REGENERATION] = 0; } // silently removed since undead automatically resist poison -- bwr you.duration[DUR_RESIST_POISON] = 0; you.is_undead = US_UNDEAD; you.hunger_state = HS_SATIATED; // no hunger effects while transformed set_redraw_status(REDRAW_HUNGER); break; default: break; } // This only has an effect if the transformation happens passively, // for example if Xom decides to transform you while you're busy // running around or butchering corpses. stop_delay(); if (you.species != SP_VAMPIRE || which_trans != TRAN_BAT) transformation_expiration_warning(); return (true); } bool transform_can_butcher_barehanded(transformation_type tt) { return (tt == TRAN_BLADE_HANDS || tt == TRAN_DRAGON || tt == TRAN_ICE_BEAST); } void untransform(bool skip_wielding) { const flight_type old_flight = you.flight_mode(); you.redraw_evasion = true; you.redraw_armour_class = true; you.wield_change = true; you.symbol = '@'; you.colour = LIGHTGREY; // Must be unset first or else infinite loops might result. -- bwr const transformation_type old_form = static_cast(you.attribute[ ATTR_TRANSFORMATION ]); // We may have to unmeld a couple of equipment types. std::set melded = _init_equipment_removal(old_form); you.attribute[ATTR_TRANSFORMATION] = TRAN_NONE; you.duration[DUR_TRANSFORMATION] = 0; burden_change(); int hp_downscale = 10; switch (old_form) { case TRAN_SPIDER: mpr("Your transformation has ended.", MSGCH_DURATION); modify_stat( STAT_DEXTERITY, -5, true, "losing the spider transformation" ); break; case TRAN_BAT: mpr("Your transformation has ended.", MSGCH_DURATION); modify_stat( STAT_DEXTERITY, -5, true, "losing the bat transformation" ); modify_stat( STAT_STRENGTH, 5, true, "losing the bat transformation" ); break; case TRAN_BLADE_HANDS: mpr( "Your hands revert to their normal proportions.", MSGCH_DURATION ); you.wield_change = true; break; case TRAN_STATUE: mpr( "You revert to your normal fleshy form.", MSGCH_DURATION ); modify_stat( STAT_DEXTERITY, 2, true, "losing the statue transformation" ); modify_stat( STAT_STRENGTH, -2, true, "losing the statue transformation"); // Note: if the core goes down, the combined effect soon disappears, // but the reverse isn't true. -- bwr if (you.duration[DUR_STONEMAIL]) you.duration[DUR_STONEMAIL] = 1; if (you.duration[DUR_STONESKIN]) you.duration[DUR_STONESKIN] = 1; hp_downscale = 15; break; case TRAN_ICE_BEAST: mpr( "You warm up again.", MSGCH_DURATION ); // Note: if the core goes down, the combined effect soon disappears, // but the reverse isn't true. -- bwr if (you.duration[DUR_ICY_ARMOUR]) you.duration[DUR_ICY_ARMOUR] = 1; hp_downscale = 12; break; case TRAN_DRAGON: mpr( "Your transformation has ended.", MSGCH_DURATION ); modify_stat(STAT_STRENGTH, -10, true, "losing the dragon transformation" ); hp_downscale = 16; break; case TRAN_LICH: mpr( "You feel yourself come back to life.", MSGCH_DURATION ); modify_stat(STAT_STRENGTH, -3, true, "losing the lich transformation" ); you.is_undead = US_ALIVE; break; case TRAN_PIG: mpr( "Your transformation has ended.", MSGCH_DURATION ); break; default: break; } _unmeld_equipment(melded); // Re-check terrain now that be may no longer be flying. if (old_flight && you.flight_mode() == FL_NONE) move_player_to_grid(you.pos(), false, true, true); if (transform_can_butcher_barehanded(old_form)) stop_butcher_delay(); // If nagas wear boots while transformed, they fall off again afterwards: // I don't believe this is currently possible, and if it is we // probably need something better to cover all possibilities. -bwr // Removed barding check, no transformed creatures can wear barding // anyway. // *coughs* Ahem, blade hands... -- jpeg if (you.species == SP_NAGA || you.species == SP_CENTAUR) { const int arm = you.equip[EQ_BOOTS]; if (arm != -1 && you.inv[arm].sub_type == ARM_BOOTS) remove_one_equip(EQ_BOOTS); } if (hp_downscale != 10 && you.hp != you.hp_max) { you.hp = you.hp * 10 / hp_downscale; if (you.hp < 1) you.hp = 1; else if (you.hp > you.hp_max) you.hp = you.hp_max; } calc_hp(); if (!skip_wielding) handle_interrupted_swap(true, false, true); you.turn_is_over = true; if (you.transform_uncancellable) you.transform_uncancellable = false; } // XXX: This whole system is a mess as it still relies on special // cases to handle a large number of things (see wear_armour()) -- bwr bool can_equip( equipment_type use_which, bool ignore_temporary ) { if (use_which == EQ_HELMET && (player_mutation_level(MUT_HORNS) || player_mutation_level(MUT_BEAK))) { return (false); } if (use_which == EQ_BOOTS && !player_has_feet()) return (false); if (use_which == EQ_GLOVES && you.has_claws(false) >= 3) return (false); if (!ignore_temporary) { switch (you.attribute[ATTR_TRANSFORMATION]) { case TRAN_NONE: case TRAN_LICH: return (true); case TRAN_BLADE_HANDS: return (use_which != EQ_WEAPON && use_which != EQ_GLOVES && use_which != EQ_SHIELD); case TRAN_STATUE: return (use_which == EQ_WEAPON || use_which == EQ_CLOAK || use_which == EQ_HELMET); case TRAN_ICE_BEAST: return (use_which == EQ_CLOAK); default: return (false); } } return (true); } void _extra_hp(int amount_extra) // must also set in calc_hp { calc_hp(); you.hp *= amount_extra; you.hp /= 10; deflate_hp(you.hp_max, false); } // Used to mark transformations which override species/mutation intrinsics. // If phys_scales is true then we're checking to see if the form keeps // the physical (AC/EV) properties from scales... the special intrinsic // features (resistances, etc.) are lost in those forms however. bool transform_changed_physiology( bool phys_scales ) { return (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE && you.attribute[ATTR_TRANSFORMATION] != TRAN_BLADE_HANDS && (!phys_scales || (you.attribute[ATTR_TRANSFORMATION] != TRAN_LICH && you.attribute[ATTR_TRANSFORMATION] != TRAN_STATUE))); }