Mercurial > hg > early-roguelike
diff srogue/command.c @ 36:2128c7dc8a40
Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Thu, 25 Nov 2010 12:21:41 +0000 |
parents | |
children | 5ea4a4d8f961 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srogue/command.c Thu Nov 25 12:21:41 2010 +0000 @@ -0,0 +1,714 @@ +/* + * Read and execute the user commands + * + * @(#)command.c 9.0 (rdk) 7/17/84 + * + * Super-Rogue + * Copyright (C) 1984 Robert D. Kindelberger + * 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 <ctype.h> +#include <signal.h> +#include <limits.h> +#include "rogue.h" +#include "rogue.ext" +#ifdef __DJGPP__ +#include <process.h> +#endif + +/* + * command: + * Process the user commands + */ +command() +{ + reg char ch; + reg int ntimes = 1; /* Number of player moves */ + static char countch, direction, newcount = FALSE; + + if (pl_on(ISHASTE)) + ntimes++; + /* + * Let the daemons start up + */ + while (ntimes-- > 0) { + do_daemons(BEFORE); + look(TRUE); + if (!running) + door_stop = FALSE; + lastscore = purse; + wmove(cw, hero.y, hero.x); + if (!(running || count)) + draw(cw); /* Draw screen */ + take = 0; + after = TRUE; + /* + * Read command or continue run + */ + if (wizard) + waswizard = TRUE; + if (player.t_nocmd <= 0) { + player.t_nocmd = 0; + if (running) + ch = runch; + else if (count) + ch = countch; + else { + ch = readchar(); + if (mpos != 0 && !running) /* Erase message if its there */ + msg(""); + } + } + else + ch = '.'; + if (player.t_nocmd > 0) { + if (--player.t_nocmd <= 0) + msg("You can move again."); + } + else { + /* + * check for prefixes + */ + if (isdigit(ch)) { + count = 0; + newcount = TRUE; + while (isdigit(ch)) { + count = count * 10 + (ch - '0'); + ch = readchar(); + } + countch = ch; + /* + * turn off count for commands which don't make sense + * to repeat + */ + 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 'f': + case 't': case 'C': case 'I': case '.': + case 'z': case 'p': + break; + default: + count = 0; + } + } + switch (ch) { + case 'f': + case 'g': + if (pl_off(ISBLIND)) { + door_stop = TRUE; + firstmove = TRUE; + } + if (count && !newcount) + ch = direction; + else + ch = readchar(); + switch (ch) { + case 'h': case 'j': case 'k': case 'l': + case 'y': case 'u': case 'b': case 'n': + ch = toupper(ch); + } + direction = ch; + } + newcount = FALSE; + /* + * execute a command + */ + if (count && !running) + count--; + switch (ch) { + case '!' : shell(); after = FALSE; + when 'h' : do_move(0, -1); + when 'j' : do_move(1, 0); + when 'k' : do_move(-1, 0); + when 'l' : do_move(0, 1); + when 'y' : do_move(-1, -1); + when 'u' : do_move(-1, 1); + when 'b' : do_move(1, -1); + when 'n' : do_move(1, 1); + when 'H' : do_run('h'); + when 'J' : do_run('j'); + when 'K' : do_run('k'); + when 'L' : do_run('l'); + when 'Y' : do_run('y'); + when 'U' : do_run('u'); + when 'B' : do_run('b'); + when 'N' : do_run('n'); + when 't': + if (!get_dir()) + after = FALSE; + else + missile(delta.y, delta.x); + when 'Q' : after = FALSE; quit(-1); + when 'i' : after = FALSE; inventory(pack, 0); + when 'I' : after = FALSE; picky_inven(); + when 'd' : drop(NULL); + when 'q' : quaff(); + when 'r' : read_scroll(); + when 'e' : eat(); + when 'w' : wield(); + when 'W' : wear(); + when 'T' : take_off(); + when 'P' : ring_on(); + when 'R' : ring_off(); + when 'O' : option(); + when 'c' : call(); + when '>' : after = FALSE; d_level(); + when '<' : after = FALSE; u_level(); + when '?' : after = FALSE; help(); + when '/' : after = FALSE; identify(0); + when 's' : search(); + when 'z' : do_zap(FALSE); + when 'p': + if (get_dir()) + do_zap(TRUE); + else + after = FALSE; + when 'v': msg("Super Rogue version %s.",release); + when 'D': dip_it(); + when CTRL('L') : after = FALSE; restscr(cw); + when CTRL('R') : after = FALSE; msg(huh); + when 'a': after = FALSE; dispmax(); + when '@' : if (author()) + msg("Hero @ %d,%d : Stairs @ %d,%d",hero.y,hero.x,stairs.y,stairs.x); + when 'S' : + after = FALSE; + if (save_game()) { + wclear(cw); + draw(cw); + endwin(); + byebye(0); + } + when '.' : ; /* Rest command */ + when ' ' : after = FALSE; /* do nothing */ + when '=' : + if (author()) { + activity(); + after = FALSE; + } + when CTRL('P') : + after = FALSE; + if (wizard) { + wizard = FALSE; + msg("Not wizard any more"); + } + else { + wizard = passwd(); + if (wizard) { + msg("Welcome back, Bob!!!!!"); + waswizard = TRUE; + } + else + msg("Sorry"); + } + when ESCAPE : /* Escape */ + door_stop = FALSE; + count = 0; + after = FALSE; + when '#': + if (levtype == POSTLEV) /* buy something */ + buy_it(); + after = FALSE; + when '$': + if (levtype == POSTLEV) /* price something */ + price_it(); + after = FALSE; + when '%': + if (levtype == POSTLEV) /* sell something */ + sell_it(); + after = FALSE; + otherwise : + after = FALSE; + if (wizard) switch (ch) { + case CTRL('A') : ; + when 'C' : create_obj(FALSE); + when CTRL('I') : inventory(lvl_obj, 1); + when CTRL('W') : whatis(NULL); + when CTRL('D') : level++; new_level(NORMLEV); + when CTRL('U') : if (level > 1) level--; new_level(NORMLEV); + when CTRL('F') : displevl(); + when CTRL('X') : dispmons(); + when CTRL('T') : teleport(rndspot,&player); + when CTRL('E') : msg("food left: %d", food_left); + when CTRL('O') : add_pass(); + when 'M' : { + int tlev, whichlev; + prbuf[0] = '\0'; + msg("Which level? "); + if (get_str(prbuf,cw) == NORM) { + whichlev = NORMLEV; + tlev = atoi(prbuf); + if (tlev < 1) + level = 1; + if (tlev >= 200) { + tlev -= 199; + whichlev = MAZELEV; + } + else if (tlev >= 100) { + tlev -= 99; + whichlev = POSTLEV; + } + level = tlev; + new_level(whichlev); + } + } + when CTRL('N') : { + struct linked_list *item; + + item = get_item("charge", STICK); + if (item != NULL) { + (OBJPTR(item))->o_charges = 10000; + msg(""); + } + } + when CTRL('H') : { + int i; + struct linked_list *item; + struct object *obj; + + him->s_exp = e_levels[him->s_lvl + 7] + 1; + check_level(); + /* + * Give the rogue a very good sword + */ + item = new_thing(FALSE, WEAPON, TWOSWORD); + obj = OBJPTR(item); + obj->o_hplus = 3; + obj->o_dplus = 3; + obj->o_flags = ISKNOW; + i = add_pack(item, TRUE); + if (i) + cur_weapon = obj; + else + discard(item); + /* + * And his suit of armor + */ + item = new_thing(FALSE, ARMOR, PLATEARMOR); + obj = OBJPTR(item); + obj->o_ac = -8; + obj->o_flags = ISKNOW; + i = add_pack(item, TRUE); + if (i) + cur_armor = obj; + else + discard(item); + nochange = FALSE; + } + otherwise: + msg(illegal, unctrl(ch)); + count = 0; + } + else { + msg(illegal, unctrl(ch)); + count = 0; + } + } + /* + * turn off flags if no longer needed + */ + if (!running) + door_stop = FALSE; + } + /* + * If he ran into something to take, let the + * hero pick it up if not in a trading post. + */ + if (take != 0 && levtype != POSTLEV) + pick_up(take); + if (!running) + door_stop = FALSE; + } + /* + * Kick off the rest if the daemons and fuses + */ + if (after) { + int j; + + look(FALSE); + do_daemons(AFTER); + do_fuses(); + if (pl_on(ISSLOW)) + waste_time(); + for (j = LEFT; j <= RIGHT; j++) { + if (cur_ring[j] != NULL) { + if (cur_ring[j]->o_which == R_SEARCH) + search(); + else if (cur_ring[j]->o_which == R_TELEPORT) + if (rnd(100) < 5) + teleport(rndspot, &player); + } + } + } +} + + +/* + * quit: + * Have player make certain, then exit. + */ +void +quit(int a) +{ + reg char ch, good; + /* + * Reset the signal in case we got here via an interrupt + */ + if (signal(SIGINT, quit) != quit) + mpos = 0; + msg("Really quit? [y/n/s]"); +/* ch = tolower(readchar());*/ + ch = readchar(); + if (ch == 'y') { + clear(); + move(LINES-1, 0); + refresh(); + score(purse, CHICKEN, 0); + byebye(0); + } + else if (ch == 's') { + good = save_game(); + if (good) { + wclear(cw); + draw(cw); + endwin(); + byebye(0); + } + } + else { + signal(SIGINT, quit); + wmove(cw, 0, 0); + wclrtoeol(cw); + draw(cw); + mpos = 0; + count = 0; + nochange = FALSE; + } +} + +/* + * search: + * Player gropes about him to find hidden things. + */ + +search() +{ + reg int x, y; + reg char ch; + + /* + * Look all around the hero, if there is something hidden there, + * give him a chance to find it. If its found, display it. + */ + if (pl_on(ISBLIND)) + return; + for (x = hero.x - 1; x <= hero.x + 1; x++) { + for (y = hero.y - 1; y <= hero.y + 1; y++) { + ch = winat(y, x); + if (isatrap(ch)) { /* see if its a trap */ + reg struct trap *tp; + + if ((tp = trap_at(y, x)) == NULL) + break; + if (tp->tr_flags & ISFOUND) + break; /* no message if its seen */ + if (mvwinch(cw, y, x) == ch) + break; + if (rnd(100) > (him->s_lvl * 9 + herowis() * 5)) + break; + tp->tr_flags |= ISFOUND; + mvwaddch(cw, y, x, tp->tr_type); + count = 0; + running = FALSE; + msg(tr_name(tp->tr_type)); + } + else if(ch == SECRETDOOR) { + if (rnd(100) < (him->s_lvl * 4 + herowis() * 5)) { + mvaddch(y, x, DOOR); + count = 0; + } + } + } + } +} + +/* + * help: + * Give single character help, or the whole mess if he wants it + */ +help() +{ + extern struct h_list helpstr[]; + reg struct h_list *strp; + reg char helpch; + reg int cnt; + + strp = &helpstr[0]; + msg("Character you want help for (* for all): "); + helpch = readchar(); + mpos = 0; + /* + * If its not a *, print the right help string + * or an error if he typed a funny character. + */ + if (helpch != '*') { + wmove(cw, 0, 0); + while (strp->h_ch) { + if (strp->h_ch == helpch) { + msg("%s%s", unctrl(strp->h_ch), strp->h_desc); + break; + } + strp++; + } + if (strp->h_ch != helpch) + msg("Unknown character '%s'", unctrl(helpch)); + return; + } + /* + * Here we print help for everything. + * Then wait before we return to command mode + */ + wclear(hw); + cnt = 0; + while (strp->h_ch) { + mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch)); + waddstr(hw, strp->h_desc); + cnt++; + strp++; + } + wmove(hw, LINES-1, 0); + wprintw(hw,spacemsg); + draw(hw); + wait_for(hw,' '); + wclear(hw); + draw(hw); + wmove(cw, 0, 0); + wclrtoeol(cw); + touchwin(cw); + nochange = FALSE; +} + + +/* + * identify: + * Tell the player what a certain thing is. + */ +char * +identify(what) +int what; +{ + reg char ch, *str; + + if (what == 0) { + msg("What do you want identified? "); + ch = readchar(); + mpos = 0; + if (ch == ESCAPE) { + msg(""); + return NULL; + } + } + else + ch = what; + if (isalpha(ch)) + str = monsters[midx(ch)].m_name; + else { + switch(ch) { + case '|': + case '-': str = "the wall of a room"; + when GOLD: str = "gold"; + when STAIRS: str = "passage leading up/down"; + when DOOR: str = "door"; + when FLOOR: str = "room floor"; + when PLAYER: str = "you"; + when PASSAGE: str = "passage"; + when POST: str = "trading post"; + when MAZETRAP: str = "maze trap"; + when TRAPDOOR: str = "trapdoor"; + when ARROWTRAP: str = "arrow trap"; + when SLEEPTRAP: str = "sleeping gas trap"; + when BEARTRAP: str = "bear trap"; + when TELTRAP: str = "teleport trap"; + when DARTTRAP: str = "dart trap"; + when POOL: str = "magic pool"; + when POTION: str = "potion"; + when SCROLL: str = "scroll"; + when FOOD: str = "food"; + when WEAPON: str = "weapon"; + when ' ' : str = "solid rock"; + when ARMOR: str = "armor"; + when AMULET: str = "The Amulet of Yendor"; + when RING: str = "ring"; + when STICK: str = "wand or staff"; + otherwise: + if (what == 0) + str = "unknown character"; + else + str = "a magical ghost"; + } + } + if (what == 0) + msg("'%s' : %s", unctrl(ch), str); + return str; +} + +/* + * d_level: + * He wants to go down a level + */ +d_level() +{ + if (winat(hero.y, hero.x) != STAIRS) + msg("I see no way down."); + else { + if (pl_on(ISHELD)) { + msg("You are being held."); + return; + } + level++; + new_level(NORMLEV); + } +} + +/* + * u_level: + * He wants to go up a level + */ +u_level() +{ + if (winat(hero.y, hero.x) == STAIRS) { + if (pl_on(ISHELD)) { + msg("You are being held."); + return; + } + else { /* player not held here */ + if (amulet) { + level--; + if (level == 0) + total_winner(); + new_level(NORMLEV); + msg("You feel a wrenching sensation in your gut."); + return; + } + } + } + msg("I see no way up."); +} + + +/* + * Let him escape for a while + */ +shell() +{ + reg int pid; + reg char *sh; + int ret_status; + + /* + * Set the terminal back to original mode + */ + sh = getenv("SHELL"); + wclear(hw); + wmove(hw, LINES-1, 0); + draw(hw); + endwin(); + in_shell = TRUE; + fflush(stdout); + /* + * Fork and do a shell + */ +#ifndef __DJGPP__ + while((pid = fork()) < 0) + sleep(1); + if (pid == 0) { + setuid(playuid); /* Set back to original user */ + setgid(playgid); + execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0); + perror("No shelly"); + byebye(-1); + } + else { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + while (wait(&ret_status) != pid) + continue; + signal(SIGINT, quit); + signal(SIGQUIT, endit); + +#else + { + char shell[PATH_MAX]; + + if (sh && *sh) + strncpy(shell,sh,PATH_MAX); + else + sprintf(shell, "%s\\bin\\sh.exe", getenv("DJDIR")); + + if (spawnl(P_WAIT,shell, "shell", "-i", 0) == -1) + msg("No shelly: %s", shell); + +#endif + printf("\n%s", retstr); + fflush(stdout); + noecho(); + crmode(); + in_shell = FALSE; + wait_for(cw, '\n'); + restscr(cw); + } +} + + +/* + * call: + * Allow a user to call a potion, scroll, or ring something + */ +call() +{ + reg struct object *obj; + reg struct linked_list *item; + reg char **guess, *elsewise; + int wh; + + if ((item = get_item("call", 0)) == NULL) + return; + obj = OBJPTR(item); + wh = obj->o_which; + switch (obj->o_type) { + case RING: + guess = r_guess; + elsewise = (r_guess[wh] != NULL ? r_guess[wh] : r_stones[wh]); + when POTION: + guess = p_guess; + elsewise = (p_guess[wh] != NULL ? p_guess[wh] : p_colors[wh]); + when SCROLL: + guess = s_guess; + elsewise = (s_guess[wh] != NULL ? s_guess[wh] : s_names[wh]); + when STICK: + guess = ws_guess; + elsewise =(ws_guess[wh] != NULL ? + ws_guess[wh] : ws_stuff[wh].ws_made); + otherwise: + msg("You can't call %ss anything",obj->o_typname); + return; + }