view urogue/misc.c @ 304:e52a8a7ad4c5

Fix many compiler warnings. There should only be two changes in behavior: arogue7/fight.c, arogue7/fight.c: a to-hit bonus is now correctly applied to characters who are not monks instead of monks who are not empty-handed. urogue/fight.c: fixed an interaction with the "debug" macro that could cause the wrong message to be displayed.
author John "Elwin" Edwards
date Wed, 14 Apr 2021 18:55:33 -0400
parents c495a4f288c6
children
line wrap: on
line source

/*
    misc.c - all sorts of miscellaneous routines
  
    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"

/*
    tr_name()
        print the name of a trap
*/

char *
tr_name(char ch, char *trname)
{
    const char *s = NULL;

    if (trname == NULL)
        return(" Your found an error in UltraRogue #100.");

    switch(ch)
    {
        case TRAPDOOR:
            s = "trapdoor.";
            break;
        case BEARTRAP:
            s = "beartrap.";
            break;
        case SLEEPTRAP:
            s = "sleeping gas trap.";
            break;
        case ARROWTRAP:
            s = "arrow trap.";
            break;
        case TELTRAP:
            s = "teleport trap.";
            break;
        case DARTTRAP:
            s = "dart trap.";
            break;
        case POOL:
            s = "shimmering pool.";
            break;
        case MAZETRAP:
            s = "maze entrance.";
            break;
        case FIRETRAP:
            s = "fire trap.";
            break;
        case POISONTRAP:
            s = "poison pool trap.";
            break;
        case LAIR:
            s = "monster lair.";
            break;
        case RUSTTRAP:
            s = "rust trap.";
            break;
        default:
            ;
    }

    sprintf(trname, "You found a %s.", s);

    return(trname);
}

/*
    look()
        A quick glance all around the player
*/

void
look(int wakeup)
{
    int     x, y;
    char   ch, och;
    int  oldx, oldy;
    int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE;
    int passcount = 0;
    struct room *rp;
    int ey, ex;

    /* Are we moving vertically or horizontally? */

    if (runch == 'h' || runch == 'l')
        horizontal = TRUE;
    else
        horizontal = FALSE;

    if (runch == 'j' || runch == 'k')
        vertical = TRUE;
    else
        vertical = FALSE;

    getyx(cw, oldy, oldx);  /* Save current position */

    /*
     * Blank out the floor around our last position and check for moving
     * out of a corridor in a maze.
    */

    if (oldrp != NULL && (oldrp->r_flags & ISDARK) &&
        !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND))
        do_blank = TRUE;

    for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++)
        for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1;
                y++)
        {
            ch = show(y, x);

            if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR)
                mvwaddch(cw, y, x, ' ');

            /* Moving out of a corridor? */

            if (levtype == MAZELEV &&
                (ch != '|' && ch != '-') && /* Not a wall */
                ((vertical && x != player.t_oldpos.x &&
                y == player.t_oldpos.y) ||
                 (horizontal && y != player.t_oldpos.y &&
                x == player.t_oldpos.x)))
                do_light = TRUE;    /* Just came to a turn */
        }

    inpass = ((rp = roomin(hero)) == NULL);    /* Are we in a passage? */

    /* Are we coming out of a wall into a corridor in a maze? */
    och = show(player.t_oldpos.y, player.t_oldpos.x);
    ch = show(hero.y, hero.x);

    if (levtype == MAZELEV && (och == '|' || och == '-' ||
        och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR))
    {
        do_light = off(player, ISBLIND);    /* Light it up if not blind */
    }

    /* Look around the player */

    ey = hero.y + 1;
    ex = hero.x + 1;

    for (x = hero.x - 1; x <= ex; x++)
        if (x >= 0 && x < COLS)
            for (y = hero.y - 1; y <= ey; y++)
            {
                if (y <= 0 || y >= LINES - 2)
                    continue;

                if (isalpha(mvwinch(mw, y, x)))
                {
                    struct linked_list  *it;
                    struct thing    *tp;

                    if (wakeup)
                        it = wake_monster(y, x);
                    else
                        it = find_mons(y, x);

                    if (it == NULL)
                        continue;

                    tp = THINGPTR(it);
                    tp->t_oldch = CCHAR( mvinch(y, x) );

                    if (isatrap(tp->t_oldch))
                    {
                        struct trap *trp = trap_at(y, x);

                        tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
                            : trp->tr_show;
                    }

                    if (tp->t_oldch == FLOOR &&
                        (rp->r_flags & ISDARK)
                        && !(rp->r_flags & HASFIRE) &&
                        off(player, ISBLIND))
                        tp->t_oldch = ' ';
                }

                /* Secret doors show as walls */

                if ((ch = show(y, x)) == SECRETDOOR)
                    ch = secretdoor(y, x);

                /*
                 * Don't show room walls if he is in a
                 * passage and check for maze turns
                */

                if (off(player, ISBLIND))
                {
                    if ((y == hero.y && x == hero.x) || (inpass && (ch == '-' ||
                        ch == '|')))
                        continue;

                    /* Are we at a crossroads in a maze? */

                    if (levtype == MAZELEV && (ch != '|' && ch != '-') &&
                        /* Not a wall */
                        ((vertical && x != hero.x && y == hero.y) ||
                         (horizontal && y != hero.y && x == hero.x)))
                        do_light = TRUE;
                        /* Just came to a turn */
                }
                else if (y != hero.y || x != hero.x)
                    continue;

                wmove(cw, y, x);
                waddch(cw, ch);

                if (door_stop && !firstmove && running)
                {
                    switch (runch)
                    {
                        case 'h':
                            if (x == ex)
                                continue;
                            break;
                        case 'j':
                            if (y == hero.y - 1)
                                continue;
                            break;
                        case 'k':
                            if (y == ey)
                                continue;
                            break;
                        case 'l':
                            if (x == hero.x - 1)
                                continue;
                            break;
                        case 'y':
                            if ((x + y) - (hero.x + hero.y) >= 1)
                                continue;
                            break;
                        case 'u':
                            if ((y - x) - (hero.y - hero.x) >= 1)
                                continue;
                            break;
                        case 'n':
                            if ((x + y) - (hero.x + hero.y) <= -1)
                                continue;
                            break;
                        case 'b':
                            if ((y - x) - (hero.y - hero.x) <= -1)
                                continue;
                            break;
                    }

                    switch (ch)
                    {
                        case DOOR:
                            if (x == hero.x || y == hero.y)
                                running = FALSE;
                            break;
                        case PASSAGE:
                            if (x == hero.x || y == hero.y)
                                passcount++;
                            break;
                        case FLOOR:

                        /*
                         * Stop by new passages in a
                         * maze (floor next to us)
                         */
                            if ((levtype == MAZELEV) &&
                                ((horizontal && x == hero.x && y != hero.y) ||
                                (vertical &&   y == hero.y && x != hero.x)))
                                running = FALSE;

                        case '|':
                        case '-':
                        case ' ':
                            break;

                        default:
                            running = FALSE;
                            break;
                    }
                }
            }

    if (door_stop && !firstmove && passcount > 1)
        running = FALSE;

    /*
     * Do we have to light up the area (just stepped into a new
     * corridor)?
     */

    if (do_light && wakeup &&   /* wakeup will be true on a normal move */
        !(rp->r_flags & ISDARK) &&  /* We have some light */
        !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */
        light(&hero);

    mvwaddch(cw, hero.y, hero.x, PLAYER);
    wmove(cw, oldy, oldx);

    if (wakeup)
    {
        player.t_oldpos = hero; /* Don't change if we didn't move */
        oldrp = rp;
    }
}

/*
    secret_door()
        Figure out what a secret door looks like.
*/

char
secretdoor(int y, int x)
{
    struct room *rp;
    coord cp;

    cp.x = x;
    cp.y = y;

    if ((rp = roomin(cp)) != NULL)
    {
        if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
            return ('-');
        else
            return ('|');
    }
    return ('p');
}

/*
    find_obj()
        find the unclaimed object at y, x
*/

struct linked_list  *
find_obj(int y, int x)
{
    struct linked_list  *obj, *sobj;
    struct object   *op;

    sobj = lvl_obj;

    for (obj = sobj; obj != NULL; obj = next(obj))
    {
        op = OBJPTR(obj);

        if (op && op->o_pos.y == y && op->o_pos.x == x)
            return(obj);
    }

    return(NULL);
}

/*
    eat()
        He wants to eat something, so let him try
*/

void
eat(void)
{
    struct object   *obj;
    int amount;
    float scale = (float) (LINES * COLS) / (25.0F * 80.0F);

    if ((obj = get_object(pack, "eat", FOOD, NULL)) == NULL)
        return;

    switch (obj->o_which)
    {
        case FD_RATION:
            amount = (int)(scale * (HUNGERTIME + rnd(400) - 200));

            if (rnd(100) > 70)
            {
                msg("Yuk, this food tastes awful.");
                pstats.s_exp++;
                check_level();
            }
            else
                msg("Yum, that tasted good.");
            break;

        case FD_FRUIT:
            amount = (int)(scale * (200 + rnd(HUNGERTIME)));
            msg("My, that was a yummy %s.", fruit);
            break;

        case FD_CRAM:
            amount = (int)(scale * (rnd(HUNGERTIME / 2) + 600));
            msg("The cram tastes dry in your mouth.");
            break;

        case FD_CAKES:
            amount = (int)(scale * ((HUNGERTIME / 3) + rnd(600)));
            msg("Yum, the honey cakes tasted good.");
            break;

        case FD_LEMBA:
            amount = (int)(scale * ((HUNGERTIME / 2) + rnd(900)));
            quaff(&player, P_HEALING, ISNORMAL);
            break;

        case FD_MIRUVOR:
            amount = (int)(scale * ((HUNGERTIME / 3) + rnd(500)));
            quaff(&player, P_HEALING, ISNORMAL);
            quaff(&player, P_RESTORE, ISNORMAL);
            break;

        default:
            msg("What a strange thing to eat!");
            amount = (int)(scale * HUNGERTIME);
    }
    
    food_left += amount;

    if (obj->o_flags & ISBLESSED)
    {
        food_left += 2 * amount;
        msg("You have a tingling feeling in your mouth.");
    }
    else if (food_left > scale * STOMACHSIZE)
    {
        food_left = (int)(scale * STOMACHSIZE);
        msg("You feel satiated and too full to move.");
        no_command = HOLDTIME;
    }

    hungry_state = F_OK;
    updpack();

    if (obj == cur_weapon)
        cur_weapon = NULL;

    if (--obj->o_count <= 0) /* Remove this pack entry if last of food */
        discard_pack(obj);
}

/*
 * Used to modify the player's strength it keeps track of the highest it has
 * been, just in case
 */

void
chg_str(int amt, int both, int lost)
{
    int           ring_str; /* ring strengths */
    struct stats *ptr;      /* for speed */

    ptr = &pstats;

    ring_str = ring_value(R_ADDSTR) + (on(player, POWERSTR) ? 10 : 0) +
        (on(player, SUPERHERO) ? 10 : 0);

    ptr->s_str -= ring_str;
    ptr->s_str += amt;

    if (ptr->s_str < 3)
    {
        ptr->s_str = 3;
        lost = FALSE;
    }
    else if (ptr->s_str > 25)
        ptr->s_str = 25;

    if (both)
        max_stats.s_str = ptr->s_str;

    if (lost)
        lost_str -= amt;

    ptr->s_str += ring_str;

    if (ptr->s_str < 0)
        ptr->s_str = 0;

    updpack();
}

/*
 * Used to modify the player's dexterity it keeps track of the highest it has
 * been, just in case
 */

void
chg_dext(int amt, int both, int lost)
{
    int ring_dext;      /* ring strengths   */
    struct stats *ptr;  /* for speed        */

    ptr = &pstats;

    ring_dext = ring_value(R_ADDHIT) + (on(player, POWERDEXT) ? 10 : 0) +
        (on(player, SUPERHERO) ? 5 : 0);

    ptr->s_dext -= ring_dext;
    ptr->s_dext += amt;

    if (ptr->s_dext < 3)
    {
        ptr->s_dext = 3;
        lost = FALSE;
    }
    else if (ptr->s_dext > 25)
        ptr->s_dext = 25;

    if (both)
        max_stats.s_dext = ptr->s_dext;

    if (lost)
        lost_dext -= amt;

    ptr->s_dext += ring_dext;

    if (ptr->s_dext < 0)
        ptr->s_dext = 0;
}

/*
    add_haste()
        add a haste to the player
*/

void
add_haste(int blessed)
{
    short   hasttime;

    if (blessed)
        hasttime = 10;
    else
        hasttime = 6;

    if (on(player, ISSLOW))    /* Is person slow? */
    {
        extinguish_fuse(FUSE_NOSLOW);
        noslow(NULL);

        if (blessed)
            hasttime = 4;
        else
            return;
    }

    if (on(player, ISHASTE))
    {
        msg("You faint from exhaustion.");
        no_command += rnd(hasttime);
        lengthen_fuse(FUSE_NOHASTE, rnd(hasttime) + (roll(1, 4) * hasttime));
    }
    else
    {
        turn_on(player, ISHASTE);
        light_fuse(FUSE_NOHASTE, 0, roll(hasttime, hasttime), AFTER);
    }
}

/*
    aggravate()
        aggravate all the monsters on this level
*/

void
aggravate(void)
{
    struct linked_list *mi;
    struct thing *tp;

    for (mi = mlist; mi != NULL; mi = next(mi))
    {
        tp = THINGPTR(mi);
        chase_it(&tp->t_pos, &player);
    }
}

/*
    vowelstr()
        for printfs: if string starts with a vowel, return "n" for an "an"
*/

char *
vowelstr(char *str)
{
    switch (*str)
    {
        case 'a':
        case 'A':
        case 'e':
        case 'E':
        case 'i':
        case 'I':
        case 'o':
        case 'O':
        case 'u':
        case 'U':
            return "n";
        default:
            return "";
    }
}

/*
    is_object()
        see if the object is one of the currently used items
*/

int
is_current(struct object *obj)
{
    if (obj == NULL)
        return FALSE;

    if (obj == cur_armor || obj == cur_weapon ||
        obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
        obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
        obj == cur_ring[LEFT_5] ||
        obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
        obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
        obj == cur_ring[RIGHT_5]) {
        msg("That's already in use.");
        return TRUE;
    }

    return FALSE;
}

/*
    get_dir()
        set up the direction co_ordinate for use in varios "prefix" commands
*/

int
get_dir(void)
{
    char *prompt;
    int   gotit;

    prompt = "Which direction? ";
    msg(prompt);

    do
    {
        gotit = TRUE;

        switch (readchar())
        {
            case 'h':
            case 'H':
                delta.y = 0;
                delta.x = -1;
                break;

            case 'j':
            case 'J':
                delta.y = 1;
                delta.x = 0;
                break;

            case 'k':
            case 'K':
                delta.y = -1;
                delta.x = 0;
                break;

            case 'l':
            case 'L':
                delta.y = 0;
                delta.x = 1;
                break;

            case 'y':
            case 'Y':
                delta.y = -1;
                delta.x = -1;
                break;

            case 'u':
            case 'U':
                delta.y = -1;
                delta.x = 1;
                break;
				
            case 'b':
            case 'B':
                delta.y = 1;
                delta.x = -1;
                break;
				
            case 'n':
            case 'N':
                delta.y = 1;
                delta.x = 1;
                break;
				
            case  ESCAPE:
                return FALSE;

            default:
                mpos = 0;
                msg(prompt);
                gotit = FALSE;
        }
    }
    while(!gotit);

    if (on(player, ISHUH) && rnd(100) > 80)
        do
        {
            delta.y = rnd(3) - 1;
            delta.x = rnd(3) - 1;
        }
        while (delta.y == 0 && delta.x == 0);

    mpos = 0;

    return(TRUE);
}

/*
    is_wearing()
        is the hero wearing a particular ring
*/

int
is_wearing(int type)
{
#define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)

    return(
        ISRING(LEFT_1,  type) || ISRING(LEFT_2, type) ||
        ISRING(LEFT_3,  type) || ISRING(LEFT_4, type) ||
        ISRING(LEFT_5,  type) ||
        ISRING(RIGHT_1, type) || ISRING(RIGHT_2, type) ||
        ISRING(RIGHT_3, type) || ISRING(RIGHT_4, type) ||
        ISRING(RIGHT_5, type)  );
}

/*
    maze_view()
        Returns true if the player can see the specified location
        within the confines of a maze (within one column or row)
*/

int
maze_view(int y, int x)
{
    int start, goal, delt, ycheck = 0, xcheck = 0, absy, absx;
    int row;

    /* Get the absolute value of y and x differences */

    absy = hero.y - y;
    absx = hero.x - x;

    if (absy < 0)
        absy = -absy;

    if (absx < 0)
        absx = -absx;

    /* Must be within one row or column */

    if (absy > 1 && absx > 1)
        return(FALSE);

    if (absy <= 1)      /* Go along row */
    {
        start = hero.x;
        goal = x;
        row = TRUE;
        ycheck = hero.y;
    }
    else            /* Go along column */
    {
        start = hero.y;
        goal = y;
        row = FALSE;
        xcheck = hero.x;
    }

    if (start <= goal)
        delt = 1;
    else
        delt = -1;

    while (start != goal)
    {
        if (row)
            xcheck = start;
        else
            ycheck = start;

        switch(CCHAR(winat(ycheck, xcheck)))
        {
            case '|':
            case '-':
            case WALL:
            case DOOR:
            case SECRETDOOR:
                return(FALSE);

            default:
                break;
        }
        start += delt;
    }

    return(TRUE);
}

/*
    listen()
        listen for monsters less than 5 units away
*/

void
listen(void)
{
    struct linked_list  *item;
    struct thing    *tp;
    int thief_bonus = -50;
    int mcount = 0;

    if (player.t_ctype == C_THIEF)
        thief_bonus = 10;

    for (item = mlist; item != NULL; item = next(item))
    {
        tp = THINGPTR(item);

        if (DISTANCE(hero, tp->t_pos) < 81
            && rnd(70) < (thief_bonus + 4 * pstats.s_dext +
            6 * pstats.s_lvl))
        {
            msg("You hear a%s %s nearby.",
                vowelstr(monsters[tp->t_index].m_name),
                monsters[tp->t_index].m_name);
            mcount++;
        }
    }

    if (mcount == 0)
        msg("You hear nothing.");
}

/*
 * nothing_message - print out "Nothing <adverb> happens."
 */

static const char *nothings[] =
{
    "",
    "unusual ",
    "seems to ",
    "at all ",
    "really ",
    "noticeable ",
    "different ",
    "strange ",
    "wierd ",
    "bizzare ",
    "wonky ",
    ""
};

void
nothing_message(int flags)
{
    int adverb = rnd(sizeof(nothings) / sizeof(char *));

    NOOP(flags);   

    msg("Nothing %shappens.", nothings[adverb]);
}

/*
    feel_message()
        print out "You feel <description>."
*/

void
feel_message(void)
{
    char *charp;

    switch (rnd(25))
    {
        case 1:  charp = "bad";      break;
        case 2:  charp = "hurt";     break;
        case 3:  charp = "sick";     break;
        case 4:  charp = "faint";    break;
        case 5:  charp = "yucky";    break;
        case 6:  charp = "wonky";    break;
        case 7:  charp = "wierd";    break;
        case 8:  charp = "queasy";   break;
        case 9:  charp = "wounded";  break;
        case 11: charp = "unusual";  break;
        case 12: charp = "no pain";  break;
        case 13: charp = "strange";  break;
        case 14: charp = "noticable"; break;
        case 15: charp = "bizzare";   break;
        case 16: charp = "distressed";break;
        case 17: charp = "different"; break;
        case 18: charp = "a touch of ague"; break;
        case 19: charp = "a migrane coming on"; break;
        case 20: charp = "Excedrin headache #666"; break;
        case 21: charp = "a disturbance in the force"; break;
        case 22: charp = "like someone dropped a house on you"; break;
        case 23: charp = "as if every nerve in your body is on fire"; break;
        case 24: charp = "like thousands of red-hot army ants are crawling under your skin";
                    break;

        default:
            charp = "ill";
            break;
    }
    msg("You feel %s.", charp);
}

/*
    const_bonus()
        Hit point adjustment for changing levels
*/

int
const_bonus(void)
{
    int ret_val = -2;

    if (pstats.s_const > 12)
        ret_val = pstats.s_const - 12;
    else if (pstats.s_const > 6)
        ret_val = 0;
    else if (pstats.s_const > 3)
        ret_val = -1;

    return(ret_val);
}

/*
    int_wis_bonus()
        Spell point adjustment for changing levels
*/

int
int_wis_bonus(void)
{
    int ret_val = -2;
    int casters_stat;

    switch (player.t_ctype)
    {
        case C_PALADIN:
        case C_CLERIC:
            casters_stat = pstats.s_wisdom;
            break;
        case C_RANGER:
        case C_DRUID:
            casters_stat = pstats.s_wisdom;
            break;
        case  C_MAGICIAN:
            casters_stat = pstats.s_intel;
            break;
        case  C_ILLUSION:
            casters_stat = pstats.s_intel;
            break;

        default:
            if (is_wearing(R_WIZARD))
                casters_stat = pstats.s_intel;
            else if (is_wearing(R_PIETY))
                casters_stat = pstats.s_wisdom;
            else
                casters_stat = (rnd(2) ? pstats.s_wisdom :
                    pstats.s_intel);
    }

    if (casters_stat > 12)
        ret_val = casters_stat - 12;
    else if (casters_stat > 6)
        ret_val = 0;
    else if (casters_stat > 3)
        ret_val = -1;

    return(ret_val);
}

void
electrificate(void)
{
    int affect_dist = 4 + player.t_stats.s_lvl / 4;
    struct linked_list  *item, *nitem;

    for (item = mlist; item != NULL; item = nitem)
    {
        struct thing *tp = THINGPTR(item);
        char *mname = monsters[tp->t_index].m_name;

        nitem = next(item);

        if (DISTANCE(tp->t_pos, hero) < affect_dist)
        {
            int damage = roll(2, player.t_stats.s_lvl);

            debug("Charge does %d (%d)", damage, tp->t_stats.s_hpt - damage);

            if (on(*tp, NOBOLT))
                continue;

            if ((tp->t_stats.s_hpt -= damage) <= 0)
            {
                msg("The %s is killed by an electric shock.", mname);
                killed(&player, item, NOMESSAGE, POINTS);
                continue;
            }

            if (rnd(tp->t_stats.s_intel / 5) == 0)
            {
                turn_on(*tp, ISFLEE);
                msg("The %s is shocked by electricity.", mname);
            }
            else
                msg("The %s is zapped by your electricity.", mname);

            summon_help(tp, NOFORCE);
            turn_off(*tp, ISFRIENDLY);
            turn_off(*tp, ISCHARMED);
            turn_on(*tp, ISRUN);
            turn_off(*tp, ISDISGUISE);
            chase_it(&tp->t_pos, &player);
            fighting = after = running = FALSE;
        }
    }
}

/*
    feed_me -    Print out interesting messages about food consumption
*/

static char *f_hungry[] =
{
    "want a cookie",
    "feel like a snack",
    "feel like some fruit",
    "start having the munchies",
    "are starting to get hungry"
};

static char *f_weak[] =
{
    "are really hungry",
    "could eat a horse",
    "want some food - now",
    "are starting to feel weak",
    "feel a gnawing in your stomach",
    "are even willing to eat up cram",
    "feel lightheaded from not eating"
};

static char *f_faint[] =
{
    "get dizzy from not eating",
    "are starving for nutrients",
    "feel too weak from lack of food",
    "see a mirage of an incredible banquet",
    "have incredible cramps in your stomach"
};

static char *f_plop[] =
{
    "faint",
    "pass out",
    "keel over",
    "black out"
};

void
feed_me(int hunger)
{
    char    *charp = NULL, *charp2 = NULL;

    switch (hunger)
    {
        case F_OK:
        default:
            debug("feed_me(%d) called.", hunger);
            break;

        case  F_HUNGRY:
            charp = f_hungry[rnd(sizeof(f_hungry) /
                sizeof(char *))];
            break;

        case  F_WEAK:
            charp = f_weak[rnd(sizeof(f_weak) / sizeof(char *))];
            break;

        case F_FAINT:
            charp = f_faint[rnd(sizeof(f_faint) / sizeof(char *))];
            charp2 = f_plop[rnd(sizeof(f_plop) / sizeof(char *))];
            break;
    }

    msg("You %s.", charp);

    if (hunger == F_FAINT)
        msg("You %s.", charp2);
}


/*
    get_monster_number()
        prompt player for a monster on list returns 0 if none selected
*/

int
get_monster_number(char *message)
{
    int  i;
    int  pres_monst = 1;
    int  ret_val = -1;
    char buf[2 * LINELEN];
    char monst_name[2 * LINELEN];

    while (ret_val == -1)
    {
        msg("Which monster do you wish to %s? (* for list)", message);

        if ((get_string(buf, cw)) != NORM)
            return(0);

        if ((i = atoi(buf)) != 0)
            ret_val = i;
        else if (buf[0] != '*')
        {
            for (i = 1; i < nummonst; i++)
                if ((strcmp(monsters[i].m_name, buf) == 0))
                    ret_val = i;
        }
        /* The following hack should be redone by the windowing code */
        else
            while (pres_monst < nummonst)   /* Print out the monsters */
            {
                int num_lines = LINES - 3;

                wclear(hw);
                touchwin(hw);

                wmove(hw, 2, 0);

                for (i = 0; i < num_lines && pres_monst < nummonst; i++)
                {
                    sprintf(monst_name, "[%d] %s\n", pres_monst,
                        monsters[pres_monst].m_name);
                    waddstr(hw, monst_name);
                    pres_monst++;
                }

                if (pres_monst < nummonst)
                {
                    mvwaddstr(hw, LINES - 1, 0, morestr);
                    wrefresh(hw);
                    wait_for(' ');
                }
                else
                {
                    mvwaddstr(hw, 0, 0, "Which monster");
                    waddstr(hw, "? ");
                    wrefresh(hw);
                }
            }

get_monst:
        get_string(monst_name, hw);
        ret_val = atoi(monst_name);

        if ((ret_val < 1 || ret_val > nummonst - 1))
        {
            mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
            wrefresh(hw);
            goto get_monst;
        }

        /* Set up for redraw */

        clearok(cw, TRUE);
        touchwin(cw);
    }

    return(ret_val);
}