From 4b54f4f18ad2a1dad93721bd95cd6b4aed1daab4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 7 Jul 2021 12:02:59 +0300 Subject: [PATCH] Split scroll effects into separate functions --- src/read.c | 1693 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 978 insertions(+), 715 deletions(-) diff --git a/src/read.c b/src/read.c index 7e1ebdf4f..518537163 100644 --- a/src/read.c +++ b/src/read.c @@ -24,6 +24,31 @@ static int maybe_tame(struct monst *, struct obj *); static boolean get_valid_stinking_cloud_pos(int, int); static boolean is_valid_stinking_cloud_pos(int, int, boolean); static void display_stinking_cloud_positions(int); +static void seffect_enchant_armor(struct obj **); +static void seffect_destroy_armor(struct obj **); +static void seffect_confuse_monster(struct obj **); +static void seffect_scare_monster(struct obj **); +static void seffect_remove_curse(struct obj **); +static void seffect_create_monster(struct obj **); +static void seffect_enchant_weapon(struct obj **); +static void seffect_taming(struct obj **); +static void seffect_genocide(struct obj **); +static void seffect_light(struct obj **); +static void seffect_charging(struct obj **); +static void seffect_amnesia(struct obj **); +static void seffect_fire(struct obj **); +static void seffect_earth(struct obj **); +static void seffect_punishment(struct obj **); +static void seffect_stinking_cloud(struct obj **); +static void seffect_blank_paper(struct obj **); +static void seffect_teleportation(struct obj **); +static void seffect_gold_detection(struct obj **); +static void seffect_food_detection(struct obj **); +static void seffect_identify(struct obj **); +static void seffect_magic_mapping(struct obj **); +#ifdef MAIL_STRUCTURES +static void seffect_mail(struct obj **); +#endif /* MAIL_STRUCTURES */ static void set_lit(int, int, genericptr); static void do_class_genocide(void); static boolean create_particular_parse(char *, @@ -932,574 +957,843 @@ display_stinking_cloud_positions(int state) } } -/* scroll effects; return 1 if we use up the scroll and possibly make it - become discovered, 0 if caller should take care of those side-effects */ -int -seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ +static void +seffect_enchant_armor(struct obj **sobjp) { - int cval, otyp = sobj->otyp; - boolean confused = (Confusion != 0), sblessed = sobj->blessed, - scursed = sobj->cursed, already_known, old_erodeproof, - new_erodeproof; - struct obj *otmp; - - if (objects[otyp].oc_magic) - exercise(A_WIS, TRUE); /* just for trying */ - already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ - || objects[otyp].oc_name_known); + struct obj *sobj = *sobjp; + register schar s; + boolean special_armor; + boolean same_color; + struct obj *otmp = some_armor(&g.youmonst); + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + boolean old_erodeproof, new_erodeproof; + + if (!otmp) { + strange_feeling(sobj, !Blind + ? "Your skin glows then fades." + : "Your skin feels warm for a moment."); + *sobjp = 0; /* useup() in strange_feeling() */ + exercise(A_CON, !scursed); + exercise(A_STR, !scursed); + return; + } + if (confused) { + old_erodeproof = (otmp->oerodeproof != 0); + new_erodeproof = !scursed; + otmp->oerodeproof = 0; /* for messages */ + if (Blind) { + otmp->rknown = FALSE; + pline("%s warm for a moment.", Yobjnam2(otmp, "feel")); + } else { + otmp->rknown = TRUE; + pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"), + scursed ? "mottled" : "shimmering", + hcolor(scursed ? NH_BLACK : NH_GOLDEN), + scursed ? "glow" + : (is_shield(otmp) ? "layer" : "shield")); + } + if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) { + otmp->oeroded = otmp->oeroded2 = 0; + pline("%s as good as new!", + Yobjnam2(otmp, Blind ? "feel" : "look")); + } + if (old_erodeproof && !new_erodeproof) { + /* restore old_erodeproof before shop charges */ + otmp->oerodeproof = 1; + costly_alteration(otmp, COST_DEGRD); + } + otmp->oerodeproof = new_erodeproof ? 1 : 0; + return; + } + /* elven armor vibrates warningly when enchanted beyond a limit */ + special_armor = is_elven_armor(otmp) + || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM); + if (scursed) + same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL + || otmp->otyp == BLACK_DRAGON_SCALES); + else + same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL + || otmp->otyp == SILVER_DRAGON_SCALES + || otmp->otyp == SHIELD_OF_REFLECTION); + if (Blind) + same_color = FALSE; + + /* KMH -- catch underflow */ + s = scursed ? -otmp->spe : otmp->spe; + if (s > (special_armor ? 5 : 3) && rn2(s)) { + otmp->in_use = TRUE; + pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp), + otense(otmp, Blind ? "vibrate" : "glow"), + (!Blind && !same_color) ? " " : "", + (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK + : NH_SILVER), + otense(otmp, "evaporate")); + remove_worn_item(otmp, FALSE); + useup(otmp); + return; + } + s = scursed ? -1 + : (otmp->spe >= 9) + ? (rn2(otmp->spe) == 0) + : sblessed + ? rnd(3 - otmp->spe / 3) + : 1; + if (s >= 0 && Is_dragon_scales(otmp)) { + /* dragon scales get turned into dragon scale mail */ + pline("%s merges and hardens!", Yname2(otmp)); + setworn((struct obj *) 0, W_ARM); + /* assumes same order */ + otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES; + if (sblessed) { + otmp->spe++; + cap_spe(otmp); + if (!otmp->blessed) + bless(otmp); + } else if (otmp->cursed) + uncurse(otmp); + otmp->known = 1; + setworn(otmp, W_ARM); + if (otmp->unpaid) + alter_cost(otmp, 0L); /* shop bill */ + return; + } + pline("%s %s%s%s%s for a %s.", Yname2(otmp), + (s == 0) ? "violently " : "", + otense(otmp, Blind ? "vibrate" : "glow"), + (!Blind && !same_color) ? " " : "", + (Blind || same_color) + ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER), + (s * s > 1) ? "while" : "moment"); + /* [this cost handling will need updating if shop pricing is + ever changed to care about curse/bless status of armor] */ + if (s < 0) + costly_alteration(otmp, COST_DECHNT); + if (scursed && !otmp->cursed) + curse(otmp); + else if (sblessed && !otmp->blessed) + bless(otmp); + else if (!scursed && otmp->cursed) + uncurse(otmp); + if (s) { + int oldspe = otmp->spe; + /* despite being schar, it shouldn't be possible for spe to wrap + here because it has been capped at 99 and s is quite small; + however, might need to change s if it takes spe past 99 */ + otmp->spe += s; + cap_spe(otmp); /* make sure that it doesn't exceed SPE_LIM */ + s = otmp->spe - oldspe; /* cap_spe() might have throttled 's' */ + if (s) /* skip if it got changed to 0 */ + adj_abon(otmp, s); /* adjust armor bonus for Dex or Int+Wis */ + g.known = otmp->known; + /* update shop bill to reflect new higher price */ + if (s > 0 && otmp->unpaid) + alter_cost(otmp, 0L); + } - switch (otyp) { -#ifdef MAIL_STRUCTURES - case SCR_MAIL: { - boolean odd = (sobj->o_id % 2) == 1; + if ((otmp->spe > (special_armor ? 5 : 3)) + && (special_armor || !rn2(7))) + pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"), + Blind ? "again" : "unexpectedly"); +} - g.known = TRUE; - switch (sobj->spe) { - case 2: - /* "stamped scroll" created via magic marker--without a stamp */ - pline("This scroll is marked \"%s\".", - odd ? "Postage Due" : "Return to Sender"); - break; - case 1: - /* scroll of mail obtained from bones file or from wishing; - note to the puzzled: the game Larn actually sends you junk - mail if you win! */ - pline("This seems to be %s.", - odd ? "a chain letter threatening your luck" - : "junk mail addressed to the finder of the Eye of Larn"); - break; - default: -#ifdef MAIL - readmail(sobj); -#else - /* unreachable since with MAIL undefined, sobj->spe won't be 0; - as a precaution, be prepared to give arbitrary feedback; - caller has already reported that it disappears upon reading */ - pline("That was a scroll of mail?"); -#endif - break; - } - break; - } -#endif - case SCR_ENCHANT_ARMOR: { - register schar s; - boolean special_armor; - boolean same_color; +static void +seffect_destroy_armor(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + struct obj *otmp = some_armor(&g.youmonst); + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + boolean old_erodeproof, new_erodeproof; - otmp = some_armor(&g.youmonst); + if (confused) { if (!otmp) { - strange_feeling(sobj, !Blind - ? "Your skin glows then fades." - : "Your skin feels warm for a moment."); - sobj = 0; /* useup() in strange_feeling() */ - exercise(A_CON, !scursed); - exercise(A_STR, !scursed); - break; - } - if (confused) { - old_erodeproof = (otmp->oerodeproof != 0); - new_erodeproof = !scursed; - otmp->oerodeproof = 0; /* for messages */ - if (Blind) { - otmp->rknown = FALSE; - pline("%s warm for a moment.", Yobjnam2(otmp, "feel")); - } else { - otmp->rknown = TRUE; - pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"), - scursed ? "mottled" : "shimmering", - hcolor(scursed ? NH_BLACK : NH_GOLDEN), - scursed ? "glow" - : (is_shield(otmp) ? "layer" : "shield")); - } - if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) { - otmp->oeroded = otmp->oeroded2 = 0; - pline("%s as good as new!", - Yobjnam2(otmp, Blind ? "feel" : "look")); - } - if (old_erodeproof && !new_erodeproof) { - /* restore old_erodeproof before shop charges */ - otmp->oerodeproof = 1; - costly_alteration(otmp, COST_DEGRD); - } - otmp->oerodeproof = new_erodeproof ? 1 : 0; - break; - } - /* elven armor vibrates warningly when enchanted beyond a limit */ - special_armor = is_elven_armor(otmp) - || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM); - if (scursed) - same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL - || otmp->otyp == BLACK_DRAGON_SCALES); - else - same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL - || otmp->otyp == SILVER_DRAGON_SCALES - || otmp->otyp == SHIELD_OF_REFLECTION); - if (Blind) - same_color = FALSE; - - /* KMH -- catch underflow */ - s = scursed ? -otmp->spe : otmp->spe; - if (s > (special_armor ? 5 : 3) && rn2(s)) { - otmp->in_use = TRUE; - pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp), - otense(otmp, Blind ? "vibrate" : "glow"), - (!Blind && !same_color) ? " " : "", - (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK - : NH_SILVER), - otense(otmp, "evaporate")); - remove_worn_item(otmp, FALSE); - useup(otmp); - break; - } - s = scursed ? -1 - : (otmp->spe >= 9) - ? (rn2(otmp->spe) == 0) - : sblessed - ? rnd(3 - otmp->spe / 3) - : 1; - if (s >= 0 && Is_dragon_scales(otmp)) { - /* dragon scales get turned into dragon scale mail */ - pline("%s merges and hardens!", Yname2(otmp)); - setworn((struct obj *) 0, W_ARM); - /* assumes same order */ - otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES; - if (sblessed) { - otmp->spe++; - cap_spe(otmp); - if (!otmp->blessed) - bless(otmp); - } else if (otmp->cursed) - uncurse(otmp); - otmp->known = 1; - setworn(otmp, W_ARM); - if (otmp->unpaid) - alter_cost(otmp, 0L); /* shop bill */ - break; + strange_feeling(sobj, "Your bones itch."); + *sobjp = 0; /* useup() in strange_feeling() */ + exercise(A_STR, FALSE); + exercise(A_CON, FALSE); + return; } - pline("%s %s%s%s%s for a %s.", Yname2(otmp), - (s == 0) ? "violently " : "", - otense(otmp, Blind ? "vibrate" : "glow"), - (!Blind && !same_color) ? " " : "", - (Blind || same_color) - ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER), - (s * s > 1) ? "while" : "moment"); - /* [this cost handling will need updating if shop pricing is - ever changed to care about curse/bless status of armor] */ - if (s < 0) - costly_alteration(otmp, COST_DECHNT); - if (scursed && !otmp->cursed) - curse(otmp); - else if (sblessed && !otmp->blessed) - bless(otmp); - else if (!scursed && otmp->cursed) - uncurse(otmp); - if (s) { - int oldspe = otmp->spe; - /* despite being schar, it shouldn't be possible for spe to wrap - here because it has been capped at 99 and s is quite small; - however, might need to change s if it takes spe past 99 */ - otmp->spe += s; - cap_spe(otmp); /* make sure that it doesn't exceed SPE_LIM */ - s = otmp->spe - oldspe; /* cap_spe() might have throttled 's' */ - if (s) /* skip if it got changed to 0 */ - adj_abon(otmp, s); /* adjust armor bonus for Dex or Int+Wis */ - g.known = otmp->known; - /* update shop bill to reflect new higher price */ - if (s > 0 && otmp->unpaid) - alter_cost(otmp, 0L); + old_erodeproof = (otmp->oerodeproof != 0); + new_erodeproof = scursed; + otmp->oerodeproof = 0; /* for messages */ + p_glow2(otmp, NH_PURPLE); + if (old_erodeproof && !new_erodeproof) { + /* restore old_erodeproof before shop charges */ + otmp->oerodeproof = 1; + costly_alteration(otmp, COST_DEGRD); } - - if ((otmp->spe > (special_armor ? 5 : 3)) - && (special_armor || !rn2(7))) - pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"), - Blind ? "again" : "unexpectedly"); - break; + otmp->oerodeproof = new_erodeproof ? 1 : 0; + return; } - case SCR_DESTROY_ARMOR: { - otmp = some_armor(&g.youmonst); - if (confused) { - if (!otmp) { - strange_feeling(sobj, "Your bones itch."); - sobj = 0; /* useup() in strange_feeling() */ - exercise(A_STR, FALSE); - exercise(A_CON, FALSE); - break; - } - old_erodeproof = (otmp->oerodeproof != 0); - new_erodeproof = scursed; - otmp->oerodeproof = 0; /* for messages */ - p_glow2(otmp, NH_PURPLE); - if (old_erodeproof && !new_erodeproof) { - /* restore old_erodeproof before shop charges */ - otmp->oerodeproof = 1; - costly_alteration(otmp, COST_DEGRD); - } - otmp->oerodeproof = new_erodeproof ? 1 : 0; - break; - } - if (!scursed || !otmp || !otmp->cursed) { - if (!destroy_arm(otmp)) { - strange_feeling(sobj, "Your skin itches."); - sobj = 0; /* useup() in strange_feeling() */ - exercise(A_STR, FALSE); - exercise(A_CON, FALSE); - break; - } else - g.known = TRUE; - } else { /* armor and scroll both cursed */ - pline("%s.", Yobjnam2(otmp, "vibrate")); - if (otmp->spe >= -6) { - otmp->spe += -1; - adj_abon(otmp, -1); - } - make_stunned((HStun & TIMEOUT) + (long) rn1(10, 10), TRUE); + if (!scursed || !otmp || !otmp->cursed) { + if (!destroy_arm(otmp)) { + strange_feeling(sobj, "Your skin itches."); + *sobjp = 0; /* useup() in strange_feeling() */ + exercise(A_STR, FALSE); + exercise(A_CON, FALSE); + return; + } else + g.known = TRUE; + } else { /* armor and scroll both cursed */ + pline("%s.", Yobjnam2(otmp, "vibrate")); + if (otmp->spe >= -6) { + otmp->spe += -1; + adj_abon(otmp, -1); } - } break; - case SCR_CONFUSE_MONSTER: - case SPE_CONFUSE_MONSTER: - if (g.youmonst.data->mlet != S_HUMAN || scursed) { - if (!HConfusion) - You_feel("confused."); + make_stunned((HStun & TIMEOUT) + (long) rn1(10, 10), TRUE); + } +} + +static void +seffect_confuse_monster(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + if (g.youmonst.data->mlet != S_HUMAN || scursed) { + if (!HConfusion) + You_feel("confused."); + make_confused(HConfusion + rnd(100), FALSE); + } else if (confused) { + if (!sblessed) { + Your("%s begin to %s%s.", makeplural(body_part(HAND)), + Blind ? "tingle" : "glow ", + Blind ? "" : hcolor(NH_PURPLE)); make_confused(HConfusion + rnd(100), FALSE); - } else if (confused) { - if (!sblessed) { - Your("%s begin to %s%s.", makeplural(body_part(HAND)), - Blind ? "tingle" : "glow ", - Blind ? "" : hcolor(NH_PURPLE)); - make_confused(HConfusion + rnd(100), FALSE); - } else { - pline("A %s%s surrounds your %s.", - Blind ? "" : hcolor(NH_RED), - Blind ? "faint buzz" : " glow", body_part(HEAD)); - make_confused(0L, TRUE); - } } else { - if (!sblessed) { - Your("%s%s %s%s.", makeplural(body_part(HAND)), - Blind ? "" : " begin to glow", - Blind ? (const char *) "tingle" : hcolor(NH_RED), - u.umconf ? " even more" : ""); + pline("A %s%s surrounds your %s.", + Blind ? "" : hcolor(NH_RED), + Blind ? "faint buzz" : " glow", body_part(HEAD)); + make_confused(0L, TRUE); + } + } else { + if (!sblessed) { + Your("%s%s %s%s.", makeplural(body_part(HAND)), + Blind ? "" : " begin to glow", + Blind ? (const char *) "tingle" : hcolor(NH_RED), + u.umconf ? " even more" : ""); + u.umconf++; + } else { + if (Blind) + Your("%s tingle %s sharply.", makeplural(body_part(HAND)), + u.umconf ? "even more" : "very"); + else + Your("%s glow a%s brilliant %s.", + makeplural(body_part(HAND)), + u.umconf ? "n even more" : "", hcolor(NH_RED)); + /* after a while, repeated uses become less effective */ + if (u.umconf >= 40) u.umconf++; - } else { - if (Blind) - Your("%s tingle %s sharply.", makeplural(body_part(HAND)), - u.umconf ? "even more" : "very"); - else - Your("%s glow a%s brilliant %s.", - makeplural(body_part(HAND)), - u.umconf ? "n even more" : "", hcolor(NH_RED)); - /* after a while, repeated uses become less effective */ - if (u.umconf >= 40) - u.umconf++; - else - u.umconf += rn1(8, 2); - } + else + u.umconf += rn1(8, 2); } - break; - case SCR_SCARE_MONSTER: - case SPE_CAUSE_FEAR: { - register int ct = 0; - register struct monst *mtmp; + } +} - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) - continue; - if (cansee(mtmp->mx, mtmp->my)) { - if (confused || scursed) { - mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0; - mtmp->mcanmove = 1; - } else if (!resist(mtmp, sobj->oclass, 0, NOTELL)) - monflee(mtmp, 0, FALSE, FALSE); - if (!mtmp->mtame) - ct++; /* pets don't laugh at you */ - } +static void +seffect_scare_monster(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + register int ct = 0; + register struct monst *mtmp; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + if (cansee(mtmp->mx, mtmp->my)) { + if (confused || scursed) { + mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0; + mtmp->mcanmove = 1; + } else if (!resist(mtmp, sobj->oclass, 0, NOTELL)) + monflee(mtmp, 0, FALSE, FALSE); + if (!mtmp->mtame) + ct++; /* pets don't laugh at you */ } - if (otyp == SCR_SCARE_MONSTER || !ct) - You_hear("%s %s.", (confused || scursed) ? "sad wailing" - : "maniacal laughter", - !ct ? "in the distance" : "close by"); - break; } - case SCR_BLANK_PAPER: - if (Blind) - You("don't remember there being any magic words on this scroll."); - else - pline("This scroll seems to be blank."); - g.known = TRUE; - break; - case SCR_REMOVE_CURSE: - case SPE_REMOVE_CURSE: { - register struct obj *obj; - - You_feel(!Hallucination - ? (!confused ? "like someone is helping you." - : "like you need some help.") - : (!confused ? "in touch with the Universal Oneness." - : "the power of the Force against you!")); + if (otyp == SCR_SCARE_MONSTER || !ct) + You_hear("%s %s.", (confused || scursed) ? "sad wailing" + : "maniacal laughter", + !ct ? "in the distance" : "close by"); +} - if (scursed) { - pline_The("scroll disintegrates."); - } else { - for (obj = g.invent; obj; obj = obj->nobj) { - long wornmask; +static void +seffect_remove_curse(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + register struct obj *obj; + + You_feel(!Hallucination + ? (!confused ? "like someone is helping you." + : "like you need some help.") + : (!confused ? "in touch with the Universal Oneness." + : "the power of the Force against you!")); + + if (scursed) { + pline_The("scroll disintegrates."); + } else { + for (obj = g.invent; obj; obj = obj->nobj) { + long wornmask; - /* gold isn't subject to cursing and blessing */ - if (obj->oclass == COIN_CLASS) - continue; - /* hide current scroll from itself so that perm_invent won't - show known blessed scroll losing bknown when confused */ - if (obj == sobj && obj->quan == 1L) - continue; - wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI)); - if (wornmask && !sblessed) { - /* handle a couple of special cases; we don't - allow auxiliary weapon slots to be used to - artificially increase number of worn items */ - if (obj == uswapwep) { - if (!u.twoweap) + /* gold isn't subject to cursing and blessing */ + if (obj->oclass == COIN_CLASS) + continue; + /* hide current scroll from itself so that perm_invent won't + show known blessed scroll losing bknown when confused */ + if (obj == sobj && obj->quan == 1L) + continue; + wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI)); + if (wornmask && !sblessed) { + /* handle a couple of special cases; we don't + allow auxiliary weapon slots to be used to + artificially increase number of worn items */ + if (obj == uswapwep) { + if (!u.twoweap) + wornmask = 0L; + } else if (obj == uquiver) { + if (obj->oclass == WEAPON_CLASS) { + /* mergeable weapon test covers ammo, + missiles, spears, daggers & knives */ + if (!objects[obj->otyp].oc_merge) wornmask = 0L; - } else if (obj == uquiver) { - if (obj->oclass == WEAPON_CLASS) { - /* mergeable weapon test covers ammo, - missiles, spears, daggers & knives */ - if (!objects[obj->otyp].oc_merge) - wornmask = 0L; - } else if (obj->oclass == GEM_CLASS) { - /* possibly ought to check whether - alternate weapon is a sling... */ - if (!uslinging()) - wornmask = 0L; - } else { - /* weptools don't merge and aren't - reasonable quivered weapons */ + } else if (obj->oclass == GEM_CLASS) { + /* possibly ought to check whether + alternate weapon is a sling... */ + if (!uslinging()) wornmask = 0L; - } - } - } - if (sblessed || wornmask || obj->otyp == LOADSTONE - || (obj->otyp == LEASH && obj->leashmon)) { - /* water price varies by curse/bless status */ - boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER); - - if (confused) { - blessorcurse(obj, 2); - /* lose knowledge of this object's curse/bless - state (even if it didn't actually change) */ - obj->bknown = 0; - /* blessorcurse() only affects uncursed items - so no need to worry about price of water - going down (hence no costly_alteration) */ - if (shop_h2o && (obj->cursed || obj->blessed)) - alter_cost(obj, 0L); /* price goes up */ - } else if (obj->cursed) { - if (shop_h2o) - costly_alteration(obj, COST_UNCURS); - uncurse(obj); - /* if the object was known to be cursed and is now - known not to be, make the scroll known; it's - trivial to identify anyway by comparing inventory - before and after */ - if (obj->bknown && otyp == SCR_REMOVE_CURSE) - learnscrolltyp(SCR_REMOVE_CURSE); + } else { + /* weptools don't merge and aren't + reasonable quivered weapons */ + wornmask = 0L; } } } - /* if riding, treat steed's saddle as if part of hero's invent */ - if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) { + if (sblessed || wornmask || obj->otyp == LOADSTONE + || (obj->otyp == LEASH && obj->leashmon)) { + /* water price varies by curse/bless status */ + boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER); + if (confused) { blessorcurse(obj, 2); - obj->bknown = 0; /* skip set_bknown() */ + /* lose knowledge of this object's curse/bless + state (even if it didn't actually change) */ + obj->bknown = 0; + /* blessorcurse() only affects uncursed items + so no need to worry about price of water + going down (hence no costly_alteration) */ + if (shop_h2o && (obj->cursed || obj->blessed)) + alter_cost(obj, 0L); /* price goes up */ } else if (obj->cursed) { + if (shop_h2o) + costly_alteration(obj, COST_UNCURS); uncurse(obj); - /* like rndcurse(sit.c), effect on regular inventory - doesn't show things glowing but saddle does */ - if (!Blind) { - pline("%s %s.", Yobjnam2(obj, "glow"), - hcolor("amber")); - obj->bknown = Hallucination ? 0 : 1; - } else { - obj->bknown = 0; /* skip set_bknown() */ - } + /* if the object was known to be cursed and is now + known not to be, make the scroll known; it's + trivial to identify anyway by comparing inventory + before and after */ + if (obj->bknown && otyp == SCR_REMOVE_CURSE) + learnscrolltyp(SCR_REMOVE_CURSE); } } } - if (Punished && !confused) - unpunish(); - if (u.utrap && u.utraptype == TT_BURIEDBALL) { - buried_ball_to_freedom(); - pline_The("clasp on your %s vanishes.", body_part(LEG)); + /* if riding, treat steed's saddle as if part of hero's invent */ + if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) { + if (confused) { + blessorcurse(obj, 2); + obj->bknown = 0; /* skip set_bknown() */ + } else if (obj->cursed) { + uncurse(obj); + /* like rndcurse(sit.c), effect on regular inventory + doesn't show things glowing but saddle does */ + if (!Blind) { + pline("%s %s.", Yobjnam2(obj, "glow"), + hcolor("amber")); + obj->bknown = Hallucination ? 0 : 1; + } else { + obj->bknown = 0; /* skip set_bknown() */ + } + } } - update_inventory(); - break; } - case SCR_CREATE_MONSTER: - case SPE_CREATE_MONSTER: - if (create_critters(1 + ((confused || scursed) ? 12 : 0) - + ((sblessed || rn2(73)) ? 0 : rnd(4)), - confused ? &mons[PM_ACID_BLOB] - : (struct permonst *) 0, - FALSE)) - g.known = TRUE; - /* no need to flush monsters; we ask for identification only if the - * monsters are not visible - */ - break; - case SCR_ENCHANT_WEAPON: - /* [What about twoweapon mode? Proofing/repairing/enchanting both - would be too powerful, but shouldn't we choose randomly between - primary and secondary instead of always acting on primary?] */ - if (confused && uwep - && erosion_matters(uwep) && uwep->oclass != ARMOR_CLASS) { - old_erodeproof = (uwep->oerodeproof != 0); - new_erodeproof = !scursed; - uwep->oerodeproof = 0; /* for messages */ - if (Blind) { - uwep->rknown = FALSE; - Your("weapon feels warm for a moment."); - } else { - uwep->rknown = TRUE; - pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"), - scursed ? "mottled" : "shimmering", - hcolor(scursed ? NH_PURPLE : NH_GOLDEN), - scursed ? "glow" : "shield"); + if (Punished && !confused) + unpunish(); + if (u.utrap && u.utraptype == TT_BURIEDBALL) { + buried_ball_to_freedom(); + pline_The("clasp on your %s vanishes.", body_part(LEG)); + } + update_inventory(); +} + +static void +seffect_create_monster(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + if (create_critters(1 + ((confused || scursed) ? 12 : 0) + + ((sblessed || rn2(73)) ? 0 : rnd(4)), + confused ? &mons[PM_ACID_BLOB] + : (struct permonst *) 0, + FALSE)) + g.known = TRUE; + /* no need to flush monsters; we ask for identification only if the + * monsters are not visible + */ +} + +static void +seffect_enchant_weapon(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + boolean old_erodeproof, new_erodeproof; + + /* [What about twoweapon mode? Proofing/repairing/enchanting both + would be too powerful, but shouldn't we choose randomly between + primary and secondary instead of always acting on primary?] */ + if (confused && uwep + && erosion_matters(uwep) && uwep->oclass != ARMOR_CLASS) { + old_erodeproof = (uwep->oerodeproof != 0); + new_erodeproof = !scursed; + uwep->oerodeproof = 0; /* for messages */ + if (Blind) { + uwep->rknown = FALSE; + Your("weapon feels warm for a moment."); + } else { + uwep->rknown = TRUE; + pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"), + scursed ? "mottled" : "shimmering", + hcolor(scursed ? NH_PURPLE : NH_GOLDEN), + scursed ? "glow" : "shield"); + } + if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) { + uwep->oeroded = uwep->oeroded2 = 0; + pline("%s as good as new!", + Yobjnam2(uwep, Blind ? "feel" : "look")); + } + if (old_erodeproof && !new_erodeproof) { + /* restore old_erodeproof before shop charges */ + uwep->oerodeproof = 1; + costly_alteration(uwep, COST_DEGRD); + } + uwep->oerodeproof = new_erodeproof ? 1 : 0; + return; + } + if (!chwepon(sobj, scursed ? -1 + : !uwep ? 1 + : (uwep->spe >= 9) ? !rn2(uwep->spe) + : sblessed ? rnd(3 - uwep->spe / 3) + : 1)) + *sobjp = 0; /* nothing enchanted: strange_feeling -> useup */ + if (uwep) + cap_spe(uwep); +} + +static void +seffect_taming(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean confused = (Confusion != 0); + int candidates, res, results, vis_results; + + if (u.uswallow) { + candidates = 1; + results = vis_results = maybe_tame(u.ustuck, sobj); + } else { + int i, j, bd = confused ? 5 : 1; + struct monst *mtmp; + + /* note: maybe_tame() can return either positive or + negative values, but not both for the same scroll */ + candidates = results = vis_results = 0; + for (i = -bd; i <= bd; i++) + for (j = -bd; j <= bd; j++) { + if (!isok(u.ux + i, u.uy + j)) + continue; + if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0 + || (!i && !j && (mtmp = u.usteed) != 0)) { + ++candidates; + res = maybe_tame(mtmp, sobj); + results += res; + if (canspotmon(mtmp)) + vis_results += res; + } } - if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) { - uwep->oeroded = uwep->oeroded2 = 0; - pline("%s as good as new!", - Yobjnam2(uwep, Blind ? "feel" : "look")); + } + if (!results) { + pline("Nothing interesting %s.", + !candidates ? "happens" : "seems to happen"); + } else { + pline_The("neighborhood %s %sfriendlier.", + vis_results ? "is" : "seems", + (results < 0) ? "un" : ""); + if (vis_results > 0) + g.known = TRUE; + } +} + +static void +seffect_genocide(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ + || objects[otyp].oc_name_known); + + if (!already_known) + You("have found a scroll of genocide!"); + g.known = TRUE; + if (sblessed) + do_class_genocide(); + else + do_genocide((!scursed) | (2 * !!Confusion)); +} + +static void +seffect_light(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + if (!confused) { + if (!Blind) + g.known = TRUE; + litroom(!scursed, sobj); + if (!scursed) { + if (lightdamage(sobj, TRUE, 5)) + g.known = TRUE; + } + } else { + int pm = scursed ? PM_BLACK_LIGHT : PM_YELLOW_LIGHT; + + if ((g.mvitals[pm].mvflags & G_GONE)) { + pline("Tiny lights sparkle in the air momentarily."); + } else { + /* surround with cancelled tame lights which won't explode */ + boolean sawlights = FALSE; + int numlights = rn1(2,3) + (sblessed * 2); + int i; + + for (i = 0; i < numlights; ++i) { + struct monst * mon = makemon(&mons[pm], u.ux, u.uy, + MM_EDOG | NO_MINVENT); + initedog(mon); + mon->msleeping = 0; + mon->mcan = TRUE; + if (canspotmon(mon)) + sawlights = TRUE; + newsym(mon->mx, mon->my); } - if (old_erodeproof && !new_erodeproof) { - /* restore old_erodeproof before shop charges */ - uwep->oerodeproof = 1; - costly_alteration(uwep, COST_DEGRD); + if (sawlights) { + pline("Lights appear all around you!"); + g.known = TRUE; } - uwep->oerodeproof = new_erodeproof ? 1 : 0; - break; } - if (!chwepon(sobj, scursed ? -1 - : !uwep ? 1 - : (uwep->spe >= 9) ? !rn2(uwep->spe) - : sblessed ? rnd(3 - uwep->spe / 3) - : 1)) - sobj = 0; /* nothing enchanted: strange_feeling -> useup */ - if (uwep) - cap_spe(uwep); - break; - case SCR_TAMING: - case SPE_CHARM_MONSTER: { - int candidates, res, results, vis_results; + } +} - if (u.uswallow) { - candidates = 1; - results = vis_results = maybe_tame(u.ustuck, sobj); +static void +seffect_charging(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + boolean already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ + || objects[otyp].oc_name_known); + struct obj *otmp; + + if (confused) { + if (scursed) { + You_feel("discharged."); + u.uen = 0; } else { - int i, j, bd = confused ? 5 : 1; - struct monst *mtmp; - - /* note: maybe_tame() can return either positive or - negative values, but not both for the same scroll */ - candidates = results = vis_results = 0; - for (i = -bd; i <= bd; i++) - for (j = -bd; j <= bd; j++) { - if (!isok(u.ux + i, u.uy + j)) - continue; - if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0 - || (!i && !j && (mtmp = u.usteed) != 0)) { - ++candidates; - res = maybe_tame(mtmp, sobj); - results += res; - if (canspotmon(mtmp)) - vis_results += res; - } - } + You_feel("charged up!"); + u.uen += d(sblessed ? 6 : 4, 4); + if (u.uen > u.uenmax) /* if current energy is already at */ + u.uenmax = u.uen; /* or near maximum, increase maximum */ + else + u.uen = u.uenmax; /* otherwise restore current to max */ + } + g.context.botl = 1; + return; + } + /* known = TRUE; -- handled inline here */ + if (!already_known) { + pline("This is a charging scroll."); + learnscroll(sobj); + } + /* use it up now to prevent it from showing in the + getobj picklist because the "disappears" message + was already delivered */ + useup(sobj); + sobjp = 0; /* it's gone */ + otmp = getobj("charge", charge_ok, GETOBJ_PROMPT | GETOBJ_ALLOWCNT); + if (otmp) + recharge(otmp, scursed ? -1 : sblessed ? 1 : 0); +} + +static void +seffect_amnesia(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + + g.known = TRUE; + forget((!sblessed ? ALL_SPELLS : 0)); + if (Hallucination) /* Ommmmmm! */ + Your("mind releases itself from mundane concerns."); + else if (!strncmpi(g.plname, "Maud", 4)) + pline( + "As your mind turns inward on itself, you forget everything else."); + else if (rn2(2)) + pline("Who was that Maud person anyway?"); + else + pline("Thinking of Maud you forget everything else."); + exercise(A_WIS, FALSE); +} + +static void +seffect_fire(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean sblessed = sobj->blessed; + boolean confused = (Confusion != 0); + boolean already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ + || objects[otyp].oc_name_known); + coord cc; + int dam, cval; + + cc.x = u.ux; + cc.y = u.uy; + cval = bcsign(sobj); + dam = (2 * (rn1(3, 3) + 2 * cval) + 1) / 3; + useup(sobj); + sobjp = 0; /* it's gone */ + if (!already_known) + (void) learnscrolltyp(SCR_FIRE); + if (confused) { + if (Underwater) { + pline("A little %s around you vaporizes.", hliquid("water")); } - if (!results) { - pline("Nothing interesting %s.", - !candidates ? "happens" : "seems to happen"); + else if (Fire_resistance) { + shieldeff(u.ux, u.uy); + monstseesu(M_SEEN_FIRE); + if (!Blind) + pline("Oh, look, what a pretty fire in your %s.", + makeplural(body_part(HAND))); + else + You_feel("a pleasant warmth in your %s.", + makeplural(body_part(HAND))); } else { - pline_The("neighborhood %s %sfriendlier.", - vis_results ? "is" : "seems", - (results < 0) ? "un" : ""); - if (vis_results > 0) - g.known = TRUE; + pline_The("scroll catches fire and you burn your %s.", + makeplural(body_part(HAND))); + losehp(1, "scroll of fire", KILLED_BY_AN); } - break; + return; } - case SCR_GENOCIDE: - if (!already_known) - You("have found a scroll of genocide!"); - g.known = TRUE; - if (sblessed) - do_class_genocide(); - else - do_genocide((!scursed) | (2 * !!Confusion)); - break; - case SCR_LIGHT: - if (!confused) { - if (!Blind) - g.known = TRUE; - litroom(!scursed, sobj); - if (!scursed) { - if (lightdamage(sobj, TRUE, 5)) - g.known = TRUE; + if (Underwater) { + pline_The("%s around you vaporizes violently!", hliquid("water")); + } else { + if (sblessed) { + if (!already_known) + pline("This is a scroll of fire!"); + dam *= 5; + pline("Where do you want to center the explosion?"); + getpos_sethilite(display_stinking_cloud_positions, + get_valid_stinking_cloud_pos); + (void) getpos(&cc, TRUE, "the desired position"); + if (!is_valid_stinking_cloud_pos(cc.x, cc.y, FALSE)) { + /* try to reach too far, get burned */ + cc.x = u.ux; + cc.y = u.uy; } - } else { - int pm = scursed ? PM_BLACK_LIGHT : PM_YELLOW_LIGHT; + } + if (cc.x == u.ux && cc.y == u.uy) { + pline_The("scroll erupts in a tower of flame!"); + iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */ + burn_away_slime(); + } + } + explode(cc.x, cc.y, 11, dam, SCROLL_CLASS, EXPL_FIERY); +} - if ((g.mvitals[pm].mvflags & G_GONE)) { - pline("Tiny lights sparkle in the air momentarily."); - } else { - /* surround with cancelled tame lights which won't explode */ - boolean sawlights = FALSE; - int numlights = rn1(2,3) + (sblessed * 2); - int i; - - for (i = 0; i < numlights; ++i) { - struct monst * mon = makemon(&mons[pm], u.ux, u.uy, - MM_EDOG | NO_MINVENT); - initedog(mon); - mon->msleeping = 0; - mon->mcan = TRUE; - if (canspotmon(mon)) - sawlights = TRUE; - newsym(mon->mx, mon->my); - } - if (sawlights) { - pline("Lights appear all around you!"); - g.known = TRUE; +static void +seffect_earth(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + /* TODO: handle steeds */ + if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz) + && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { + register int x, y; + int nboulders = 0; + + /* Identify the scroll */ + if (u.uswallow) + You_hear("rumbling."); + else + pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy), + sblessed ? "around" : "above"); + g.known = 1; + sokoban_guilt(); + + /* Loop through the surrounding squares */ + if (!scursed) + for (x = u.ux - 1; x <= u.ux + 1; x++) { + for (y = u.uy - 1; y <= u.uy + 1; y++) { + /* Is this a suitable spot? */ + if (isok(x, y) && !closed_door(x, y) + && !IS_ROCK(levl[x][y].typ) + && !IS_AIR(levl[x][y].typ) + && (x != u.ux || y != u.uy)) { + nboulders += + drop_boulder_on_monster(x, y, confused, TRUE); + } } } - } - break; - case SCR_TELEPORTATION: - if (confused || scursed) { - level_tele(); - /* gives "materialize on different/same level!" message, must - be a teleport scroll */ - g.known = TRUE; - } else { - scrolltele(sobj); - /* this will call learnscroll() as appropriate, and has results - which maybe shouldn't result in the scroll becoming known; - either way, no need to set g.known here */ - } - break; - case SCR_GOLD_DETECTION: - if ((confused || scursed) ? trap_detect(sobj) : gold_detect(sobj)) - sobj = 0; /* failure: strange_feeling() -> useup() */ - break; - case SCR_FOOD_DETECTION: - case SPE_DETECT_FOOD: - if (food_detect(sobj)) - sobj = 0; /* nothing detected: strange_feeling -> useup */ - break; - case SCR_IDENTIFY: + /* Attack the player */ + if (!sblessed) { + drop_boulder_on_player(confused, !scursed, TRUE, FALSE); + } else if (!nboulders) + pline("But nothing else happens."); + } +} + +static void +seffect_punishment(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean sblessed = sobj->blessed; + boolean confused = (Confusion != 0); + + g.known = TRUE; + if (confused || sblessed) { + You_feel("guilty."); + return; + } + punish(sobj); +} + +static void +seffect_stinking_cloud(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ + || objects[otyp].oc_name_known); + coord cc; + + if (!already_known) + You("have found a scroll of stinking cloud!"); + g.known = TRUE; + pline("Where do you want to center the %scloud?", + already_known ? "stinking " : ""); + cc.x = u.ux; + cc.y = u.uy; + getpos_sethilite(display_stinking_cloud_positions, + get_valid_stinking_cloud_pos); + if (getpos(&cc, TRUE, "the desired position") < 0) { + pline1(Never_mind); + return; + } + if (!is_valid_stinking_cloud_pos(cc.x, cc.y, TRUE)) + return; + (void) create_gas_cloud(cc.x, cc.y, 3 + bcsign(sobj), + 8 + 4 * bcsign(sobj)); +} + +static void +seffect_blank_paper(struct obj **sobjp UNUSED) +{ + if (Blind) + You("don't remember there being any magic words on this scroll."); + else + pline("This scroll seems to be blank."); + g.known = TRUE; +} + +static void +seffect_teleportation(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + if (confused || scursed) { + level_tele(); + /* gives "materialize on different/same level!" message, must + be a teleport scroll */ + g.known = TRUE; + } else { + scrolltele(sobj); + /* this will call learnscroll() as appropriate, and has results + which maybe shouldn't result in the scroll becoming known; + either way, no need to set g.known here */ + } +} + +static void +seffect_gold_detection(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + + if ((confused || scursed) ? trap_detect(sobj) : gold_detect(sobj)) + sobjp = 0; /* failure: strange_feeling() -> useup() */ +} + +static void +seffect_food_detection(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + + if (food_detect(sobj)) + sobjp = 0; /* nothing detected: strange_feeling -> useup */ +} + +static void +seffect_identify(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + int otyp = sobj->otyp; + boolean is_scroll = (sobj->oclass == SCROLL_CLASS); + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + boolean already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ + || objects[otyp].oc_name_known); + + if (is_scroll) { /* scroll of identify */ /* known = TRUE; -- handled inline here */ /* use up the scroll first, before learnscrolltyp() -> makeknown() performs perm_invent update; also simplifies empty invent check */ useup(sobj); - sobj = 0; /* it's gone */ + sobjp = 0; /* it's gone */ /* scroll just identifies itself for any scroll read while confused or for cursed scroll read without knowing identify yet */ if (confused || (scursed && !already_known)) @@ -1509,56 +1803,37 @@ seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ if (!already_known) (void) learnscrolltyp(SCR_IDENTIFY); if (confused || (scursed && !already_known)) - break; - /*FALLTHRU*/ - case SPE_IDENTIFY: - if (g.invent) { - cval = 1; - if (sblessed || (!scursed && !rn2(5))) { - cval = rn2(5); - /* note: if cval==0, identify all items */ - if (cval == 1 && sblessed && Luck > 0) - ++cval; - } - identify_pack(cval, !already_known); - } else { - /* spell cast with inventory empty or scroll read when it's - the only item leaving empty inventory after being used up */ - pline("You're not carrying anything%s to be identified.", - (otyp == SCR_IDENTIFY) ? " else" : ""); - } - break; - case SCR_CHARGING: - if (confused) { - if (scursed) { - You_feel("discharged."); - u.uen = 0; - } else { - You_feel("charged up!"); - u.uen += d(sblessed ? 6 : 4, 4); - if (u.uen > u.uenmax) /* if current energy is already at */ - u.uenmax = u.uen; /* or near maximum, increase maximum */ - else - u.uen = u.uenmax; /* otherwise restore current to max */ - } - g.context.botl = 1; - break; - } - /* known = TRUE; -- handled inline here */ - if (!already_known) { - pline("This is a charging scroll."); - learnscroll(sobj); + return; + } + + if (g.invent) { + int cval = 1; + if (sblessed || (!scursed && !rn2(5))) { + cval = rn2(5); + /* note: if cval==0, identify all items */ + if (cval == 1 && sblessed && Luck > 0) + ++cval; } - /* use it up now to prevent it from showing in the - getobj picklist because the "disappears" message - was already delivered */ - useup(sobj); - sobj = 0; /* it's gone */ - otmp = getobj("charge", charge_ok, GETOBJ_PROMPT | GETOBJ_ALLOWCNT); - if (otmp) - recharge(otmp, scursed ? -1 : sblessed ? 1 : 0); - break; - case SCR_MAGIC_MAPPING: + identify_pack(cval, !already_known); + } else { + /* spell cast with inventory empty or scroll read when it's + the only item leaving empty inventory after being used up */ + pline("You're not carrying anything%s to be identified.", + (is_scroll) ? " else" : ""); + } +} + +static void +seffect_magic_mapping(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean is_scroll = (sobj->oclass == SCROLL_CLASS); + boolean sblessed = sobj->blessed; + boolean scursed = sobj->cursed; + boolean confused = (Confusion != 0); + int cval; + + if (is_scroll) { if (g.level.flags.nommap) { Your("mind is filled with crazy lines!"); if (Hallucination) @@ -1566,7 +1841,7 @@ seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ else Your("%s spins in bewilderment.", body_part(HEAD)); make_confused(HConfusion + rnd(30), FALSE); - break; + return; } if (sblessed) { register int x, y; @@ -1578,163 +1853,151 @@ seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ /* do_mapping() already reveals secret passages */ } g.known = TRUE; - /*FALLTHRU*/ + } + + if (g.level.flags.nommap) { + Your("%s spins as %s blocks the spell!", body_part(HEAD), + something); + make_confused(HConfusion + rnd(30), FALSE); + return; + } + pline("A map coalesces in your mind!"); + cval = (scursed && !confused); + if (cval) + HConfusion = 1; /* to screw up map */ + do_mapping(); + if (cval) { + HConfusion = 0; /* restore */ + pline("Unfortunately, you can't grasp the details."); + } +} + +#ifdef MAIL_STRUCTURES +static void +seffect_mail(struct obj **sobjp) +{ + struct obj *sobj = *sobjp; + boolean odd = (sobj->o_id % 2) == 1; + + g.known = TRUE; + switch (sobj->spe) { + case 2: + /* "stamped scroll" created via magic marker--without a stamp */ + pline("This scroll is marked \"%s\".", + odd ? "Postage Due" : "Return to Sender"); + break; + case 1: + /* scroll of mail obtained from bones file or from wishing; + note to the puzzled: the game Larn actually sends you junk + mail if you win! */ + pline("This seems to be %s.", + odd ? "a chain letter threatening your luck" + : "junk mail addressed to the finder of the Eye of Larn"); + break; + default: +#ifdef MAIL + readmail(sobj); +#else + /* unreachable since with MAIL undefined, sobj->spe won't be 0; + as a precaution, be prepared to give arbitrary feedback; + caller has already reported that it disappears upon reading */ + pline("That was a scroll of mail?"); +#endif + break; + } +} +#endif /* MAIL_STRUCTURES */ + +/* scroll effects; return 1 if we use up the scroll and possibly make it + become discovered, 0 if caller should take care of those side-effects */ +int +seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ +{ + int otyp = sobj->otyp; + + if (objects[otyp].oc_magic) + exercise(A_WIS, TRUE); /* just for trying */ + + switch (otyp) { +#ifdef MAIL_STRUCTURES + case SCR_MAIL: + seffect_mail(&sobj); + break; +#endif + case SCR_ENCHANT_ARMOR: + seffect_enchant_armor(&sobj); + break; + case SCR_DESTROY_ARMOR: + seffect_destroy_armor(&sobj); + break; + case SCR_CONFUSE_MONSTER: + case SPE_CONFUSE_MONSTER: + seffect_confuse_monster(&sobj); + break; + case SCR_SCARE_MONSTER: + case SPE_CAUSE_FEAR: + seffect_scare_monster(&sobj); + break; + case SCR_BLANK_PAPER: + seffect_blank_paper(&sobj); + break; + case SCR_REMOVE_CURSE: + case SPE_REMOVE_CURSE: + seffect_remove_curse(&sobj); + break; + case SCR_CREATE_MONSTER: + case SPE_CREATE_MONSTER: + seffect_create_monster(&sobj); + break; + case SCR_ENCHANT_WEAPON: + seffect_enchant_weapon(&sobj); + break; + case SCR_TAMING: + case SPE_CHARM_MONSTER: + seffect_taming(&sobj); + break; + case SCR_GENOCIDE: + seffect_genocide(&sobj); + break; + case SCR_LIGHT: + seffect_light(&sobj); + break; + case SCR_TELEPORTATION: + seffect_teleportation(&sobj); + break; + case SCR_GOLD_DETECTION: + seffect_gold_detection(&sobj); + break; + case SCR_FOOD_DETECTION: + case SPE_DETECT_FOOD: + seffect_food_detection(&sobj); + break; + case SCR_IDENTIFY: + case SPE_IDENTIFY: + seffect_identify(&sobj); + break; + case SCR_CHARGING: + seffect_charging(&sobj); + break; + case SCR_MAGIC_MAPPING: case SPE_MAGIC_MAPPING: - if (g.level.flags.nommap) { - Your("%s spins as %s blocks the spell!", body_part(HEAD), - something); - make_confused(HConfusion + rnd(30), FALSE); - break; - } - pline("A map coalesces in your mind!"); - cval = (scursed && !confused); - if (cval) - HConfusion = 1; /* to screw up map */ - do_mapping(); - if (cval) { - HConfusion = 0; /* restore */ - pline("Unfortunately, you can't grasp the details."); - } + seffect_magic_mapping(&sobj); break; case SCR_AMNESIA: - g.known = TRUE; - forget((!sblessed ? ALL_SPELLS : 0)); - if (Hallucination) /* Ommmmmm! */ - Your("mind releases itself from mundane concerns."); - else if (!strncmpi(g.plname, "Maud", 4)) - pline( - "As your mind turns inward on itself, you forget everything else."); - else if (rn2(2)) - pline("Who was that Maud person anyway?"); - else - pline("Thinking of Maud you forget everything else."); - exercise(A_WIS, FALSE); + seffect_amnesia(&sobj); break; - case SCR_FIRE: { - coord cc; - int dam; - - cc.x = u.ux; - cc.y = u.uy; - cval = bcsign(sobj); - dam = (2 * (rn1(3, 3) + 2 * cval) + 1) / 3; - useup(sobj); - sobj = 0; /* it's gone */ - if (!already_known) - (void) learnscrolltyp(SCR_FIRE); - if (confused) { - if (Underwater) { - pline("A little %s around you vaporizes.", hliquid("water")); - } - else if (Fire_resistance) { - shieldeff(u.ux, u.uy); - monstseesu(M_SEEN_FIRE); - if (!Blind) - pline("Oh, look, what a pretty fire in your %s.", - makeplural(body_part(HAND))); - else - You_feel("a pleasant warmth in your %s.", - makeplural(body_part(HAND))); - } else { - pline_The("scroll catches fire and you burn your %s.", - makeplural(body_part(HAND))); - losehp(1, "scroll of fire", KILLED_BY_AN); - } - break; - } - if (Underwater) { - pline_The("%s around you vaporizes violently!", hliquid("water")); - } else { - if (sblessed) { - if (!already_known) - pline("This is a scroll of fire!"); - dam *= 5; - pline("Where do you want to center the explosion?"); - getpos_sethilite(display_stinking_cloud_positions, - get_valid_stinking_cloud_pos); - (void) getpos(&cc, TRUE, "the desired position"); - if (!is_valid_stinking_cloud_pos(cc.x, cc.y, FALSE)) { - /* try to reach too far, get burned */ - cc.x = u.ux; - cc.y = u.uy; - } - } - if (cc.x == u.ux && cc.y == u.uy) { - pline_The("scroll erupts in a tower of flame!"); - iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */ - burn_away_slime(); - } - } - explode(cc.x, cc.y, 11, dam, SCROLL_CLASS, EXPL_FIERY); + case SCR_FIRE: + seffect_fire(&sobj); break; - } case SCR_EARTH: - /* TODO: handle steeds */ - if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz) - && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { - register int x, y; - int nboulders = 0; - - /* Identify the scroll */ - if (u.uswallow) - You_hear("rumbling."); - else - pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy), - sblessed ? "around" : "above"); - g.known = 1; - sokoban_guilt(); - - /* Loop through the surrounding squares */ - if (!scursed) - for (x = u.ux - 1; x <= u.ux + 1; x++) { - for (y = u.uy - 1; y <= u.uy + 1; y++) { - /* Is this a suitable spot? */ - if (isok(x, y) && !closed_door(x, y) - && !IS_ROCK(levl[x][y].typ) - && !IS_AIR(levl[x][y].typ) - && (x != u.ux || y != u.uy)) { - nboulders += - drop_boulder_on_monster(x, y, confused, TRUE); - } - } - } - /* Attack the player */ - if (!sblessed) { - drop_boulder_on_player(confused, !scursed, TRUE, FALSE); - } else if (!nboulders) - pline("But nothing else happens."); - } + seffect_earth(&sobj); break; case SCR_PUNISHMENT: - g.known = TRUE; - if (confused || sblessed) { - You_feel("guilty."); - break; - } - punish(sobj); + seffect_punishment(&sobj); break; - case SCR_STINKING_CLOUD: { - coord cc; - - if (!already_known) - You("have found a scroll of stinking cloud!"); - g.known = TRUE; - pline("Where do you want to center the %scloud?", - already_known ? "stinking " : ""); - cc.x = u.ux; - cc.y = u.uy; - getpos_sethilite(display_stinking_cloud_positions, - get_valid_stinking_cloud_pos); - if (getpos(&cc, TRUE, "the desired position") < 0) { - pline1(Never_mind); - break; - } - if (!is_valid_stinking_cloud_pos(cc.x, cc.y, TRUE)) - break; - (void) create_gas_cloud(cc.x, cc.y, 3 + bcsign(sobj), - 8 + 4 * bcsign(sobj)); + case SCR_STINKING_CLOUD: + seffect_stinking_cloud(&sobj); break; - } default: impossible("What weird effect is this? (%u)", otyp); } -- 2.50.1