view urogue/command.c @ 306:057c5114e244

Super-Rogue: fix some out-of-range constants. Constants K_ARROW etc., for causes of death other than monsters, are in the 240-255 range. They were often passed to functions taking char, which is usually signed, making the values out of range. The function declarations have been changed to unsigned char, which is also the type used by the scoreboard code.
author John "Elwin" Edwards
date Sat, 17 Apr 2021 15:41:12 -0400
parents e52a8a7ad4c5
children c03d0b87211c
line wrap: on
line source

/*
    command.c  -  Read and execute the user commands
 
    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 <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "rogue.h"

/*
    command()
        Process the user commands
*/

void
command(void)
{
    static char repcommand;     /* Command to repeat if we are repeating */
    static int fight_to_death; /* Flags if we are fighting to death     */
    static coord dir;          /* Last direction specified              */

#ifdef WIZARD
    object  *obj;
#endif
    char     ch;
    int      ntimes = 1; /* Number of player moves */
    coord    nullcoord;

    nullcoord.x = nullcoord.y = 0;

    if (on(player, CANFLY) && rnd(2))
        ntimes++;

    if (on(player, ISHASTE))
        ntimes++;

    if (fighting && att_bonus())
        ntimes *= 2;

    if (on(player, ISSLOW))
    {
        if (player.t_turn != TRUE)
            ntimes--;

        player.t_turn ^= TRUE;
    }

    if (ntimes == 0)
        return;

    while (ntimes--)
    {
        moving = FALSE;

        /* If player is infested, take off a hit point */

        if (on(player, HASINFEST) && !is_wearing(R_HEALTH))
        {
            if ((pstats.s_hpt -= infest_dam) <= 0)
            {
                death(D_INFESTATION);
                return;
            }
        }

        look(after);

        if (!running)
            door_stop = FALSE;

        status(FALSE);
        wmove(cw, hero.y, hero.x);

        if (!((running || count) && jump))
            wrefresh(cw);   /* Draw screen */

        take = 0;
        after = TRUE;

        /*
         * Read command or continue run
         */

        if (!no_command)
        {
            if (fighting)
            {
                ch = (fight_to_death) ? 'F' : 'f';
            }
            else if (running)
            {
                /*
                 * If in a corridor, if we are at a turn with
                 * only one way to go, turn that way.
                 */

                if ((winat(hero.y, hero.x) == PASSAGE) && off(player, ISHUH) &&
                    (off(player, ISBLIND)))
                    switch (runch)
                    {
                        case 'h': corr_move(0, -1); break;
                        case 'j': corr_move(1, 0); break;
                        case 'k': corr_move(-1, 0); break;
                        case 'l': corr_move(0, 1); break;
                    }

                ch = runch;
            }
            else if (count)
                ch = repcommand;
            else
            {
                ch = readchar();

                if (mpos != 0 && !running)
                    msg("");    /* Erase message if its there */
            }
        }
        else
        {
            ch = '.';
            fighting = moving = FALSE;
        }

        if (no_command)
        {
            if (--no_command == 0)
                msg("You can move again.");
        }
        else
        {

            /*
             * check for prefixes
             */

            if (isdigit(ch))
            {
                count = 0;
                while (isdigit(ch))
                {
                    count = count * 10 + (ch - '0');
                    ch = readcharw(cw);
                }
                repcommand = ch;

                /*
                 * Preserve count for commands which can be
                 * repeated.
                 */

                switch(ch)
                {
                    case 'h':
                    case 'j':
                    case 'k':
                    case 'l':
                    case 'y':
                    case 'u':
                    case 'b':
                    case 'n':
                    case 'H':
                    case 'J':
                    case 'K':
                    case 'L':
                    case 'Y':
                    case 'U':
                    case 'B':
                    case 'N':
                    case 'q':
                    case 'r':
                    case 's':
                    case 'm':
                    case 't':
                    case 'C':
                    case 'I':
                    case '.':
                    case 'z':
                    case 'p':
                        break;
                    default:
                        count = 0;
                }
            }

            /* Save current direction */

            if (!running)   /* If running, it is already saved */
                switch (ch)
                {
                    case 'h':
                    case 'j':
                    case 'k':
                    case 'l':
                    case 'y':
                    case 'u':
                    case 'b':
                    case 'n':
                        runch = ch;
                        break;
                    case 'H':
                    case 'J':
                    case 'K':
                    case 'L':
                    case 'Y':
                    case 'U':
                    case 'B':
                    case 'N':
                        runch = (char) tolower(ch);
                        break;
                }

            /*
             * execute a command
             */

            if (count && !running)
                count--;

            switch(ch)
            {
                /*
                 * Movement and combat commands
                 */

                case 'h': do_move(0,-1); break;
                case 'j': do_move(1, 0);  break;
                case 'k': do_move(-1, 0); break;
                case 'l': do_move(0, 1); break;
                case 'y': do_move(-1, -1); break;
                case 'u': do_move(-1, 1); break;
                case 'b': do_move(1, -1); break;
                case 'n': do_move(1, 1); break;
                case 'H': do_run('h'); break;
                case 'J': do_run('j'); break;
                case 'K': do_run('k'); break;
                case 'L': do_run('l'); break;
                case 'Y': do_run('y'); break;
                case 'U': do_run('u'); break;
                case 'B': do_run('b'); break;
                case 'N': do_run('n'); break;
                case 'm':
                    moving = TRUE;
                    if (!get_dir())
                    {
                        after = FALSE;
                        break;
                    }
                    do_move(delta.y, delta.x);
                    break;
                case 'F':
                case 'f':
                    fight_to_death = (ch == 'F');
                    if (!fighting)
                    {
                        if (get_dir())
                        {
                            dir = delta;
                            beast = NULL;
                        }
                        else
                        {
                            after = FALSE;
                            break;
                        }
                    }
                    do_fight(dir, (ch == 'F') ? TRUE : FALSE);
                    break;
                case 't':
                    if (get_dir())
                        missile(delta.y, delta.x, get_item("throw", 0),
                            &player);
                    else
                        after = FALSE;

                    /*
                     * Informational commands - Do not do
                     * after daemons
                     */
                     break;

                case 0x7f:            /* sometime generated by */
                                      /* suspend/foreground    */
                case ESCAPE:
                case ' ':
                    after = FALSE;    /* do nothing */
                    break;
                case 'Q':
                    after = FALSE;
                    quit();
                    break;
                case 'i':
                    after = FALSE;
                    inventory(pack, '*');
                    break;
                case 'I':
                    after = FALSE;
                    inventory(pack, 0);
                    break;
                case '~':
                    after = FALSE;
                    next_exp_level(MESSAGE);
                    break;
                case '>':
                    after = FALSE;
                    d_level();
                    break;
                case '<':
                    after = FALSE;
                    u_level();
                    break;
                case '?':
                    after = FALSE;
                    help();
                    break;
                case '/':
                    after = FALSE;
                    identify();
                    break;
                case 'v':
                    after = FALSE;
                    msg("UltraRogue Version %s.", release);
                    break;
                case 'o':
                    after = FALSE;
                    option();
                    strcpy(fd_data[1].mi_name, fruit);
                    break;
                case 12:    /* ctrl-l */
                case 18:    /* ctrl-r */
                    after = FALSE;
                    clearok(cw, TRUE);
					wrefresh(cw);
                    break;
                case 16: /* ctrl-p */
                {
                    int decrement = FALSE;
                    after = FALSE;

                    if (mpos == 0)
                        decrement = TRUE;

                    msg_index = (msg_index + 9) % 10;
                    msg(msgbuf[msg_index]);
                    if (decrement)
                        msg_index = (msg_index + 9) % 10;
                }
                break;

                case 'S':
                    after = FALSE;
                    if (save_game())
                    {
                        wclear(cw);
                        wrefresh(cw);
                        endwin();
			printf("\n");
                        exit(0);
                    }
                    break;

                /*
                 * Other misc commands
                 */

                case '.':   break;   /* rest */
                case ',':   add_pack(NULL, NOMESSAGE); break;
                case 'q': quaff(&player, -1, ISNORMAL); break;
                case 'r': read_scroll(&player, -1, ISNORMAL); break;
                case 'd': drop(NULL); break;
                case '^': set_trap(&player, hero.y, hero.x); break;
                case 'c': incant(&player, nullcoord); break;
                case 'D': dip_it(); break;
                case 'e': eat(); break;
                case '=': listen(); break;
                case 'A': apply(); break;
                case 'w': wield(); break;
                case 'W': wear(); break;
                case 'T': take_off(); break;
                case 'P': ring_on(); break;
                case 'R': ring_off(); break;
                case 'p': prayer(); break;
                case 'C': call(FALSE); break;
                case 'M': call(TRUE); break;
                case 's': search(FALSE); break;

                /*
                 * Directional commands - get_dir sets delta
                 */
                case 20:    /* ctrl-t */
                    if (get_dir())
                        steal();
                    else
                        after = FALSE;
                    break;

                case 'z':
                    if (get_dir())
                        do_zap(&player, -1, ISNORMAL);
                    else
                        after = FALSE;
                    break;

                case 'a':
                    if (get_dir())
                        affect();
                    else
                        after = FALSE;
                    touchwin(cw);
                    break;

                /*
                 * wizard commands
                 */

#ifdef WIZARD
                case 0x17:    /* ctrl-w */
                    after = FALSE;

                    if (!wizard)
                    {
                        if (!canwizard)
                        {
                            msg("Illegal command '^W'.");
                            break;
                        }

                        if (passwd())
                        {
                            msg("Welcome, oh mighty wizard.");
                            wizard = waswizard = TRUE;
                        }
                        else
                        {
                            msg("Incorrect password.");
                            break;
                        }
                    }

                    msg("Wizard command: ");
                    mpos = 0;
                    ch = readchar();

                    switch (ch)
                    {
                        case 'v':
                            wiz_verbose = !wiz_verbose;
                            break;

                        case 'e':
                            wizard = FALSE;
                            msg("Not wizard any more.");
                            break;

                        case 's': activity(); break;
                        case 't': teleport(); break;
                        case 'm': overlay(mw, cw); break;
                        case 'f': overlay(stdscr, cw); break;
                        case 'i': inventory(lvl_obj, 0); break;
                        case 'c': buy_it('\0', ISNORMAL); break;
                        case 'I': whatis(NULL); break;
                        case 'F':
                             msg("food left: %d\tfood level: %d",
                                  food_left,foodlev);
                             break;
                        case 'M':
                            creat_mons(&player, get_monster_number("create"),
                                       MESSAGE);
                            break;

                        case 'r':
                            msg("rnd(4)%d, rnd(40)%d, rnd(100)%d",
                                 rnd(4), rnd(40), rnd(100));
                            break;

                        case 'C':
                            obj = get_object(pack, "charge", STICK, NULL);

                            if (obj != NULL)
                                obj->o_charges = 10000;

                            break;

                        case 'w':
                            obj = get_object(pack, "price", 0, NULL);

                            if (obj != NULL)
                                msg("Worth %d.", get_worth(obj));

                            break;

                        case 'g':
                            {
                                int tlev;

                                prbuf[0] = '\0';
                                msg("Which level? ");

                                if (get_string(prbuf, cw) == NORM)
                                {
                                    msg("");

                                    if ((tlev = atoi(prbuf)) < 1)
                                        msg("Illegal level.");
                                    else if (tlev > 3000)
                                    {
                                        levtype = THRONE;
                                        level = tlev - 3000;
                                    }
                                    else if (tlev > 2000)
                                    {
                                        levtype = MAZELEV;
                                        level = tlev - 2000;
                                    }
                                    else if (tlev > 1000)
                                    {
                                        levtype = POSTLEV;
                                        level = tlev - 1000;
                                    }
                                    else
                                    {
                                        levtype = NORMLEV;
                                        level = tlev;
                                    }

                                    new_level(levtype,0);
                                }
                            }
                            break;

                        case 'o':   make_omnipotent(); break;

                        case ESCAPE: /* Escape */
                            door_stop = FALSE;

                            count = 0;
                            after = FALSE;
                            break;

                        default:
                            msg("Illegal wizard command '%s', %d.",
                                unctrl(ch), ch);
                            count = 0;
                            break;

                    }

                break;
#endif

                default:
                    msg("Illegal command '%s', %d.",
                        unctrl(ch), ch);
                    count = 0;
                    after = FALSE;
                    break;
            }

            /*
             * turn off flags if no longer needed
             */
            if (!running)
                door_stop = FALSE;
        }

        /*
         * If he ran into something to take, let him pick it up.
         */
        if (take != 0)
	{
            if (!moving)
                pick_up(take);
            else
                show_floor();
	}
        if (!running)
            door_stop = FALSE;
    } /* end while */
}


void
do_after_effects(void)
{
    int i;

    /* Kick off the rest of the daemons and fuses */

    look(FALSE);
    do_daemons(AFTER);
    do_fuses(AFTER);

    /* Special abilities */

    if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN ||
     player.t_ctype == C_NINJA || player.t_ctype == C_RANGER) &&
     (rnd(100) < (2 * pstats.s_dext + 5 * pstats.s_lvl)))
        search(TRUE);

    for (i = 0; i < ring_value(R_SEARCH); i++)
        search(FALSE);

    if (is_wearing(R_TELEPORT) && rnd(50) < 2)
    {
        teleport();

        if (off(player, ISCLEAR))
        {
            if (on(player, ISHUH))
                lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
            else
                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);

            turn_on(player, ISHUH);
        }
        else
            msg("You feel dizzy for a moment, but it quickly passes.");
    }

    /* accidents and general clumsiness */

    if (fighting && rnd(50) == 0)
    {
        msg("You become tired of this nonsense.");
        fighting = after = FALSE;
    }

    if (on(player, ISELECTRIC))
        electrificate();

    if (!fighting && (no_command == 0) && cur_weapon != NULL
        && rnd(on(player, STUMBLER) ? 399 : 9999) == 0
        && rnd(pstats.s_dext) <
        2 - hitweight() + (on(player, STUMBLER) ? 4 : 0))
    {
        msg("You trip and stumble over your weapon.");
        running = after = FALSE;

        if (rnd(8) == 0 && (pstats.s_hpt -= roll(1, 10)) <= 0)
        {
            msg("You break your neck and die.");
            death(D_FALL);
            return;
        }
        else if (cur_weapon->o_flags & ISPOISON && rnd(4) == 0)
        {
            msg("You are cut by your %s!",
                inv_name(cur_weapon, LOWERCASE));

            if (player.t_ctype != C_PALADIN
                && !(player.t_ctype == C_NINJA &&
                pstats.s_lvl > 12)
                && !save(VS_POISON))
            {
                if (pstats.s_hpt == 1)
                {
                    msg("You die from the poison in the cut.");
                    death(D_POISON);
                    return;
                }
                else
                {
                    msg("You feel very sick now.");
                    pstats.s_hpt /= 2;
                    chg_str(-2, FALSE, FALSE);
                }
            }
       }
    }

    /* Time to enforce weapon and armor restrictions */
    if (rnd(9999) == 0)
    {
        if (((cur_weapon == NULL) ||
            (wield_ok(&player, cur_weapon, NOMESSAGE)))
            && ((cur_armor == NULL) ||
            (wear_ok(&player, cur_armor, NOMESSAGE))))
        {
            switch (player.t_ctype)
            {
                case C_CLERIC:
                case C_DRUID:
                case C_RANGER:
                case C_PALADIN:
                    if (rnd(luck) != 0)
                        /* You better have done
                         * little wrong */
                        goto bad_cleric;

                    msg("You are enraptured by the renewed "
                        "power of your god.");
                    break;

                case C_MAGICIAN:
                case C_ILLUSION:
                    msg("You become in tune with the universe.");
                    break;

                case C_THIEF:
                case C_NINJA:
                case C_ASSASIN:
                    msg("You become supernaly sensitive to your "
                        "surroundings.");
                    break;

                case C_FIGHTER:
                    msg("You catch your second wind.");
                    break;

                default:
                    msg("What a strange type you are!");
                    break;
           }
           pstats.s_hpt = max_stats.s_hpt += rnd(pstats.s_lvl) + 1;
            pstats.s_power = max_stats.s_power += rnd(pstats.s_lvl) + 1;
        }
        else
        {   /* he blew it - make him pay */

            int death_cause = 0;

            switch (player.t_ctype)
            {
                case C_CLERIC:
                case C_DRUID:
                case C_RANGER:
                case C_PALADIN:
            bad_cleric:
                    msg("Your god scourges you for your misdeeds.");
                    death_cause = D_GODWRATH;
                    break;

                case C_MAGICIAN:
                case C_ILLUSION:
                    msg("You short out your manna on the unfamiliar %s.",
                        (cur_armor != NULL ? "armor" : "weapon"));

                   death_cause = D_SPELLFUMBLE;
                   break;

                case C_THIEF:
                case C_NINJA:
                case C_ASSASIN:
                    msg("You trip and fall because of the unfamiliar %s.",
                        (cur_armor != NULL ? "armor" : "weapon"));
                    death_cause = D_CLUMSY;
                    break;

                case C_FIGHTER:
                    debug("Fighter getting raw deal?");
                   break;

                default:
                    msg("What a strange type you are!");
                    break;
            }

            aggravate();
            pstats.s_power /= 2;
            pstats.s_hpt /= 2;
            player.t_no_move++;

            if ((pstats.s_hpt -= rnd(pstats.s_lvl)) <= 0)
            {
                death(death_cause);
            }
        }
    }

    if (rnd(500000) == 0)
    {
        new_level(THRONE,0);
        fighting = running = after = FALSE;
        command();
    }
}

void
make_omnipotent(void)
{
    int i;
    struct linked_list  *item;
    struct object *obj;

    for (i = 0; i < 20; i++)
        raise_level();

    max_stats.s_hpt += 1000;
    max_stats.s_power += 1000;
    pstats.s_hpt = max_stats.s_hpt;
    pstats.s_power = max_stats.s_power;
    max_stats.s_str = pstats.s_str = 25;
    max_stats.s_intel = pstats.s_intel = 25;
    max_stats.s_wisdom = pstats.s_wisdom = 25;
    max_stats.s_dext = pstats.s_dext = 25;
    max_stats.s_const = pstats.s_const = 25;

    if (cur_weapon == NULL || cur_weapon->o_which != CLAYMORE)
    {
        item = spec_item(WEAPON, CLAYMORE, 10, 10);
        cur_weapon = OBJPTR(item);
        cur_weapon->o_flags |= ISKNOW;
        add_pack(item, NOMESSAGE);
    }

    /* and a kill-o-zap stick */

    item = spec_item(STICK, WS_DISINTEGRATE, 10000, 0);
    obj = OBJPTR(item);
    obj->o_flags |= ISKNOW;
    know_items[TYP_STICK][WS_DISINTEGRATE] = TRUE;

    if (guess_items[TYP_STICK][WS_DISINTEGRATE])
    {
        ur_free(guess_items[TYP_STICK][WS_DISINTEGRATE]);