diff xrogue/scrolls.c @ 133:e6179860cb76

Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 21 Apr 2015 08:55:20 -0400
parents
children ce0cf824c192
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xrogue/scrolls.c	Tue Apr 21 08:55:20 2015 -0400
@@ -0,0 +1,901 @@
+/*
+    scrolls.c - Functions for dealing with scrolls
+
+    XRogue: Expeditions into the Dungeons of Doom
+    Copyright (C) 1991 Robert Pietkivitch
+    All rights reserved.
+    
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
+    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 <curses.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * let the hero get rid of some type of monster 
+ */
+
+genocide()
+{
+    register struct linked_list *ip;
+    register struct thing *mp;
+    register struct linked_list *nip;
+                             /* cannot genocide any uniques */
+    register int num_monst = NUMMONST-NUMUNIQUE-NUMDINOS;
+    register int which_monst;
+
+    which_monst = makemonster(FALSE, "wipe out");
+    if (which_monst <= 0 || which_monst >= num_monst) {
+        msg("");
+        return;
+    }
+
+    /* Remove this monster from the present level */
+    for (ip = mlist; ip; ip = nip) {
+        mp = THINGPTR(ip);
+        nip = next(ip);
+        if (mp->t_index == which_monst) {
+            killed(ip, FALSE, FALSE, TRUE);
+        }
+    }
+
+    /* Remove from available monsters */
+    monsters[which_monst].m_normal = FALSE;
+    monsters[which_monst].m_wander = FALSE;
+    mpos = 0;
+    msg("You have wiped out the %s.", monsters[which_monst].m_name);
+}
+
+read_scroll(which, flag, is_scroll)
+register int which;
+int flag;
+bool is_scroll;
+{
+    register struct object *obj = NULL, *nobj;
+    register struct linked_list *item, *nitem;
+    register int i,j;
+    register unsigned char ch, nch;
+    bool cursed, blessed;
+
+    blessed = FALSE;
+    cursed = FALSE;
+    item = NULL;
+
+    if (which < 0) {
+        if (on(player, ISBLIND)) {
+            msg("You can't see to read anything!");
+            return;
+        }
+        if (on(player, ISINWALL)) {
+            msg("You can't see the scroll while inside rock!");
+            return;
+        }
+
+        /* This is a scroll or book. */
+        if (player.t_action != C_READ) {
+            int units;
+
+            item = get_item(pack, "read", READABLE, FALSE, FALSE);
+
+            /*
+             * Make certain that it is somethings that we want to read
+             */
+            if (item == NULL)
+                return;
+
+            /* How long does it take to read? */
+            units = usage_time(item);
+            if (units < 0) return;
+
+            player.t_using = item;      /* Remember what it is */
+            player.t_no_move = units * movement(&player);
+            if ((OBJPTR(item))->o_type == SCROLL) player.t_action = C_READ;
+            else player.t_action = C_USE;
+            return;
+        }
+
+        /* We have waited our time, let's quaff the potion */
+        item = player.t_using;
+        player.t_using = NULL;
+        player.t_action = A_NIL;
+
+        obj = OBJPTR(item);
+        /* remove it from the pack */
+        inpack--;
+        detach(pack, item);
+
+        msg("As you read the scroll, it vanishes.");
+        cursed = obj->o_flags & ISCURSED;
+        blessed = obj->o_flags & ISBLESSED;
+
+        which = obj->o_which;
+    }
+    else {
+        cursed = flag & ISCURSED;
+        blessed = flag & ISBLESSED;
+    }
+
+    switch (which) {
+        case S_CONFUSE: /* Scroll of monster confusion. Give him that power. */
+    {
+        register char *str;
+
+        switch (rnd(5)) {
+        case 0:
+            str = "glow red";
+        when 1:
+            str = "vibrate";
+        when 2:
+            str = "glow blue";
+        when 3:
+            str = "radiate green";
+        otherwise:
+            str = "itch with a strange desire";
+        }
+            msg("Your hands begin to %s. ", str);
+            turn_on(player, CANHUH);
+    }
+        when S_CURING:
+            /*
+             * A cure disease spell
+             */
+            if (on(player, HASINFEST) || 
+                on(player, HASDISEASE)|| 
+                on(player, DOROT)) {
+                if (on(player, HASDISEASE)) {
+                    extinguish(cure_disease);
+                    cure_disease();
+                }
+                if (on(player, HASINFEST)) {
+                    msg(terse ? "You feel yourself improving."
+                              : "You begin to feel yourself improving.");
+                    turn_off(player, HASINFEST);
+                    infest_dam = 0;
+                }
+                if (on(player, DOROT)) {
+                    msg("You feel your skin returning to normal.");
+                    turn_off(player, DOROT);
+                }
+            }
+            else {
+                /* msg(nothing); */
+                break;
+            }
+            if (is_scroll) s_know[S_CURING] = TRUE;
+        when S_LIGHT:
+            if (blue_light(blessed, cursed) && is_scroll)
+                s_know[S_LIGHT] = TRUE;
+        when S_HOLD:
+            if (cursed) {
+                /*
+                 * This scroll aggravates all the monsters on the current
+                 * level and sets them running towards the hero
+                 */
+                msg("You hear a high-pitched humming noise.");
+                /* protect good charactors */
+                if (player.t_ctype == C_PALADIN ||
+                    player.t_ctype == C_RANGER  || player.t_ctype == C_MONK) {
+                        msg("A chill runs up your spine! ");
+                        aggravate(TRUE, FALSE);
+                }
+                else {
+                    aggravate(TRUE, TRUE);
+                }
+            }
+            else if (blessed) { /* Hold all monsters on level */
+                if (mlist == NULL) msg(nothing);
+                else {
+                    register struct linked_list *mon;
+                    register struct thing *th;
+
+                    for (mon = mlist; mon != NULL; mon = next(mon)) {
+                        th = THINGPTR(mon);
+                        turn_off(*th, ISRUN);
+                        turn_on(*th, ISHELD);
+                        turn_off(*th, ISCHARMED);
+                    }
+                    if (levtype == OUTSIDE)
+                        msg("A sudden peace comes over the land.. ");
+                    else
+                        msg("A sudden peace comes over the dungeon.. ");
+                }
+            }
+            else {
+                /*
+                 * Hold monster scroll.  Stop all monsters within two spaces
+                 * from chasing after the hero.
+                 */
+                    register int x,y;
+                    register struct linked_list *mon;
+                    bool gotone=FALSE;
+
+                    for (x = hero.x-2; x <= hero.x+2; x++) {
+                        for (y = hero.y-2; y <= hero.y+2; y++) {
+                            if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
+                                continue;
+                            if (isalpha(mvwinch(mw, y, x))) {
+                                if ((mon = find_mons(y, x)) != NULL) {
+                                    register struct thing *th;
+
+                                    gotone = TRUE;
+                                    th = THINGPTR(mon);
+                                    turn_off(*th, ISRUN);
+                                    turn_on(*th, ISHELD);
+                                    turn_off(*th, ISCHARMED);
+                                }
+                            }
+                        }
+                    }
+                    if (gotone) msg("A sudden peace surrounds you.");
+                    else msg(nothing);
+            }
+        when S_SLEEP:
+            /*
+             * if cursed, you fall asleep
+             */
+            if (is_scroll) s_know[S_SLEEP] = TRUE;
+            if (cursed) {
+                if (ISWEARING(R_ALERT))
+                    msg("You feel drowsy for a moment.");
+                else {
+                    msg("You fall asleep.");
+                    player.t_no_move += movement(&player)*(4 + rnd(SLEEPTIME));
+                    player.t_action = A_FREEZE;
+                }
+            }
+            else {
+                /*
+                 * sleep monster scroll.  
+                 * puts all monsters within 2 spaces asleep
+                 */
+                    register int x,y;
+                    register struct linked_list *mon;
+                    bool gotone=FALSE;
+
+                    for (x = hero.x-2; x <= hero.x+2; x++) {
+                        for (y = hero.y-2; y <= hero.y+2; y++) {
+                            if (y < 1 || x < 0 || y > lines - 3 || x > cols - 1)
+                                continue;
+                            if (isalpha(mvwinch(mw, y, x))) {
+                                if ((mon = find_mons(y, x)) != NULL) {
+                                    register struct thing *th;
+
+                                    th = THINGPTR(mon);
+                                    if (on(*th, ISUNDEAD))
+                                        continue;
+                                    th->t_no_move += movement(th)*(SLEEPTIME+4);
+                                    th->t_action = A_FREEZE;
+                                    gotone = TRUE;
+                                }
+                            }
+                        }
+                    }
+                    if (gotone) 
+                        msg("The monster(s) around you seem to have fallen asleep!");
+                    else 
+                        msg(nothing);
+            }
+        when S_CREATE:
+            /*
+             * Create a monster
+             * First look in a circle around him, next try his room
+             * otherwise give up
+             */
+            creat_mons(&player, (short) 0, TRUE);
+            light(&hero);
+        when S_IDENT:
+            /* 
+             * if its blessed then identify everything in the pack
+             */
+            if (blessed) {
+                msg("You feel more Knowledgeable!");
+                idenpack();
+            }
+            else {
+                /*
+                 * Identify, let the rogue figure something out
+                 */
+                if (is_scroll && s_know[S_IDENT] != TRUE) {
+                    msg("This scroll is an identify scroll");
+                }
+                whatis((struct linked_list *)NULL);
+            }
+            if (is_scroll) s_know[S_IDENT] = TRUE;
+        when S_MAP:
+            /*
+             * Scroll of magic mapping.
+             */
+            if (blessed) {
+                register int i;
+
+                if (is_scroll && s_know[S_MAP] != TRUE)
+                    s_know[S_MAP] = TRUE;
+                  /* light rooms */
+                for (i=0; i<MAXROOMS; i++){
+                    rooms[i].r_flags &= ~ISDARK;
+                }
+
+                msg("This scroll has a very detailed map on it!  --More--");
+                wait_for(' ');
+                overwrite(stdscr, hw);
+                overlay(stdscr, cw);    /* wizard CTRL(F) */
+                overlay(mw, cw);        /* wizard CTRL(X) */
+                draw(cw);
+                goto map_jump;          /* skip over regular mapping routine */
+            }
+            if (is_scroll && s_know[S_MAP] != TRUE) {
+                msg("Oh, now this scroll has a map on it.");
+                s_know[S_MAP] = TRUE;
+            }
+            overwrite(stdscr, hw);
+            /*
+             * Take all the things we want to keep hidden out of the window
+             */
+            for (i = 1; i < lines-2; i++)
+                for (j = 0; j < cols; j++)
+                {
+                    switch (nch = ch = mvwinch(hw, i, j))
+                    {
+                        case SECRETDOOR:
+                            nch = secretdoor (i, j);
+                            break;
+                        case HORZWALL:
+                        case VERTWALL:
+                        case DOOR:
+                        case PASSAGE:
+                        case ' ':
+                        case STAIRS:
+                            if (mvwinch(mw, i, j) != ' ')
+                            {
+                                register struct thing *it;
+
+                                it = THINGPTR(find_mons(i, j));
+                                if (it && it->t_oldch == ' ')
+                                    it->t_oldch = nch;
+                            }
+                            break;
+                        default:
+                            nch = ' ';
+                    }
+                    if (nch != ch)
+                        waddch(hw, nch);
+                }
+            /*
+             * Copy in what he has discovered
+             */
+            overlay(cw, hw);
+            /*
+             * And set up for display
+             */
+            overwrite(hw, cw);
+            map_jump:           /* blessed map jump from above */
+        when S_GFIND:
+            /*
+             * Scroll of gold detection
+             */
+            {
+                int gtotal = 0;
+
+                if (is_scroll) s_know[S_GFIND] = TRUE;
+                wclear(hw);
+                for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) {
+                    nobj = OBJPTR(nitem);
+                    if (nobj->o_type == GOLD) {
+                        gtotal += nobj->o_count;
+                        mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, GOLD);
+                    }
+                }
+                for (nitem = mlist; nitem != NULL; nitem = next(nitem)) {
+                    register struct linked_list *gitem;
+                    register struct thing *th;
+
+                    th = THINGPTR(nitem);
+                    if (on(*th, NODETECT)) continue;
+                    for(gitem = th->t_pack; gitem != NULL; gitem = next(gitem)){
+                        nobj = OBJPTR(gitem);
+                        if (nobj->o_type == GOLD) {
+                            gtotal += nobj->o_count;
+                            mvwaddch(hw, th->t_pos.y, th->t_pos.x, GOLD);
+                        }
+                    }
+                }
+                if (gtotal) {
+                    rmmsg();
+                    overlay(hw,cw);
+                    draw(cw);
+                    msg("You begin to feel greedy.  You sense gold!");
+                    break;
+                }
+            }
+            msg("You begin to feel a pull downward..");
+        when S_TELEP:
+            /*
+             * Scroll of teleportation:
+             * Make him disappear and reappear
+             */
+            if (cursed) {
+                int old_max = cur_max;
+
+                turns = (vlevel * NLEVMONS) * LEVEL;
+                /* if (turns > 42000) turns = 42000; limit turns */
+                debug ("vlevel = %d  turns = %d", vlevel, turns);
+
+                level = rnd(201)+80;   /* cursed teleport range */
+
+                msg("You are banished to the lower regions! ");
+                new_level(NORMLEV);
+
+                status(TRUE);
+                mpos = 0;
+                if (old_max == cur_max) { /* if he's been here make it harder */
+                /* protect good charactors */
+                if (player.t_ctype == C_PALADIN ||
+                    player.t_ctype == C_RANGER  || player.t_ctype == C_MONK) {
+                        aggravate(TRUE, FALSE);
+                }
+                else {
+                    aggravate(TRUE, TRUE);
+                }
+                }
+            }
+            else if (blessed) {
+                int     old_level, 
+                        much = rnd(6) - 7;
+
+                old_level = level;
+                if (much != 0) {
+                    level += much;
+                    if (level < 1)
+                        level = 1;
+                    mpos = 0;
+                    cur_max = level;
+                    turns += much*LEVEL;
+                    if (turns < 0)
+                        turns = 0;
+                    new_level(NORMLEV);         /* change levels */
+                    if (level == old_level)
+                        status(TRUE);
+                    msg("You are whisked away to another region!");
+                }
+            }
+            else {
+                teleport();
+            }
+            if (is_scroll) s_know[S_TELEP] = TRUE;
+        when S_SCARE:
+            /*
+             * 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.");
+        when S_REMOVE:
+            if (cursed) { /* curse all player's possessions */
+                for (nitem = pack; nitem != NULL; nitem = next(nitem)) {
+                    nobj = OBJPTR(nitem);
+                    if (nobj->o_flags & ISBLESSED) 
+                        nobj->o_flags &= ~ISBLESSED;
+                    else 
+                        nobj->o_flags |= ISCURSED;
+                }
+                msg("The smell of fire and brimstone fills the air!");
+        /* return; leaks item, go through end of function */
+            }
+            else if (blessed) {
+                for (nitem = pack; nitem != NULL; nitem = next(nitem)) {
+                    nobj = OBJPTR(nitem);
+                    nobj->o_flags &= ~ISCURSED;
+                }
+                msg("Your pack glistens brightly!");
+                do_panic(NULL);         /* this startles them */
+        /* return; leaks item, go through end of function */
+            }
+            else {
+                nitem = get_item(pack, "remove the curse on",ALL,FALSE,FALSE);
+                if (nitem != NULL) {
+                    nobj = OBJPTR(nitem);
+                    nobj->o_flags &= ~ISCURSED;
+                    msg("Removed the curse from %s",inv_name(nobj,TRUE));
+                }
+            }
+            if (is_scroll) s_know[S_REMOVE] = TRUE;
+        when S_PETRIFY:
+            switch (mvinch(hero.y, hero.x)) {
+                case WORMHOLE:
+                case TRAPDOOR:
+                case DARTTRAP:
+                case TELTRAP:
+                case ARROWTRAP:
+                case SLEEPTRAP:
+                case BEARTRAP:
+                    {
+                        register int i;
+
+                        /* Find the right trap */
+                        for (i=0; i<ntraps && !ce(traps[i].tr_pos, hero); i++);
+                        ntraps--;
+
+                        if (!ce(traps[i].tr_pos, hero))
+                            msg("What a strange trap!");
+                        else {
+                            while (i < ntraps) {
+                                traps[i] = traps[i + 1];
+                                i++;
+                            }
+                        }
+                    }
+                    goto pet_message;
+                case DOOR:
+                case SECRETDOOR:
+                case FLOOR:
+                case PASSAGE:
+pet_message:        msg("The dungeon begins to rumble and shake!");
+                    addch(WALL);
+
+                    /* If the player is phased, unphase him */
+                    if (on(player, CANINWALL)) {
+                        extinguish(unphase);
+                        turn_off(player, CANINWALL);
+                        msg("The dizzy feeling leaves you.");
+                    }
+
+                    /* Mark the player as in a wall */
+                    turn_on(player, ISINWALL);
+                    break;
+                default:
+                    msg(nothing);
+            }
+        when S_GENOCIDE:
+            msg("You have been granted the boon of genocide!  --More--");
+            wait_for(' ');
+            msg("");
+            genocide();
+            if (is_scroll) s_know[S_GENOCIDE] = TRUE;
+        when S_PROTECT: {
+            struct linked_list *ll;
+            struct object *lb;
+            bool did_it = FALSE;
+            msg("You are granted the power of protection.");
+            if ((ll=get_item(pack,"protect",PROTECTABLE,FALSE,FALSE)) != NULL) {
+                lb = OBJPTR(ll);
+                mpos = 0;
+                if (cursed) {
+                    switch(lb->o_type) {        /* ruin it completely */
+                        case RING: if (lb->o_ac > 0) {
+                                    if (is_current(lb)) {
+                                        switch (lb->o_which) {
+                                            case R_ADDWISDOM:
+                                                pstats.s_wisdom -= lb->o_ac;
+                                            when R_ADDINTEL:  
+                                                pstats.s_intel -= lb->o_ac;
+                                            when R_ADDSTR:
+                                                pstats.s_str -= lb->o_ac;
+                                            when R_ADDHIT:
+                                                pstats.s_dext -= lb->o_ac;
+                                        }
+                                    }
+                                    did_it = TRUE;
+                                        lb->o_ac = 0;
+                                }
+                        when ARMOR: if (lb->o_ac > 10) {
+                                        did_it = TRUE;
+                                        lb->o_ac = 10;
+                                    }
+                        when STICK: if (lb->o_charges > 0) {
+                                        did_it = TRUE;
+                                        lb->o_charges = 0;
+                                    }
+                        when WEAPON:if (lb->o_hplus > 0) {