diff xrogue/misc.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/misc.c	Tue Apr 21 08:55:20 2015 -0400
@@ -0,0 +1,1296 @@
+/*
+    misc.c - routines dealing specifically with miscellaneous magic
+    
+    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.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <curses.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * changeclass:
+ *      Change the player's class to the specified one.
+ */
+
+changeclass(newclass)
+long *newclass;
+{
+    if (*newclass == player.t_ctype) {
+        msg("You feel more skillful.");
+        raise_level();
+    }
+    else {
+        /*
+         * reset his class and then use check_level to reset hit
+         * points and the right level for his exp pts
+         * drop exp pts by 10%
+         */
+        long save;
+
+        msg("You are transformed into a %s! ", char_class[*newclass].name);
+
+        /*
+         * if he becomes a thief or an assassin give him studded leather armor
+         */
+        if ((*newclass == C_THIEF || *newclass == C_ASSASSIN) &&
+            cur_armor != NULL && cur_armor->o_which != STUDDED_LEATHER)
+                cur_armor->o_which = STUDDED_LEATHER;
+        /*
+         * if he becomes a monk he can't wear any armor
+     * so give him a cloak of protection
+         */
+        if (*newclass == C_MONK && cur_armor != NULL) {
+                cur_armor->o_ac = armors[cur_armor->o_which].a_class - 
+                                  cur_armor->o_ac;
+                cur_armor->o_type = MM;
+                cur_armor->o_which = MM_PROTECT;
+                cur_armor->o_flags &= ~(ISPROT | ISKNOW);
+                cur_misc[WEAR_CLOAK] = cur_armor;
+                cur_armor = NULL;
+        }
+    /*
+     * otherwise give him plate armor
+     */
+        if ((*newclass != C_THIEF ||
+         *newclass != C_ASSASSIN || *newclass != C_MONK) &&
+         cur_armor != NULL && cur_armor->o_which != PLATE_ARMOR) 
+                cur_armor->o_which = PLATE_ARMOR;
+
+        /*
+         * if he used to be a spell caster of some sort, kill the fuse
+         */
+        if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER)
+                extinguish(spell_recovery);
+        if (player.t_ctype == C_DRUID || player.t_ctype == C_MONK)
+                extinguish(chant_recovery);
+        if ((player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) &&
+             !cur_relic[HEIL_ANKH])
+                extinguish(prayer_recovery);
+
+        /*
+         * if he becomes a spell caster of some kind, give him a fuse
+         */
+        if (*newclass == C_MAGICIAN || *newclass == C_RANGER)
+                fuse(spell_recovery, (VOID *)NULL, SPELLTIME, AFTER);
+        if (*newclass == C_DRUID || *newclass == C_MONK)
+                fuse(chant_recovery, (VOID *)NULL, SPELLTIME, AFTER);
+        if ((*newclass==C_CLERIC || *newclass==C_PALADIN) && !cur_misc[HEIL_ANKH])
+                fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER);
+        /*
+         * if he's changing from a fighter, ranger, or paladin then we
+     * may have to change his sword since only these types can wield
+     * the two-handed sword.
+         */
+        if ((player.t_ctype == C_FIGHTER ||
+        player.t_ctype == C_RANGER   ||
+            player.t_ctype == C_PALADIN) &&
+        cur_weapon != NULL && cur_weapon->o_type == WEAPON &&
+            (cur_weapon->o_which == BASWORD  ||
+        cur_weapon->o_which == TWOSWORD) &&
+            !(*newclass == C_FIGHTER || *newclass == C_RANGER ||
+            *newclass == C_PALADIN)  &&
+        cur_weapon->o_which == TWOSWORD)
+                cur_weapon->o_which = SWORD;
+
+        /*
+         * if he's changing from a thief, assassin, fighter, or monk
+     * then we may have to change his sword again since only these
+     * types can wield the bastard sword.
+         */
+        if ((player.t_ctype == C_THIEF  || player.t_ctype == C_ASSASSIN ||
+            player.t_ctype == C_FIGHTER || player.t_ctype == C_MONK)    &&
+        cur_weapon != NULL && cur_weapon->o_type == WEAPON &&
+            (cur_weapon->o_which == BASWORD  ||
+            cur_weapon->o_which == TWOSWORD) &&
+            !(*newclass == C_THIEF || *newclass == C_ASSASSIN ||
+            *newclass == C_MONK)   &&
+        cur_weapon->o_which == BASWORD)
+                cur_weapon->o_which = SWORD;
+
+        /*
+         * if he was a thief, assassin, or monk then take out
+     * the trap_look() daemon
+         */
+        if (player.t_ctype == C_THIEF || player.t_ctype == C_MONK ||
+            player.t_ctype == C_ASSASSIN)
+                kill_daemon(trap_look);
+
+        /*
+         * if he becomes a thief, assassin, or monk then add 
+     * the trap_look() daemon
+         */
+        if (*newclass == C_THIEF || *newclass == C_ASSASSIN ||
+        *newclass == C_MONK)
+                daemon(trap_look, (VOID *)NULL, AFTER);
+
+    /* adjust stats */
+        char_type = player.t_ctype = *newclass;
+        save = pstats.s_hpt;
+        max_stats.s_hpt = pstats.s_hpt = 0;
+        max_stats.s_lvl = pstats.s_lvl = 0; 
+        max_stats.s_lvladj = pstats.s_lvladj = 0; 
+        max_stats.s_exp = pstats.s_exp + rnd(4);
+        check_level();
+        if (pstats.s_hpt > save) /* don't add to current hits */
+            pstats.s_hpt = save;
+    }
+    dsrpt_player(); /* this should disrupt whatever we were doing */
+}
+
+/*
+ * Use the relic that our monster is wielding.
+ */
+
+m_use_relic(monster)
+register struct thing *monster;
+{
+    register struct object *obj;
+
+    /* Make sure we really have it */
+    if (monster->t_using) obj = OBJPTR(monster->t_using);
+    else {
+        debug("Relic not set!");
+        monster->t_action = A_NIL;
+        return;
+    }
+
+    /* Now let's see what we're using */
+    if (obj->o_type == RELIC) switch (obj->o_which) {
+        case MING_STAFF: {
+            static struct object missile = {
+              MISSILE, {0,0}, 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
+            };
+
+            debug("Firing Ming's staff");
+            sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl);
+            do_motion(&missile,
+                       monster->t_newpos.y, monster->t_newpos.x, monster);
+            hit_monster(unc(missile.o_pos), &missile, monster);
+            monster->t_artifact = monster->t_artifact * 4 / 5;
+        }
+        when EMORI_CLOAK:
+            debug("stunning with Emori's cloak");
+            do_zap(monster, obj, &monster->t_newpos, WS_PARALYZE, NULL);
+            obj->o_charges = 0;
+
+        when ASMO_ROD: {
+            char *name;
+
+            switch (rnd(3)) { /* Select a function */
+                case 0:    name = "lightning bolt";
+                when 1:    name = "flame";
+                otherwise: name = "ice";
+            }
+            shoot_bolt( monster, 
+                        monster->t_pos, 
+                        monster->t_newpos, 
+                        FALSE, 
+                        monster->t_index, 
+                        name, 
+                        roll(monster->t_stats.s_lvl,6));
+            monster->t_artifact /= 2;
+        }
+        when BRIAN_MANDOLIN:
+            /* Make sure the defendant is still around */
+            if (DISTANCE(monster->t_pos.y, monster->t_pos.x,
+                         hero.y, hero.x) < 25) {
+                if (!save(VS_MAGIC, &player, -4) &&
+                    !ISWEARING(R_ALERT)) {
+                    msg("Some beautiful music enthralls you.");
+                    player.t_no_move += movement(&player) * FREEZETIME;
+                    player.t_action = A_FREEZE;
+                    monster->t_artifact = monster->t_artifact * 2 / 3;
+                }
+                else {
+                    msg("You wince at a sour note.");
+                    monster->t_artifact /= 3;
+                }
+            }
+        when GERYON_HORN:
+            /* Make sure the defendant is still around */
+            if (DISTANCE(monster->t_pos.y, monster->t_pos.x,
+                         hero.y, hero.x) < 25) {
+                if (!ISWEARING(R_HEROISM) &&
+                    !save(VS_MAGIC, &player, -4)) {
+                        turn_on(player, ISFLEE);
+                        player.t_dest = &monster->t_pos;
+                        msg("A shrill blast terrifies you.");
+                        monster->t_artifact = monster->t_artifact * 3 / 4;
+                }
+                else  {
+                    msg("A shrill blast sends chills up your spine! ");
+                    monster->t_artifact /= 3;
+                }
+            }
+
+        otherwise:
+            /* Unknown RELIC! */
+            debug("Unknown wielded relic %d", obj->o_which);
+    }
+    else debug("Declared relic is %d", obj->o_type);
+
+    turn_off(*monster, CANSURPRISE);
+    /* Reset the monsters actions */
+    monster->t_action = A_NIL;
+    monster->t_using = NULL;
+}
+ 
+/*
+ * add something to the contents of something else
+ */
+
+put_contents(bag, item)
+register struct object *bag;            /* the holder of the items */
+register struct linked_list *item;      /* the item to put inside  */
+{
+    register struct linked_list *titem;
+    register struct object *tobj;
+
+    bag->o_ac++;
+    tobj = OBJPTR(item);
+    for (titem = bag->contents; titem != NULL; titem = next(titem)) {
+        if ((OBJPTR(titem))->o_which == tobj->o_which)
+            break;
+    }
+    if (titem == NULL) {        /* if not a duplicate put at beginning */
+        attach(bag->contents, item);
+    }
+    else {
+        item->l_prev = titem;
+        item->l_next = titem->l_next;
+        if (next(titem) != NULL) 
+            (titem->l_next)->l_prev = item;
+        titem->l_next = item;
+    }
+}
+
+/*
+ * remove something from something else
+ */
+
+take_contents(bag, item)
+register struct object *bag;            /* the holder of the items */
+register struct linked_list *item;
+{
+
+    if (bag->o_ac <= 0) {
+        msg("Nothing to take out");
+        return;
+    }
+    bag->o_ac--;
+    detach(bag->contents, item);
+    if (!add_pack(item, FALSE))
+        put_contents(bag, item);
+}
+
+
+do_bag(item)
+register struct linked_list *item;
+{
+
+    register struct linked_list *titem = NULL;
+    register struct object *obj, *tobj;
+    bool doit = TRUE;
+
+    obj = OBJPTR(item);
+    while (doit) {
+        msg("What do you want to do? (* for a list): ");
+        mpos = 0;
+        switch (wgetch(cw)) {
+            case EOF:
+            case ESC:
+                msg ("");
+                doit = FALSE;
+            when '1':
+                inventory(obj->contents, ALL);
+
+            when '2':
+                if (obj->o_ac >= MAXCONTENTS) {
+                    msg("the %s is full", m_magic[obj->o_which].mi_name);
+                    break;
+                }
+                switch (obj->o_which) {
+                case MM_BEAKER:
+                    titem = get_item(pack, "put in", POTION, FALSE, FALSE);
+                when MM_BOOK:
+                    titem = get_item(pack, "put in", SCROLL, FALSE, FALSE);
+                }
+                if (titem == NULL)
+                    break;
+                detach(pack, titem);
+                inpack--;
+                put_contents(obj, titem);
+            
+            when '3':
+                titem = get_item(obj->contents,"take out",ALL,FALSE,FALSE);
+                if (titem == NULL)
+                    break;
+                take_contents(obj, titem);
+                
+            when '4': 
+                switch (obj->o_which) {
+                case MM_BEAKER:
+                    titem = get_item(obj->contents,"quaff",ALL,FALSE,FALSE);
+                    if (titem == NULL)
+                        break;
+                    tobj = OBJPTR(titem);
+                    obj->o_ac--;
+                    detach(obj->contents, titem);
+                    quaff(tobj->o_which, 
+                          tobj->o_kind,
+                          tobj->o_flags,
+                          TRUE);
+                    if (p_know[tobj->o_which] && p_guess[tobj->o_which])
+                    {
+                        free(p_guess[tobj->o_which]);
+                        p_guess[tobj->o_which] = NULL;
+                    }
+                    else if (!p_know[tobj->o_which]             && 
+                             askme                              &&
+                             (tobj->o_flags & ISKNOW) == 0      &&
+                             (tobj->o_flags & ISPOST) == 0      &&
+                             p_guess[tobj->o_which] == NULL) {
+                        nameitem(titem, FALSE);
+                    }
+                    o_discard(titem);
+                when MM_BOOK:   
+                    if (on(player, ISBLIND)) {
+                        msg("You can't see to read anything! ");
+                        break;
+                    }
+                    titem = get_item(obj->contents,"read",ALL,FALSE,FALSE);
+                    if (titem == NULL)
+                        break;
+                    tobj = OBJPTR(titem);
+                    obj->o_ac--;
+                    detach(obj->contents, titem);
+                    read_scroll(tobj->o_which, 
+                                tobj->o_flags & (ISCURSED|ISBLESSED),
+                                TRUE);
+                    if (s_know[tobj->o_which] && s_guess[tobj->o_which])
+                    {
+                        free(s_guess[tobj->o_which]);
+                        s_guess[tobj->o_which] = NULL;
+                    }
+                    else if (!s_know[tobj->o_which]             && 
+                             askme                              &&
+                             (tobj->o_flags & ISKNOW) == 0      &&
+                             (tobj->o_flags & ISPOST) == 0      &&
+                             s_guess[tobj->o_which] == NULL) {
+                        nameitem(titem, FALSE);
+                    }
+                    o_discard(titem);
+                }
+                doit = FALSE;
+
+            otherwise:
+                wclear(hw);
+                touchwin(hw);
+                mvwaddstr(hw,0,0,"The following operations are available:");
+                mvwaddstr(hw,2,0,"[1]\tInventory\n");
+                wprintw(hw,"[2]\tPut something in the %s\n",
+                        m_magic[obj->o_which].mi_name);
+                wprintw(hw,"[3]\tTake something out of the %s\n",
+                        m_magic[obj->o_which].mi_name);
+                switch(obj->o_which) {
+                    case MM_BEAKER: waddstr(hw,"[4]\tQuaff a potion\n");
+                    when MM_BOOK:   waddstr(hw,"[4]\tRead a scroll\n");
+                }
+        /* this is confusing! <press space to continue> */
+                /* waddstr(hw,"[ESC]\tLeave this menu\n"); */
+                mvwaddstr(hw, lines-1, 0, spacemsg);
+                draw(hw);
+                wait_for (' ');
+                restscr(cw);
+        }
+    }
+}
+
+do_panic(who)
+int who;        /* Kind of monster to panic (all if who is NULL) */
+{
+    register int x,y;
+    register struct linked_list *mon, *item;
+    register struct thing *th;
+
+    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) {
+                    th = THINGPTR(mon);
+
+                    /* Is this the right kind of monster to panic? */
+                    if (who && th->t_index != who) continue;
+
+                    if ((who && th->t_stats.s_intel < 14) || 
+                        (!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0) &&
+              off(*th, WASTURNED))) {
+                          msg("%s %s.", prname(monster_name(th), TRUE),
+                            terse ? "panics" : "turns to run in panic");
+
+                        turn_on(*th, ISFLEE);
+                        turn_on(*th, WASTURNED);
+                        turn_off(*th, CANSURPRISE);
+
+                        /* Disrupt what it was doing */
+                        dsrpt_monster(th, TRUE, TRUE);
+
+                        /* If monster was suffocating, stop it */
+                        if (on(*th, DIDSUFFOCATE)) {
+                            turn_off(*th, DIDSUFFOCATE);
+                            extinguish(suffocate);
+                        }
+
+                        /* If monster held us, stop it */
+                        if (on(*th, DIDHOLD) && (--hold_count == 0))
+                                turn_off(player, ISHELD);
+                        turn_off(*th, DIDHOLD);
+
+                        /*
+                         * if he has something he might drop it
+                         */
+                        if ((item = th->t_pack) != NULL         && 
+                            (OBJPTR(item))->o_type != RELIC     && 
+                            rnd(100) < 67) {
+                                detach(th->t_pack, item);
+                                fall(item, FALSE);
+                        }
+
+                        /* It is okay to turn tail */
+                        th->t_oldpos = th->t_pos;
+                    }
+                    runto(th, &hero);
+                }
+            }
+        }
+    }
+}
+
+/*
+ * print miscellaneous magic bonuses
+ */
+
+int
+misc_name(str,obj)
+char *str;
+register struct object *obj;
+{
+    char buf1[LINELEN];
+
+    *str = 0;
+    buf1[0] = 0;
+
+    if (!(obj->o_flags & ISKNOW))
+    {
+        strcat(str,m_magic[obj->o_which].mi_name);
+        return(0);
+    }
+
+    switch (obj->o_which) 
+    {
+        case MM_BRACERS:
+        case MM_PROTECT:
+            strcat(str, num(obj->o_ac, 0));
+            strcat(str, " ");
+    }
+    switch (obj->o_which) {
+    case MM_CRYSTAL:
+            if (obj->o_flags & ISBLESSED)
+                strcat(str, "glowing ");
+    }
+    switch (obj->o_which) {
+        case MM_G_OGRE:
+        case MM_G_DEXTERITY:
+        case MM_JEWEL:
+        case MM_STRANGLE:
+        case MM_R_POWERLESS:
+        case MM_DANCE:
+            if (obj->o_flags & ISCURSED)
+                strcat(str, "cursed ");
+        when MM_CRYSTAL:
+            if (obj->o_flags & ISCURSED)
+                strcat(str, "opaque ");
+    }
+    strcat(str, m_magic[obj->o_which].mi_name);
+
+    switch (obj->o_which) 
+    {
+        case MM_JUG:
+            if (obj->o_ac == JUG_EMPTY)
+                strcat(buf1, " [empty]");
+            else if (p_know[obj->o_ac])
+                sprintf(buf1, " [containing a potion of %s (%s)]",
+                        p_magic[obj->o_ac].mi_name,
+                        p_colors[obj->o_ac]);
+            else sprintf(buf1, " [containing a%s %s liquid]", 
+                        vowelstr(p_colors[obj->o_ac]),
+                        p_colors[obj->o_ac]);
+        when MM_BEAKER:         
+        case MM_BOOK: {
+            sprintf(buf1, " [containing %d]", obj->o_ac);
+        }
+        when MM_OPEN:
+        case MM_HUNGER:
+            sprintf(buf1, " [%d ring%s]", obj->o_charges, 
+                          obj->o_charges == 1 ? "" : "s");
+        when MM_DRUMS:
+            sprintf(buf1, " [%d beat%s]", obj->o_charges, 
+                          obj->o_charges == 1 ? "" : "s");
+        when MM_DISAPPEAR:
+        case MM_CHOKE:
+            sprintf(buf1, " [%d pinch%s]", obj->o_charges, 
+                          obj->o_charges == 1 ? "" : "es");
+        when MM_KEOGHTOM:
+            sprintf(buf1, " [%d application%s]", obj->o_charges, 
+                          obj->o_charges == 1 ? "" : "s");
+        when MM_SKILLS:
+            sprintf(buf1, " [%s]", char_class[obj->o_ac].name);
+    }
+    strcat(str, buf1);
+    
+    return(0);
+}
+
+use_emori()
+{
+    char selection;     /* Cloak function */
+    int state = 0;      /* Menu state */
+
+    msg("What do you want to do? (* for a list): ");
+    do {
+        selection = wgetch(cw);
+        switch (selection) {
+            case '*':
+              if (state != 1) {
+                wclear(hw);
+                touchwin(hw);
+                mvwaddstr(hw, 2, 0,  "[1] Fly\n[2] Stop flying\n");
+                waddstr(hw,          "[3] Turn invisible\n[4] Turn Visible\n");
+                mvwaddstr(hw, 0, 0, "What do you want to do? ");
+                draw(hw);
+                state = 1;      /* Now in prompt window */
+              }
+              break;
+
+            case ESC:
+                if (state == 1) {
+                    restscr(cw);
+                }
+                msg("");
+
+                after = FALSE;
+                return;
+
+            when '1':
+            case '2':
+            case '3':
+            case '4':
+                if (state == 1) {       /* In prompt window */
+                    restscr(cw);
+                }
+
+                msg("");
+
+                state = 2;      /* Finished */
+                break;
+
+            default:
+                if (state == 1) {       /* In the prompt window */
+                    mvwaddstr(hw, 0, 0,
+                                "Please enter a selection between 1 and 4:  ");
+                    draw(hw);
+                }
+                else {  /* Normal window */
+                    mpos = 0;
+                    msg("Please enter a selection between 1 and 4:  ");
+                }
+        }
+    } while (state != 2);
+
+    /* We now must have a selection between 1 and 4 */
+    switch (selection) {
+        case '1':       /* Fly */
+            if (on(player, ISFLY)) {
+                extinguish(land);       /* Extinguish in case of potion */
+                msg("%slready flying.", terse ? "A" : "You are a");
+            }
+            else {
+                msg("You feel lighter than air!");
+                turn_on(player, ISFLY);
+            }
+        when '2':       /* Stop flying */
+            if (off(player, ISFLY))
+                msg("%sot flying.", terse ? "N" : "You are n");
+            else {
+                if (find_slot(land))
+                    msg("%sot flying by the cloak.",
+                        terse ? "N" : "You are n");
+                else land();
+            }
+        when '3':       /* Turn invisible */
+            if (off(player, ISINVIS)) {
+                turn_on(player, ISINVIS);
+                msg("You have a tingling feeling all over your body. ");
+                PLAYER = IPLAYER;
+                light(&hero);
+            }
+            else {
+                extinguish(appear);     /* Extinguish in case of potion */
+                extinguish(dust_appear);/* dust of disappearance        */
+                msg("%slready invisible.", terse ? "A" : "You are a");
+            }
+        when '4':       /* Turn visible */
+            if (off(player, ISINVIS))
+                msg("%sot invisible.", terse ? "N" : "You are n");
+            else {
+                if (find_slot(appear) || find_slot(dust_appear))
+                    msg("%sot invisible by the cloak.",
+                        terse ? "N" : "You are n");
+                else appear();
+            }
+    }
+}
+
+/*
+ * try to write a scroll with the quill of Nagrom
+ */
+
+use_quill(obj)
+struct object *obj;
+{
+    struct linked_list  *item;
+    register int        i,
+                        scroll_ability;
+    int                 which_scroll,
+                        curlen,
+                        maxlen = 0,
+                        dummy = 0;
+    bool                nohw = FALSE;
+
+    i = which_scroll = 0;
+    scroll_ability = obj->o_charges;
+
+    /* Prompt for scrolls */
+    msg("Which scroll are you writing? (* for list): ");
+
+    which_scroll = (int) (wgetch(cw) - 'a');
+    msg("");    /* Get rid of the prompt */
+    if (which_scroll == (int) ESC - (int) 'a') {
+        after = FALSE;
+        return;
+    }
+    if (which_scroll >= 0 && which_scroll < MAXQUILL) nohw = TRUE;
+
+    else if (slow_invent) {
+        register char c;
+
+        nohw = TRUE;
+        do {
+            for (i=0; i<MAXQUILL; i++) {
+                msg("");
+                mvwaddch(msgw, 0, 0, '[');
+                waddch(msgw, (char) ((int) 'a' + i));
+                waddstr(msgw, "] A scroll of ");
+                waddstr(msgw, s_magic[quill_scrolls[i].s_which].mi_name);
+                waddstr(msgw, morestr);
+                clearok(msgw, FALSE);
+                draw(msgw);
+                do {
+                    c = wgetch(cw);
+                } while (c != ' ' && c != ESC);
+                if (c == ESC)
+                    break;
+            }
+            msg("");
+            mvwaddstr(msgw, 0, 0, "Which scroll are you writing? ");
+            clearok(msgw, FALSE);
+            draw(msgw);
+
+            which_scroll = (int) (wgetch(cw) - 'a');
+        } while (which_scroll != (int) (ESC - 'a') &&
+                 (which_scroll < 0 || which_scroll >= MAXQUILL));
+
+        if (which_scroll == (int) (ESC - 'a')) {
+            mpos = 0;
+            msg("");
+            after = FALSE;
+            return;
+        }
+    }
+    else {
+        /* Now display the possible scrolls */
+        wclear(hw);
+        touchwin(hw);
+        mvwaddstr(hw, 2, 0, "   Cost            Scroll");
+        mvwaddstr(hw, 3, 0,
+                "-----------------------------------------------");
+        maxlen = 47;    /* Maximum width of header */
+
+        for (i=0; i<MAXQUILL; i++) {
+            wmove(hw, i+4, 0);
+            sprintf(prbuf, "[%c]        %3d     A scroll of %s",
+                    (char) ((int) 'a' + i),
+                    quill_scrolls[i].s_cost,
+                    s_magic[quill_scrolls[i].s_which].mi_name);
+            waddstr(hw, prbuf);
+
+            /* Get the length of the line */
+            getyx(hw, dummy, curlen);
+            if (maxlen < curlen) maxlen = curlen;
+        }
+
+        sprintf(prbuf, "[Current scroll power = %d]", scroll_ability);
+        mvwaddstr(hw, 0, 0, prbuf);
+        waddstr(hw, " Which scroll are you writing? ");
+        getyx(hw, dummy, curlen);
+        if (maxlen < curlen) maxlen = curlen;
+
+        /* Should we overlay? */
+        if (menu_overlay && MAXQUILL + 3 < lines - 3) {
+            over_win(cw, hw, MAXQUILL + 5, maxlen + 3, 0, curlen, NULL);
+        }
+        else draw(hw);
+    }
+
+    if (!nohw) {
+        which_scroll = (int) (wgetch(cw) - 'a');
+        while (which_scroll < 0 || which_scroll >= MAXQUILL) {
+            if (which_scroll == (int) ESC - (int) 'a') {
+                after = FALSE;
+
+                /* Restore the screen */
+                if (MAXQUILL + 3 < lines / 2) {
+                    clearok(cw, FALSE);
+                    touchwin(cw);
+                }
+                else restscr(cw);
+                return;
+            }
+            wmove(hw, 0, 0);
+            wclrtoeol(hw);
+            waddstr(hw, "Please enter one of the listed scrolls. ");
+            getyx(hw, dummy, curlen);
+            if (maxlen < curlen) maxlen = curlen;
+
+            /* Should we overlay? */
+            if (menu_overlay && MAXQUILL + 3 < lines - 3) {
+                over_win(cw, hw, MAXQUILL + 5, maxlen + 3,
+                            0, curlen, NULL);
+            }
+            else draw(hw);
+
+            which_scroll = (int) (wgetch(cw) - 'a');
+        }
+    }
+
+    /* Now restore the screen if we have to */
+    if (!nohw) {
+        if (MAXQUILL + 3 < lines / 2) {
+            touchwin(cw);
+            clearok(cw, FALSE);
+        }
+        else restscr(cw);
+    }
+
+    /* We've waited our required time. */
+    player.t_using = NULL;
+    player.t_action = A_NIL;
+
+    if (quill_scrolls[which_scroll].s_cost > scroll_ability) {
+        msg("Your attempt fails.");
+        return;
+    }
+
+    obj->o_charges -= quill_scrolls[which_scroll].s_cost;
+    item = spec_item(SCROLL, quill_scrolls[which_scroll].s_which, 0, 0);
+    if (add_pack(item, FALSE) == FALSE) {
+        (OBJPTR(item))->o_pos = hero;
+        fall(item, TRUE);
+    }
+
+    which_scroll = dummy; /* Hack to stop IRIX complaint about dummy not */
+                          /* being used */
+}
+
+/*
+ * Use something
+ */
+
+use_mm(which)
+int which;
+{
+    register struct object *obj = NULL;
+    register struct linked_list *item = NULL;
+    bool is_mm;
+
+    is_mm = FALSE;
+
+    if (which < 0) {    /* A real miscellaneous magic item  */
+        /* This is miscellaneous magic.  It takes 3 movement periods to use */
+        if (player.t_action != C_USE) {
+            int units;  /* Number of movement units for the item */
+
+            item = get_item(pack, "use", USEABLE, FALSE, FALSE);
+
+            /*
+             * Make certain that it is a micellaneous magic item
+             */
+            if (item == NULL)
+                return;
+
+            units = usage_time(item);
+            if (units < 0) return;
+
+            player.t_using = item;      /* Remember what it is */
+            player.t_action = C_USE;    /* We are quaffing */
+            player.t_no_move = units * movement(&player);
+            return;
+        }
+
+        /* We have waited our time, let's use the item */
+        item = player.t_using;
+        player.t_using = NULL;
+        player.t_action = A_NIL;
+
+        is_mm = TRUE;
+
+        obj = OBJPTR(item);
+        which = obj->o_which;
+    }
+
+    if (obj->o_type == POTION) {                /* A potion */
+        is_mm = FALSE;
+        inpack--;
+        detach (pack, item);
+        switch (obj->o_which) {
+            case P_POISON:
+                if (cur_weapon) {
+                    if (cur_weapon->o_type == RELIC) {
+                        msg("The poison burns off %s", 
+                            inv_name(cur_weapon,FALSE));
+                    }
+                    else {
+                        cur_weapon->o_flags |= ISPOISON;
+                        msg("Your weapon has %s gooey stuff on it",
+                            p_colors[cur_weapon->o_which]);
+                    }
+                }
+                else 
+                    msg("The poison pours on the floor and disappears!");
+        }
+        o_discard(item);
+    }
+    else if (obj->o_type == RELIC) {            /* An artifact */
+        is_mm = FALSE;
+        switch (obj->o_which) {
+            case EMORI_CLOAK:
+                use_emori();
+            when QUILL_NAGROM:
+                use_quill(obj);
+            when BRIAN_MANDOLIN:
+                /* Put monsters around us to sleep */
+                read_scroll(S_HOLD, 0, FALSE);
+            when GERYON_HORN:
+                /* Chase close monsters away */
+                msg("The horn blasts a shrill tone.");
+                do_panic(NULL);
+            when EYE_VECNA:
+                msg("The pain slowly subsides.. ");
+            when HEIL_ANKH:
+                msg("Your hand grows very warm. ");
+            when YENDOR_AMULET:
+                msg("Your chest glows! ");
+                do_panic(findmindex("frost giant"));
+            when STONEBONES_AMULET:
+                msg("Your chest glows! ");
+                do_panic(findmindex("storm giant"));
+            when SURTUR_RING:
+                do_panic(findmindex("fire giant"));
+            when ALTERAN_CARD:  /* the card allows you to teleport anywhere */
+        do_teleport();
+        }
+    }
+    else switch (which) {               /* Miscellaneous Magic */
+        /*
+         * the jug of alchemy manufactures potions when you drink
+         * the potion it will make another after a while
+         */
+        case MM_JUG:
+            if (obj->o_ac == JUG_EMPTY) {
+                msg("The jug is empty");
+                break;
+            }
+            quaff (obj->o_ac, NULL, NULL, FALSE);
+            obj->o_ac = JUG_EMPTY;
+            fuse (alchemy, obj, ALCHEMYTIME, AFTER);
+            if (!(obj->o_flags & ISKNOW))
+                whatis(item);
+
+        /*
+         * the beaker of plentiful potions is used to hold potions
+         * the book of infinite spells is used to hold scrolls
+         */
+        when MM_BEAKER:
+        case MM_BOOK:
+            do_bag(item);
+
+        /*
+         * the chime of opening opens up secret doors
+         */
+        when MM_OPEN:
+        {
+            register struct linked_list *exit;
+            register struct room *rp;
+            register coord *cp;
+
+            if (obj->o_charges <= 0) {
+                msg("The chime is cracked!");
+                break;
+            }
+            obj->o_charges--;
+            msg("chime... chime... hime... ime... me... e...");
+            if ((rp = roomin(&hero)) == NULL) {
+                search(FALSE, TRUE); /* Non-failing search for door */
+                break;
+            }
+            for (exit = rp->r_exit; exit != NULL; exit = next(exit)) {
+                cp = DOORPTR(exit);
+                if (winat(cp->y, cp->x) == SECRETDOOR) {
+                    mvaddch (cp->y, cp->x, DOOR);
+                    if (cansee (cp->y, cp->x))
+                        mvwaddch(cw, cp->y, cp->x, DOOR);
+                }
+            }
+        }
+
+        /*
+         * the chime of hunger just makes the hero hungry
+         */
+        when MM_HUNGER:
+            if (obj->o_charges <= 0) {
+                msg("The chime is spent. ");
+                break;
+            }
+            obj->o_charges--;
+            if (food_left >= MORETIME + 5) {
+                food_left = MORETIME + 5;
+                msg("A strange sensation comes over you.. ");
+                msg(terse? "Getting hungry" : "You are starting to get hungry");
+                hungry_state = F_HUNGRY;
+            }
+            if (player.t_ctype == C_PALADIN ||
+                player.t_ctype == C_RANGER  || player.t_ctype == C_MONK) {
+                    msg("You feel a chilling sensation!");
+                    aggravate(TRUE, FALSE);
+            }
+            else {
+                aggravate(TRUE, TRUE);
+            }
+
+        /*
+         * the drums of panic make all creatures within two squares run
+         * from the hero in panic unless they save or they are mindless
+         * undead
+         */
+        when MM_DRUMS:
+            if (obj->o_charges <= 0) {
+                msg("The drum is broken.");
+                break;
+            }
+            obj->o_charges--;
+            do_panic(NULL);
+        return;
+        /*
+         * dust of disappearance makes the player invisible for a while
+         */
+        when MM_DISAPPEAR:
+            m_know[MM_DISAPPEAR] = TRUE;
+            if (obj->o_charges <= 0) {
+                msg("No more dust!");
+                break;
+            }
+            obj->o_charges--;
+            if (terse) msg("You sneeze! ");
+            else msg("Ahh.. Ahh... Choo!! ");
+            if (!find_slot(dust_appear)) {
+                turn_on(player, ISINVIS);
+                fuse(dust_appear, (VOID *)NULL, DUSTTIME, AFTER);
+                PLAYER = IPLAYER;
+                light(&hero);
+            }
+            else lengthen(dust_appear, DUSTTIME);
+
+        /*
+         * dust of choking and sneezing can kill the hero if he misses
+         * the save
+         */
+        when MM_CHOKE:
+            m_know[MM_CHOKE] = TRUE;
+            if (obj->o_charges <= 0) {
+                msg("No more dust!");
+                break;
+            }
+            obj->o_charges--;
+            if (terse) msg("You snort! ");
+            else msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze.");
+            if (!cur_relic[SURTUR_RING] && !save(VS_POISON, &player, 0)) {
+                msg ("You choke to death!!!  --More--");
+                wait_for(' ');
+                pstats.s_hpt = -1;  /* in case he hangs up the phone! */
+                death(D_CHOKE);
+            }
+            else {
+                msg("You begin to cough and choke uncontrollably! ");
+                if (find_slot(unchoke))
+                    lengthen(unchoke, DUSTTIME);
+                else
+                    fuse(unchoke, (VOID *)NULL, DUSTTIME, AFTER);
+                turn_on(player, ISHUH);
+                turn_on(player, ISBLIND);
+                light(&hero);
+            }
+                
+        when MM_KEOGHTOM:
+            /*
+             * this is a very powerful healing ointment
+             * but it takes a while to put on...
+             */
+            obj->o_charges--;
+            if (on(player, HASDISEASE)) {
+                extinguish(cure_disease);
+                cure_disease();
+                msg(terse ? "You feel yourself improving."
+                          : "You begin to feel yourself improving again.");
+            }
+            if (on(player, HASINFEST)) {
+                turn_off(player, HASINFEST);
+                infest_dam = 0;
+                msg(terse ? "You feel yourself improving."
+                          : "You begin to feel yourself improving again.");
+            }
+            if (on(player, DOROT)) {
+                msg("You feel your skin returning to normal.");
+                turn_off(player, DOROT);
+            }
+            pstats.s_hpt += roll(pstats.s_lvl, 6);
+            if (pstats.s_hpt > max_stats.s_hpt)
+                pstats.s_hpt = max_stats.s_hpt;
+            sight();
+            msg("You begin to feel much better.");
+                
+        /*
+         * The book has a character class associated with it.
+         * if your class matches that of the book, it will raise your 
+         * level by one. If your class does not match the one of the book, 
+         * it change your class to that of book.
+         * Note that it takes a while to read.
+         */
+        when MM_SKILLS:
+            detach (pack, item);
+            inpack--;
+            changeclass(&obj->o_ac);
+    when MM_CRYSTAL:
+    {
+        register char *str;
+
+            detach (pack, item);
+            inpack--;
+            if (obj->o_flags & ISCURSED) {
+            if (is_mm && !m_know[MM_CRYSTAL])
+                str = "rock in a curious sort of way";
+        else
+            str = "crystal briefly";
+        msg("You rub the %s and yell out in agony! ", str);
+          /* curse his pack */
+        read_scroll(S_REMOVE, obj->o_flags & ISCURSED, FALSE);
+          /* aggravate monsters */
+        read_scroll(S_HOLD, obj->o_flags & ISCURSED, FALSE);
+                player.t_no_move += (2 * movement(&player) * FREEZETIME);
+                player.t_action = A_FREEZE;
+          /* loss of 1/4 total hit points */
+        pstats.s_hpt -= ((max_stats.s_hpt / 4));
+                max_stats.s_hpt -= rnd(3)+3;
+        if (pstats.s_hpt > max_stats.s_hpt) 
+                pstats.s_hpt = max_stats.s_hpt;
+                if ((pstats.s_hpt < 1) || (max_stats.s_hpt < 1)) {
+            pstats.s_hpt = -1;
+            msg("The crystal has absorbed you...  --More--");
+            wait_for(' ');
+                    death(D_CRYSTAL);
+        }
+        }
+        else {  /* if normal, give him a bonus */
+            if (is_mm && !m_know[MM_CRYSTAL])
+                    str = "flashes brightly";
+        else
+            str = "vibrates softly";
+        msg("You rub the crystal and it %s...  ", str);
+          /* cure him */
+        read_scroll(S_CURING, NULL, FALSE);
+          /* give him weird hands */
+                turn_on(player, CANHUH);
+        msg("Your fingertips turn blue.  ");
+          /* add intelligence */
+                if (player.t_ctype == C_MAGICIAN) {
+                max_stats.s_intel += 1;
+                pstats.s_intel += 1;
+        }
+          /* add strength */
+                if (player.t_ctype == C_FIGHTER) {
+            max_stats.s_str += 1;
+                pstats.s_str += 1;
+        }
+          /* add wisdom */
+                if (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) {
+                    max_stats.s_wisdom += 1;
+                    pstats.s_wisdom += 1;
+        }
+          /* add dexterity */
+                if (player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) {
+                    max_stats.s_dext += 1;
+                    pstats.s_dext += 1;
+        }
+              /* add constitution */
+                if (player.t_ctype == C_MONK) {
+                    max_stats.s_const += 1;
+                    pstats.s_const += 1;
+        }
+          /* add charisma */
+                if (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN) {
+                max_stats.s_charisma += 1;
+                pstats.s_charisma += 1;
+        }
+        }
+            if (obj->o_flags & ISBLESSED) {  /* if blessed */
+            if (is_mm && !m_know[MM_CRYSTAL])
+            msg("The crystal disappears from your hands.  ");
+        else
+            msg("Your hands absorb the medicine crystal.  ");
+            /* set hit points to at least 50 */
+        if (max_stats.s_hpt < 50) {
+            max_stats.s_hpt = 50;
+                    pstats.s_hpt = max_stats.s_hpt;
+        }
+        else {  /* or just add 10% */
+            max_stats.s_hpt += (max_stats.s_hpt / 10);
+                    pstats.s_hpt = max_stats.s_hpt;
+        }
+            /* heck, really make it memorable */
+        read_scroll(S_REMOVE, obj->o_flags & ISBLESSED, FALSE);
+        }
+    }
+        otherwise:
+            msg("What a strange magic item you have!");
+    }
+    status(FALSE);
+    if (is_mm && m_know[which] && m_guess[which]) {
+        free(m_guess[which]);
+        m_guess[which] = NULL;
+    }
+    else if (is_mm && !m_know[which] && askme &&
+             (obj->o_flags & ISKNOW) == 0 &&
+             m_guess[which] == NULL) {
+        nameitem(item, FALSE);
+    }
+    if (item != NULL && (which == MM_SKILLS || which == MM_CRYSTAL))
+        o_discard(item);
+    updpack(TRUE, &player);
+}
+
+/*
+ * usage_time:
+ *      Return how long it takes to use an item.  For now we only give time
+ *      for MM, RELIC, SCROLL, and POTION items.
+ */
+
+int
+usage_time(item)
+struct linked_list *item;
+{
+    register struct object *obj;
+    register int units = -1;
+
+    obj = OBJPTR(item);
+    switch (obj->o_type) {
+        case SCROLL:    units = 4;
+        when POTION:    units = 3;
+        when RELIC:                     /* An artifact */
+            switch (obj->o_which) {
+                case BRIAN_MANDOLIN:
+                case GERYON_HORN:       units = 4;
+                when QUILL_NAGROM:
+                case EMORI_CLOAK:
+                case HEIL_ANKH:         units = 3;
+                when YENDOR_AMULET:
+                case STONEBONES_AMULET: units = 2;
+                when EYE_VECNA:         units = 6;
+                    /* The eye will do nothing other than give a headache */
+                    pstats.s_hpt -= rnd(25)+1;
+                    msg("You feel a sharp pain shoot through your forehead!");
+                    if (pstats.s_hpt < 1) {
+               pstats.s_hpt = -1;
+                       msg ("The pain is too much for you to bear!  --More--");
+                       wait_for(' ');
+                       death(D_RELIC);
+                    }
+                when SURTUR_RING:
+                    units = 3;
+                    msg("Your nose tickles a bit.");
+        when ALTERAN_CARD:
+            units = 2;
+            msg("You gaze intently at the card... ");
+            }
+        when MM:
+            switch (obj->o_which) {     /* Miscellaneous Magic */
+                case MM_JUG:
+                    if (obj->o_ac == JUG_EMPTY) {
+                        msg("The jug is empty");
+                        return (-1);
+                    }
+                    units = 2;
+                when MM_BEAKER:
+                case MM_BOOK:
+                    /* This is a strange case because it can go forever */
+                    units = 1;
+                case MM_CHOKE: /* Dust */
+                when MM_HUNGER: /* Chimes */
+                    units = 3;
+                when MM_OPEN:
+                case MM_DRUMS:
+                case MM_DISAPPEAR:
+                    units = 4;
+                when MM_KEOGHTOM:
+            /* Ointment */
+                    if (obj->o_charges <= 0) {
+                        msg("The jar is empty!");
+                        return (-1);
+                    }
+                    units = 5;
+                when MM_SKILLS:
+                    /* A whole book! */
+                    units = 15;
+                when MM_CRYSTAL:
+            /* Enhance player's quest */
+            units = 5;
+                otherwise:
+                    /* What is it? */
+                    units = -1;
+            }
+        otherwise:      units = -1;
+    }
+
+    return (units);
+}
+