diff options
author | Adam Borowski <kilobyte@angband.pl> | 2010-01-07 21:35:39 +0100 |
---|---|---|
committer | Adam Borowski <kilobyte@angband.pl> | 2010-01-07 21:35:39 +0100 |
commit | f536c278597be3ae8664785ba1997085f177e89b (patch) | |
tree | 3c3baf1e2b0d2c046e07ae4cb179dcb60c5806e6 /crawl-ref/source/transform.cc | |
parent | 81ae2f6d115443d5e75ae4a4c4bb9e3629e93fe7 (diff) | |
download | crawl-ref-f536c278597be3ae8664785ba1997085f177e89b.tar.gz crawl-ref-f536c278597be3ae8664785ba1997085f177e89b.zip |
Rename transfor.{cc,h} to transform.{cc,h}.
Diffstat (limited to 'crawl-ref/source/transform.cc')
-rw-r--r-- | crawl-ref/source/transform.cc | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/crawl-ref/source/transform.cc b/crawl-ref/source/transform.cc new file mode 100644 index 0000000000..ad8e8545ca --- /dev/null +++ b/crawl-ref/source/transform.cc @@ -0,0 +1,1045 @@ +/* + * File: transform.cc + * Summary: Misc function related to player transformations. + * Written by: Linley Henzell + */ + +#include "AppHdr.h" + +#include "transform.h" + +#include <stdio.h> +#include <string.h> + +#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<transformation_type>( + 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<equipment_type> +_init_equipment_removal(transformation_type trans) +{ + std::set<equipment_type> 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<equipment_type>(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<equipment_type>& removed, + bool meld = true, bool mutation = false) +{ + // Meld items into you in (reverse) order. (std::set is a sorted container) + std::set<equipment_type>::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<equipment_type>& melded) +{ + // Unmeld items in order. + std::set<equipment_type>::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<equipment_type> e; + e.insert(eq); + _unmeld_equipment(e); +} + +void remove_one_equip(equipment_type eq, bool meld, bool mutation) +{ + std::set<equipment_type> 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<equipment_type> &remove, + const int trans, bool quiet = false) +{ + std::set<equipment_type>::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<equipment_type> &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<equipment_type>::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<equipment_type> &remove) +{ + // Check over all items to be removed or melded. + std::set<equipment_type>::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<unsigned>(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<equipment_type> 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<transformation_type>(you.attribute[ ATTR_TRANSFORMATION ]); + + // We may have to unmeld a couple of equipment types. + std::set<equipment_type> 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))); +} |