view urogue/scrolls.c @ 292:ebf49a933e51

UltraRogue: ask about unidentified magic items by default.
author John "Elwin" Edwards
date Fri, 29 Dec 2017 14:16:24 -0500
parents c495a4f288c6
children e52a8a7ad4c5
line wrap: on
line source

/*
    scrolls.c - Functions for dealing with scrolls
  
    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
    All rights reserved.

    Based on "Advanced Rogue"
    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
    All rights reserved.

    Based on "Rogue: Exploring the Dungeons of Doom"
    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
    All rights reserved.

    See the file LICENSE.TXT for full copyright and licensing information.
*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "rogue.h"

/*
    read_scroll - read a scroll (or effect a scroll-like spell)
        reader:  who does it
        which:   which S_SCROLL (-1 means ask from pack)
        flags:   ISBLESSED, ISCURSED
*/

void
read_scroll(struct thing *reader, int which, int flags)
{
    struct object   *obj;
    struct linked_list  *item, *nitem;
    int i, j, charm_power;
    char    ch, nch;
    int     blessed = flags & ISBLESSED;
    int     cursed = flags & ISCURSED;
    int     is_scroll = (which < 0 ? TRUE : FALSE);
    char    buf[2 * LINELEN];

    if (reader != &player)
    {
        monread(reader, which, flags);
        return;
    }

    if (is_scroll)      /* A regular scroll */
    {
        if ((item = get_item("read", SCROLL)) == NULL)
            return;

        obj = OBJPTR(item);

        if (obj->o_type != SCROLL)
        {
            msg("It says 'Made in Yugoslavia'!");
            return;
        }

        if (on(player, ISBLIND))
        {
            msg("You can't see to read anything.");
            return;
        }

        /* Calculate its effect */

        cursed = obj->o_flags & ISCURSED;
        blessed = obj->o_flags & ISBLESSED;
        flags = obj->o_flags;
        which = obj->o_which;

        /* remove it from the pack */

        rem_pack(obj);
        discard(item);
        updpack();
    }

    switch (which)
    {
        case S_CONFUSE:  /* Touch causes monster confusion.  */
            if (cursed)
                quaff(reader, P_CLEAR, ISCURSED);
            else
            {
                msg("Your hands begin to glow red.");
                turn_on(player, CANHUH);
                /* if blessed... */
            }
            break;

        case  S_CURING:   /* A cure disease spell */
            if (on(player, HASINFEST) || on(player, HASDISEASE))
            {
                if (!cursed && on(player, HASDISEASE))
                {
                    extinguish_fuse(FUSE_CURE_DISEASE);
                    cure_disease(NULL);
                }

                if (on(player, HASINFEST))
                {
                    msg("You begin to feel yourself improving again.");
                    turn_off(player, HASINFEST);
                    infest_dam = 0;
                }

                if (is_scroll)
                    know_items[TYP_SCROLL][S_CURING] = TRUE;
            }
            else
                nothing_message(flags);
            break;

        case S_LIGHT:
            if (blue_light(flags) && is_scroll)
                know_items[TYP_SCROLL][S_LIGHT] = TRUE;
            break;

        case S_HOLD:
            if (cursed)
            {
                /*
                 * This scroll aggravates all the monsters on the
                 * current level and sets them running towards the
                 * hero
                 */
                aggravate();
                hearmsg("You hear a high pitched humming noise.");
            }
            else if (blessed)   /* Hold all monsters on level */
            {
                if (mlist == NULL)
                    nothing_message(flags);
                else
                {
                    struct linked_list  *mon;
                    struct thing    *th;

                    for (mon = mlist; mon != NULL; mon = next(mon))
                    {
                        th = THINGPTR(mon);
                        turn_off(*th, ISRUN);
                        turn_on(*th, ISHELD);
                    }
                    msg("A sudden peace comes over the dungeon.");
                }
            }
            else
            {
                /*
                 * Hold monster scroll.  Stop all monsters within two
                 * spaces from chasing after the hero.
                 */
                int x, y;
                struct linked_list  *mon;
                int gotone = FALSE;

                for (x = hero.x - 2; x <= hero.x + 2; x++)
                {
                    for (y = hero.y - 2; y <= hero.y + 2; y++)
                    {
                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
                        {
                            if ((mon = find_mons(y, x)) != NULL)
                            {
                                struct thing    *th;

                                gotone = TRUE;
                                th = THINGPTR(mon);
                                turn_off(*th, ISRUN);
                                turn_on(*th, ISHELD);
                            }
                        }
                    }
                }

                if (gotone)
                    msg("A sudden peace surrounds you.");
                else
                    nothing_message(flags);
            }
            break;

        case S_SLEEP:

            /* if cursed, you fall asleep */

            if (cursed)
            {
                if (is_wearing(R_ALERT))
                    msg("You feel drowsy for a moment.");
                else
                {
                    msg("You fall asleep.");
                    no_command += 4 + rnd(SLEEPTIME);
                }
            }
            else
            {
                /*
                 * sleep monster scroll.  puts all monsters within 2
                 * spaces asleep
                 */
                int x, y;
                struct linked_list  *mon;
                int gotone = FALSE;

                for (x = hero.x - 2; x <= hero.x + 2; x++)
                {
                    for (y = hero.y - 2; y <= hero.y + 2; y++)
                    {
                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
                        {
                            if ((mon = find_mons(y, x)) != NULL)
                            {
                                struct thing    *th;
                                th = THINGPTR(mon);

                                if (on(*th, ISUNDEAD))
                                    continue;

                                gotone = TRUE;
                                th->t_no_move += SLEEPTIME;
                            }
                        }
                    }
                }

                if (gotone)
                    msg("The monster(s) around you seem to have fallen asleep.");
                else
                    nothing_message(flags);
            }
            break;

        case S_CREATE:
        {
            /*
             * Create a monster. First look in a circle around
             * him, next try his room otherwise give up
             */

            struct thing    *tp;
            struct linked_list  *ip;

            if (blessed)
                summon_monster((short) 0, NOFAMILIAR, MESSAGE);
            else if (cursed)
            {
                i = rnd(4) + 3;
                for (j = 0; j < i; j++)
                {
                    if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL)
                    {
                        tp = THINGPTR(ip);
                        turn_off(*tp, ISFRIENDLY);
                    }
                }
            }
            else if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL)
            {
                tp = THINGPTR(ip);
                turn_off(*tp, ISFRIENDLY);
            }
        }
        break;

        case S_IDENTIFY:
            if (cursed)
                msg("You identify this scroll as an identify scroll");
            else if (blessed)   /* identify everything in the pack */
            {
                msg("You feel more Knowledgeable!");
                idenpack();
            }
            else
            {
                /* Identify, let the rogue figure something out  */

                if (is_scroll && know_items[TYP_SCROLL][S_IDENTIFY] != TRUE)
                {
                    msg("This scroll is an identify scroll.");
                    know_items[TYP_SCROLL][S_IDENTIFY] = TRUE;
                }
                whatis(NULL);
            }
            break;

        case S_MAP:

            /* Scroll of magic mapping. */

            if (cursed)
            {
                msg("Your mind goes blank for a moment.");
                wclear(cw);
                light(&hero);
                status(TRUE);
                break;
            }

            if (is_scroll && know_items[TYP_SCROLL][S_MAP] != TRUE)
            {
                msg("Oh! This scroll has a map on it!!");
                know_items[TYP_SCROLL][S_MAP] = TRUE;
            }

            if (blessed)
                turn_on(player, BLESSMAP);

            overwrite(stdscr, hw);

            /* Take all the things we want to keep hidden out of the window */

            for (i = 0; i < LINES; i++)
                for (j = 0; j < COLS; j++)
                {
                    switch (nch = ch = CCHAR(mvwinch(hw, i, j)))
                    {
                        case SECRETDOOR:
                            nch = DOOR;
                            mvaddch(i, j, nch);
                            break;

                        case '-':
                        case '|':
                        case DOOR:
                        case PASSAGE:
                        case ' ':
                        case STAIRS:
                            if (mvwinch(mw, i, j) != ' ')
                            {
                                struct thing    *it;
                                struct linked_list  *lit;

                                lit = find_mons(i, j);

				if (lit) {
				    it = THINGPTR(lit);

				    if (it && it->t_oldch == ' ')
					it->t_oldch = nch;
				}
                            }
                            break;

                        default:
                            if (!blessed || !isatrap(ch))
                                nch = ' ';
                            else
                            {
                                struct trap *tp;
                                struct room *rp;

                                tp = trap_at(i, j);
                                rp = roomin(hero);

                                if (tp->tr_type == FIRETRAP && rp != NULL)
                                {
                                    rp->r_flags &= ~ISDARK;
                                    light(&hero);
                                }

                                tp->tr_flags |= ISFOUND;
                            }
                    }
                    if (nch != ch)
                        waddch(hw, nch);
                }

            /* Copy in what he has discovered */
            overlay(cw, hw);

            /* And set up for display */
            overwrite(hw, cw);

            break;

        case S_GFIND:
            /* Scroll of gold detection */

            if (cursed)
            {
                int n = roll(3, 6);
                int k;
                struct room *rp;
                coord   pos;

                msg("You begin to feel greedy and you sense gold.");
                wclear(hw);

                for (k = 1; k < n; k++)
                {
                    rp = &rooms[rnd_room()];
                    rnd_pos(rp, &pos);
                    mvwaddch(hw, pos.y, pos.x, GOLD);
                }
                overlay(hw, cw);

                break;
            }

            if (blessed)
                turn_on(player, BLESSGOLD);

            if (gsense() && is_scroll)
                know_items[TYP_SCROLL][S_GFIND] = TRUE;

            break;

        case S_SELFTELEP:

            /* Scroll of teleportation: Make him disappear and reappear */

            if (cursed)
            {
                level += 5 + rnd(5);
                new_level(NORMLEV,0);
                mpos = 0;
                msg("You are banished to the lower regions.");
            }
            else if (blessed)
            {
                level -= rnd(3) + 1;

                if (level < 1)
                    level = 1;

                mpos = 0;
                new_level(NORMLEV,0); /* change levels */
                status(TRUE);
                msg("You are whisked away to another region.");
            }
            else
            {
                teleport();

                if (is_scroll)
                    know_items[TYP_SCROLL][S_SELFTELEP] = TRUE;
            }

            if (off(player, ISCLEAR))
            {
                if (on(player, ISHUH))
                    lengthen_fuse(FUSE_UNCONFUSE, rnd(4) + 4);
                else
                {
                    light_fuse(FUSE_UNCONFUSE, 0, rnd(4) + 4, AFTER);
                    turn_on(player, ISHUH);
                }
            }
            else
                msg("You feel dizzy for a moment, but it quickly passes.");

            break;

        case S_SCARE:

            /*
             * A blessed scroll of scare monster automatically transports
             * itself to the hero's feet
             *
             */

            if (blessed)
            {
                ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );

                if (ch != FLOOR && ch != PASSAGE)
                {
                    msg("Your feet tickle for a moment");
                    return;
                }

                item = spec_item(SCROLL, S_SCARE, 0, 0);

                obj = OBJPTR(item);
                obj->o_flags = ISCURSED;
                obj->o_pos = hero;
                add_obj(item, hero.y, hero.x);
                msg("A wave of terror sweeps throughout the room");
            }
            else
            {
                /*
                 * A monster will refuse to step on a scare monster
                 * scroll if it is dropped.  Thus reading it is a
                 * mistake and produces laughter at the poor rogue's
                 * boo boo.
                 */

                msg("You hear maniacal laughter in the distance.");

                if (cursed) /* If cursed, monsters get mad */
                    aggravate();
            }
            break;

        case S_REMOVECURSE:
            if (cursed)     /* curse a player's possession */
            {
                for (nitem = pack; nitem != NULL; nitem = next(nitem))
                {
                    obj = OBJPTR(nitem);

                    if (rnd(5) == 0)
                        if (obj->o_flags & ISBLESSED)
                            obj->o_flags &= ~ISBLESSED;
                        else
                            obj->o_flags |= ISCURSED;
                }
                msg("The smell of fire and brimstone comes from your pack.");
            }
            else if (blessed)
            {
                for (nitem = pack; nitem != NULL; nitem = next(nitem))
                    (OBJPTR(nitem))->o_flags &= ~ISCURSED;

                msg("Your pack glistens brightly.");
            }
            else
            {
                if ((nitem = get_item("remove the curse on", 0)) != NULL)
                {
                    obj = OBJPTR(nitem);
                    msg("Removed the curse from %s.", inv_name(obj, LOWERCASE));
                    obj->o_flags &= ~ISCURSED;

                    if (is_scroll)
                        know_items[TYP_SCROLL][S_REMOVECURSE] = TRUE;
                }
            }
            break;

        case S_PETRIFY:
            switch(CCHAR(mvinch(hero.y, hero.x)))
            {
                case TRAPDOOR:
                case DARTTRAP:
                case TELTRAP:
                case ARROWTRAP:
                case SLEEPTRAP:
                case BEARTRAP:
                case FIRETRAP:
                {
                    int n;

                    /* Find the right trap */
                    for (n = 0; n < ntraps && !ce(traps[n].tr_pos, hero); n++)
                        ;

                    ntraps--;

                    if (!ce(traps[n].tr_pos, hero))
                        msg("What a strange trap!");
                    else
                    {
                        while (n < ntraps)
                        {
                            traps[n] = traps[n + 1];
                            n++;
                        }
                    }

                    msg("The dungeon begins to rumble and shake!");
                    addch(WALL);

                    if (on(player, CANINWALL))
                    {
                        extinguish_fuse(FUSE_UNPHASE);
                        turn_off(player, CANINWALL);
                        msg("Your dizzy feeling leaves you.");
                    }

                    turn_on(player, ISINWALL);
                }
                break;

                case DOOR:
                case SECRETDOOR:
                {
                    struct room *rp = roomin(hero);
                    short   n;

                    /* Find the right door */

                    for (n=0; n<rp->r_nexits && !ce(rp->r_exit[n], hero); n++)
                        /* do nothing */ ;

                    rp->r_nexits--;

                    if (!ce(rp->r_exit[n], hero))
                        msg("What a strange door!");
                    else
                    {
                        while (n < rp->r_nexits)
                        {
                            rp->r_exit[n] = rp->r_exit[n + 1];
                            n++;
                        }
                    }
                    /* No break - fall through */
                }
                case FLOOR:
                case PASSAGE:
                    msg("The dungeon begins to rumble and shake!");
                    addch(WALL);

                    if (on(player, CANINWALL))
                    {
                        extinguish_fuse(FUSE_UNPHASE);
                        turn_off(player, CANINWALL);
                        msg("Your dizzy feeling leaves you.");
                    }

                    turn_on(player, ISINWALL);
                    break;

                default:
                    nothing_message(flags);
                    break;
            }
            break;

        case  S_GENOCIDE:
            msg("You have been granted the boon of genocide!--More--");

            wait_for(' ');
            msg("");

            genocide(flags);

            if (is_scroll)
                know_items[TYP_SCROLL][S_GENOCIDE] = TRUE;

            break;

        case S_PROTECT:
            if (is_scroll && know_items[TYP_SCROLL][S_PROTECT] == FALSE)
            {
                msg("You can protect something from rusting or theft.");
                know_items[TYP_SCROLL][S_PROTECT] = TRUE;
            }

            if ((item = get_item("protect", 0)) != NULL)
            {
                struct object   *lb = OBJPTR(item);

                if (cursed)
                {
                    lb->o_flags &= ~ISPROT;
                    mpos = 0;
                    msg("Unprotected %s.", inv_name(lb, LOWERCASE));
                }
                else
                {
                    lb->o_flags |= ISPROT;
                    mpos = 0;
                    msg("Protected %s.", inv_name(lb, LOWERCASE));
                }
            }
            break;

        case S_MAKEITEMEM:
            if (!is_scroll || rnd(luck))
                feel_message();
            else
            {
                char itemtype;

                if (is_scroll)
                    know_items[TYP_SCROLL][S_MAKEITEMEM] = TRUE;

                msg("You have been endowed with the power of creation.");

                if (blessed)
                    itemtype = '\0';
                else
                    switch (rnd(6))
                    {
                        case 0: itemtype = RING;    break;
                        case 1: itemtype = POTION;  break;
                        case 2: itemtype = SCROLL;  break;
                        case 3: itemtype = ARMOR;   break;
                        case 4: itemtype = WEAPON;  break;
                        case 5: itemtype = STICK;   break;
                    }

                flags |= SCR_MAGIC;
                buy_it(itemtype, flags);
            }
            break;

        case S_ENCHANT:
        {
            struct linked_list  *ll;
            struct object   *lb;
            int howmuch, flg=0;

            if (is_scroll && know_items[TYP_SCROLL][S_ENCHANT] == FALSE)
            {
                msg("You are granted the power of enchantment.");
                msg("You may enchant anything(weapon,ring,armor,scroll,potion)");
                know_items[TYP_SCROLL][S_ENCHANT] = TRUE;
            }

            if ((ll = get_item("enchant", 0)) != NULL)
            {
                lb = OBJPTR(ll);
                lb->o_flags &= ~ISCURSED;

                if (blessed)
                    howmuch = 2;
                else if (cursed)
                    howmuch = -1;
                else
                {
                    howmuch = 1;
                    flg |= ISBLESSED;
                }

                switch (lb->o_type)
                {
                    case RING:
                        lb->o_ac += howmuch;

                        if (lb->o_ac > 5 && rnd(5) == 0)
                        {
                            msg("Your ring explodes in a cloud of smoke.");
                            lb->o_flags &= ~ISCURSED;
                            dropcheck(lb);

                            switch (lb->o_which)
                            {
                                case R_ADDSTR:
                                    chg_str(-2, TRUE, FALSE);
                                    break;
                                case R_ADDHIT:
                                    chg_dext(-2, TRUE, FALSE);
                                    break;
                                case R_ADDINTEL:
                                    pstats.s_intel -= 2;
                                    max_stats.s_intel -= 2;
                                    break;
                                case R_ADDWISDOM:
                                    pstats.s_wisdom -= 2;
                                    max_stats.s_wisdom -= 2;
                                    break;
                            }

                            del_pack(ll);
                            lb = NULL;
                        }
                        else if (is_r_on(lb))
                            switch (lb->o_which)
                            {
                                case R_ADDSTR:
                                    pstats.s_str += howmuch;
                                    break;
                                case R_ADDHIT:
                                    pstats.s_dext += howmuch;
                                    break;
                                case R_ADDINTEL:
                                    pstats.s_intel += howmuch;
                                    break;
                                case R_ADDWISDOM:
                                    pstats.s_wisdom += howmuch;
                                    break;
                                case R_CARRYING:
                                    updpack();
                                    break;
                            }

                        break;

                    case ARMOR:
                        lb->o_ac -= howmuch;

                        if (armors[lb->o_which].a_class - lb->o_ac > 5 && rnd(5) == 0)
                        {
                            msg("Your %s explodes in a cloud of dust.",
                                inv_name(lb, LOWERCASE));

                            lb->o_flags &= ~ISCURSED;

                            if (lb == cur_armor)
                                pstats.s_hpt /= 2;

                            dropcheck(lb);
                            del_pack(ll);
                            lb = NULL;
                        }
                        break;

                    case STICK:
                        if (wizard || howmuch != 1 && rnd(5) == 0)
                            lb->o_flags |= flg;

                        lb->o_charges += howmuch + 10;

                        if (lb->o_charges < 0)
                            lb->o_charges = 0;

                        if (lb->o_charges > 50 && rnd(5) == 0)
                        {
                            msg("Your %s explodes into splinters.",
                                inv_name(lb, LOWERCASE));

                            lb->o_flags &= ~ISCURSED;
                            dropcheck(lb);
                            del_pack(ll);
                            lb = NULL;