diff options
Diffstat (limited to 'src/cmd6.c')
-rw-r--r-- | src/cmd6.c | 7948 |
1 files changed, 7948 insertions, 0 deletions
diff --git a/src/cmd6.c b/src/cmd6.c new file mode 100644 index 00000000..5511f6db --- /dev/null +++ b/src/cmd6.c @@ -0,0 +1,7948 @@ +/* File: cmd6.c */ + +/* Purpose: Object commands */ + +/* + * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke + * + * This software may be copied and distributed for educational, research, and + * not for profit purposes provided that this copyright and statement are + * included in all such copies. + */ + +#include "angband.h" + + +/* + * Forward declare + */ +static bool activate_spell(object_type * o_ptr, byte choice); + + +/* + * General function to find an item by its name + */ +cptr get_item_hook_find_obj_what; +bool get_item_hook_find_obj(int *item) +{ + int i; + char buf[80]; + char buf2[100]; + + strcpy(buf, ""); + if (!get_string(get_item_hook_find_obj_what, buf, 79)) + return FALSE; + + for (i = 0; i < INVEN_TOTAL; i++) + { + object_type *o_ptr = &p_ptr->inventory[i]; + + if (!item_tester_okay(o_ptr)) continue; + + object_desc(buf2, o_ptr, -1, 0); + if (!strcmp(buf, buf2)) + { + *item = i; + return TRUE; + } + } + return FALSE; +} + + +/* + * This file includes code for eating food, drinking potions, + * reading scrolls, aiming wands, using staffs, zapping rods, + * and activating artifacts. + * + * In all cases, if the player becomes "aware" of the item's use + * by testing it, mark it as "aware" and reward some experience + * based on the object's level, always rounding up. If the player + * remains "unaware", mark that object "kind" as "tried". + * + * This code now correctly handles the unstacking of wands, staffs, + * and rods. Note the overly paranoid warning about potential pack + * overflow, which allows the player to use and drop a stacked item. + * + * In all "unstacking" scenarios, the "used" object is "carried" as if + * the player had just picked it up. In particular, this means that if + * the use of an item induces pack overflow, that item will be dropped. + * + * For simplicity, these routines induce a full "pack reorganization" + * which not only combines similar items, but also reorganizes various + * items to obey the current "sorting" method. This may require about + * 400 item comparisons, but only occasionally. + * + * There may be a BIG problem with any "effect" that can cause "changes" + * to the p_ptr->inventory. For example, a "scroll of recharging" can cause + * a wand/staff to "disappear", moving the p_ptr->inventory up. Luckily, the + * scrolls all appear BEFORE the staffs/wands, so this is not a problem. + * But, for example, a "staff of recharging" could cause MAJOR problems. + * In such a case, it will be best to either (1) "postpone" the effect + * until the end of the function, or (2) "change" the effect, say, into + * giving a staff "negative" charges, or "turning a staff into a stick". + * It seems as though a "rod of recharging" might in fact cause problems. + * The basic problem is that the act of recharging (and destroying) an + * item causes the inducer of that action to "move", causing "o_ptr" to + * no longer point at the correct item, with horrifying results. + * + * Note that food/potions/scrolls no longer use bit-flags for effects, + * but instead use the "sval" (which is also used to sort the objects). + */ + + +/* + * Determine the effects of eating a corpse. A corpse can be + * eaten whole or cut into pieces for later. + */ +static void corpse_effect(object_type *o_ptr, bool cutting) +{ + monster_race *r_ptr = &r_info[o_ptr->pval2]; + + /* Assume no bad effects */ + bool harmful = FALSE; + + byte method, effect, d_dice, d_side; + + int i, dam, idam = 0, mdam, brpow, brdam = 0; + + + /* How much of the monster's breath attack remains */ + if (o_ptr->pval <= r_ptr->weight) + { + brpow = 0; + } + else + { + brpow = (o_ptr->pval - r_ptr->weight) / 5; + if (brpow > (r_ptr->weight / 5)) brpow = r_ptr->weight / 5; + } + + if (o_ptr->weight <= 0) o_ptr->weight = 1; + if (o_ptr->pval <= 0) o_ptr->pval = 1; + + /* + * The breath is only discharged by accident or by slicing off pieces + * of meat, and only by corpses. + */ + if ((o_ptr->sval != SV_CORPSE_CORPSE) || + (rand_int(o_ptr->weight / 5) && !cutting)) brpow = 0; + + /* Immediate effects - poison, acid, fire, etc. */ + if (!cutting) + { + for (i = 0; i < 4; i++) + { + /* skip empty blow slot */ + if (!r_ptr->blow[i].method) continue; + + method = r_ptr->blow[i].method; + effect = r_ptr->blow[i].effect; + d_dice = r_ptr->blow[i].d_dice; + d_side = r_ptr->blow[i].d_side; + dam = damroll(d_dice, d_side) * o_ptr->pval / o_ptr->weight / 2; + idam = damroll(d_dice, d_side) * + ((o_ptr->weight / o_ptr->pval > 2) ? + o_ptr->weight / o_ptr->pval : 2); + mdam = maxroll(d_dice, d_side) * 2; + + /* Analyse method */ + switch (method) + { + /* Methods that are meaningless after death */ + case RBM_BITE: + case RBM_STING: + case RBM_ENGULF: + case RBM_DROOL: + case RBM_SPIT: + case RBM_GAZE: + case RBM_WAIL: + case RBM_BEG: + case RBM_INSULT: + case RBM_MOAN: + { + continue; + } + } + + /* Analyse effect */ + switch (effect) + { + /* Effects that are meaningless after death */ + case RBE_HURT: + case RBE_UN_BONUS: + case RBE_UN_POWER: + case RBE_EAT_GOLD: + case RBE_EAT_ITEM: + case RBE_EAT_FOOD: + case RBE_EAT_LITE: + case RBE_ELEC: + case RBE_COLD: + case RBE_SHATTER: + { + break; + } + + case RBE_POISON: + { + if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + set_poisoned(p_ptr->poisoned + dam + idam + 10); + harmful = TRUE; + } + + break; + } + + case RBE_ACID: + { + /* Total Immunity */ + if (!(p_ptr->immune_acid || (dam <= 0))) + { + /* Resist the damage */ + if (p_ptr->resist_acid) dam = (dam + 2) / 3; + if (p_ptr->oppose_acid) dam = (dam + 2) / 3; + + /* Take damage */ + take_hit(dam, "acidic food"); + harmful = TRUE; + } + else + { + set_oppose_acid(p_ptr->oppose_acid + idam); + } + + break; + } + + case RBE_FIRE: + { + /* Totally immune */ + if (p_ptr->immune_fire || (dam <= 0)) + { + /* Resist the damage */ + if (p_ptr->resist_fire) dam = (dam + 2) / 3; + if (p_ptr->oppose_fire) dam = (dam + 2) / 3; + + /* Take damage */ + take_hit(dam, "a fiery meal"); + harmful = TRUE; + } + else + { + set_oppose_fire(p_ptr->oppose_fire + idam); + } + + break; + } + + case RBE_BLIND: + { + if (!p_ptr->resist_blind) + { + set_blind(p_ptr->blind + dam * 2 + idam * 2 + 20); + } + + break; + } + + case RBE_CONFUSE: + { + if (!p_ptr->resist_conf) + { + set_confused(p_ptr->confused + dam + idam + 10); + } + if (!p_ptr->resist_chaos && rand_int(mdam - dam)) + { + set_image(p_ptr->image + dam * 10 + idam * 10 + 100); + } + + break; + } + + case RBE_HALLU: + { + if (!p_ptr->resist_chaos && rand_int(mdam - dam)) + { + set_image(p_ptr->image + dam * 10 + idam * 10 + 50); + } + + break; + } + + case RBE_TERRIFY: + { + if (!p_ptr->resist_fear) + { + set_afraid(p_ptr->afraid + dam + idam + 10); + } + + break; + } + + case RBE_PARALYZE: + { + if (!p_ptr->free_act) + { + set_paralyzed(p_ptr->paralyzed + dam + idam + 10); + } + + break; + } + + case RBE_LOSE_STR: + { + do_dec_stat(A_STR, STAT_DEC_NORMAL); + + break; + } + + case RBE_LOSE_INT: + { + do_dec_stat(A_INT, STAT_DEC_NORMAL); + + break; + } + + case RBE_LOSE_WIS: + { + do_dec_stat(A_WIS, STAT_DEC_NORMAL); + + break; + } + + case RBE_LOSE_DEX: + { + do_dec_stat(A_DEX, STAT_DEC_NORMAL); + + break; + } + + case RBE_LOSE_CON: + { + do_dec_stat(A_CON, STAT_DEC_NORMAL); + + break; + } + + case RBE_LOSE_CHR: + { + do_dec_stat(A_CHR, STAT_DEC_NORMAL); + + break; + } + + /* Don't eat Morgoth's corpse :) */ + case RBE_LOSE_ALL: + { + do_dec_stat(A_STR, STAT_DEC_NORMAL); + do_dec_stat(A_INT, STAT_DEC_NORMAL); + do_dec_stat(A_WIS, STAT_DEC_NORMAL); + do_dec_stat(A_DEX, STAT_DEC_NORMAL); + do_dec_stat(A_CON, STAT_DEC_NORMAL); + do_dec_stat(A_CHR, STAT_DEC_NORMAL); + o_ptr->pval = 1; + + break; + } + + case RBE_SANITY: + { + msg_print("You feel your sanity slipping away!"); + take_sanity_hit(dam, "eating an insane monster"); + + break; + } + + /* Unlife is bad to eat */ + case RBE_EXP_10: + { + msg_print("A black aura surrounds the corpse!"); + + if (p_ptr->hold_life && (rand_int(100) < 50)) + { + msg_print("You keep hold of your life force!"); + } + else + { + s32b d = damroll(10, 6) + + (p_ptr->exp / 100) * MON_DRAIN_LIFE; + + if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(d / 10); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(d); + } + } + + o_ptr->pval = 1; + + break; + } + + case RBE_EXP_20: + { + msg_print("A black aura surrounds the corpse!"); + + if (p_ptr->hold_life && (rand_int(100) < 50)) + { + msg_print("You keep hold of your life force!"); + } + else + { + s32b d = damroll(20, 6) + + (p_ptr->exp / 100) * MON_DRAIN_LIFE; + + if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(d / 10); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(d); + } + } + + o_ptr->pval = 1; + + break; + } + + case RBE_EXP_40: + { + msg_print("A black aura surrounds the corpse!"); + + if (p_ptr->hold_life && (rand_int(100) < 50)) + { + msg_print("You keep hold of your life force!"); + } + else + { + s32b d = damroll(40, 6) + + (p_ptr->exp / 100) * MON_DRAIN_LIFE; + + if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(d / 10); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(d); + } + } + + o_ptr->pval = 1; + + break; + } + + case RBE_EXP_80: + { + msg_print("A black aura surrounds the corpse!"); + + if (p_ptr->hold_life && (rand_int(100) < 50)) + { + msg_print("You keep hold of your life force!"); + } + else + { + s32b d = damroll(80, 6) + + (p_ptr->exp / 100) * MON_DRAIN_LIFE; + + if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(d / 10); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(d); + } + } + + o_ptr->pval = 1; + + break; + } + } + } + } /* if (!cutting) */ + + + /* + * The organ that supplies breath attacks is not + * immediately emptied upon death, although some types + * of breath have no effect. + * AMHD's make rather risky meals, and deadly snacks. + */ + + /* Acid */ + if (r_ptr->flags4 & RF4_BR_ACID && brpow > 0) + { + brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3)); + + msg_print("You are hit by a gush of acid!"); + + /* Total Immunity */ + if (!(p_ptr->immune_acid || (brdam <= 0))) + { + /* Take damage */ + acid_dam(brdam, "a gush of acid"); + harmful = TRUE; + } + o_ptr->pval = 1; + } + else if (r_ptr->flags4 & RF4_BR_ACID) + { + set_oppose_acid(p_ptr->oppose_acid + rand_int(10) + 10); + } + + /* Electricity */ + if (r_ptr->flags4 & RF4_BR_ELEC && brpow > 0) + { + brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3)); + + msg_print("You receive a heavy shock!"); + + /* Total Immunity */ + if (!(p_ptr->immune_elec || (brdam <= 0))) + { + /* Take damage */ + elec_dam(brdam, "an electric shock"); + harmful = TRUE; + } + o_ptr->weight = o_ptr->weight - brpow; + o_ptr->pval = o_ptr->weight; + } + else if (r_ptr->flags4 & RF4_BR_ELEC) + { + set_oppose_elec(p_ptr->oppose_elec + rand_int(10) + 10); + } + + /* Fire */ + if (r_ptr->flags4 & RF4_BR_FIRE && brpow > 0) + { + brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3)); + + msg_print("Roaring flames engulf you!"); + + /* Total Immunity */ + if (!(p_ptr->immune_fire || (brdam <= 0))) + { + /* Take damage */ + fire_dam(brdam, "an explosion"); + harmful = TRUE; + } + o_ptr->pval = 1; + } + else if (r_ptr->flags4 & RF4_BR_FIRE) + { + set_oppose_fire(p_ptr->oppose_fire + rand_int(10) + 10); + } + + /* Cold */ + if (r_ptr->flags4 & RF4_BR_COLD && brpow > 0) + { + brdam = ((brpow / 3) > 1600 ? 1600 : (brpow / 3)); + + msg_print("You are caught in a freezing liquid!"); + + /* Total Immunity */ + if (!(p_ptr->immune_cold || (brdam <= 0))) + { + /* Take damage */ + cold_dam(brdam, "a chilling blast"); + harmful = TRUE; + } + o_ptr->weight = o_ptr->weight - brpow; + o_ptr->pval = o_ptr->weight; + } + else if (r_ptr->flags4 & RF4_BR_COLD) + { + set_oppose_cold(p_ptr->oppose_cold + rand_int(10) + 10); + } + + /* Poison */ + if (r_ptr->flags4 & RF4_BR_POIS && brpow > 0) + { + brdam = ((brpow / 3) > 800 ? 800 : (brpow / 3)); + + msg_print("You are surrounded by toxic gases!"); + + /* Resist the damage */ + if (p_ptr->resist_pois) brdam = (brdam + 2) / 3; + if (p_ptr->oppose_pois) brdam = (brdam + 2) / 3; + + if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + (void)set_poisoned(p_ptr->poisoned + rand_int(brdam) + 10); + } + + /* Take damage */ + take_hit(brdam, "toxic gases"); + o_ptr->weight = o_ptr->weight - brpow; + o_ptr->pval = o_ptr->weight; + harmful = TRUE; + } + + /* Nether */ + if (r_ptr->flags4 & RF4_BR_NETH && brpow > 0) + { + brdam = ((brpow / 6) > 550 ? 550 : (brpow / 6)); + + msg_print("A black aura surrounds the corpse!"); + + if (p_ptr->resist_neth) + { + brdam *= 6; + brdam /= (randint(6) + 6); + } + else + { + if (p_ptr->hold_life && (rand_int(100) < 75)) + { + msg_print("You keep hold of your life force!"); + } + else if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(200 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(200 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); + } + } + + /* Take damage */ + take_hit(brdam, "an unholy blast"); + harmful = TRUE; + o_ptr->weight = o_ptr->weight - brpow; + o_ptr->pval = o_ptr->weight; + } + + /* Confusion */ + if (r_ptr->flags4 & RF4_BR_CONF && brpow > 0) + { + msg_print("A strange liquid splashes on you!"); + + if (!p_ptr->resist_conf) + { + set_confused(p_ptr->confused + brdam + idam + 10); + } + o_ptr->weight = o_ptr->weight - brpow; + o_ptr->pval = o_ptr->weight; + } + + /* Chaos */ + if (r_ptr->flags4 & RF4_BR_CHAO && brpow > 0) + { + brdam = ((brpow / 6) > 600 ? 600 : (brpow / 6)); + + msg_print("A swirling cloud surrounds you!"); + + if (p_ptr->resist_chaos) + { + brdam *= 6; + brdam /= (randint(6) + 6); + } + + if (!p_ptr->resist_conf) + { + (void)set_confused(p_ptr->confused + rand_int(20) + 10); + } + + if (!p_ptr->resist_chaos) + { + (void)set_image(p_ptr->image + randint(10)); + } + + if (!p_ptr->resist_neth && !p_ptr->resist_chaos) + { + if (p_ptr->hold_life && (rand_int(100) < 75)) + { + msg_print("You keep hold of your life force!"); + } + else if (p_ptr->hold_life) + { + msg_print("You feel your life slipping away!"); + lose_exp(500 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE); + } + else + { + msg_print("You feel your life draining away!"); + lose_exp(5000 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); + } + } + + /* Take damage */ + take_hit(brdam, "chaotic forces"); + o_ptr->pval = 1; + } + + /* Disenchantment */ + if (r_ptr->flags4 & RF4_BR_DISE && brpow > 0) + { + brdam = ((brpow / 6) > 500 ? 500 : (brpow / 6)); + + msg_print("You are blasted by raw mana!"); + + if (p_ptr->resist_disen) + { + brdam *= 6; + brdam /= (randint(6) + 6); + } + else + { + (void)apply_disenchant(0); + } + + /* Take damage */ + take_hit(brdam, "raw mana"); + o_ptr->pval = 1; + } + + /* Plasma */ + if (r_ptr->flags4 & RF4_BR_PLAS && brpow > 0) + { + brdam = ((brpow / 6) > 150 ? 150 : (brpow / 6)); + + msg_print("Searing flames engulf the corpse!"); + + /* Resist the damage */ + if (p_ptr->resist_fire || p_ptr->oppose_fire) brdam = (brdam + 2) / 3; + + if (!p_ptr->resist_sound) + { + int k = (randint((brdam > 40) ? 35 : (brdam * 3 / 4 + 5))); + (void)set_stun(p_ptr->stun + k); + } + + /* Take damage */ + take_hit(brdam, "an explosion"); + harmful = TRUE; + o_ptr->pval = 1; + } + + /* Hack -- Jellies are immune to acid only if they are already acidic */ + if (strchr("j", r_ptr->d_char) && (r_ptr->flags3 & RF3_IM_ACID)) + { + dam = damroll(8, 8); + + /* Total Immunity */ + if (!(p_ptr->immune_acid || (dam <= 0))) + { + /* Resist the damage */ + if (p_ptr->resist_acid) dam = (dam + 2) / 3; + if (p_ptr->oppose_acid) dam = (dam + 2) / 3; + + /* Take damage */ + take_hit(dam, "acidic food"); + } + harmful = TRUE; + } + + /* + * Hack -- Jellies, kobolds, spiders, icky things, molds, and mushrooms + * are immune to poison because their body already contains + * poisonous chemicals. + */ + if (strchr("ijkmS,", r_ptr->d_char) && (r_ptr->flags3 & RF3_IM_POIS)) + { + if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + set_poisoned(p_ptr->poisoned + rand_int(15) + 10); + } + harmful = TRUE; + } + + /* + * Bad effects override good effects + * and hacked-up corpses lose intrinsics. + */ + if (!harmful && !cutting && (o_ptr->sval != SV_CORPSE_MEAT)) + { + if (r_ptr->flags3 & RF3_IM_ACID) + { + set_oppose_acid(p_ptr->oppose_acid + rand_int(10) + 10); + } + if (r_ptr->flags3 & RF3_IM_ELEC) + { + set_oppose_elec(p_ptr->oppose_elec + rand_int(10) + 10); + } + if (r_ptr->flags3 & RF3_IM_FIRE) + { + set_oppose_fire(p_ptr->oppose_fire + rand_int(10) + 10); + } + if (r_ptr->flags3 & RF3_IM_COLD) + { + set_oppose_cold(p_ptr->oppose_cold + rand_int(10) + 10); + } + if (r_ptr->flags3 & RF3_IM_POIS) + { + set_oppose_pois(p_ptr->oppose_pois + rand_int(10) + 10); + } + if (r_ptr->flags3 & RF3_RES_NETH) + { + set_protevil(p_ptr->protevil + rand_int(25) + 3 * r_ptr->level); + } + if (r_ptr->flags3 & RF3_RES_PLAS) + { + set_oppose_fire(p_ptr->oppose_fire + rand_int(20) + 20); + } + if (r_ptr->flags2 & RF2_SHAPECHANGER) + { + // DGDGDG (void)set_mimic(20 , rand_int(MIMIC_VALAR)); + } + + if (r_ptr->flags3 & RF3_DEMON) + { + // DGDGDG (void)set_mimic(30 , MIMIC_DEMON); + } + + if (r_ptr->flags3 & RF3_UNDEAD) + { + // DGDGDG (void)set_mimic(30 , MIMIC_VAMPIRE); + } + + if (r_ptr->flags3 & RF3_NO_FEAR) + { + (void)set_afraid(0); + } + if (r_ptr->flags3 & RF3_NO_STUN) + { + (void)set_stun(0); + } + if (r_ptr->flags3 & RF3_NO_CONF) + { + (void)set_confused(0); + } + if (r_ptr->flags6 & RF6_S_THUNDERLORD) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_THUNDERLORD, FALSE); + } + if (r_ptr->flags6 & RF6_S_DEMON) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DEMON, FALSE); + } + if (r_ptr->flags6 & RF6_S_KIN) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_KIN, FALSE); + } + if (r_ptr->flags6 & RF6_S_HI_DEMON) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_DEMON, FALSE); + } + if (r_ptr->flags6 & RF6_S_MONSTER) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, 0, FALSE); + } + if (r_ptr->flags6 & RF6_S_MONSTERS) + { + int k; + for (k = 0; k < 8; k++) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, 0, FALSE); + } + } + if (r_ptr->flags6 & RF6_S_UNDEAD) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD, FALSE); + } + if (r_ptr->flags6 & RF6_S_DRAGON) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DRAGON, FALSE); + } + if (r_ptr->flags6 & RF6_S_ANT) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANT, FALSE); + } + if (r_ptr->flags6 & RF6_S_SPIDER) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_SPIDER, FALSE); + } + if (r_ptr->flags6 & RF6_S_HOUND) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HOUND, FALSE); + } + if (r_ptr->flags6 & RF6_S_HYDRA) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HYDRA, FALSE); + } + if (r_ptr->flags6 & RF6_S_ANGEL) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_ANGEL, FALSE); + } + if (r_ptr->flags6 & RF6_S_HI_DRAGON) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_DRAGON, FALSE); + } + if (r_ptr->flags6 & RF6_S_HI_UNDEAD) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_HI_UNDEAD, FALSE); + } + if (r_ptr->flags6 & RF6_S_WRAITH) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_WRAITH, FALSE); + } + if (r_ptr->flags6 & RF6_S_UNIQUE) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNIQUE, FALSE); + } + } +} + + +/* + * Hook to determine if an object is eatable + */ +static bool item_tester_hook_eatable(object_type *o_ptr) +{ + /* Foods and, well, corpses are edible */ + if ((o_ptr->tval == TV_FOOD) || (o_ptr->tval == TV_CORPSE)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + +/* + * Eat some food (from the pack or floor) + */ +void do_cmd_eat_food(void) +{ + int item, ident, lev, fval = 0; + + object_type *o_ptr; + object_type *q_ptr, forge; + + monster_race *r_ptr; + + cptr q, s; + + bool destroy = TRUE; + + + /* Restrict choices to food */ + item_tester_hook = item_tester_hook_eatable; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Food full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Eat which item? "; + s = "You have nothing to eat."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + /* Sound */ + sound(SOUND_EAT); + + + /* Take a turn */ + energy_use = 100; + + /* Identity not known yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[o_ptr->k_idx].level; + + /* Scripted foods */ + if (process_hooks_ret(HOOK_EAT, "d", "(O)", o_ptr)) + { + ident = process_hooks_return[0].num; + } + /* (not quite) Normal foods */ + else if (o_ptr->tval == TV_FOOD) + { + /* Analyze the food */ + switch (o_ptr->sval) + { + case SV_FOOD_GREAT_HEALTH: + { + p_ptr->hp_mod += 70; + msg_print("As you eat it you begin to feel your life flow getting stronger."); + ident = TRUE; + p_ptr->update |= (PU_HP); + + break; + } + + case SV_FOOD_POISON: + { + if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + if (set_poisoned(p_ptr->poisoned + rand_int(10) + 10)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_BLINDNESS: + { + if (!p_ptr->resist_blind) + { + if (set_blind(p_ptr->blind + rand_int(200) + 200)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_PARANOIA: + { + if (!p_ptr->resist_fear) + { + if (set_afraid(p_ptr->afraid + rand_int(10) + 10)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_CONFUSION: + { + if (!p_ptr->resist_conf) + { + if (set_confused(p_ptr->confused + rand_int(10) + 10)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_HALLUCINATION: + { + if (!p_ptr->resist_chaos) + { + if (set_image(p_ptr->image + rand_int(250) + 250)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_PARALYSIS: + { + if (!p_ptr->free_act) + { + if (set_paralyzed(p_ptr->paralyzed + rand_int(10) + 10)) + { + ident = TRUE; + } + } + + break; + } + + case SV_FOOD_WEAKNESS: + { + take_hit(damroll(6, 6), "poisonous food"); + (void)do_dec_stat(A_STR, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_SICKNESS: + { + take_hit(damroll(6, 6), "poisonous food"); + (void)do_dec_stat(A_CON, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_STUPIDITY: + { + take_hit(damroll(8, 8), "poisonous food"); + (void)do_dec_stat(A_INT, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_NAIVETY: + { + take_hit(damroll(8, 8), "poisonous food"); + (void)do_dec_stat(A_WIS, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_UNHEALTH: + { + take_hit(damroll(10, 10), "poisonous food"); + (void)do_dec_stat(A_CON, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_DISEASE: + { + take_hit(damroll(10, 10), "poisonous food"); + (void)do_dec_stat(A_STR, STAT_DEC_NORMAL); + + ident = TRUE; + + break; + } + + case SV_FOOD_CURE_POISON: + { + if (set_poisoned(0)) ident = TRUE; + + break; + } + + case SV_FOOD_CURE_BLINDNESS: + { + if (set_blind(0)) ident = TRUE; + + break; + } + + case SV_FOOD_CURE_PARANOIA: + { + if (set_afraid(0)) ident = TRUE; + + break; + } + + case SV_FOOD_CURE_CONFUSION: + { + if (set_confused(0)) ident = TRUE; + + break; + } + + case SV_FOOD_CURE_SERIOUS: + { + if (hp_player(damroll(4, 8))) ident = TRUE; + + break; + } + + case SV_FOOD_RESTORE_STR: + { + if (do_res_stat(A_STR, TRUE)) ident = TRUE; + + break; + } + + case SV_FOOD_RESTORE_CON: + { + if (do_res_stat(A_CON, TRUE)) ident = TRUE; + + break; + } + + case SV_FOOD_RESTORING: + { + if (do_res_stat(A_STR, TRUE)) ident = TRUE; + if (do_res_stat(A_INT, TRUE)) ident = TRUE; + if (do_res_stat(A_WIS, TRUE)) ident = TRUE; + if (do_res_stat(A_DEX, TRUE)) ident = TRUE; + if (do_res_stat(A_CON, TRUE)) ident = TRUE; + if (do_res_stat(A_CHR, TRUE)) ident = TRUE; + + break; + } + + case SV_FOOD_FORTUNE_COOKIE: + { + char rumour[80]; + + msg_print("That tastes good."); + msg_print("There is message in the cookie. It says:"); + msg_print(NULL); + + switch (randint(20)) + { + case 1: + { + get_rnd_line("chainswd.txt", rumour); + break; + } + + case 2: + { + get_rnd_line("error.txt", rumour); + break; + } + + case 3: + case 4: + case 5: + { + get_rnd_line("death.txt", rumour); + break; + } + + default: + { + get_rnd_line("rumors.txt", rumour); + break; + } + } + + msg_format("%s", rumour); + msg_print(NULL); + + ident = TRUE; + + break; + } + + + case SV_FOOD_RATION: + case SV_FOOD_BISCUIT: + case SV_FOOD_JERKY: + { + msg_print("That tastes good."); + + ident = TRUE; + + break; + } + + case SV_FOOD_SLIME_MOLD: + { + msg_print("That tastes good."); + + /* 2% chance of getting the mold power */ + if (magik(2)) + { + ADD_POWER(p_ptr->powers_mod, PWR_GROW_MOLD); + p_ptr->update |= PU_POWERS; + } + + ident = TRUE; + + break; + } + + case SV_FOOD_WAYBREAD: + { + msg_print("That tastes very good."); + (void)set_poisoned(0); + (void)hp_player(damroll(4, 8)); + set_food(PY_FOOD_MAX - 1); + + ident = TRUE; + + break; + } + + case SV_FOOD_PINT_OF_ALE: + case SV_FOOD_PINT_OF_WINE: + { + msg_print("That tastes good."); + + ident = TRUE; + + q_ptr = &forge; + object_prep(q_ptr, lookup_kind(TV_BOTTLE, 1)); + q_ptr->number = 1; + object_aware(q_ptr); + object_known(q_ptr); + q_ptr->ident |= IDENT_STOREB; + (void)inven_carry(q_ptr, FALSE); + + break; + } + + case SV_FOOD_ATHELAS: + { + msg_print("A fresh, clean essence rises, driving away wounds and poison."); + + (void)set_poisoned(0); + (void)set_stun(0); + (void)set_cut(0); + if (p_ptr->black_breath) + { + msg_print("The hold of the Black Breath on you is broken!"); + p_ptr->black_breath = FALSE; + } + + ident = TRUE; + + break; + } + } + } + + /* Corpses... */ + else + { + r_ptr = &r_info[o_ptr->pval2]; + + /* Analyse the corpse */ + switch (o_ptr->sval) + { + case SV_CORPSE_CORPSE: + { + bool no_meat = FALSE; + + /* Not all is edible. Apologies if messy. */ + + /* Check weight -- they have to have some meat left */ + if (r_ptr->flags9 & RF9_DROP_SKELETON) + { + if (o_ptr->weight <= (r_ptr->weight * 3) / 5) + { + no_meat = TRUE; + } + } + + /* Non-skeletons are naturally have more allowances */ + else + { + if (o_ptr->weight <= (r_ptr->weight * 7) / 20) + { + no_meat = TRUE; + } + } + + /* Nothing left to eat */ + if (no_meat) + { + msg_print("There is not enough meat."); + return; + } + + + /* Check freshness */ + if (!o_ptr->timeout) msg_print("Ugh! Raw meat!"); + else msg_print("That tastes good."); + + + /* A pound of raw meat */ + o_ptr->pval -= 10; + o_ptr->weight -= 10; + + /* Corpses still have meat on them */ + destroy = FALSE; + + ident = TRUE; + + break; + } + + case SV_CORPSE_HEAD: + { + msg_print("You feel rather sick."); + + /* A pound of raw meat */ + o_ptr->pval -= 10; + o_ptr->weight -= 10; + + /* Corpses still have meat on them */ + destroy = FALSE; + + ident = TRUE; + + break; + } + + case SV_CORPSE_MEAT: + { + /* Just meat */ + if (!o_ptr->timeout) msg_print("You quickly swallow the meat."); + else msg_print("That tastes good."); + + ident = TRUE; + + /* Those darn microorganisms */ + if (!o_ptr->timeout && (o_ptr->weight > o_ptr->pval) && + !(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + set_poisoned(p_ptr->poisoned + rand_int(o_ptr->weight - o_ptr->pval) + + (o_ptr->weight - o_ptr->pval)); + } + + break; + } + } + + corpse_effect(o_ptr, FALSE); + + /* Less nutritious than food rations, but much more of it. */ + fval = (o_ptr->timeout) ? 2000 : 2500; + + /* Those darn microorganisms */ + if (!o_ptr->timeout && (o_ptr->weight - o_ptr->pval > 10) && + !(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + set_poisoned(p_ptr->poisoned + rand_int(o_ptr->weight - o_ptr->pval) + + (o_ptr->weight - o_ptr->pval)); + } + + /* Partially cured */ + if (o_ptr->weight > o_ptr->timeout) + { + /* Adjust the "timeout" without overflowing */ + o_ptr->timeout = (o_ptr->timeout * ((100 * o_ptr->timeout) / o_ptr->weight)) / 100; + } + } + + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* We have tried it */ + object_tried(o_ptr); + + /* The player is now aware of the object */ + if (ident && !object_aware_p(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + if (!fval) fval = o_ptr->pval; + + /* Food can feed the player, in a different ways */ + + /* Vampires */ + if ((PRACE_FLAG(PR1_VAMPIRE)) || (p_ptr->mimic_form == resolve_mimic_name("Vampire"))) + { + /* Reduced nutritional benefit */ + /* (void)set_food(p_ptr->food + (fval / 10)); -- No more */ + msg_print("Mere victuals hold scant sustenance for a being such as yourself."); + + /* Hungry */ + if (p_ptr->food < PY_FOOD_ALERT) + { + msg_print("Your hunger can only be satisfied with fresh blood!"); + } + } + + else if (PRACE_FLAG(PR1_NO_FOOD)) + { + if (PRACE_FLAG(PR1_UNDEAD)) + { + msg_print("The food of mortals is poor sustenance for you."); + } + else + { + msg_print("Food is poor sustenance for you."); + } + set_food(p_ptr->food + ((fval) / 40)); + } + + /* Those living in fresh */ + else + { + (void)set_food(p_ptr->food + fval); + } + + + /* Destroy a food in the pack */ + if (destroy) + { + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy a food on the floor */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } + } +} + + +/* + * Cut a corpse up for convenient storage + */ +void do_cmd_cut_corpse(void) +{ + int item, meat = 0, not_meat = 0; + + object_type *o_ptr; + + object_type *i_ptr; + + object_type object_type_body; + + monster_race *r_ptr; + + cptr q, s; + + + /* Restrict choices to corpses */ + item_tester_tval = TV_CORPSE; + + /* Get an item */ + q = "Hack up which corpse? "; + s = "You have no corpses."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + r_ptr = &r_info[o_ptr->pval2]; + + if ((o_ptr->sval != SV_CORPSE_CORPSE) && (o_ptr->sval != SV_CORPSE_HEAD)) + { + msg_print ("You cannot split that."); + return; + } + + switch (o_ptr->sval) + { + case SV_CORPSE_CORPSE: + { + if (r_ptr->flags9 & RF9_DROP_SKELETON) + { + not_meat = (r_ptr->weight * 3) / 5; + } + else + { + not_meat = (r_ptr->weight * 7) / 20; + } + meat = r_ptr->weight + r_ptr->weight / 10 - not_meat; + + break; + } + + case SV_CORPSE_HEAD: + { + not_meat = r_ptr->weight / 150; + meat = r_ptr->weight / 30 + r_ptr->weight / 300 - not_meat; + + break; + } + } + + if ((o_ptr->weight <= not_meat) || (meat < 10)) + { + msg_print("There is not enough meat."); + return; + } + + /* Hacking 10 pounds off */ + if (meat > 100) meat = 100; + + /* Take a turn */ + energy_use = 100; + + o_ptr->pval -= meat; + o_ptr->weight -= meat; + + msg_print("You hack some meat off the corpse."); + + corpse_effect(o_ptr, TRUE); + + /* Get local object */ + i_ptr = &object_type_body; + + /* Make some meat */ + object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_MEAT)); + + i_ptr->number = meat / 10; + i_ptr->pval2 = o_ptr->pval2; + + /* Length of time before decay */ + i_ptr->pval = 1000 + rand_int(1000); + + if (inven_carry_okay(i_ptr)) + { + inven_carry(i_ptr, TRUE); + } + else + { + drop_near(i_ptr, 0, p_ptr->py, p_ptr->px); + } +} + + +/* + * Use a potion to cure some meat + * + * Salt water works well. + */ +void do_cmd_cure_meat(void) +{ + int item, num, cure; + + object_type *o_ptr; + + object_type *i_ptr; + + cptr q, s; + + + /* Restrict choices to corpses */ + item_tester_tval = TV_CORPSE; + item_tester_hook = item_tester_hook_eatable; + + /* Get some meat */ + q = "Cure which meat? "; + s = "You have no meat to cure."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + /* Restrict choices to potions */ + item_tester_tval = TV_POTION; + + /* Get a potion */ + q = "Use which potion? "; + s = "You have no potions to use."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + i_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + i_ptr = &o_list[0 - item]; + } + + if (i_ptr->number > 1) + { + /* Get a number */ + get_count(1, i_ptr->number); + + /* Save it */ + num = command_arg; + } + else + { + num = 1; + } + + if (num == 0) return; + + /* Take a turn */ + energy_use = 100; + + q = "You soak the meat."; + s = "You soak the meat."; + + switch (i_ptr->sval) + { + case SV_POTION_SALT_WATER: + { + q = "You salt the meat."; + cure = 200 * num; + + break; + } + + case SV_POTION_POISON: + { + q = "You poison the meat."; + cure = 0; + o_ptr->pval /= 2; + if (o_ptr->pval > o_ptr->weight) o_ptr->pval = o_ptr->weight; + + break; + } + + case SV_POTION_CONFUSION: + { + cure = 80 * num; + + break; + } + + case SV_POTION_SLOW_POISON: + { + cure = 20 * num; + + break; + } + + case SV_POTION_CURE_POISON: + { + cure = 45 * num; + + break; + } + + case SV_POTION_DEATH: + { + q = "You ruin the meat."; + cure = 0; + o_ptr->pval /= 10; + if (o_ptr->pval > o_ptr->weight) o_ptr->pval = o_ptr->weight / 2; + + break; + } + + default: + { + cure = 0; + + break; + } + } + + /* Message */ + if (object_known_p(i_ptr)) msg_print(q); + else msg_print(s); + + /* The meat is already spoiling */ + if (((o_ptr->sval == SV_CORPSE_MEAT) && (o_ptr->weight > o_ptr->pval)) || + (o_ptr->weight - o_ptr->pval > 10)) + { + cure = (cure * o_ptr->pval) / (o_ptr->weight * 20); + } + + /* Cure the meat */ + o_ptr->timeout += cure / o_ptr->number; + + if (o_ptr->timeout > o_ptr->pval) o_ptr->timeout = o_ptr->pval; + + /* Use up the potions in the pack */ + if (item >= 0) + { + inven_item_increase(item, 0 - num); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Use up the potions on the floor */ + else + { + floor_item_increase(0 - item, 0 - num); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } +} + + +/* + * Hook to determine if an object is quaffable + */ +static bool item_tester_hook_quaffable(object_type *o_ptr) +{ + if ((o_ptr->tval == TV_POTION) || (o_ptr->tval == TV_POTION2)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + +static bool quaff_potion(int tval, int sval, int pval, int pval2) +{ + int ident = FALSE; + + + /* "Traditional" potions */ + if (tval == TV_POTION) + { + switch (sval) + { + case SV_POTION_WATER: + case SV_POTION_APPLE_JUICE: + case SV_POTION_SLIME_MOLD: + { + msg_print("You feel less thirsty."); + ident = TRUE; + + break; + } + + case SV_POTION_SLOWNESS: + { + if (set_slow(p_ptr->slow + randint(25) + 15)) ident = TRUE; + + break; + } + + case SV_POTION_SALT_WATER: + { + msg_print("The potion makes you vomit!"); + (void)set_food(PY_FOOD_STARVE - 1); + (void)set_poisoned(0); + (void)set_paralyzed(p_ptr->paralyzed + 4); + ident = TRUE; + + break; + } + + case SV_POTION_POISON: + { + if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) + { + if (set_poisoned(p_ptr->poisoned + rand_int(15) + 10)) + { + ident = TRUE; + } + } + + break; + } + + case SV_POTION_BLINDNESS: + { + if (!p_ptr->resist_blind) + { + if (set_blind(p_ptr->blind + rand_int(100) + 100)) + { + ident = TRUE; + } + } + + break; + } + + /* Booze */ + case SV_POTION_CONFUSION: + { + if (!((p_ptr->resist_conf) || (p_ptr->resist_chaos))) + { + if (set_confused(p_ptr->confused + rand_int(20) + 15)) + { + ident = TRUE; + } + if (randint(2) == 1) + { + if (set_image(p_ptr->image + rand_int(150) + 150)) + { + ident = TRUE; + } + } + if (randint(13) == 1) + { + ident = TRUE; + if (randint(3) == 1) lose_all_info(); + else wiz_dark(); + teleport_player(100); + wiz_dark(); + msg_print("You wake up elsewhere with a sore head..."); + msg_print("You can't remember a thing, or how you got here!"); + } + } + + break; + } + + case SV_POTION_SLEEP: + { + if (!p_ptr->free_act) + { + if (set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4)) + { + ident = TRUE; + } + } + + break; + } + + case SV_POTION_LOSE_MEMORIES: + { + if (!p_ptr->hold_life && (p_ptr->exp > 0)) + { + msg_print("You feel your memories fade."); + lose_exp(p_ptr->exp / 4); + ident = TRUE; + } + + break; + } + + case SV_POTION_RUINATION: + { + msg_print("Your nerves and muscles feel weak and lifeless!"); + take_hit(damroll(10, 10), "a potion of Ruination"); + (void)dec_stat(A_DEX, 25, TRUE); + (void)dec_stat(A_WIS, 25, TRUE); + (void)dec_stat(A_CON, 25, TRUE); + (void)dec_stat(A_STR, 25, TRUE); + (void)dec_stat(A_CHR, 25, TRUE); + (void)dec_stat(A_INT, 25, TRUE); + ident = TRUE; + + break; + } + + case SV_POTION_DEC_STR: + { + if (do_dec_stat(A_STR, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DEC_INT: + { + if (do_dec_stat(A_INT, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DEC_WIS: + { + if (do_dec_stat(A_WIS, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DEC_DEX: + { + if (do_dec_stat(A_DEX, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DEC_CON: + { + if (do_dec_stat(A_CON, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DEC_CHR: + { + if (do_dec_stat(A_CHR, STAT_DEC_NORMAL)) ident = TRUE; + + break; + } + + case SV_POTION_DETONATIONS: + { + msg_print("Massive explosions rupture your body!"); + take_hit(damroll(50, 20), "a potion of Detonation"); + (void)set_stun(p_ptr->stun + 75); + (void)set_cut(p_ptr->cut + 5000); + ident = TRUE; + + break; + } + + case SV_POTION_DEATH: + { + msg_print("A feeling of Death flows through your body."); + take_hit(5000, "a potion of Death"); + ident = TRUE; + + break; + } + + case SV_POTION_INFRAVISION: + { + if (set_tim_infra(p_ptr->tim_infra + 100 + randint(100))) + { + ident = TRUE; + } + + break; + } + + case SV_POTION_DETECT_INVIS: + { + if (set_tim_invis(p_ptr->tim_invis + 12 + randint(12))) + { + ident = TRUE; + } + + break; + } + + case SV_POTION_SLOW_POISON: + { + if (set_poisoned(p_ptr->poisoned / 2)) ident = TRUE; + + break; + } + + case SV_POTION_CURE_POISON: + { + if (set_poisoned(0)) ident = TRUE; + + break; + } + + case SV_POTION_BOLDNESS: + { + if (set_afraid(0)) ident = TRUE; + + break; + } + + case SV_POTION_SPEED: + { + if (!p_ptr->fast) + { + if (set_fast(randint(25) + 15, 10)) ident = TRUE; + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + + break; + } + + case SV_POTION_RESIST_HEAT: + { + if (set_oppose_fire(p_ptr->oppose_fire + randint(10) + 10)) + { + ident = TRUE; + } + + break; + } + + case SV_POTION_RESIST_COLD: + { + if (set_oppose_cold(p_ptr->oppose_cold + randint(10) + 10)) + { + ident = TRUE; + } + + break; + } + + case SV_POTION_HEROISM: + { + if (set_afraid(0)) ident = TRUE; + if (set_hero(p_ptr->hero + randint(25) + 25)) ident = TRUE; + if (hp_player(10)) ident = TRUE; + + break; + } + + case SV_POTION_BESERK_STRENGTH: + { + if (set_afraid(0)) ident = TRUE; + if (set_shero(p_ptr->shero + randint(25) + 25)) ident = TRUE; + if (hp_player(30)) ident = TRUE; + + break; + } + + case SV_POTION_CURE_LIGHT: + { + if (hp_player(damroll(2, 8))) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_cut(p_ptr->cut - 10)) ident = TRUE; + + break; + } + + case SV_POTION_CURE_SERIOUS: + { + if (hp_player(damroll(4, 8))) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_cut((p_ptr->cut / 2) - 50)) ident = TRUE; + + break; + } + + case SV_POTION_CURE_CRITICAL: + { + if (hp_player(damroll(6, 8))) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + + break; + } + + case SV_POTION_HEALING: + { + if (hp_player(300)) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + + break; + } + + case SV_POTION_STAR_HEALING: + { + if (hp_player(1200)) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + + break; + } + + case SV_POTION_LIFE: + { + msg_print("You feel life flow through your body!"); + restore_level(); + hp_player(5000); + (void)set_poisoned(0); + (void)set_blind(0); + (void)set_confused(0); + (void)set_image(0); + (void)set_stun(0); + (void)set_cut(0); + (void)do_res_stat(A_STR, TRUE); + (void)do_res_stat(A_CON, TRUE); + (void)do_res_stat(A_DEX, TRUE); + (void)do_res_stat(A_WIS, TRUE); + (void)do_res_stat(A_INT, TRUE); + (void)do_res_stat(A_CHR, TRUE); + if (p_ptr->black_breath) + { + msg_print("The hold of the Black Breath on you is broken!"); + } + p_ptr->black_breath = FALSE; + ident = TRUE; + + break; + } + + case SV_POTION_RESTORE_MANA: + { + if (p_ptr->csp < p_ptr->msp) + { + p_ptr->csp = p_ptr->msp; + p_ptr->csp_frac = 0; + msg_print("Your feel your head clear."); + p_ptr->redraw |= (PR_MANA); + p_ptr->window |= (PW_PLAYER); + ident = TRUE; + } + + break; + } + + case SV_POTION_RESTORE_EXP: + { + if (restore_level()) ident = TRUE; + + break; + } + + case SV_POTION_RES_STR: + { + if (do_res_stat(A_STR, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_RES_INT: + { + if (do_res_stat(A_INT, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_RES_WIS: + { + if (do_res_stat(A_WIS, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_RES_DEX: + { + if (do_res_stat(A_DEX, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_RES_CON: + { + if (do_res_stat(A_CON, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_RES_CHR: + { + if (do_res_stat(A_CHR, TRUE)) ident = TRUE; + + break; + } + + case SV_POTION_INC_STR: + { + if (do_inc_stat(A_STR)) ident = TRUE; + + break; + } + + case SV_POTION_INC_INT: + { + if (do_inc_stat(A_INT)) ident = TRUE; + + break; + } + + case SV_POTION_INC_WIS: + { + if (do_inc_stat(A_WIS)) ident = TRUE; + + break; + } + + case SV_POTION_INC_DEX: + { + if (do_inc_stat(A_DEX)) ident = TRUE; + + break; + } + + case SV_POTION_INC_CON: + { + if (do_inc_stat(A_CON)) ident = TRUE; + + break; + } + + case SV_POTION_INC_CHR: + { + if (do_inc_stat(A_CHR)) ident = TRUE; + + break; + } + + case SV_POTION_AUGMENTATION: + { + if (do_inc_stat(A_STR)) ident = TRUE; + if (do_inc_stat(A_INT)) ident = TRUE; + if (do_inc_stat(A_WIS)) ident = TRUE; + if (do_inc_stat(A_DEX)) ident = TRUE; + if (do_inc_stat(A_CON)) ident = TRUE; + if (do_inc_stat(A_CHR)) ident = TRUE; + + break; + } + + case SV_POTION_ENLIGHTENMENT: + { + msg_print("An image of your surroundings forms in your mind..."); + wiz_lite(); + ident = TRUE; + + break; + } + + case SV_POTION_STAR_ENLIGHTENMENT: + { + msg_print("You begin to feel more enlightened..."); + msg_print(NULL); + wiz_lite_extra(); + (void)do_inc_stat(A_INT); + (void)do_inc_stat(A_WIS); + (void)detect_traps(DEFAULT_RADIUS); + (void)detect_doors(DEFAULT_RADIUS); + (void)detect_stairs(DEFAULT_RADIUS); + (void)detect_treasure(DEFAULT_RADIUS); + (void)detect_objects_gold(DEFAULT_RADIUS); + (void)detect_objects_normal(DEFAULT_RADIUS); + identify_pack(); + self_knowledge(NULL); + ident = TRUE; + + break; + } + + case SV_POTION_SELF_KNOWLEDGE: + { + msg_print("You begin to know yourself a little better..."); + msg_print(NULL); + self_knowledge(NULL); + ident = TRUE; + + break; + } + + case SV_POTION_EXPERIENCE: + { + if (p_ptr->exp < PY_MAX_EXP) + { + s32b ee = (p_ptr->exp / 2) + 10; + if (ee > 100000L) ee = 100000L; + msg_print("You feel more experienced."); + gain_exp(ee); + ident = TRUE; + } + + break; + } + + case SV_POTION_RESISTANCE: + { + (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20); + (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20); + (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20); + (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20); + (void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20); + ident = TRUE; + + break; + } + + case SV_POTION_CURING: + { + if (hp_player(50)) ident = TRUE; + if (set_blind(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + if (set_image(0)) ident = TRUE; + if (heal_insanity(50)) ident = TRUE; + + break; + } + + case SV_POTION_INVULNERABILITY: + { + (void)set_invuln(p_ptr->invuln + randint(7) + 7); + ident = TRUE; + + break; + } + + case SV_POTION_NEW_LIFE: + { + do_cmd_rerate(); +#if 0 /* DGDGDGDG -- No, losing corruption should be near impossible, maybe a quest to do it once but thats it */ + lose_all_corruptions(); +#endif + ident = TRUE; + + break; + } + + case SV_POTION_BLOOD: + { + msg_print("You feel the blood of life running through your veins!"); + ident = TRUE; + p_ptr->allow_one_death++; + + break; + } + + case SV_POTION_MUTATION: + { + msg_print("You feel the dark corruptions of Morgoth coming over you!"); + gain_random_corruption(0); + ident = TRUE; + break; + } + + case SV_POTION_INVIS: + { + int t = 30 + randint(30); + + if (set_invis(p_ptr->tim_invis + t, 35)) + { + ident = TRUE; + } + set_tim_invis(p_ptr->tim_invis + t); + + break; + } + + case SV_POTION_LEARNING: + { + p_ptr->skill_points += rand_range(4, 10 + luck( -4, 4)); + cmsg_format(TERM_L_GREEN, "You can increase %d more skills.", p_ptr->skill_points); + + break; + } + + default: + { + break; + } + } + } + + /* "Duplicate" potions */ + else + { + switch (sval) + { + case SV_POTION2_MIMIC: + { + if (!p_ptr->mimic_form) + { + s32b time; + + call_lua("get_mimic_rand_dur", "(d)", "d", pval2, &time); + + set_mimic(time, pval2, (p_ptr->lev * 2) / 3); + + /* Redraw title */ + p_ptr->redraw |= (PR_TITLE); + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + ident = TRUE; + } + + break; + } + + case SV_POTION2_CURE_LIGHT_SANITY: + { + if (heal_insanity(damroll(4, 8))) ident = TRUE; + + break; + } + + case SV_POTION2_CURE_SERIOUS_SANITY: + { + if (heal_insanity(damroll(8, 8))) ident = TRUE; + + break; + } + + case SV_POTION2_CURE_CRITICAL_SANITY: + { + if (heal_insanity(damroll(12, 8))) ident = TRUE; + + break; + } + + case SV_POTION2_CURE_SANITY: + { + if (heal_insanity(damroll(10, 100))) ident = TRUE; + + break; + } + + default: + { + break; + } + } + } + + return (ident); +} + + +/* + * Quaff a potion (from the pack or the floor) + */ +void do_cmd_quaff_potion(void) +{ + int item, ident, lev; + + object_type *o_ptr; + + object_type *q_ptr, forge; + + cptr q, s; + + + /* Restrict choices to potions */ + item_tester_hook = item_tester_hook_quaffable; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Potion full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Quaff which potion? "; + s = "You have no potions to quaff."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + + /* Sound */ + sound(SOUND_QUAFF); + + + /* Take a turn */ + energy_use = 100; + + /* Not identified yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[o_ptr->k_idx].level; + + /* Analyze the potion */ + if (process_hooks_ret(HOOK_QUAFF, "d", "(O)", o_ptr)) + { + ident = process_hooks_return[0].num; + } + else + { + ident = quaff_potion(o_ptr->tval, o_ptr->sval, o_ptr->pval, o_ptr->pval2); + } + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* The item has been tried */ + object_tried(o_ptr); + + /* An identification was made */ + if (ident && !object_aware_p(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + if (get_skill(SKILL_ALCHEMY)) + { + if (item >= 0) + { + q_ptr = &forge; + object_prep(q_ptr, lookup_kind(TV_BOTTLE, 1)); + q_ptr->number = 1; + object_aware(q_ptr); + object_known(q_ptr); + + q_ptr->ident |= IDENT_STOREB; + + (void)inven_carry(q_ptr, FALSE); + } + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Potions can feed the player */ + (void)set_food(p_ptr->food + o_ptr->pval); + + + /* Destroy a potion in the pack */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy a potion on the floor */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } +} + + +/* + * Drink from a fountain + */ +void do_cmd_drink_fountain(void) +{ + cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px]; + + bool ident; + + int tval, sval, pval = 0; + + int i; + + char ch; + + + /* Is the fountain empty? */ + if (c_ptr->special2 <= 0) + { + msg_print("The fountain is dried out."); + return; + } + + /* We quaff or we fill ? */ + if (!get_com("Do you want to [Q]uaff or [F]ill from the fountain? ", &ch)) + { + return; + } + + if ((ch == 'F') || (ch == 'f')) + { + do_cmd_fill_bottle(); + + return; + } + + else if ((ch == 'Q') || (ch == 'q')) + { + if (c_ptr->special <= SV_POTION_LAST) + { + tval = TV_POTION; + sval = c_ptr->special; + } + else + { + tval = TV_POTION2; + sval = c_ptr->special - SV_POTION_LAST; + } + + for (i = 0; i < max_k_idx; i++) + { + object_kind *k_ptr = &k_info[i]; + + if (k_ptr->tval != tval) continue; + if (k_ptr->sval != sval) continue; + + pval = k_ptr->pval; + + break; + } + + ident = quaff_potion(tval, sval, pval, 0); + + c_ptr->special2--; + + if (c_ptr->special2 <= 0) + { + cave_set_feat(p_ptr->py, p_ptr->px, FEAT_EMPTY_FOUNTAIN); + } + + if (ident) c_ptr->info |= CAVE_IDNT; + } +} + + +/* + * Fill an empty bottle + */ +void do_cmd_fill_bottle(void) +{ + cave_type *c_ptr = &cave[p_ptr->py][p_ptr->px]; + + int tval, sval, item, amt = 1; + + object_type *q_ptr, *o_ptr, forge; + + cptr q, s; + + /* Is the fountain empty? */ + /* + * This check is redundant as it is done in do_cmd_drink_fountain() + * but I keep this because someone might want to call this directly. + * -- Kusunose + */ + if (c_ptr->special2 <= 0) + { + msg_print("The fountain has dried up."); + return; + } + + /* Determine the tval/sval of the potion */ + if (c_ptr->special <= SV_POTION_LAST) + { + tval = TV_POTION; + sval = c_ptr->special; + } + else + { + tval = TV_POTION2; + sval = c_ptr->special - SV_POTION_LAST; + } + + /* Restrict choices to bottles */ + item_tester_tval = TV_BOTTLE; + + /* Get an item */ + q = "Fill which bottle? "; + s = "You have no bottles to fill."; + if (!get_item(&item, q, s, (USE_INVEN))) return; + o_ptr = &p_ptr->inventory[item]; + + /* Find out how many the player wants */ + if (o_ptr->number > 1) + { + /* Get a quantity */ + amt = get_quantity(NULL, o_ptr->number); + + /* Allow user abort */ + if (amt <= 0) return; + } + + if (amt > c_ptr->special2) amt = c_ptr->special2; + + /* Destroy bottles in the pack */ + if (item >= 0) + { + inven_item_increase(item, -amt); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy bottles on the floor */ + else + { + floor_item_increase(0 - item, -amt); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } + + /* Create the potion */ + q_ptr = &forge; + object_prep(q_ptr, lookup_kind(tval, sval)); + q_ptr->number = amt; + + if (c_ptr->info & CAVE_IDNT) + { + object_aware(q_ptr); + object_known(q_ptr); + } + + inven_carry(q_ptr, TRUE); + + c_ptr->special2 -= amt; + + if (c_ptr->special2 <= 0) + { + cave_set_feat(p_ptr->py, p_ptr->px, FEAT_EMPTY_FOUNTAIN); + } + + return; +} + + +/* + * Curse the players armor + */ +bool curse_armor(void) +{ + object_type *o_ptr; + + char o_name[80]; + + + /* Curse the body armor */ + o_ptr = &p_ptr->inventory[INVEN_BODY]; + + /* Nothing to curse */ + if (!o_ptr->k_idx) return (FALSE); + + + /* Describe */ + object_desc(o_name, o_ptr, FALSE, 3); + + /* Attempt a saving throw for artifacts */ + if (((o_ptr->art_name) || artifact_p(o_ptr)) && (rand_int(100) < 50)) + { + /* Cool */ + msg_format("A terrible black aura tries to surround your armour, " + "but your %s resists the effects!", o_name); + } + + /* not artifact or failed save... */ + else + { + /* Oops */ + msg_format("A terrible black aura blasts your %s!", o_name); + + /* Blast the armor */ + o_ptr->name1 = 0; + o_ptr->name2 = EGO_BLASTED; + o_ptr->to_a = 0 - randint(5) - randint(5); + o_ptr->to_h = 0; + o_ptr->to_d = 0; + o_ptr->ac = 0; + o_ptr->dd = 0; + o_ptr->ds = 0; + o_ptr->art_flags1 = 0; + o_ptr->art_flags2 = 0; + o_ptr->art_flags3 = 0; + o_ptr->art_flags4 = 0; + + /* Curse it */ + o_ptr->ident |= (IDENT_CURSED); + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Recalculate mana */ + p_ptr->update |= (PU_MANA); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + } + + return (TRUE); +} + + +/* + * Curse the players weapon + */ +bool curse_weapon(void) +{ + object_type *o_ptr; + + char o_name[80]; + + + /* Curse the weapon */ + o_ptr = &p_ptr->inventory[INVEN_WIELD]; + + /* Nothing to curse */ + if (!o_ptr->k_idx) return (FALSE); + + + /* Describe */ + object_desc(o_name, o_ptr, FALSE, 3); + + /* Attempt a saving throw */ + if ((artifact_p(o_ptr) || o_ptr->art_name) && (rand_int(100) < 50)) + { + /* Cool */ + msg_format("A terrible black aura tries to surround your weapon, " + "but your %s resists the effects!", o_name); + } + + /* not artifact or failed save... */ + else + { + /* Oops */ + msg_format("A terrible black aura blasts your %s!", o_name); + + /* Shatter the weapon */ + o_ptr->name1 = 0; + o_ptr->name2 = EGO_SHATTERED; + o_ptr->to_h = 0 - randint(5) - randint(5); + o_ptr->to_d = 0 - randint(5) - randint(5); + o_ptr->to_a = 0; + o_ptr->ac = 0; + o_ptr->dd = 0; + o_ptr->ds = 0; + o_ptr->art_flags1 = 0; + o_ptr->art_flags2 = 0; + o_ptr->art_flags3 = 0; + o_ptr->art_flags4 = 0; + + + /* Curse it */ + o_ptr->ident |= (IDENT_CURSED); + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Recalculate mana */ + p_ptr->update |= (PU_MANA); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + } + + /* Notice */ + return (TRUE); +} + + +/* + * Hook to determine if an object is readable + */ +static bool item_tester_hook_readable(object_type *o_ptr) +{ + if ((o_ptr->tval == TV_SCROLL) || (o_ptr->tval == TV_PARCHMENT)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + +/* + * Read a scroll (from the pack or floor). + * + * Certain scrolls can be "aborted" without losing the scroll. These + * include scrolls with no effects but recharge or identify, which are + * cancelled before use. XXX Reading them still takes a turn, though. + */ +void do_cmd_read_scroll(void) +{ + int item, k, used_up, ident, lev; + + object_type *o_ptr; + + object_type *q_ptr, forge; + + cptr q, s; + + + /* Check some conditions */ + if (p_ptr->blind) + { + msg_print("You can't see anything."); + return; + } + + if (no_lite()) + { + msg_print("You have no light by which to read."); + return; + } + + if (p_ptr->confused) + { + msg_print("You are too confused!"); + return; + } + + + /* Restrict choices to scrolls */ + item_tester_hook = item_tester_hook_readable; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Scroll full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Read which scroll? "; + s = "You have no scrolls to read."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + + /* Take a turn */ + energy_use = 100; + + /* Not identified yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[o_ptr->k_idx].level; + + /* Assume the scroll will get used up */ + used_up = TRUE; + + /* New scripts, can override the ingame code */ + if (process_hooks_ret(HOOK_READ, "dd", "(O)", o_ptr)) + { + used_up = process_hooks_return[0].num; + ident = process_hooks_return[1].num; + } + /* Traditional scrolls */ + else if (o_ptr->tval == TV_SCROLL) + { + /* Analyze the scroll */ + switch (o_ptr->sval) + { + case SV_SCROLL_MASS_RESURECTION: + { + int k; + + ident = TRUE; + msg_print("You feel the souls of the dead coming back " + "from the Halls of Mandos."); + + for (k = 0; k < max_r_idx; k++) + { + monster_race *r_ptr = &r_info[k]; + + if (r_ptr->flags1 & RF1_UNIQUE && + !(r_ptr->flags9 & RF9_SPECIAL_GENE)) + { + r_ptr->max_num = 1; + } + } + + break; + } + + case SV_SCROLL_DEINCARNATION: + { + if (!get_check("Do you really want to leave your body? " + "(beware, it'll be destroyed!) ")) + { + used_up = FALSE; + break; + } + + do_cmd_leave_body(FALSE); + + ident = TRUE; + used_up = TRUE; + + break; + } + + /* original didn't set used_up flag ??? -- pelpel */ + case SV_SCROLL_RESET_RECALL: + { + if (!reset_recall(TRUE)) + { + used_up = FALSE; + break; + } + + msg_format("Recall reset to %s at level %d.", + d_info[p_ptr->recall_dungeon].name + d_name, + max_dlv[p_ptr->recall_dungeon]); + + ident = TRUE; + used_up = TRUE; + + break; + } + + case SV_SCROLL_DIVINATION: + { + int i, count = 0; + char buf[120]; + + while (count < 1000) + { + count++; + i = rand_int(MAX_FATES); + if (!fates[i].fate) continue; + if (fates[i].know) continue; + + msg_print("A message appears on the scroll. It says:"); + msg_print(NULL); + + fate_desc(buf, i); + msg_format("%s", buf); + + msg_print(NULL); + msg_print("The scroll disappears in a puff of smoke!"); + + fates[i].know = TRUE; + ident = TRUE; + + break; + } + + break; + } + + case SV_SCROLL_DARKNESS: + { + if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark)) + { + (void)set_blind(p_ptr->blind + 3 + randint(5)); + } + if (unlite_area(10, 3)) ident = TRUE; + + break; + } + + case SV_SCROLL_AGGRAVATE_MONSTER: + { + msg_print("There is a high-pitched humming noise."); + aggravate_monsters(1); + + ident = TRUE; + + break; + } + + case SV_SCROLL_CURSE_ARMOR: + { + if (curse_armor()) ident = TRUE; + + break; + } + + case SV_SCROLL_CURSE_WEAPON: + { + if (curse_weapon()) ident = TRUE; + + break; + } + + case SV_SCROLL_SUMMON_MONSTER: + { + for (k = 0; k < randint(3); k++) + { + if (summon_specific(p_ptr->py, p_ptr->px, dun_level, 0)) + { + ident = TRUE; + } + } + + break; + } + + case SV_SCROLL_SUMMON_MINE: + { + if (summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_MINE, FALSE)) + { + ident = TRUE; + } + + break; + } + + case SV_SCROLL_SUMMON_UNDEAD: + { + for (k = 0; k < randint(3); k++) + { + if (summon_specific(p_ptr->py, p_ptr->px, dun_level, SUMMON_UNDEAD)) + { + ident = TRUE; + } + } + + break; + } + + case SV_SCROLL_TRAP_CREATION: + { + if (trap_creation()) ident = TRUE; + + break; + } + + case SV_SCROLL_PHASE_DOOR: + { + teleport_player(10); + + ident = TRUE; + + break; + } + + case SV_SCROLL_TELEPORT: + { + teleport_player(100); + + ident = TRUE; + + break; + } + + case SV_SCROLL_TELEPORT_LEVEL: + { + (void)teleport_player_level(); + + ident = TRUE; + + break; + } + + case SV_SCROLL_WORD_OF_RECALL: + { + if ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? ")) + { + used_up = FALSE; + } + else + { + recall_player(21, 15); + + ident = TRUE; + } + + break; + } + + case SV_SCROLL_IDENTIFY: + { + ident = TRUE; + + if (!ident_spell()) used_up = FALSE; + + break; + } + + case SV_SCROLL_STAR_IDENTIFY: + { + ident = TRUE; + + if (!identify_fully()) used_up = FALSE; + + break; + } + + case SV_SCROLL_REMOVE_CURSE: + { + if (remove_curse()) + { + msg_print("You feel as if someone is watching over you."); + ident = TRUE; + } + + break; + } + + case SV_SCROLL_STAR_REMOVE_CURSE: + { + remove_all_curse(); + + ident = TRUE; + + break; + } + + case SV_SCROLL_ENCHANT_ARMOR: + { + ident = TRUE; + + if (!enchant_spell(0, 0, 1, 0)) used_up = FALSE; + + break; + } + + case SV_SCROLL_ENCHANT_WEAPON_TO_HIT: + { + if (!enchant_spell(1, 0, 0, 0)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_ENCHANT_WEAPON_TO_DAM: + { + if (!enchant_spell(0, 1, 0, 0)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_ENCHANT_WEAPON_PVAL: + { + if (!enchant_spell(0, 0, 0, 1)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_STAR_ENCHANT_ARMOR: + { + if (!enchant_spell(0, 0, randint(3) + 2, 0)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_STAR_ENCHANT_WEAPON: + { + if (!enchant_spell(randint(3), randint(3), 0, 0)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_RECHARGING: + { + if (!recharge(60)) used_up = FALSE; + + ident = TRUE; + + break; + } + + case SV_SCROLL_LIGHT: + { + if (lite_area(damroll(2, 8), 2)) ident = TRUE; + + break; + } + + case SV_SCROLL_MAPPING: + { + map_area(); + + ident = TRUE; + + break; + } + + case SV_SCROLL_DETECT_GOLD: + { + if (detect_treasure(DEFAULT_RADIUS)) ident = TRUE; + if (detect_objects_gold(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_SCROLL_DETECT_ITEM: + { + if (detect_objects_normal(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_SCROLL_DETECT_TRAP: + { + if (detect_traps(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_SCROLL_DETECT_DOOR: + { + if (detect_doors(DEFAULT_RADIUS)) ident = TRUE; + if (detect_stairs(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_SCROLL_DETECT_INVIS: + { + if (detect_monsters_invis(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_SCROLL_SATISFY_HUNGER: + { + if (set_food(PY_FOOD_MAX - 1)) ident = TRUE; + + break; + } + + case SV_SCROLL_BLESSING: + { + if (set_blessed(p_ptr->blessed + randint(12) + 6)) ident = TRUE; + + break; + } + + case SV_SCROLL_HOLY_CHANT: + { + if (set_blessed(p_ptr->blessed + randint(24) + 12)) ident = TRUE; + + break; + } + + case SV_SCROLL_HOLY_PRAYER: + { + if (set_blessed(p_ptr->blessed + randint(48) + 24)) ident = TRUE; + + break; + } + + case SV_SCROLL_MONSTER_CONFUSION: + { + if (p_ptr->confusing == 0) + { + msg_print("Your hands begin to glow."); + p_ptr->confusing = TRUE; + ident = TRUE; + } + + break; + } + + case SV_SCROLL_PROTECTION_FROM_EVIL: + { + k = 3 * p_ptr->lev; + if (set_protevil(p_ptr->protevil + randint(25) + k)) ident = TRUE; + + break; + } + + case SV_SCROLL_RUNE_OF_PROTECTION: + { + warding_glyph(); + + ident = TRUE; + + break; + } + + case SV_SCROLL_TRAP_DOOR_DESTRUCTION: + { + if (destroy_doors_touch()) ident = TRUE; + + break; + } + + case SV_SCROLL_STAR_DESTRUCTION: + { + /* Prevent destruction of quest levels and town */ + if (!is_quest(dun_level) && dun_level) + { + destroy_area(p_ptr->py, p_ptr->px, 15, TRUE, FALSE); + } + else + { + msg_print("The dungeon trembles..."); + } + + ident = TRUE; + + break; + } + + case SV_SCROLL_DISPEL_UNDEAD: + { + if (dispel_undead(60)) ident = TRUE; + + break; + } + + case SV_SCROLL_GENOCIDE: + { + (void)genocide(TRUE); + + ident = TRUE; + + break; + } + + case SV_SCROLL_MASS_GENOCIDE: + { + (void)mass_genocide(TRUE); + + ident = TRUE; + + break; + } + + case SV_SCROLL_ACQUIREMENT: + { + acquirement(p_ptr->py, p_ptr->px, 1, TRUE, FALSE); + + ident = TRUE; + + break; + } + + case SV_SCROLL_STAR_ACQUIREMENT: + { + acquirement(p_ptr->py, p_ptr->px, randint(2) + 1, TRUE, FALSE); + + ident = TRUE; + + break; + } + + /* ZAngband scrolls */ + case SV_SCROLL_FIRE: + { + fire_ball(GF_FIRE, 0, 150, 4); + + /* + * Note: "Double" damage since it is centered on + * the player ... + */ + if (!p_ptr->oppose_fire && !p_ptr->resist_fire && + !p_ptr->immune_fire) + { + take_hit(50 + randint(50) + (p_ptr->sensible_fire) ? 20 : 0, + "a Scroll of Fire"); + } + + ident = TRUE; + + break; + } + + + case SV_SCROLL_ICE: + { + fire_ball(GF_ICE, 0, 175, 4); + + if (!p_ptr->oppose_cold && !p_ptr->resist_cold && + !p_ptr->immune_cold) + { + take_hit(100 + randint(100), "a Scroll of Ice"); + } + + ident = TRUE; + + break; + } + + case SV_SCROLL_CHAOS: + { + fire_ball(GF_CHAOS, 0, 222, 4); + + if (!p_ptr->resist_chaos) + { + take_hit(111 + randint(111), "a Scroll of Chaos"); + } + + ident = TRUE; + + break; + } + + case SV_SCROLL_RUMOR: + { + char rumour[80]; + + msg_print("There is message on the scroll. It says:"); + msg_print(NULL); + + /* Pick random text */ + switch (randint(20)) + { + case 1: + { + get_rnd_line("chainswd.txt", rumour); + + break; + } + + case 2: + { + get_rnd_line("error.txt", rumour); + + break; + } + + case 3: + case 4: + case 5: + { + get_rnd_line("death.txt", rumour); + + break; + } + + default: + { + get_rnd_line("rumors.txt", rumour); + + break; + } + } + + msg_format("%s", rumour); + msg_print(NULL); + + msg_print("The scroll disappears in a puff of smoke!"); + + ident = TRUE; + + break; + } + + case SV_SCROLL_ARTIFACT: + { + ident = TRUE; + + if (!artifact_scroll()) used_up = FALSE; + + break; + } + + default: + { + break; + } + } + } + + /* Other readable items */ + else + { + /* Maps */ + if (o_ptr->sval >= 200) + { + int i, n; + char buf[80], fil[20]; + + strnfmt(fil, 20, "book-%d.txt", o_ptr->sval); + + n = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, -1)); + + /* Parse all the fields */ + for (i = 0; i < n; i += 4) + { + /* Grab the fields */ + int x = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 0)); + int y = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 1)); + int w = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 2)); + int h = atoi(get_line(fil, ANGBAND_DIR_FILE, buf, i + 3)); + + reveal_wilderness_around_player(y, x, h, w); + } + } + + /* Normal parchements */ + else + { + /* Save screen */ + screen_save(); + + /* Get the filename */ + q = format("book-%d.txt", o_ptr->sval); + + /* Peruse the help file */ + (void)show_file(q, NULL, 0, 0); + + /* Load screen */ + screen_load(); + + if (o_ptr->sval >= 100) + { + inscription_info[o_ptr->sval - 100].know = TRUE; + } + + used_up = FALSE; + } + } + + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* The item was tried */ + object_tried(o_ptr); + + /* An identification was made */ + if (ident && !object_aware_p(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Hack -- allow certain scrolls to be "preserved" */ + if (!used_up) return; + + sound(SOUND_SCROLL); + + /* Destroy a scroll in the pack */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy a scroll on the floor */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } + + if (get_skill(SKILL_ALCHEMY)) + { + if (item >= 0) + { + q_ptr = &forge; + object_prep(q_ptr, lookup_kind(TV_SCROLL, SV_SCROLL_NOTHING)); + object_aware(q_ptr); + object_known(q_ptr); + + q_ptr->ident |= IDENT_STOREB; + + (void)inven_carry(q_ptr, FALSE); + } + } +} + + + +/* Set the 'stick mode' on */ +void set_stick_mode(object_type *o_ptr) +{ + s32b bonus = o_ptr->pval3 & 0xFFFF; + s32b max = o_ptr->pval3 >> 16; + + exec_lua(format("get_level_use_stick = %d; get_level_max_stick = %d", bonus, max)); +} +/* Remove 'stick mode' */ +void unset_stick_mode() +{ + exec_lua("get_level_use_stick = -1; get_level_max_stick = -1"); +} + + +/* + * Use a staff. -RAK- + * + * One charge of one staff disappears. + * + * Hack -- staffs of identify can be "cancelled". + */ +void do_cmd_use_staff(void) +{ + int item, ident, chance; + + s32b obvious, use_charge; + + object_type *o_ptr; + + u32b f1, f2, f3, f4, f5, esp; + + cptr q, s; + + /* No magic */ + if (p_ptr->antimagic) + { + msg_print("Your anti-magic field disrupts any magic attempts."); + return; + } + + /* Restrict choices to wands */ + item_tester_tval = TV_STAFF; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Staff full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Use which staff? "; + s = "You have no staff to use."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + + /* Mega-Hack -- refuse to use a pile from the ground */ + if ((item < 0) && (o_ptr->number > 1)) + { + msg_print("You must first pick up the staffs."); + return; + } + + /* Enter device mode */ + set_stick_mode(o_ptr); + + /* Take a turn */ + energy_use = 100; + + /* Not identified yet */ + ident = FALSE; + + /* get the chance */ + chance = exec_lua(format("return spell_chance(%d)", o_ptr->pval2)); + + /* Extract object flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Is it simple to use ? */ + if (f4 & TR4_EASY_USE) + { + chance /= 3; + } + + /* Give everyone a (slight) chance */ + if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) + { + chance = USE_DEVICE; + } + + /* Roll for usage */ + if (magik(chance)) + { + if (flush_failure) flush(); + msg_print("You failed to use the staff properly."); + sound(SOUND_FAIL); + + /* Leave device mode */ + unset_stick_mode(); + return; + } + + /* Notice empty staffs */ + if (o_ptr->pval <= 0) + { + if (flush_failure) flush(); + msg_print("The staff has no charges left."); + o_ptr->ident |= (IDENT_EMPTY); + + /* Leave device mode */ + unset_stick_mode(); + return; + } + + + /* Sound */ + sound(SOUND_ZAP); + + + /* Analyze the staff */ + call_lua("activate_stick", "(d)", "dd", o_ptr->pval2, &obvious, &use_charge); + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* Tried the item */ + object_tried(o_ptr); + + /* An identification was made */ + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Hack -- some uses are "free" */ + if (!use_charge) + { + /* Leave device mode */ + unset_stick_mode(); + + return; + } + + /* An identification was made */ + if (obvious) + { + object_aware(o_ptr); + } + + /* Use a single charge */ + o_ptr->pval--; + + /* XXX Hack -- unstack if necessary */ + if ((item >= 0) && (o_ptr->number > 1)) + { + object_type forge; + object_type *q_ptr; + + /* Get local object */ + q_ptr = &forge; + + /* Obtain a local object */ + object_copy(q_ptr, o_ptr); + + /* Modify quantity */ + q_ptr->number = 1; + + /* Restore the charges */ + o_ptr->pval++; + + /* Unstack the used item */ + o_ptr->number--; + item = inven_carry(q_ptr, FALSE); + + /* Message */ + msg_print("You unstack your staff."); + } + + /* Describe charges in the pack */ + if (item >= 0) + { + inven_item_charges(item); + } + + /* Describe charges on the floor */ + else + { + floor_item_charges(0 - item); + } + + /* Leave device mode */ + unset_stick_mode(); +} + + +/* + * Aim a wand (from the pack or floor). + * + * Use a single charge from a single item. + * Handle "unstacking" in a logical manner. + * + * For simplicity, you cannot use a stack of items from the + * ground. This would require too much nasty code. + * + * There are no wands which can "destroy" themselves, in the p_ptr->inventory + * or on the ground, so we can ignore this possibility. Note that this + * required giving "wand of wonder" the ability to ignore destruction + * by electric balls. + * + * All wands can be "cancelled" at the "Direction?" prompt for free. + * + * Note that the basic "bolt" wands do slightly less damage than the + * basic "bolt" rods, but the basic "ball" wands do the same damage + * as the basic "ball" rods. + */ +void do_cmd_aim_wand(void) +{ + s32b obvious, use_charge; + + int item, ident, chance, sval; + + object_type *o_ptr; + + cptr q, s; + + u32b f1, f2, f3, f4, f5, esp; + + + /* No magic */ + if (p_ptr->antimagic) + { + msg_print("Your anti-magic field disrupts any magic attempts."); + return; + } + + /* Restrict choices to wands */ + item_tester_tval = TV_WAND; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Wand full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Aim which wand? "; + s = "You have no wand to aim."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + + /* Mega-Hack -- refuse to aim a pile from the ground */ + if ((item < 0) && (o_ptr->number > 1)) + { + msg_print("You must first pick up the wands."); + return; + } + + /* Take a turn */ + energy_use = 100; + + /* Not identified yet */ + ident = FALSE; + + /* Enter device mode */ + set_stick_mode(o_ptr); + + /* get the chance */ + chance = exec_lua(format("return spell_chance(%d)", o_ptr->pval2)); + + /* Extract object flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Is it simple to use ? */ + if (f4 & TR4_EASY_USE) + { + chance /= 3; + } + + /* Roll for usage */ + if (magik(chance)) + { + if (flush_failure) flush(); + msg_print("You failed to use the wand properly."); + sound(SOUND_FAIL); + + /* Leave device mode */ + unset_stick_mode(); + return; + } + + /* The wand is already empty! */ + if (o_ptr->pval <= 0) + { + if (flush_failure) flush(); + msg_print("The wand has no charges left."); + o_ptr->ident |= (IDENT_EMPTY); + + /* Leave device mode */ + unset_stick_mode(); + return; + } + + + /* Sound */ + sound(SOUND_ZAP); + + + /* XXX Hack -- Extract the "sval" effect */ + sval = o_ptr->sval; + + /* Analyze the wand */ + call_lua("activate_stick", "(d)", "dd", o_ptr->pval2, &obvious, &use_charge); + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* Mark it as tried */ + object_tried(o_ptr); + + /* Hack -- some uses are "free" */ + if (!use_charge) + { + /* Leave device mode */ + unset_stick_mode(); + + return; + } + + /* An identification was made */ + if (obvious) + { + object_aware(o_ptr); + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Use a single charge */ + o_ptr->pval--; + + /* Describe the charges in the pack */ + if (item >= 0) + { + inven_item_charges(item); + } + + /* Describe the charges on the floor */ + else + { + floor_item_charges(0 - item); + } + + /* Leave device mode */ + unset_stick_mode(); +} + + + + + + +/* + * Activate (zap) a Rod + * + * Unstack fully charged rods as needed. + * + * Hack -- rods of perception/genocide can be "cancelled" + * All rods can be cancelled at the "Direction?" prompt + */ + + +/* + * Hook to determine if an object is zapable + */ +static bool item_tester_hook_zapable(object_type *o_ptr) +{ + if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_ROD_MAIN)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + +/* + * Hook to determine if an object is attachable + */ +static bool item_tester_hook_attachable(object_type *o_ptr) +{ + if ((o_ptr->tval == TV_ROD_MAIN) && + (o_ptr->pval == SV_ROD_NOTHING)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + +/* + * Combine a rod and a rod tip + */ +void zap_combine_rod_tip(object_type *q_ptr, int tip_item) +{ + int item; + + object_type *o_ptr; + + object_kind *k_ptr; + + cptr q, s; + + u32b f1, f2, f3, f4, f5, esp; + s32b cost; + + + /* No magic */ + if (p_ptr->antimagic) + { + msg_print("Your anti-magic field disrupts any magic attempts."); + return; + } + + /* Restrict choices to rods */ + item_tester_hook = item_tester_hook_attachable; + + /* Get an item */ + q = "Attach the rod tip with which rod? "; + s = "You have no rod to attach to."; + if (!get_item(&item, q, s, (USE_INVEN))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + k_ptr = &k_info[o_ptr->k_idx]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + k_ptr = &k_info[o_ptr->k_idx]; + } + + /* Examine the rod */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Calculate rod tip's mana cost */ + cost = q_ptr->pval; + + if (f4 & TR4_CHEAPNESS) + { + cost /= 2; + } + + /* + * The rod must have at least the same mana capacity as the + * rod tip spell needs + */ + if (o_ptr->pval2 < cost) + { + msg_print("This rod doesn't have enough mana for the rod tip."); + return; + } + + /* Attach the tip to the rod */ + o_ptr->pval = q_ptr->sval; + + /* Destroy a rod tip in the pack */ + if (tip_item >= 0) + { + inven_item_increase(tip_item, -1); + inven_item_describe(tip_item); + inven_item_optimize(tip_item); + } + /* Destroy a rod tip on the floor */ + else + { + floor_item_increase(0 - tip_item, -1); + floor_item_describe(0 - tip_item); + floor_item_optimize(0 - tip_item); + } +} + + +/* + * Zap a rod, or attack a rod tip to a rod + */ +void do_cmd_zap_rod(void) +{ + int item, ident, chance, dir, lev; + + int cost; + + bool require_dir; + + object_type *o_ptr; + + object_kind *k_ptr; + + object_kind *tip_ptr; + + u32b f1, f2, f3, f4, f5, esp; + + cptr q, s; + + /* Hack -- let perception get aborted */ + bool use_charge = TRUE; + + + /* No magic */ + if (p_ptr->antimagic) + { + msg_print("Your anti-magic field disrupts any magic attempts."); + return; + } + + + /* Restrict choices to rods */ + item_tester_hook = item_tester_hook_zapable; + + /* Set up the extra finder */ + get_item_hook_find_obj_what = "Rod full name? "; + get_item_extra_hook = get_item_hook_find_obj; + + /* Get an item */ + q = "Zap which rod? "; + s = "You have no rod to zap."; + if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_EXTRA))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + k_ptr = &k_info[o_ptr->k_idx]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + k_ptr = &k_info[o_ptr->k_idx]; + } + + + /* "Zapping" a Rod Tip on rod of nothing will attach it */ + if (o_ptr->tval == TV_ROD) + { + if (item >= 0) + { + zap_combine_rod_tip(o_ptr, item); + return; + } + else + { + msg_print("You can't zap a rod tip that's on the floor."); + return; + } + } + + + /* Non-directed rods */ + if (o_ptr->pval < SV_ROD_MIN_DIRECTION) + { + require_dir = FALSE; + } + + /* Some rods always require direction */ + else + { + switch (o_ptr->pval) + { + case SV_ROD_DETECT_TRAP: + case SV_ROD_HAVOC: + case SV_ROD_HOME: + { + require_dir = FALSE; + break; + } + + default: + { + require_dir = TRUE; + break; + } + } + } + + /* Get a direction (unless KNOWN not to need it) */ + if (!object_aware_p(o_ptr) || require_dir) + { + /* Get a direction, allow cancel */ + if (!get_aim_dir(&dir)) return; + } + + /* Take a turn */ + energy_use = 100; + + /* Examine the rod */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + if (f4 & TR4_FAST_CAST) energy_use /= 2; + + /* Not identified yet */ + ident = FALSE; + + /* Extract the item level */ + tip_ptr = &k_info[lookup_kind(TV_ROD, o_ptr->pval)]; + lev = k_info[lookup_kind(TV_ROD, o_ptr->pval)].level; + + /* Base chance of success */ + chance = p_ptr->skill_dev; + + /* Confusion hurts skill */ + if (p_ptr->confused) chance = chance / 2; + + /* High level objects are harder */ + chance = chance - ((lev > 50) ? 50 : lev); + + if (chance <= 0) + { + chance = 1; + } + + /* Is it simple to use ? */ + if (f4 & TR4_EASY_USE) + { + chance *= 10; + } + + /* Give everyone a (slight) chance */ + if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) + { + chance = USE_DEVICE; + } + + /* Roll for usage */ + if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) + { + /* Flush input if necessary */ + if (flush_failure) flush(); + + /* Message */ + msg_print("You failed to use the rod properly."); + + sound(SOUND_FAIL); + + return; + } + + /* Extract mana cost */ + cost = tip_ptr->pval; + + /* "Cheapness" ego halven the cost */ + if (f4 & TR4_CHEAPNESS) cost = cost / 2; + + /* A single rod is still charging */ + if (o_ptr->timeout < cost) + { + /* Flush input if necessary */ + if (flush_failure) flush(); + + /* Message */ + msg_print("The rod does not have enough mana yet."); + + return; + } + + /* Increase the timeout by the rod kind's pval. */ + o_ptr->timeout -= cost; + + /* Sound */ + sound(SOUND_ZAP); + + /* Analyze the rod */ + switch (o_ptr->pval) + { + case SV_ROD_HOME: + { + ident = TRUE; + + do_cmd_home_trump(); + + break; + } + + case SV_ROD_DETECT_TRAP: + { + if (detect_traps(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_ROD_DETECT_DOOR: + { + if (detect_doors(DEFAULT_RADIUS)) ident = TRUE; + if (detect_stairs(DEFAULT_RADIUS)) ident = TRUE; + + break; + } + + case SV_ROD_IDENTIFY: + { + ident = TRUE; + + if (!ident_spell()) use_charge = FALSE; + + break; + } + + case SV_ROD_RECALL: + { + if ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? ")) + { + use_charge = FALSE; + } + else + { + recall_player(21, 15); + + ident = TRUE; + } + + break; + } + + case SV_ROD_ILLUMINATION: + { + if (lite_area(damroll(2, 8), 2)) ident = TRUE; + + break; + } + + case SV_ROD_MAPPING: + { + map_area(); + + ident = TRUE; + + break; + } + + case SV_ROD_DETECTION: + { + detect_all(DEFAULT_RADIUS); + + ident = TRUE; + + break; + } + + case SV_ROD_PROBING: + { + probing(); + + ident = TRUE; + + break; + } + + case SV_ROD_CURING: + { + if (set_blind(0)) ident = TRUE; + if (set_poisoned(0)) ident = TRUE; + if (set_confused(0)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + if (set_image(0)) ident = TRUE; + + break; + } + + case SV_ROD_HEALING: + { + if (hp_player(500)) ident = TRUE; + if (set_stun(0)) ident = TRUE; + if (set_cut(0)) ident = TRUE; + + break; + } + + case SV_ROD_RESTORATION: + { + if (restore_level()) ident = TRUE; + if (do_res_stat(A_STR, TRUE)) ident = TRUE; + if (do_res_stat(A_INT, TRUE)) ident = TRUE; + if (do_res_stat(A_WIS, TRUE)) ident = TRUE; + if (do_res_stat(A_DEX, TRUE)) ident = TRUE; + if (do_res_stat(A_CON, TRUE)) ident = TRUE; + if (do_res_stat(A_CHR, TRUE)) ident = TRUE; + + break; + } + + case SV_ROD_SPEED: + { + if (!p_ptr->fast) + { + if (set_fast(randint(30) + 15, 10)) ident = TRUE; + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + + break; + } + + case SV_ROD_TELEPORT_AWAY: + { + if (teleport_monster(dir)) ident = TRUE; + + break; + } + + case SV_ROD_DISARMING: + { + if (disarm_trap(dir)) ident = TRUE; + + break; + } + + case SV_ROD_LITE: + { + msg_print("A line of blue shimmering light appears."); + lite_line(dir); + + ident = TRUE; + + break; + } + + case SV_ROD_SLEEP_MONSTER: + { + if (sleep_monster(dir)) ident = TRUE; + + break; + } + + case SV_ROD_SLOW_MONSTER: + { + if (slow_monster(dir)) ident = TRUE; + + break; + } + + case SV_ROD_DRAIN_LIFE: + { + if (drain_life(dir, 75)) ident = TRUE; + + break; + } + + case SV_ROD_POLYMORPH: + { + if (poly_monster(dir)) ident = TRUE; + + break; + } + + case SV_ROD_ACID_BOLT: + { + fire_bolt_or_beam(10, GF_ACID, dir, damroll(6, 8)); + + ident = TRUE; + + break; + } + + case SV_ROD_ELEC_BOLT: + { + fire_bolt_or_beam(10, GF_ELEC, dir, damroll(3, 8)); + + ident = TRUE; + + break; + } + + case SV_ROD_FIRE_BOLT: + { + fire_bolt_or_beam(10, GF_FIRE, dir, damroll(8, 8)); + + ident = TRUE; + + break; + } + + case SV_ROD_COLD_BOLT: + { + fire_bolt_or_beam(10, GF_COLD, dir, damroll(5, 8)); + + ident = TRUE; + + break; + } + + case SV_ROD_ACID_BALL: + { + fire_ball(GF_ACID, dir, 60, 2); + + ident = TRUE; + + break; + } + + case SV_ROD_ELEC_BALL: + { + fire_ball(GF_ELEC, dir, 32, 2); + + ident = TRUE; + + break; + } + + case SV_ROD_FIRE_BALL: + { + fire_ball(GF_FIRE, dir, 72, 2); + + ident = TRUE; + + break; + } + + case SV_ROD_COLD_BALL: + { + fire_ball(GF_COLD, dir, 48, 2); + + ident = TRUE; + + break; + } + + case SV_ROD_HAVOC: + { + call_chaos(); + + ident = TRUE; + + break; + } + + default: + { + process_hooks(HOOK_ZAP, "(d,d)", o_ptr->tval, o_ptr->sval); + + break; + } + } + + + /* Combine / Reorder the pack (later) */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* Tried the object */ + object_tried(o_ptr); + + /* Successfully determined the object function */ + if (ident && !object_aware_p(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + /* Hack -- deal with cancelled zap */ + if (!use_charge) + { + o_ptr->timeout += cost; + + return; + } +} + + + + +/* + * Hook to determine if an object is activable + */ +static bool item_tester_hook_activate(object_type *o_ptr) +{ + u32b f1, f2, f3, f4, f5, esp; + + + /* Not known */ + if (!object_known_p(o_ptr)) return (FALSE); + + /* Extract the flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Check activation flag */ + if (f3 & (TR3_ACTIVATE)) return (TRUE); + + /* Assume not */ + return (FALSE); +} + + + +/* + * Hack -- activate the ring of power + */ +int ring_of_power() +{ + char ch = 0, p = 0; + + int plev = p_ptr->lev; + + int timeout = 0; + + + /* Select power to use */ + while (TRUE) + { + if (!get_com("[S]ummon a wraith, [R]ule the world or " + "[C]ast a powerful attack? ", &ch)) + { + return (0); + } + + if (ch == 'S' || ch == 's') + { + p = 1; + break; + } + if (ch == 'R' || ch == 'r') + { + p = 2; + break; + } + if (ch == 'C' || ch == 'c') + { + p = 3; + break; + } + } + + /* Summon a Wraith */ + if (p == 1) + { + /* Rewrite this -- pelpel */ + if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + (plev > 47 ? SUMMON_HI_UNDEAD_NO_UNIQUES : SUMMON_UNDEAD), + (bool)(((plev > 24) && (randint(3) == 1)) ? TRUE : FALSE))) + { + msg_print("Cold winds begin to blow around you, " + "carrying with them the stench of decay..."); + msg_print("Ancient, long-dead forms arise from the ground " + "to serve you!"); + } + timeout = 200 + rand_int(200); + } + + /* Rule the World -- only if we can really do so */ + else if (p == 2) + { + msg_print("The power of the ring destroys the world!"); + msg_print("The world changes!"); + + if (autosave_l) + { + is_autosave = TRUE; + msg_print("Autosaving the game..."); + do_cmd_save_game(); + is_autosave = FALSE; + } + + /* Leaving */ + p_ptr->leaving = TRUE; + timeout = 250 + rand_int(250); + } + + /* Cast a powerful spell */ + else if (p == 3) + { + int dir; + + if (!get_aim_dir(&dir)) return (0); + + if (rand_int(3) == 0) + { + msg_print("You call the fire of Mount Doom!"); + fire_ball(GF_METEOR, dir, 600, 4); + } + else + { + msg_print("Your ring tries to take possession of your enemy's mind!"); + fire_bolt(GF_CHARM, dir, 600); + } + timeout = 300 + rand_int(300); + } + + return (timeout); +} + + + + +/* + * Enchant some bolts + */ +bool brand_bolts(void) +{ + int i; + + + /* Use the first acceptable bolts */ + for (i = 0; i < INVEN_PACK; i++) + { + object_type *o_ptr = &p_ptr->inventory[i]; + + /* Skip non-bolts */ + if (o_ptr->tval != TV_BOLT) continue; + + /* Skip artifacts and ego-items */ + if (o_ptr->art_name || artifact_p(o_ptr) || ego_item_p(o_ptr)) continue; + + /* Skip cursed/broken items */ + if (cursed_p(o_ptr)) continue; + + /* Randomize */ + if (rand_int(100) < 75) continue; + + /* Message */ + msg_print("Your bolts are covered in a fiery aura!"); + + /* Ego-item */ + o_ptr->name2 = EGO_FLAME; + + /* Apply the ego */ + apply_magic(o_ptr, dun_level, FALSE, FALSE, FALSE); + + /* Enchant */ + enchant(o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM); + + /* Notice */ + return (TRUE); + } + + /* Flush */ + if (flush_failure) flush(); + + /* Fail */ + msg_print("The fiery enchantment failed."); + + /* Notice */ + return (TRUE); +} + + +/* + * Objects in the p_ptr->inventory can now be activated, and + * SOME of those may be able to stack (ego wands or something) + * in any case, we can't know that it's impossible. *BUT* we'll + * ignore it for now, and the timeout will be set on the entire stack + * of objects. Reduces their utility, but oh well. + * + * Note that it always takes a turn to activate an object, even if + * the user hits "escape" at the "direction" prompt. + */ +void do_cmd_activate(void) +{ + int item, lev, chance; + + char ch, spell_choice; + + object_type *o_ptr; + + u32b f1, f2, f3, f4, f5, esp; + + cptr q, s; + + + /* Prepare the hook */ + item_tester_hook = item_tester_hook_activate; + + /* Get an item */ + command_see = TRUE; + command_wrk = USE_EQUIP; + q = "Activate which item? "; + s = "You have nothing to activate."; + if (!get_item(&item, q, s, (USE_EQUIP | USE_INVEN))) return; + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + /* Extract object flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Wearable items have to be worn */ + if (!(f5 & TR5_ACTIVATE_NO_WIELD)) + { + if (item < INVEN_WIELD) + { + msg_print("You must wear it to activate it."); + return; + } + } + + /* Take a turn */ + energy_use = 100; + + /* Extract the item level */ + lev = k_info[o_ptr->k_idx].level; + + /* Hack -- Use artifact level instead */ + if (artifact_p(o_ptr)) + { + if (o_ptr->tval == TV_RANDART) + { + lev = random_artifacts[o_ptr->sval].level; + } + else + { + lev = a_info[o_ptr->name1].level; + } + } + + /* Base chance of success */ + chance = p_ptr->skill_dev; + + /* Confusion hurts skill */ + if (p_ptr->confused) chance = chance / 2; + + /* Hight level objects are harder */ + chance = chance - ((lev > 50) ? 50 : lev); + + if (chance <= 0) + { + chance = 1; + } + + /* Is it simple to use ? */ + if (f4 & TR4_EASY_USE) + { + chance *= 10; + } + + /* Give everyone a (slight) chance */ + if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) + { + chance = USE_DEVICE; + } + + /* Roll for usage */ + if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) + { + if (flush_failure) flush(); + msg_print("You failed to activate it properly."); + sound(SOUND_FAIL); + return; + } + + /* Check the recharge */ + if (o_ptr->timeout) + { + /* Mage Staff of Spells -- Have another timeout in xtra2 */ + if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL) && o_ptr->xtra2) + { + msg_print("It whines, glows and fades..."); + return; + } + + /* Monster eggs */ + else if (o_ptr->tval == TV_EGG) + { + msg_print("You resume the development of the egg."); + o_ptr->timeout = 0; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Success */ + return; + } + + /* Normal activatable items */ + else + { + msg_print("It whines, glows and fades..."); + return; + } + } + + + /* Activate the item */ + msg_print("You activate it..."); + + /* Sound */ + sound(SOUND_ZAP); + + /* Lua hook ? -- go first to allow lua to override */ + if (process_hooks(HOOK_ACTIVATE, "(d)", item)) + { + return; + } + + /* New mostly unified activation code + This has to be early to allow artifacts to override normal items -- neil */ + + if ( activation_aux(o_ptr, TRUE, item) == NULL ) + { + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Success */ + return; + } + + /* Mage Staff of Spells */ + if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)) + { + while (TRUE) + { + if (!get_com("Use Spell [1] or [2]?", &ch)) + { + return; + } + + if (ch == '1') + { + spell_choice = 1; + break; + } + + if (ch == '2') + { + spell_choice = 2; + break; + } + } + + if (spell_choice == 1) + { + /* Still need to check timeouts because there is another counter */ + if (o_ptr->timeout) + { + msg_print("The first spell is still charging!"); + return; + } + + /* Cast spell 1 */ + activate_spell(o_ptr, spell_choice); + } + else if (spell_choice == 2) + { + /* Still need to check timeouts because there is another counter */ + if (o_ptr->xtra2) + { + msg_print("The second spell is still charging!"); + return; + } + + /* Cast spell 2 */ + activate_spell(o_ptr, spell_choice); + } + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Success */ + return; + } + + /* Monster eggs */ + if (o_ptr->tval == TV_EGG) + { + msg_print("You stop the development of the egg."); + o_ptr->timeout = -1; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Success */ + return; + } + + /* Musical instruments */ + if (o_ptr->tval == TV_INSTRUMENT) + { + /* Horns */ + if (o_ptr->sval == SV_HORN) + { + msg_format("Your instrument emits a loud sound!"); + + aggravate_monsters(1); + + o_ptr->timeout = 100; + } + + /* Success */ + return; + } + + /* Mistake */ + msg_print("Oops. That object cannot be activated."); +} + + + +const char *activation_aux(object_type * o_ptr, bool doit, int item) +{ + int plev = get_skill(SKILL_DEVICE); + + int i = 0, ii = 0, ij = 0, k, dir, dummy = 0; + int chance; + bool is_junkart = (o_ptr->tval == TV_RANDART); + + int spell = 0; + + /* Junkarts */ + if (is_junkart) + spell = activation_info[o_ptr->pval2].spell; + + /* True Actifacts */ + if (!spell && o_ptr->name1) + spell = a_info[o_ptr->name1].activate; + + /* Random and Alchemist Artifacts */ + if (!spell && o_ptr->art_name) + spell = o_ptr->xtra2; + + /* Ego Items */ + if (!spell && o_ptr->name2) + spell = e_info[o_ptr->name2].activate; + + /* Dual egos with the second ego having the activation */ + if (!spell && o_ptr->name2b) + spell = e_info[o_ptr->name2b].activate; + + /* Intrinsic to item type (rings of Ice, etc) */ + if (!spell) + spell = k_info[o_ptr->k_idx].activate; + + /* Complain about mis-configured .txt files? */ + if (!spell) + return "Unknown!"; + + /* Negative means a unified spell index */ + if (spell < 0) + { + if (doit) + { + call_lua("activate_activation", "(d,d)", "", -spell, item); + o_ptr->timeout = exec_lua(format("return get_activation_timeout(%d)", -spell)); + } + else + { + return string_exec_lua(format("return get_activation_desc(%d)", -spell)); + } + } + else + { + /* Activate for attack */ + switch (spell) + { + case ACT_GILGALAD: + { + if (!doit) return "starlight (75) every 75+d75 turns"; + for (k = 1; k < 10; k++) + { + if (k - 5) fire_beam(GF_LITE, k, 75); + } + + o_ptr->timeout = rand_int(75) + 75; + + break; + } + + case ACT_CELEBRIMBOR: + { + if (!doit) return "temporary ESP (dur 20+d20) every 20+d50 turns"; + set_tim_esp(p_ptr->tim_esp + randint(20) + 20); + + o_ptr->timeout = rand_int(50) + 20; + + break; + } + + case ACT_SKULLCLEAVER: + { + if (!doit) return "destruction every 200+d200 turns"; + destroy_area(p_ptr->py, p_ptr->px, 15, TRUE, FALSE); + + o_ptr->timeout = rand_int(200) + 200; + + break; + } + + case ACT_HARADRIM: + { + if (!doit) return "berserk strength every 50+d50 turns"; + set_afraid(0); + set_shero(p_ptr->shero + randint(25) + 25); + hp_player(30); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + + case ACT_FUNDIN: + { + if (!doit) return "dispel evil (x4) every 100+d100 turns"; + dispel_evil(p_ptr->lev * 4); + + o_ptr->timeout = rand_int(100) + 100; + + break; + } + + case ACT_EOL: + { + if (!doit) return "mana bolt (9d8) 7+d7 turns"; + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_MANA, dir, damroll(9, 8)); + + o_ptr->timeout = rand_int(7) + 7; + + break; + } + + case ACT_UMBAR: + { + if (!doit) return "magic arrow (10d10) every 20+d20 turns"; + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_MISSILE, dir, damroll(10, 10)); + + o_ptr->timeout = rand_int(20) + 20; + + break; + } + + case ACT_NUMENOR: + { + /* Give full knowledge */ + /* Hack -- Maximal info */ + monster_race *r_ptr; + cave_type *c_ptr; + int x, y, m; + + if (!doit) return "analyze monster every 500+d200 turns"; + + if (!tgt_pt(&x, &y)) break; + + c_ptr = &cave[y][x]; + if (!c_ptr->m_idx) break; + + r_ptr = &r_info[c_ptr->m_idx]; + + /* Observe "maximal" attacks */ + for (m = 0; m < 4; m++) + { + /* Examine "actual" blows */ + if (r_ptr->blow[m].effect || r_ptr->blow[m].method) + { + /* Hack -- maximal observations */ + r_ptr->r_blows[m] = MAX_UCHAR; + } + } + + /* Hack -- maximal drops */ + r_ptr->r_drop_gold = r_ptr->r_drop_item = + (((r_ptr->flags1 & (RF1_DROP_4D2)) ? 8 : 0) + + ((r_ptr->flags1 & (RF1_DROP_3D2)) ? 6 : 0) + + ((r_ptr->flags1 & (RF1_DROP_2D2)) ? 4 : 0) + + ((r_ptr->flags1 & (RF1_DROP_1D2)) ? 2 : 0) + + ((r_ptr->flags1 & (RF1_DROP_90)) ? 1 : 0) + + ((r_ptr->flags1 & (RF1_DROP_60)) ? 1 : 0)); + + /* Hack -- but only "valid" drops */ + if (r_ptr->flags1 & (RF1_ONLY_GOLD)) r_ptr->r_drop_item = 0; + if (r_ptr->flags1 & (RF1_ONLY_ITEM)) r_ptr->r_drop_gold = 0; + + /* Hack -- observe many spells */ + r_ptr->r_cast_inate = MAX_UCHAR; + r_ptr->r_cast_spell = MAX_UCHAR; + + /* Hack -- know all the flags */ + r_ptr->r_flags1 = r_ptr->flags1; + r_ptr->r_flags2 = r_ptr->flags2; + r_ptr->r_flags3 = r_ptr->flags3; + r_ptr->r_flags4 = r_ptr->flags4; + r_ptr->r_flags5 = r_ptr->flags5; + r_ptr->r_flags6 = r_ptr->flags6; + r_ptr->r_flags7 = r_ptr->flags7; + r_ptr->r_flags8 = r_ptr->flags8; + r_ptr->r_flags9 = r_ptr->flags9; + + o_ptr->timeout = rand_int(200) + 500; + + break; + } + + case ACT_KNOWLEDGE: + { + if (!doit) return "whispers from beyond(sanity drain) 100+d200 turns"; + identify_fully(); + take_sanity_hit(damroll(10, 7), "the sounds of the dead"); + + o_ptr->timeout = rand_int(200) + 100; + + break; + } + + case ACT_UNDEATH: + { + if (!doit) return "ruination every 10+d10 turns"; + msg_print("The phial wells with dark light..."); + unlite_area(damroll(2, 15), 3); + take_hit(damroll(10, 10), "activating The Phial of Undeath"); + (void)dec_stat(A_DEX, 25, STAT_DEC_PERMANENT); + (void)dec_stat(A_WIS, 25, STAT_DEC_PERMANENT); + (void)dec_stat(A_CON, 25, STAT_DEC_PERMANENT); + (void)dec_stat(A_STR, 25, STAT_DEC_PERMANENT); + (void)dec_stat(A_CHR, 25, STAT_DEC_PERMANENT); + (void)dec_stat(A_INT, 25, STAT_DEC_PERMANENT); + + o_ptr->timeout = rand_int(10) + 10; + + break; + } + + case ACT_THRAIN: + { + if (!doit) return "detection every 30+d30 turns"; + msg_print("The stone glows a deep green..."); + detect_all(DEFAULT_RADIUS); + + o_ptr->timeout = rand_int(30) + 30; + + break; + } + + case ACT_BARAHIR: + { + if (!doit) return "dispel small life every 55+d55 turns"; + msg_print("You exterminate small life."); + (void)dispel_monsters(4); + + o_ptr->timeout = rand_int(55) + 55; + + break; + } + + case ACT_TULKAS: + { + if (!doit) return "haste self (75+d75 turns) every 150+d150 turns"; + msg_print("The ring glows brightly..."); + if (!p_ptr->fast) + { + (void)set_fast(randint(75) + 75, 10); + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + + o_ptr->timeout = rand_int(150) + 150; + + break; + } + + case ACT_NARYA: + { + if (!doit) return "healing (500) every 200+d100 turns"; + msg_print("The ring glows deep red..."); + hp_player(500); + set_blind(0); + set_confused(0); + set_poisoned(0); + set_stun(0); + set_cut(0); + + o_ptr->timeout = rand_int(100) + 200; + + break; + } + + case ACT_NENYA: + { + if (!doit) return "healing (800) every 100+d200 turns"; + msg_print("The ring glows bright white..."); + hp_player(800); + set_blind(0); + set_confused(0); + set_poisoned(0); + set_stun(0); + set_cut(0); + + o_ptr->timeout = rand_int(200) + 100; + + break; + } + + case ACT_VILYA: + { + if (!doit) return "greater healing (900) every 200+d200 turns"; + msg_print("The ring glows deep blue..."); + hp_player(900); + set_blind(0); + set_confused(0); + set_poisoned(0); + set_stun(0); + set_cut(0); + if (p_ptr->black_breath) + { + p_ptr->black_breath = FALSE; + msg_print("The hold of the Black Breath on you is broken!"); + } + + o_ptr->timeout = rand_int(200) + 200; + + break; + } + + case ACT_POWER: + { + if (!doit) return "powerful things"; + msg_print("The ring glows intensely black..."); + + o_ptr->timeout = ring_of_power(); + + break; + } + + + /* The Stone of Lore is perilous, for the sake of game balance. */ + case ACT_STONE_LORE: + { + if (!doit) return "perilous identify every turn"; + msg_print("The stone reveals hidden mysteries..."); + if (!ident_spell()) break; + + if (has_ability(AB_PERFECT_CASTING)) + { + /* Sufficient mana */ + if (20 <= p_ptr->csp) + { + /* Use some mana */ + p_ptr->csp -= 20; + } + + /* Over-exert the player */ + else + { + int oops = 20 - p_ptr->csp; + + /* No mana left */ + p_ptr->csp = 0; + p_ptr->csp_frac = 0; + + /* Message */ + msg_print("You are too weak to control the stone!"); + + /* Hack -- Bypass free action */ + (void)set_paralyzed(p_ptr->paralyzed + + randint(5 * oops + 1)); + + /* Confusing. */ + (void)set_confused(p_ptr->confused + + randint(5 * oops + 1)); + } + + /* Redraw mana */ + p_ptr->redraw |= (PR_MANA); + } + + take_hit(damroll(1, 12), "perilous secrets"); + + /* Confusing. */ + if (rand_int(5) == 0) + { + (void)set_confused(p_ptr->confused + randint(10)); + } + + /* Exercise a little care... */ + if (rand_int(20) == 0) + { + take_hit(damroll(4, 10), "perilous secrets"); + } + + o_ptr->timeout = 1; + + break; + } + + case ACT_RAZORBACK: + { + if (!doit) return "star ball (150) every 1000 turns"; + msg_print("Your armor is surrounded by lightning..."); + for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i], 150, 3); + + o_ptr->timeout = 1000; + + break; + } + + case ACT_BLADETURNER: + { + if (!doit) return "invulnerability (4+d8) every 800 turns"; + set_invuln(p_ptr->invuln + randint(8) + 4); + + o_ptr->timeout = 800; + + break; + } + + case ACT_MEDIATOR: + { + if (!doit) return "breathe elements (300), berserk rage, bless, and resistance every 400 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe the elements."); + fire_ball(GF_MISSILE, dir, 300, 4); + msg_print("Your armor glows many colours..."); + (void)set_afraid(0); + (void)set_shero(p_ptr->shero + randint(50) + 50); + (void)hp_player(30); + (void)set_blessed(p_ptr->blessed + randint(50) + 50); + (void)set_oppose_acid(p_ptr->oppose_acid + randint(50) + 50); + (void)set_oppose_elec(p_ptr->oppose_elec + randint(50) + 50); + (void)set_oppose_fire(p_ptr->oppose_fire + randint(50) + 50); + (void)set_oppose_cold(p_ptr->oppose_cold + randint(50) + 50); + (void)set_oppose_pois(p_ptr->oppose_pois + randint(50) + 50); + + o_ptr->timeout = 400; + + break; + } + + case ACT_BELEGENNON: + { + if (!doit) return ("heal (777), curing and heroism every 300 turns"); + msg_print("A heavenly choir sings..."); + (void)set_poisoned(0); + (void)set_cut(0); + (void)set_stun(0); + (void)set_confused(0); + (void)set_blind(0); + (void)set_hero(p_ptr->hero + randint(25) + 25); + (void)hp_player(777); + + o_ptr->timeout = 300; + + break; + } + + case ACT_GORLIM: + { + if (!doit) return "rays of fear in every direction"; + turn_monsters(40 + p_ptr->lev); + + o_ptr->timeout = 3 * (p_ptr->lev + 10); + + break; + } + + case ACT_COLLUIN: + { + if (!doit) return "resistance (20+d20 turns) every 111 turns"; + msg_print("Your cloak glows many colours..."); + (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20); + (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20); + (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20); + (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20); + (void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20); + + o_ptr->timeout = 111; + + break; + } + + + case ACT_BELANGIL: + { + if (!doit) return "frost ball (48) every 5+d5 turns"; + msg_print("Your dagger is covered in frost..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_COLD, dir, 48, 2); + + o_ptr->timeout = rand_int(5) + 5; + + break; + } + + case ACT_ANGUIREL: + { + if (!doit) return "a getaway every 35 turns"; + switch (randint(13)) + { + case 1: + case 2: + case 3: + case 4: + case 5: + { + teleport_player(10); + + break; + } + + case 6: + case 7: + case 8: + case 9: + case 10: + { + teleport_player(222); + + break; + } + + case 11: + case 12: + { + (void)stair_creation(); + + break; + } + + default: + { + if (get_check("Leave this level? ")) + { + if (autosave_l) + { + is_autosave = TRUE; + msg_print("Autosaving the game..."); + do_cmd_save_game(); + is_autosave = FALSE; + } + + /* Leaving */ + p_ptr->leaving = TRUE; + } + + break; + } + } + + o_ptr->timeout = 35; + + break; + } + + case ACT_ERU: + { + if (!doit) return "healing(7000), curing every 500 turns"; + msg_print("Your sword glows an intense white..."); + hp_player(7000); + heal_insanity(50); + set_blind(0); + set_poisoned(0); + set_confused(0); + set_stun(0); + set_cut(0); + set_image(0); + + o_ptr->timeout = 500; + + break; + } + + case ACT_DAWN: + { + if (!doit) return "summon the Legion of the Dawn every 500+d500 turns"; + msg_print("You summon the Legion of the Dawn."); + (void)summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_DAWN, TRUE); + + o_ptr->timeout = 500 + randint(500); + + break; + } + + case ACT_FIRESTAR: + { + if (!doit) return "large fire ball (72) every 100 turns"; + msg_print("Your morning star rages in fire..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_FIRE, dir, 72, 3); + + o_ptr->timeout = 100; + + break; + } + + case ACT_TURMIL: + { + if (!doit) return "drain life (90) every 70 turns"; + msg_print("Your hammer glows white..."); + if (!get_aim_dir(&dir)) break; + drain_life(dir, 90); + + o_ptr->timeout = 70; + + break; + } + + case ACT_CUBRAGOL: + { + if (!doit) return "fire branding of bolts every 999 turns"; + msg_print("Your crossbow glows deep red..."); + (void)brand_bolts(); + + o_ptr->timeout = 999; + + break; + } + + case ACT_ELESSAR: + { + if (!doit) return "heal and cure black breath every 200 turns"; + if (p_ptr->black_breath) + { + msg_print("The hold of the Black Breath on you is broken!"); + } + p_ptr->black_breath = FALSE; + hp_player(100); + + o_ptr->timeout = 200; + + break; + } + + case ACT_GANDALF: + { + if (!doit) return "restore mana every 666 turns"; + msg_print("Your mage staff glows deep blue..."); + if (p_ptr->csp < p_ptr->msp) + { + p_ptr->csp = p_ptr->msp; + p_ptr->csp_frac = 0; + msg_print("Your feel your head clear."); + p_ptr->redraw |= (PR_MANA); + p_ptr->window |= (PW_PLAYER); + } + + o_ptr->timeout = 666; + + break; + } + + case ACT_MARDA: + { + if (!doit) return "summon a thunderlord every 1000 turns"; + if (randint(3) == 1) + { + if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_THUNDERLORD)) + { + msg_print("A Thunderlord comes from thin air!"); + msg_print("'I will burn you!'"); + } + } + else + { + if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + SUMMON_THUNDERLORD, (bool)(plev == 50 ? TRUE : FALSE))) + { + msg_print("A Thunderlord comes from thin air!"); + msg_print("'I will help you in your difficult task.'"); + } + } + + o_ptr->timeout = 1000; + + break; + } + + case ACT_PALANTIR: + { + if (!doit) return "clairvoyance every 100+d100 turns"; + msg_print("The stone glows a deep green..."); + wiz_lite_extra(); + (void)detect_traps(DEFAULT_RADIUS); + (void)detect_doors(DEFAULT_RADIUS); + (void)detect_stairs(DEFAULT_RADIUS); + + o_ptr->timeout = rand_int(100) + 100; + + break; + } + + case ACT_EREBOR: + { + if (!doit) return "open a secret passage every 75 turns"; + msg_print("Your pick twists in your hands."); + + if (!get_aim_dir(&dir)) break; + if (passwall(dir, TRUE)) + { + msg_print("A passage opens, and you step through."); + } + else + { + msg_print("There is no wall there!"); + } + + o_ptr->timeout = 75; + + break; + } + + case ACT_DRUEDAIN: + { + if (!doit) return "detection every 99 turns"; + msg_print("Your drum shows you the world."); + detect_all(DEFAULT_RADIUS); + + o_ptr->timeout = 99; + + break; + } + + case ACT_ROHAN: + { + if (!doit) return "heroism, berserker, and haste every 250 turns"; + msg_print("Your horn glows deep red."); + set_afraid(0); + set_shero(p_ptr->shero + damroll(5, 10) + 30); + set_afraid(0); + set_hero(p_ptr->hero + damroll(5, 10) + 30); + set_fast(p_ptr->fast + damroll(5, 10) + 30, 10); + hp_player(30); + + o_ptr->timeout = 250; + + break; + } + + case ACT_HELM: + { + if (!doit) return "sound ball (300) every 300 turns"; + msg_print("Your horn emits a loud sound."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_SOUND, dir, 300, 6); + + o_ptr->timeout = 300; + + break; + } + + case ACT_BOROMIR: + { + if (!doit) return "mass human summoning every 1000 turns"; + msg_print("Your horn calls for help."); + for (i = 0; i < 15; i++) + { + summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_HUMAN, TRUE); + } + + o_ptr->timeout = 1000; + + break; + } + + case ACT_HURIN: + { + if (!doit) return "berserker and +10 to speed (50) every 100+d200 turns"; + if (!p_ptr->fast) + { + (void)set_fast(randint(50) + 50, 10); + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + hp_player(30); + set_afraid(0); + set_shero(p_ptr->shero + randint(50) + 50); + + o_ptr->timeout = rand_int(200) + 100; + + break; + } + + case ACT_AXE_GOTHMOG: + { + if (!doit) return "fire ball (300) every 200+d200 turns"; + msg_print("Your lochaber axe erupts in fire..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_FIRE, dir, 300, 4); + + o_ptr->timeout = 200 + rand_int(200); + + break; + } + + case ACT_MELKOR: + { + if (!doit) return "darkness ball (150) every 100 turns"; + msg_print("Your spear is covered of darkness..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_DARK, dir, 150, 3); + + o_ptr->timeout = 100; + + break; + } + + case ACT_GROND: + { + if (!doit) return "alter reality every 100 turns"; + msg_print("Your hammer hits the floor..."); + alter_reality(); + + o_ptr->timeout = 100; + + break; + } + + case ACT_NATUREBANE: + { + if (!doit) return "dispel monsters (300) every 200+d200 turns"; + msg_print("Your axe glows blood red..."); + dispel_monsters(300); + + o_ptr->timeout = 200 + randint(200); + + break; + } + + case ACT_NIGHT: + { + if (!doit) return "vampiric drain (3*100) every 250 turns"; + msg_print("Your axe emits a black aura..."); + if (!get_aim_dir(&dir)) break; + for (i = 0; i < 3; i++) + { + if (drain_life(dir, 100)) hp_player(100); + } + + o_ptr->timeout = 250; + + break; + } + + case ACT_ORCHAST: + { + if (!doit) return "detect orcs every 10 turns"; + msg_print("Your weapon glows brightly..."); + (void)detect_monsters_xxx(RF3_ORC, DEFAULT_RADIUS); + + o_ptr->timeout = 10; + + break; + } + case ACT_SUNLIGHT: + { + if (!doit) return "beam of sunlight every 10 turns"; + + if (!get_aim_dir(&dir)) break; + msg_print("A line of sunlight appears."); + lite_line(dir); + + o_ptr->timeout = 10; + + break; + } + + case ACT_BO_MISS_1: + { + if (!doit) return "magic missile (2d6) every 2 turns"; + msg_print("It glows extremely brightly..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_MISSILE, dir, damroll(2, 6)); + + o_ptr->timeout = 2; + + break; + } + + case ACT_BA_POIS_1: + { + if (!doit) return "stinking cloud (12), rad. 3, every 4+d4 turns"; + msg_print("It throbs deep green..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_POIS, dir, 12, 3); + + o_ptr->timeout = rand_int(4) + 4; + + break; + } + + case ACT_BO_ELEC_1: + { + if (!doit) return "lightning bolt (4d8) every 6+d6 turns"; + msg_print("It is covered in sparks..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_ELEC, dir, damroll(4, 8)); + + o_ptr->timeout = rand_int(6) + 6; + + break; + } + + case ACT_BO_ACID_1: + { + if (!doit) return "acid bolt (5d8) every 5+d5 turns"; + msg_print("It is covered in acid..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_ACID, dir, damroll(5, 8)); + + o_ptr->timeout = rand_int(5) + 5; + + break; + } + + case ACT_BO_COLD_1: + { + if (!doit) return "frost bolt (6d8) every 7+d7 turns"; + msg_print("It is covered in frost..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_COLD, dir, damroll(6, 8)); + + o_ptr->timeout = rand_int(7) + 7; + + break; + } + + case ACT_BO_FIRE_1: + { + if (!doit) return "fire bolt (9d8) every 8+d8 turns"; + msg_print("It is covered in fire..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_FIRE, dir, damroll(9, 8)); + + o_ptr->timeout = rand_int(8) + 8; + + break; + } + + case ACT_BA_COLD_1: + { + if (!doit) return "ball of cold (48) every 400 turns"; + msg_print("It is covered in frost..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_COLD, dir, 48, 2); + + o_ptr->timeout = 400; + + break; + } + + case ACT_BA_FIRE_1: + { + if (!doit) return "ball of fire (72) every 400 turns"; + msg_print("It glows an intense red..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_FIRE, dir, 72, 2); + + o_ptr->timeout = 400; + + break; + } + + case ACT_DRAIN_1: + { + if (!doit) return "drain life (100) every 100+d100 turns"; + msg_print("It glows black..."); + if (!get_aim_dir(&dir)) break; + if (drain_life(dir, 100)) + + o_ptr->timeout = rand_int(100) + 100; + + break; + } + + case ACT_BA_COLD_2: + { + if (!doit) return "ball of cold (100) every 300 turns"; + msg_print("It glows an intense blue..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_COLD, dir, 100, 2); + + o_ptr->timeout = 300; + + break; + } + + case ACT_BA_ELEC_2: + { + if (!doit) return "ball of lightning (100) every 500 turns"; + msg_print("It crackles with electricity..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_ELEC, dir, 100, 3); + + o_ptr->timeout = 500; + + break; + } + + case ACT_DRAIN_2: + { + if (!doit) return "drain life (120) every 400 turns"; + msg_print("It glows black..."); + if (!get_aim_dir(&dir)) break; + drain_life(dir, 120); + + o_ptr->timeout = 400; + + break; + } + + case ACT_VAMPIRE_1: + { + if (!doit) return "vampiric drain (3*50) every 400 turns"; + if (!get_aim_dir(&dir)) break; + for (dummy = 0; dummy < 3; dummy++) + { + if (drain_life(dir, 50)) + hp_player(50); + } + + o_ptr->timeout = 400; + + break; + } + + case ACT_BO_MISS_2: + { + if (!doit) return "arrows (150) every 90+d90 turns"; + msg_print("It grows magical spikes..."); + if (!get_aim_dir(&dir)) break; + fire_bolt(GF_ARROW, dir, 150); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BA_FIRE_2: + { + if (!doit) return "fire ball (120) every 225+d225 turns"; + msg_print("It glows deep red..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_FIRE, dir, 120, 3); + + o_ptr->timeout = rand_int(225) + 225; + + break; + } + + case ACT_BA_COLD_3: + { + if (!doit) return "ball of cold (200) every 325+d325 turns"; + msg_print("It glows bright white..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_COLD, dir, 200, 3); + + o_ptr->timeout = rand_int(325) + 325; + + break; + } + + case ACT_BA_ELEC_3: + { + if (!doit) return "Lightning Ball (250) every 425+d425 turns"; + msg_print("It glows deep blue..."); + if (!get_aim_dir(&dir)) break; + fire_ball(GF_ELEC, dir, 250, 3); + + o_ptr->timeout = rand_int(425) + 425; + + break; + } + + case ACT_WHIRLWIND: + { + int y = 0, x = 0; + cave_type *c_ptr; + monster_type *m_ptr; + if (!doit) return "whirlwind attack every 250 turns"; + + for (dir = 0; dir <= 9; dir++) + { + y = p_ptr->py + ddy[dir]; + x = p_ptr->px + ddx[dir]; + c_ptr = &cave[y][x]; + + /* Get the monster */ + m_ptr = &m_list[c_ptr->m_idx]; + + /* Hack -- attack monsters */ + if (c_ptr->m_idx && (m_ptr->ml || cave_floor_bold(y, x))) + { + py_attack(y, x, -1); + } + } + + o_ptr->timeout = 250; + + break; + } + + case ACT_VAMPIRE_2: + { + if (!doit) return "vampiric drain (3*100) every 400 turns"; + if (!get_aim_dir(&dir)) break; + for (dummy = 0; dummy < 3; dummy++) + { + if (drain_life(dir, 100)) + hp_player(100); + } + + o_ptr->timeout = 400; + + break; + } + + + case ACT_CALL_CHAOS: + { + if (!doit) return "call chaos every 350 turns"; + msg_print("It glows in scintillating colours..."); + call_chaos(); + + o_ptr->timeout = 350; + + break; + } + + case ACT_ROCKET: + { + if (!doit) return "launch rocket (120+level) every 400 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You launch a rocket!"); + fire_ball(GF_ROCKET, dir, 120 + (plev), 2); + + o_ptr->timeout = 400; + + break; + } + + case ACT_DISP_EVIL: + { + if (!doit) return "dispel evil (level*5) every 300+d300 turns"; + msg_print("It floods the area with goodness..."); + dispel_evil(p_ptr->lev * 5); + + o_ptr->timeout = rand_int(300) + 300; + + break; + } + + case ACT_DISP_GOOD: + { + if (!doit) return "dispel good (level*5) every 300+d300 turns"; + msg_print("It floods the area with evil..."); + dispel_good(p_ptr->lev * 5); + + o_ptr->timeout = rand_int(300) + 300; + + break; + } + + case ACT_BA_MISS_3: + { + if (!doit) return "elemental breath (300) every 500 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe the elements."); + fire_ball(GF_MISSILE, dir, 300, 4); + + o_ptr->timeout = 500; + + break; + } + + /* Activate for other offensive action */ + + case ACT_CONFUSE: + { + if (!doit) return "confuse monster every 15 turns"; + msg_print("It glows in scintillating colours..."); + if (!get_aim_dir(&dir)) break; + confuse_monster(dir, 20); + + o_ptr->timeout = 15; + + break; + } + + case ACT_SLEEP: + { + if (!doit) return "sleep nearby monsters every 55 turns"; + msg_print("It glows deep blue..."); + sleep_monsters_touch(); + + o_ptr->timeout = 55; + + break; + } + + case ACT_QUAKE: + { + if (!doit) return "earthquake (rad 10) every 50 turns"; + /* Prevent destruction of quest levels and town */ + if (!is_quest(dun_level) && dun_level) + { + earthquake(p_ptr->py, p_ptr->px, 10); + o_ptr->timeout = 50; + } + + break; + } + + case ACT_TERROR: + { + if (!doit) return "terror every 3 * (level+10) turns"; +#if 0 + for (i = 0; i < 8; i++) fear_monster(ddd[i], (p_ptr->lev) + 10); +#else +turn_monsters(40 + p_ptr->lev); +#endif + + o_ptr->timeout = 3 * (p_ptr->lev + 10); + + break; + } + + case ACT_TELE_AWAY: + { + if (!doit) return "teleport away every 200 turns"; + if (!get_aim_dir(&dir)) break; + (void)fire_beam(GF_AWAY_ALL, dir, plev); + + o_ptr->timeout = 200; + + break; + } + + case ACT_BANISH_EVIL: + { + if (!doit) return "banish evil every 250+d250 turns"; + if (banish_evil(100)) + { + msg_print("The power of the artifact banishes evil!"); + } + + o_ptr->timeout = 250 + randint(250); + + break; + } + + case ACT_GENOCIDE: + { + if (!doit) return "genocide every 500 turns"; + msg_print("It glows deep blue..."); + (void)genocide(TRUE); + + o_ptr->timeout = 500; + + break; + } + + case ACT_MASS_GENO: + { + if (!doit) return "mass genocide every 1000 turns"; + msg_print("It lets out a long, shrill note..."); + (void)mass_genocide(TRUE); + + o_ptr->timeout = 1000; + + break; + } + + /* Activate for summoning / charming */ + + case ACT_CHARM_ANIMAL: + { + if (!doit) return "charm animal every 300 turns"; + if (!get_aim_dir(&dir)) break; + (void) charm_animal(dir, plev); + + o_ptr->timeout = 300; + + break; + } + + case ACT_CHARM_UNDEAD: + { + if (!doit) return "enslave undead every 333 turns"; + if (!get_aim_dir(&dir)) break; + (void)control_one_undead(dir, plev); + + o_ptr->timeout = 333; + + break; + } + + case ACT_CHARM_OTHER: + { + if (!doit) return "charm monster every 400 turns"; + if (!get_aim_dir(&dir)) break; + (void) charm_monster(dir, plev); + + o_ptr->timeout = 400; + + break; + } + + case ACT_CHARM_ANIMALS: + { + if (!doit) return "animal friendship every 500 turns"; + (void) charm_animals(plev * 2); + + o_ptr->timeout = 500; + + break; + } + + case ACT_CHARM_OTHERS: + { + if (!doit) return "mass charm every 750 turns"; + charm_monsters(plev * 2); + + o_ptr->timeout = 750; + + break; + } + + case ACT_SUMMON_ANIMAL: + { + if (!doit) return "summon animal every 200+d300 turns"; + (void)summon_specific_friendly(p_ptr->py, p_ptr->px, plev, SUMMON_ANIMAL_RANGER, TRUE); + + o_ptr->timeout = 200 + randint(300); + + break; + } + + case ACT_SUMMON_PHANTOM: + { + if (!doit) return "summon phantasmal servant every 200+d200 turns"; + msg_print("You summon a phantasmal servant."); + (void)summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level, SUMMON_PHANTOM, TRUE); + + o_ptr->timeout = 200 + randint(200); + + break; + } + + case ACT_SUMMON_ELEMENTAL: + { + if (!doit) return "summon elemental every 750 turns"; + if (randint(3) == 1) + { + if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_ELEMENTAL)) + { + msg_print("An elemental materialises..."); + msg_print("You fail to control it!"); + } + } + else + { + if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + SUMMON_ELEMENTAL, (bool)(plev == 50 ? TRUE : FALSE))) + { + msg_print("An elemental materialises..."); + msg_print("It seems obedient to you."); + } + } + + o_ptr->timeout = 750; + + break; + } + + case ACT_SUMMON_DEMON: + { + if (!doit) return "summon demon every 666+d333 turns"; + if (randint(3) == 1) + { + if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), SUMMON_DEMON)) + { + msg_print("The area fills with a stench of sulphur and brimstone."); + msg_print("'NON SERVIAM! Wretch! I shall feast on thy mortal soul!'"); + } + } + else + { + if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + SUMMON_DEMON, (bool)(plev == 50 ? TRUE : FALSE))) + { + msg_print("The area fills with a stench of sulphur and brimstone."); + msg_print("'What is thy bidding... Master?'"); + } + } + + o_ptr->timeout = 666 + randint(333); + + break; + } + + case ACT_SUMMON_UNDEAD: + { + if (!doit) return "summon undead every 666+d333 turns"; + if (randint(3) == 1) + { + if (summon_specific(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + (plev > 47 ? SUMMON_HI_UNDEAD : SUMMON_UNDEAD))) + { + msg_print("Cold winds begin to blow around you, carrying with them the stench of decay..."); + msg_print("'The dead arise... to punish you for disturbing them!'"); + } + } + else + { + if (summon_specific_friendly(p_ptr->py, p_ptr->px, ((plev * 3) / 2), + (plev > 47 ? SUMMON_HI_UNDEAD_NO_UNIQUES : SUMMON_UNDEAD), + (bool)(((plev > 24) && (randint(3) == 1)) ? TRUE : FALSE))) + { + msg_print("Cold winds begin to blow around you, carrying with them the stench of decay..."); + msg_print("Ancient, long-dead forms arise from the ground to serve you!"); + } + } + + o_ptr->timeout = 666 + randint(333); + + break; + } + + /* Activate for healing */ + + case ACT_CURE_LW: + { + if (!doit) return format("cure light wounds every %d turns", (is_junkart ? 50 : 10)); + (void)set_afraid(0); + (void)hp_player(30); + + o_ptr->timeout = 10; + + break; + } + + case ACT_CURE_MW: + { + if (!doit) return format("cure serious wounds every %s turns", (is_junkart? "75" : "3+d3")); + msg_print("It radiates deep purple..."); + hp_player(damroll(4, 8)); + (void)set_cut((p_ptr->cut / 2) - 50); + + o_ptr->timeout = rand_int(3) + 3; + + break; + } + + case ACT_CURE_POISON: + { + if (!doit) return "remove fear and cure poison every 5 turns"; + msg_print("It glows deep blue..."); + (void)set_afraid(0); + (void)set_poisoned(0); + + o_ptr->timeout = 5; + + break; + } + + case ACT_REST_LIFE: + { + if (!doit) return "restore life levels every 450 turns"; + msg_print("It glows a deep red..."); + restore_level(); + + o_ptr->timeout = 450; + + break; + } + + case ACT_REST_ALL: + { + if (!doit) return format("restore stats and life levels every %d turns", (is_junkart ? 200 : 750)); + msg_print("It glows a deep green..."); + (void)do_res_stat(A_STR, TRUE); + (void)do_res_stat(A_INT, TRUE); + (void)do_res_stat(A_WIS, TRUE); + (void)do_res_stat(A_DEX, TRUE); + (void)do_res_stat(A_CON, TRUE); + (void)do_res_stat(A_CHR, TRUE); + (void)restore_level(); + + o_ptr->timeout = 750; + + break; + } + + case ACT_CURE_700: + { + if (!doit) return format("heal 700 hit points every %d turns", (is_junkart ? 100 : 250)); + msg_print("It glows deep blue..."); + msg_print("You feel a warm tingling inside..."); + (void)hp_player(700); + (void)set_cut(0); + + o_ptr->timeout = 250; + + break; + } + + case ACT_CURE_1000: + { + if (!doit) return "heal 1000 hit points every 888 turns"; + msg_print("It glows a bright white..."); + msg_print("You feel much better..."); + (void)hp_player(1000); + (void)set_cut(0); + + o_ptr->timeout = 888; + + break; + } + + case ACT_ESP: + { + if (!doit) return "temporary ESP (dur 25+d30) every 200 turns"; + (void)set_tim_esp(p_ptr->tim_esp + randint(30) + 25); + + o_ptr->timeout = 200; + + break; + } + + case ACT_BERSERK: + { + if (!doit) return "heroism and berserk (dur 50+d50) every 100+d100 turns"; + (void)set_shero(p_ptr->shero + randint(50) + 50); + (void)set_blessed(p_ptr->blessed + randint(50) + 50); + + o_ptr->timeout = 100 + randint(100); + + break; + } + + case ACT_PROT_EVIL: + { + if (!doit) return "protection from evil (dur level*3 + d25) every 225+d225 turns"; + msg_print("It lets out a shrill wail..."); + k = 3 * p_ptr->lev; + (void)set_protevil(p_ptr->protevil + randint(25) + k); + + o_ptr->timeout = rand_int(225) + 225; + + break; + } + + case ACT_RESIST_ALL: + { + if (!doit) return "resist elements (dur 40+d40) every 200 turns"; + msg_print("It glows many colours..."); + (void)set_oppose_acid(p_ptr->oppose_acid + randint(40) + 40); + (void)set_oppose_elec(p_ptr->oppose_elec + randint(40) + 40); + (void)set_oppose_fire(p_ptr->oppose_fire + randint(40) + 40); + (void)set_oppose_cold(p_ptr->oppose_cold + randint(40) + 40); + (void)set_oppose_pois(p_ptr->oppose_pois + randint(40) + 40); + + o_ptr->timeout = 200; + + break; + } + + case ACT_SPEED: + { + if (!doit) return "speed (dur 20+d20) every 250 turns"; + msg_print("It glows bright green..."); + if (!p_ptr->fast) + { + (void)set_fast(randint(20) + 20, 10); + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + + o_ptr->timeout = 250; + + break; + } + + case ACT_XTRA_SPEED: + { + if (!doit) return "speed (dur 75+d75) every 200+d200 turns"; + msg_print("It glows brightly..."); + if (!p_ptr->fast) + { + (void)set_fast(randint(75) + 75, 10); + } + else + { + (void)set_fast(p_ptr->fast + 5, 10); + } + + o_ptr->timeout = rand_int(200) + 200; + + break; + } + + case ACT_WRAITH: + { + if (!doit) return "wraith form (level/2 + d(level/2)) every 1000 turns"; + set_shadow(p_ptr->tim_wraith + randint(plev / 2) + (plev / 2)); + + o_ptr->timeout = 1000; + + break; + } + + case ACT_INVULN: + { + if (!doit) return "invulnerability (dur 8+d8) every 1000 turns"; + (void)set_invuln(p_ptr->invuln + randint(8) + 8); + + o_ptr->timeout = 1000; + + break; + } + + /* Activate for general purpose effect (detection etc.) */ + + case ACT_LIGHT: + { + if (!doit) return format("light area (dam 2d15) every %s turns", (is_junkart ? "100" : "10+d10")); + msg_print("It wells with clear light..."); + lite_area(damroll(2, 15), 3); + + o_ptr->timeout = rand_int(10) + 10; + + break; + } + + case ACT_MAP_LIGHT: + { + if (!doit) return "light (dam 2d15) & map area every 50+d50 turns"; + msg_print("It shines brightly..."); + map_area(); + lite_area(damroll(2, 15), 3); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + + case ACT_DETECT_ALL: + { + if (!doit) return "detection every 55+d55 turns"; + msg_print("It glows bright white..."); + msg_print("An image forms in your mind..."); + detect_all(DEFAULT_RADIUS); + + o_ptr->timeout = rand_int(55) + 55; + + break; + } + + case ACT_DETECT_XTRA: + { + if (!doit) return "detection, probing and identify true every 1000 turns"; + msg_print("It glows brightly..."); + detect_all(DEFAULT_RADIUS); + probing(); + identify_fully(); + + o_ptr->timeout = 1000; + + break; + } + + case ACT_ID_FULL: + { + if (!doit) return "identify true every 750 turns"; + msg_print("It glows yellow..."); + identify_fully(); + + o_ptr->timeout = 750; + + break; + } + + case ACT_ID_PLAIN: + { + if (!doit) return "identify spell every 10 turns"; + if (!ident_spell()) break; + + o_ptr->timeout = 10; + + break; + } + + case ACT_RUNE_EXPLO: + { + if (!doit) return "explosive rune every 200 turns"; + msg_print("It glows bright red..."); + explosive_rune(); + + o_ptr->timeout = 200; + + break; + } + + case ACT_RUNE_PROT: + { + if (!doit) return "rune of protection every 400 turns"; + msg_print("It glows light blue..."); + warding_glyph(); + + o_ptr->timeout = 400; + + break; + } + + case ACT_SATIATE: + { + if (!doit) return "satisfy hunger every 200 turns"; + (void)set_food(PY_FOOD_MAX - 1); + + o_ptr->timeout = 200; + + break; + } + + case ACT_DEST_DOOR: + { + if (!doit) return "destroy doors and traps every 10 turns"; + msg_print("It glows bright red..."); + destroy_doors_touch(); + + o_ptr->timeout = 10; + + break; + } + + case ACT_STONE_MUD: + { + if (!doit) return "stone to mud every 5 turns"; + msg_print("It pulsates..."); + if (!get_aim_dir(&dir)) break; + wall_to_mud(dir); + + o_ptr->timeout = 5; + + break; + } + + case ACT_RECHARGE: + { + if (!doit) return "recharging every 70 turns"; + recharge(60); + + o_ptr->timeout = 70; + + break; + } + + case ACT_ALCHEMY: + { + if (!doit) return "alchemy every 500 turns"; + msg_print("It glows bright yellow..."); + (void) alchemy(); + + o_ptr->timeout = 500; + + break; + } + + case ACT_DIM_DOOR: + { + if (!doit) return "dimension door every 100 turns"; + if (dungeon_flags2 & DF2_NO_TELEPORT) + { + msg_print("Not on special levels!"); + break; + } + + msg_print("You open a Void Jumpgate. Choose a destination."); + if (!tgt_pt(&ii, &ij)) break; + + p_ptr->energy -= 60 - plev; + + if (!cave_empty_bold(ij, ii) || (cave[ij][ii].info & CAVE_ICKY) || + (distance(ij, ii, p_ptr->py, p_ptr->px) > plev + 2) || + (!rand_int(plev * plev / 2))) + { + msg_print("You fail to exit the void correctly!"); + p_ptr->energy -= 100; + get_pos_player(10, &ij, &ii); + } + + cave_set_feat(p_ptr->py, p_ptr->px, FEAT_BETWEEN); + cave_set_feat(ij, ii, FEAT_BETWEEN); + cave[p_ptr->py][p_ptr->px].special = ii + (ij << 8); + cave[ij][ii].special = p_ptr->px + (p_ptr->py << 8); + + o_ptr->timeout = 100; + + break; + } + + case ACT_TELEPORT: + { + if (!doit) return format("teleport (range 100) every %d turns", (is_junkart? 100 : 45)); + msg_print("It twists space around you..."); + teleport_player(100); + + o_ptr->timeout = 45; + + break; + } + + case ACT_RECALL: + { + if (!(dungeon_flags2 & DF2_ASK_LEAVE) || ((dungeon_flags2 & DF2_ASK_LEAVE) && !get_check("Leave this unique level forever? "))) + { + if (!doit) return "word of recall every 200 turns"; + msg_print("It glows soft white..."); + recall_player(20,15); + + o_ptr->timeout = 200; + } + + break; + } + + case ACT_DEATH: + { + if (!doit) return "death"; + take_hit(5000, "activating a death spell"); + + /* Timeout is set before return */ + + break; + } + + case ACT_RUINATION: + { + if (!doit) return "Ruination"; + msg_print("Your nerves and muscles feel weak and lifeless!"); + + take_hit(damroll(10, 10), "activating Ruination"); + (void)dec_stat(A_DEX, 25, TRUE); + (void)dec_stat(A_WIS, 25, TRUE); + (void)dec_stat(A_CON, 25, TRUE); + (void)dec_stat(A_STR, 25, TRUE); + (void)dec_stat(A_CHR, 25, TRUE); + (void)dec_stat(A_INT, 25, TRUE); + + /* Timeout is set before return */ + + break; + } + + case ACT_DESTRUC: + { + if (!doit) return "Destruction every 100 turns"; + earthquake(p_ptr->py, p_ptr->px, 12); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNINT: + { + if (!doit) return "decreasing Intelligence"; + (void)dec_stat(A_INT, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNSTR: + { + if (!doit) return "decreasing Strength"; + (void)dec_stat(A_STR, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNCON: + { + if (!doit) return "decreasing Constitution"; + (void)dec_stat(A_CON, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNCHR: + { + if (!doit) return "decreasing Charisma"; + (void)dec_stat(A_CHR, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNDEX: + { + if (!doit) return "decreasing Dexterity"; + (void)dec_stat(A_DEX, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_UNWIS: + { + if (!doit) return "decreasing Wisdom"; + (void)dec_stat(A_WIS, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_STATLOSS: + { + if (!doit) return "stat loss"; + (void)dec_stat(A_STR, 15, FALSE); + (void)dec_stat(A_INT, 15, FALSE); + (void)dec_stat(A_WIS, 15, FALSE); + (void)dec_stat(A_DEX, 15, FALSE); + (void)dec_stat(A_CON, 15, FALSE); + (void)dec_stat(A_CHR, 15, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_HISTATLOSS: + { + if (!doit) return "high stat loss"; + (void)dec_stat(A_STR, 25, FALSE); + (void)dec_stat(A_INT, 25, FALSE); + (void)dec_stat(A_WIS, 25, FALSE); + (void)dec_stat(A_DEX, 25, FALSE); + (void)dec_stat(A_CON, 25, FALSE); + (void)dec_stat(A_CHR, 25, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_EXPLOSS: + { + if (!doit) return "experience loss"; + lose_exp(p_ptr->exp / 20); + + /* Timeout is set before return */ + + break; + } + + case ACT_HIEXPLOSS: + { + if (!doit) return "high experience loss"; + lose_exp(p_ptr->exp / 10); + + /* Timeout is set before return */ + + break; + } + + case ACT_SUMMON_MONST: + { + if (!doit) return "summon monster"; + summon_specific(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0); + + /* Timeout is set before return */ + + break; + } + + case ACT_PARALYZE: + { + if (!doit) return "paralyze"; + set_paralyzed(p_ptr->paralyzed + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_HALLU: + { + if (!doit) return "hallucination every 10 turns"; + set_image(p_ptr->image + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_POISON: + { + if (!doit) return "poison"; + set_poisoned(p_ptr->poisoned + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_HUNGER: + { + if (!doit) return "create hunger"; + (void)set_food(PY_FOOD_WEAK); + + /* Timeout is set before return */ + + break; + } + + case ACT_STUN: + { + if (!doit) return "stun"; + set_stun(p_ptr->stun + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_CUTS: + { + if (!doit) return "cuts"; + set_cut(p_ptr->cut + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_PARANO: + { + if (!doit) return "confusion"; + set_confused(p_ptr->confused + 30 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_CONFUSION: + { + if (!doit) return "confusion"; + set_confused(p_ptr->confused + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_BLIND: + { + if (!doit) return "blindness"; + set_blind(p_ptr->blind + 20 + randint(10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_PET_SUMMON: + { + if (!doit) return "summon pet every 101 turns"; + summon_specific_friendly(p_ptr->py, p_ptr->px, max_dlv[dungeon_type], 0, FALSE); + + /* Timeout is set before return */ + /*FINDME*/ + + break; + } + + case ACT_CURE_PARA: + { + if (!doit) return "cure confusion every 500 turns"; + set_confused(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_HALLU: + { + if (!doit) return "cure hallucination every 100 turns"; + set_image(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_POIS: + { + if (!doit) return "cure poison every 100 turns"; + set_poisoned(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_HUNGER: + { + if (!doit) return "satisfy hunger every 100 turns"; + (void)set_food(PY_FOOD_MAX - 1); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_STUN: + { + if (!doit) return "cure stun every 100 turns"; + set_stun(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_CUTS: + { + if (!doit) return "cure cuts every 100 turns"; + set_cut(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_FEAR: + { + if (!doit) return "cure fear every 100 turns"; + set_afraid(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_CONF: + { + if (!doit) return "cure confusion every 100 turns"; + set_confused(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_BLIND: + { + if (!doit) return "cure blindness every 100 turns"; + set_blind(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURING: + { + if (!doit) return "curing every 110 turns"; + set_blind(0); + set_poisoned(0); + set_confused(0); + set_stun(0); + set_cut(0); + set_image(0); + + /* Timeout is set before return */ + + break; + } + + case ACT_DARKNESS: + { + if (!doit) return "darkness"; + unlite_area(damroll(2, 10), 10); + + /* Timeout is set before return */ + + break; + } + + case ACT_LEV_TELE: + { + if (!doit) return "teleport level every 50 turns"; + teleport_player_level(); + + /* Timeout is set before return */ + + break; + } + + case ACT_ACQUIREMENT: + { + if (!doit) return "acquirement every 3000 turns"; + acquirement(p_ptr->py, p_ptr->px, 1, FALSE, FALSE); + + /* Timeout is set before return */ + + break; + } + + case ACT_WEIRD: + { + if (!doit) return "something weird every 5 turns"; + /* It doesn't do anything */ + + /* Timeout is set before return */ + + break; + } + + case ACT_AGGRAVATE: + { + if (!doit) return "aggravate"; + aggravate_monsters(1); + + /* Timeout is set before return */ + + break; + } + + case ACT_MUT: + { + if (!doit) return "gain corruption every 10 turns"; + gain_random_corruption(0); + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_INSANITY: + { + if (!doit) return "cure insanity every 200 turns"; + heal_insanity(damroll(10, 10)); + + /* Timeout is set before return */ + + break; + } + + case ACT_CURE_MUT: + { +#if 0 // DGDGDGD +#else + msg_print("Ahah, you wish."); +#endif + /* Timeout is set before return */ + + break; + } + + case ACT_LIGHT_ABSORBTION: + { + int y, x, light = 0, dir; + cave_type *c_ptr; + + if (!doit) return "light absorption every 80 turns"; + + for (y = p_ptr->py - 6; y <= p_ptr->py + 6; y++) + { + for (x = p_ptr->px - 6; x <= p_ptr->px + 6; x++) + { + if (!in_bounds(y, x)) continue; + + c_ptr = &cave[y][x]; + + if (distance(y, x, p_ptr->py, p_ptr->px) > 6) continue; + + if (c_ptr->info & CAVE_GLOW) + { + light++; + + /* No longer in the array */ + c_ptr->info &= ~(CAVE_TEMP); + + /* Darken the grid */ + c_ptr->info &= ~(CAVE_GLOW); + + /* Hack -- Forget "boring" grids */ + if (cave_plain_floor_grid(c_ptr) && + !(c_ptr->info & (CAVE_TRDT))) + { + /* Forget the grid */ + c_ptr->info &= ~(CAVE_MARK); + + /* Notice */ + note_spot(y, x); + } + + /* Process affected monsters */ + if (c_ptr->m_idx) + { + /* Update the monster */ + update_mon(c_ptr->m_idx, FALSE); + } + + /* Redraw */ + lite_spot(y, x); + } + } + } + + if (!get_aim_dir(&dir)) return (FALSE); + + msg_print("The light around you is absorbed... " + "and released in a powerful bolt!"); + fire_bolt(GF_LITE, dir, damroll(light, p_ptr->lev)); + + /* Timeout is set before return */ + + break; + } + /* Horns of DragonKind (Note that these are new egos)*/ + case ACT_BA_FIRE_H: + { + if (!doit) return "large fire ball (300) every 100 turns"; + fire_ball(GF_FIRE, 5, 300, 7); + + o_ptr->timeout = 100; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + break; + } + case ACT_BA_COLD_H: + { + if (!doit) return "large cold ball (300) every 100 turns"; + fire_ball(GF_COLD, 5, 300, 7); + + o_ptr->timeout = 100; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + break; + } + case ACT_BA_ELEC_H: + { + if (!doit) return "large lightning ball (300) every 100 turns"; + fire_ball(GF_ELEC, 5, 300, 7); + + o_ptr->timeout = 100; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + break; + } + case ACT_BA_ACID_H: + { + if (!doit) return "large acid ball (300) every 100 turns"; + fire_ball(GF_ACID, 5, 300, 7); + + o_ptr->timeout = 100; + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + break; + } + + case ACT_SPIN: + { + if (!doit) return "spinning around every 50+d25 turns"; + do_spin(); + + o_ptr->timeout = 50 + randint(25); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Done */ + break; + } + case ACT_NOLDOR: + { + if (!doit) return "detect treasure every 10+d20 turns"; + detect_treasure(DEFAULT_RADIUS); + + o_ptr->timeout = 10 + randint(20); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Done */ + break; + } + case ACT_SPECTRAL: + { + if (!doit) return "wraith-form every 50+d50 turns"; + if (!p_ptr->wraith_form) + { + set_shadow(20 + randint(20)); + } + else + { + set_shadow(p_ptr->tim_wraith + randint(20)); + } + + o_ptr->timeout = 50 + randint(50); + + /* Window stuff */ + p_ptr->window |= PW_INVEN | PW_EQUIP; + + /* Done */ + break; + } + case ACT_JUMP: + { + if (!doit) return "phasing every 10+d10 turns"; + teleport_player(10); + o_ptr->timeout = 10 + randint(10); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Done */ + break; + } + + case ACT_DEST_TELE: + { + if (!doit) return "teleportation and destruction of the ring"; + if (!item) + { + msg_print("You can't activate this when it's there!"); + } + if (get_check("This will destroy the ring. Do you wish to continue? ")) + { + msg_print("The ring explodes into a space distortion."); + teleport_player(200); + + /* It explodes, doesn't it ? */ + take_hit(damroll(2, 10), "an exploding ring"); + if ( item > 0) + { + inven_item_increase(item, -255); + inven_item_optimize(item); + } + else + { + floor_item_increase( -item, -255); + floor_item_optimize( -item); + } + } + + break; + } + /*amulet of serpents dam 100, rad 2 timeout 40+d60 */ + case ACT_BA_POIS_4: + { + if (!doit) return "venom breathing every 40+d60 turns"; + /* Get a direction for breathing (or abort) */ + if (!get_aim_dir(&dir)) break; + + msg_print("You breathe venom..."); + fire_ball(GF_POIS, dir, 100, 2); + + o_ptr->timeout = rand_int(60) + 40; + + /* Window stuff */ + p_ptr->window |= PW_INVEN | PW_EQUIP; + + /* Done */ + break; + } + /*rings of X 50,50+d50 dur 20+d20 */ + case ACT_BA_COLD_4: + { + if (!doit) return "ball of cold and resist cold every 50+d50 turns"; + /* Get a direction for breathing (or abort) */ + if (!get_aim_dir(&dir)) break; + + fire_ball(GF_COLD, dir, 50, 2); + (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + + case ACT_BA_FIRE_4: + { + if (!doit) return "ball of fire and resist fire every 50+d50 turns"; + /* Get a direction for breathing (or abort) */ + if (!get_aim_dir(&dir)) break; + + fire_ball(GF_FIRE, dir, 50, 2); + (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + case ACT_BA_ACID_4: + { + if (!doit) return "ball of acid and resist acid every 50+d50 turns"; + /* Get a direction for breathing (or abort) */ + if (!get_aim_dir(&dir)) break; + + fire_ball(GF_ACID, dir, 50, 2); + (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + + case ACT_BA_ELEC_4: + { + if (!doit) return "ball of lightning and resist lightning every 50+d50 turns"; + /* Get a direction for breathing (or abort) */ + if (!get_aim_dir(&dir)) break; + + fire_ball(GF_ELEC, dir, 50, 2); + (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20); + + o_ptr->timeout = rand_int(50) + 50; + + break; + } + + case ACT_BR_ELEC: + { + if (!doit) return "breathe lightning (100) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe lightning."); + fire_ball(GF_ELEC, dir, 100, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_COLD: + { + if (!doit) return "breathe frost (110) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe frost."); + fire_ball(GF_COLD, dir, 110, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_FIRE: + { + if (!doit) return "breathe fire (200) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe fire."); + fire_ball(GF_FIRE, dir, 200, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_ACID: + { + if (!doit) return "breathe acid (130) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe acid."); + fire_ball(GF_ACID, dir, 130, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_POIS: + { + if (!doit) return "breathe poison gas (150) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe poison gas."); + fire_ball(GF_POIS, dir, 150, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_MANY: + { + if (!doit) return "breathe multi-hued (250) every 60+d60 turns"; + if (!get_aim_dir(&dir)) break; + chance = rand_int(5); + msg_format("You breathe %s.", + ((chance == 1) ? "lightning" : + ((chance == 2) ? "frost" : + ((chance == 3) ? "acid" : + ((chance == 4) ? "poison gas" : "fire"))))); + fire_ball(((chance == 1) ? GF_ELEC : + ((chance == 2) ? GF_COLD : + ((chance == 3) ? GF_ACID : + ((chance == 4) ? GF_POIS : GF_FIRE)))), + dir, 250, 2); + + o_ptr->timeout = rand_int(60) + 60; + + break; + } + + case ACT_BR_CONF: + { + if (!doit) return "breathe confusion (120) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe confusion."); + fire_ball(GF_CONFUSION, dir, 120, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_SOUND: + { + if (!doit) return "breathe sound (130) every 90+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe sound."); + fire_ball(GF_SOUND, dir, 130, 2); + + o_ptr->timeout = rand_int(90) + 90; + + break; + } + + case ACT_BR_CHAOS: + { + if (!doit) return "breathe chaos/disenchant (220) every 60+d90 turns"; + if (!get_aim_dir(&dir)) break; + chance = rand_int(2); + msg_format("You breathe %s.", + ((chance == 1 ? "chaos" : "disenchantment"))); + fire_ball((chance == 1 ? GF_CHAOS : GF_DISENCHANT), + dir, 220, 2); + + o_ptr->timeout = rand_int(90) + 60; + + break; + } + + case ACT_BR_SHARD: + { + if (!doit) return "breathe sound/shards (230) every 60+d90 turns"; + if (!get_aim_dir(&dir)) break; + chance = rand_int(2); + msg_format("You breathe %s.", + ((chance == 1 ? "sound" : "shards"))); + fire_ball((chance == 1 ? GF_SOUND : GF_SHARDS), + dir, 230, 2); + + o_ptr->timeout = rand_int(90) + 60; + + break; + } + + case ACT_BR_BALANCE: + { + if (!doit) return "breathe balance (250) every 60+d90 turns"; + if (!get_aim_dir(&dir)) break; + chance = rand_int(4); + msg_format("You breathe %s.", + ((chance == 1) ? "chaos" : + ((chance == 2) ? "disenchantment" : + ((chance == 3) ? "sound" : "shards")))); + fire_ball(((chance == 1) ? GF_CHAOS : + ((chance == 2) ? GF_DISENCHANT : + ((chance == 3) ? GF_SOUND : GF_SHARDS))), + dir, 250, 2); + + o_ptr->timeout = rand_int(90) + 60; + + break; + } + + case ACT_BR_LIGHT: + { + if (!doit) return "breathe light/darkness (200) every 60+d90 turns"; + if (!get_aim_dir(&dir)) break; + chance = rand_int(2); + msg_format("You breathe %s.", + ((chance == 0 ? "light" : "darkness"))); + fire_ball((chance == 0 ? GF_LITE : GF_DARK), dir, 200, 2); + + o_ptr->timeout = rand_int(90) + 60; + + break; + } + case ACT_BR_POWER: + { + if (!doit) return "breathe the elements (300) every 60+d90 turns"; + if (!get_aim_dir(&dir)) break; + msg_print("You breathe the elements."); + fire_ball(GF_MISSILE, dir, 300, 3); + + o_ptr->timeout = rand_int(90) + 60; + + break; + } + case ACT_GROW_MOLD: + { + if (!doit) return "grow mushrooms every 50+d50 turns"; + msg_print("You twirl and spores fly everywhere!"); + for (i = 0; i < 8; i++) + summon_specific_friendly(p_ptr->py, p_ptr->px, p_ptr->lev, SUMMON_BIZARRE1, FALSE); + + o_ptr->timeout = randint(50) + 50; + + break; + } + case ACT_MUSIC: + /* + fall through to unknown, as music should be + handled by calling procedure. + */ + + default: + { + msg_format("Unknown activation effect: %d.", spell); + if ( !doit ) return "Unknown Activation"; + return NULL; + } + } + } + + /* Set timeout for junkarts + * Note that I still need to set the timeouts for other + * (non-random) artifacts above + */ + if (is_junkart && doit) + o_ptr->timeout = activation_info[o_ptr->pval2].cost / 10; + + return NULL; +} + + +static bool activate_spell(object_type * o_ptr, byte choice) +{ + int mana = 0, gf = 0, mod = 0; + + rune_spell s_ptr; + + + if (choice == 1) + { + gf = o_ptr->pval & 0xFFFF; + mod = o_ptr->pval3 & 0xFFFF; + mana = o_ptr->pval2 & 0xFF; + } + else if (choice == 2) + { + gf = o_ptr->pval >> 16; + mod = o_ptr->pval3 >> 16; + mana = o_ptr->pval2 >> 8; + } + + s_ptr.type = gf; + s_ptr.rune2 = 1 << mod; + s_ptr.mana = mana; + + /* Execute */ + rune_exec(&s_ptr, 0); + + if (choice == 1) o_ptr->timeout = mana * 5; + if (choice == 2) o_ptr->xtra2 = mana * 5; + + return (TRUE); +} |