diff urogue/scrolls.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children e52a8a7ad4c5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/scrolls.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1491 @@
+/*
+    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;