diff arogue5/command.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children 7aff18a8d508
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue5/command.c	Thu Aug 09 22:58:48 2012 +0000
@@ -0,0 +1,938 @@
+/*
+ * Read and execute the user commands
+ *
+ * Advanced Rogue
+ * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
+ * All rights reserved.
+ *
+ * Based on "Rogue: Exploring the Dungeons of Doom"
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+ * All rights reserved.
+ *
+ * See the file LICENSE.TXT for full copyright and licensing information.
+ */
+
+#include "curses.h"
+#include <limits.h>
+#include <ctype.h>
+#include <signal.h>
+#include "mach_dep.h"
+#include "rogue.h"
+
+/*
+ * command:
+ *	Process the user commands
+ */
+
+command()
+{
+    register char ch;
+    register int ntimes = 1;			/* Number of player moves */
+    static char countch, direction, newcount = FALSE;
+    struct linked_list *item;
+    bool an_after = FALSE;
+
+    if (on(player, ISHASTE)) {
+	ntimes++;
+	turns--;	/* correct for later */
+    }
+    if (on(player, ISSLOW) || on(player, ISDANCE)) {
+	if (player.t_turn != TRUE) {
+	    ntimes--;
+	    turns++;
+	    an_after = TRUE;
+	}
+	player.t_turn ^= TRUE;
+    }
+
+    /*
+     * Let the daemons start up
+     */
+    do_daemons(BEFORE);
+    do_fuses(BEFORE);
+    while (ntimes-- > 0)
+    {	
+	/* One more tick of the clock. */
+	if ((++turns % DAYLENGTH) == 0) {
+	    daytime ^= TRUE;
+	    if (levtype == OUTSIDE) {
+		if (daytime) msg("The sun rises above the horizon");
+		else msg("The sun sinks below the horizon");
+	    }
+	    light(&hero);
+	}
+
+	look(after, FALSE);
+	if (!running) door_stop = FALSE;
+	lastscore = purse;
+	wmove(cw, hero.y, hero.x);
+	if (!((running || count) && jump)) {
+	    status(FALSE);
+	    wmove(cw, hero.y, hero.x);
+	    draw(cw);			/* Draw screen */
+	}
+	take = 0;
+	after = TRUE;
+	/*
+	 * Read command or continue run
+	 */
+	if (!no_command)
+	{
+	    if (running) {
+		/* If in a corridor or maze, if we are at a turn with only one
+		 * way to go, turn that way.
+		 */
+		if ((winat(hero.y, hero.x) == PASSAGE || levtype == MAZELEV) &&
+		    off(player, ISHUH) && (off(player, ISBLIND))) {
+		    int y, x;
+		    if (getdelta(runch, &y, &x) == TRUE) {
+			corr_move(y, x);
+		    }
+		}
+	        ch = runch;
+	    }
+	    else if (count) ch = countch;
+	    else
+	    {
+		ch = readchar();
+		if (mpos != 0 && !running)	/* Erase message if its there */
+		    msg("");
+	    }
+	}
+	else ch = '.';
+	if (no_command)
+	{
+	    if (--no_command == 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');
+		    if (count > 255)
+			count = 255;
+		    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;
+		}
+	    }
+
+	    /* 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':
+		case 'H': case 'J': case 'K': case 'L':
+		case 'Y': case 'U': case 'B': case 'N':
+		    runch = tolower(ch);
+	    }
+
+	    /* Perform the action */
+	    switch (ch) {
+		case 'f':
+		    if (!on(player, 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();
+		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((item=get_item(pack,"throw", ALL)) != NULL && get_dir())
+			missile(delta.y, delta.x, item, &player);
+		    else
+			after = FALSE;
+		when 'Q' : after = FALSE; quit(-1);
+		when 'i' : after = FALSE; inventory(pack, ALL);
+		when 'I' : after = FALSE; picky_inven();
+		when 'd' : drop(NULL);
+		when 'P' : grab(hero.y, hero.x);
+		when 'q' : quaff(-1, NULL, TRUE);
+		when 'r' : read_scroll(-1, NULL, TRUE);
+		when 'e' : eat();
+		when 'w' : wield();
+		when 'W' : wear();
+		when 'T' : take_off();
+		when 'o' : option();
+		when 'c' : call(FALSE);
+		when 'm' : call(TRUE);
+		when '>' : after = FALSE; d_level();
+		when '<' : after = FALSE; u_level();
+		when '?' : after = FALSE; help();
+		when '/' : after = FALSE; identify();
+		when CTRL('U') : use_mm(-1);
+		when CTRL('T') :
+		    if (get_dir()) steal();
+		    else after = FALSE;
+		when 'D' : dip_it();
+		when 'G' : gsense();
+		when '^' : set_trap(&player, hero.y, hero.x);
+		when 's' : search(FALSE, FALSE);
+		when 'z' : if (!do_zap(TRUE, NULL, FALSE))
+				after=FALSE;
+		when 'p' : pray();
+		when 'C' : cast();
+		when 'a' :
+		    if (get_dir())
+			affect();
+		    else after = FALSE;
+		when 'v' : after = FALSE;
+			   msg("Advanced Rogue Version %s.",
+				release);
+		when CTRL('L') : after = FALSE; clearok(curscr, TRUE);
+				touchwin(cw); /* MMMMMMMMMM */
+		when CTRL('R') : after = FALSE; msg(huh);
+		when 'S' : 
+		    after = FALSE;
+		    if (save_game())
+		    {
+			wclear(cw);
+			draw(cw);
+			endwin();
+			printf("\n");
+			exit(0);
+		    }
+		when '.' : ;			/* Rest command */
+		when ' ' : after = FALSE;	/* Do Nothing */
+#ifdef WIZARD
+		when CTRL('P') :
+		    after = FALSE;
+		    if (wizard)
+		    {
+			wizard = FALSE;
+			trader = 0;
+			msg("Not wizard any more");
+		    }
+		    else
+		    {
+			if (waswizard || passwd())
+			{
+			    msg("Welcome, oh mighty wizard.");
+			    wizard = waswizard = TRUE;
+			}
+			else
+			    msg("Sorry");
+		    }
+#endif
+		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;
+#ifdef WIZARD
+		    if (wizard) switch (ch)
+		    {
+			case 'M' : create_obj(TRUE, 0, 0);
+			when CTRL('W') : wanderer();
+			when CTRL('I') : inventory(lvl_obj, ALL);
+			when CTRL('Z') : whatis(NULL);
+			when CTRL('D') : level++; new_level(NORMLEV);
+			when CTRL('F') : overlay(stdscr,cw);
+			when CTRL('X') : overlay(mw,cw);
+			when CTRL('J') : teleport();
+			when CTRL('E') : sprintf(outstring,"food left: %d\tfood level: %d", 
+						food_left, foodlev);
+				       msg(outstring);
+			when CTRL('A') : activity();
+			when CTRL('C') : 
+			{
+			    int tlev;
+			    prbuf[0] = '\0';
+			    msg("Which level? ");
+			    if(get_str(prbuf,cw) == NORM) {
+				tlev = atoi(prbuf);
+				if(tlev < 1) {
+				    mpos = 0;
+				    msg("Illegal level.");
+				}
+				else if (tlev > 199) {
+					levtype = MAZELEV;
+					level = tlev - 200 + 1;
+				}
+				else if (tlev > 99) {
+					levtype = POSTLEV;
+					level = tlev - 100 + 1;
+				} 
+				else {
+					levtype = NORMLEV;
+					level = tlev;
+				}
+				new_level(levtype);
+			    }
+			}
+			when CTRL('N') :
+			{
+			    if ((item=get_item(pack, "charge", STICK)) != NULL){
+				(OBJPTR(item))->o_charges=10000;
+			    }
+			}
+			when CTRL('H') :
+			{
+			    register int i;
+			    register struct object *obj;
+
+			    for (i = 0; i < 9; i++)
+				raise_level(TRUE);
+			    /*
+			     * Give the rogue a sword 
+			     */
+			    if(cur_weapon==NULL || cur_weapon->o_type!=RELIC) {
+				item = spec_item(WEAPON, TWOSWORD, 5, 5);
+				add_pack(item, TRUE, NULL);
+				cur_weapon = OBJPTR(item);
+				cur_weapon->o_flags |= (ISKNOW | ISPROT);
+			    }
+			    /*
+			     * And his suit of armor
+			     */
+			    if (player.t_ctype == C_THIEF)
+				item = spec_item(ARMOR, STUDDED_LEATHER, 10, 0);
+			    else
+				item = spec_item(ARMOR, PLATE_ARMOR, 7, 0);
+			    obj = OBJPTR(item);
+			    obj->o_flags |= (ISKNOW | ISPROT);
+			    obj->o_weight = armors[PLATE_ARMOR].a_wght;
+			    cur_armor = obj;
+			    add_pack(item, TRUE, NULL);
+			    purse += 20000;
+			}
+			otherwise :
+			    msg("Illegal command '%s'.", unctrl(ch));
+			    count = 0;
+		    }
+		    else
+#endif
+		    {
+			msg("Illegal command '%s'.", unctrl(ch));
+			count = 0;
+			after = FALSE;
+		    }
+	    }
+	    /*
+	     * turn off flags if no longer needed
+	     */
+	    if (!running)
+		door_stop = FALSE;
+	}
+	/*
+	 * If he ran into something to take, let him pick it up.
+	 * unless its a trading post
+	 */
+	if (auto_pickup && take != 0 && levtype != POSTLEV)
+	    pick_up(take);
+	if (!running)
+	    door_stop = FALSE;
+
+	/* If after is true, mark an_after as true so that if
+	 * we are hasted, the first "after" will be noted.
+	 * if after is FALSE then stay in this loop
+	 */
+	if (after) an_after = TRUE;
+	else ntimes++;
+    }
+
+    /*
+     * Kick off the rest if the daemons and fuses
+     */
+    if (an_after)
+    {
+	/* 
+	 * If player is infested, take off a hit point 
+	 */
+	if (on(player, HASINFEST)) {
+	    if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION);
+	}
+	/* 
+	 * if player has body rot then take off five hits 
+	 */
+	if (on(player, DOROT)) {
+	     if ((pstats.s_hpt -= 5) <= 0) death(D_ROT);
+	}
+	do_daemons(AFTER);
+	do_fuses(AFTER);
+	if (!((running || count) && jump)) look(FALSE, FALSE);
+
+
+    }
+    t_free_list(monst_dead);
+}
+
+/*
+ * quit:
+ *	Have player make certain, then exit.
+ */
+
+void
+quit(int sig)
+{
+    NOOP(sig);
+
+    /*
+     * Reset the signal in case we got here via an interrupt
+     */
+    if (signal(SIGINT, &quit) != &quit)
+	mpos = 0;
+    msg("Really quit? ");
+    draw(cw);
+    if (readchar() == 'y')
+    {
+	clear();
+	move(LINES-1, 0);
+	draw(stdscr);
+	score(pstats.s_exp + (long) purse, CHICKEN, 0);
+	exit(0);
+    }
+    else
+    {
+	signal(SIGINT, quit);
+	wmove(cw, 0, 0);
+	wclrtoeol(cw);
+	status(FALSE);
+	draw(cw);
+	mpos = 0;
+	count = 0;
+	running = FALSE;
+    }
+}
+
+/*
+ * bugkill:
+ *	killed by a program bug instead of voluntarily.
+ */
+
+void
+bugkill(sig)
+int sig;
+{
+    signal(sig, quit);	/* If we get it again, give up */
+    death(D_SIGNAL);	/* Killed by a bug */
+}
+
+
+/*
+ * search:
+ *	Player gropes about him to find hidden things.
+ */
+
+search(is_thief, door_chime)
+register bool is_thief, door_chime;
+{
+    register int x, y;
+    register char ch,	/* The trap or door character */
+		 sch,	/* Trap or door character (as seen on screen) */
+		 mch;	/* Monster, if a monster is on the trap or door */
+    register struct linked_list *item;
+    register struct thing *mp; /* Status on surrounding monster */
+
+    /*
+     * Look all around the hero, if there is something hidden there,
+     * give him a chance to find it.  If its found, display it.
+     */
+    if (on(player, ISBLIND))
+	return;
+    for (x = hero.x - 1; x <= hero.x + 1; x++)
+	for (y = hero.y - 1; y <= hero.y + 1; y++)
+	{
+	    if (y==hero.y && x==hero.x)
+		continue;
+
+	    /* Mch and ch will be the same unless there is a monster here */
+	    mch = CCHAR( winat(y, x) );
+	    ch = CCHAR( mvwinch(stdscr, y, x) );
+	    sch = CCHAR( mvwinch(cw, y, x) );	/* What's on the screen */
+
+	    if (door_chime == FALSE && isatrap(ch)) {
+		    register struct trap *tp;
+
+		    /* Is there a monster on the trap? */
+		    if (mch != ch && (item = find_mons(y, x)) != NULL) {
+			mp = THINGPTR(item);
+			if (sch == mch) sch = mp->t_oldch;
+		    }
+		    else mp = NULL;
+
+		    /* 
+		     * is this one found already?
+		     */
+		    if (isatrap(sch)) 
+			continue;	/* give him chance for other traps */
+		    tp = trap_at(y, x);
+		    /* 
+		     * if the thief set it then don't display it.
+		     * if its not a thief he has 50/50 shot
+		     */
+		    if((tp->tr_flags&ISTHIEFSET) || (!is_thief && rnd(100)>50))
+			continue;	/* give him chance for other traps */
+		    tp->tr_flags |= ISFOUND;
+
+		    /* Let's update the screen */
+		    if (mp != NULL && CCHAR(mvwinch(cw, y, x)) == mch)
+			mp->t_oldch = ch; /* Will change when monst moves */
+		    else mvwaddch(cw, y, x, ch);
+
+		    count = 0;
+		    running = FALSE;
+		    msg(tr_name(tp->tr_type));
+	    }
+	    else if (ch == SECRETDOOR) {
+		if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) {
+		    /* Is there a monster on the door? */
+		    if (mch != ch && (item = find_mons(y, x)) != NULL) {
+			mp = THINGPTR(item);
+
+			/* Screen will change when monster moves */
+			if (sch == mch) mp->t_oldch = ch;
+		    }
+		    mvaddch(y, x, DOOR);
+		    count = 0;
+		}
+	    }
+	}
+}
+
+
+/*
+ * help:
+ *	Give single character help, or the whole mess if he wants it
+ */
+
+help()
+{
+    register struct h_list *strp = helpstr;
+#ifdef WIZARD
+    struct h_list *wizp = wiz_help;
+#endif
+    register char helpch;
+    register int cnt;
+
+    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) {
+		sprintf(outstring,"%s%s", unctrl(strp->h_ch), strp->h_desc);
+		msg(outstring);
+		return;
+	    }
+	    strp++;
+	}
+#ifdef WIZARD
+	if (wizard) {
+	    while (wizp->h_ch) {
+		if (wizp->h_ch == helpch) {
+		    sprintf(outstring,"%s%s", unctrl(wizp->h_ch), wizp->h_desc);
+		    msg(outstring);
+		    return;
+		}
+		wizp++;
+	    }
+	}
+#endif
+
+	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);
+	strp++;
+	if (++cnt >= 46 && strp->h_ch) {
+	    wmove(hw, LINES-1, 0);
+	    wprintw(hw, morestr);
+	    draw(hw);
+	    wait_for(hw,' ');
+	    wclear(hw);
+	    cnt = 0;
+	}
+    }
+#ifdef WIZARD
+    if (wizard) {
+	while (wizp->h_ch) {
+	    mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(wizp->h_ch));
+	    waddstr(hw, wizp->h_desc);
+	    wizp++;
+	    if (++cnt >= 46 && wizp->h_ch) {
+		wmove(hw, LINES-1, 0);
+		wprintw(hw, morestr);
+		draw(hw);
+		wait_for(hw,' ');
+		wclear(hw);
+		cnt = 0;
+	    }
+	}
+    }
+#endif
+    wmove(hw, LINES-1, 0);
+    wprintw(hw, spacemsg);
+    draw(hw);
+    wait_for(hw,' ');
+    wclear(hw);
+    draw(hw);
+    wmove(cw, 0, 0);
+    wclrtoeol(cw);
+    status(FALSE);
+    touchwin(cw);
+}
+/*
+ * identify:
+ *	Tell the player what a certain thing is.
+ */
+
+identify()
+{
+    register char ch;
+    const char *str;
+
+    msg("What do you want identified? ");
+    ch = readchar();
+    mpos = 0;
+    if (ch == ESCAPE)
+    {
+	msg("");
+	return;
+    }
+    if (isalpha(ch))
+	str = monsters[id_monst(ch)].m_name;
+    else switch(ch)
+    {
+	case '|':
+	case '-':
+	    str = (levtype == OUTSIDE) ? "boundary of sector"
+				       : "wall of a room";
+	when GOLD:	str = "gold";
+	when STAIRS :	str = (levtype == OUTSIDE) ? "entrance to a dungeon"
+						   : "passage leading down";
+	when DOOR:	str = "door";
+	when FLOOR:	str = (levtype == OUTSIDE) ? "meadow" : "room floor";
+	when VPLAYER:	str = "the hero of the game ---> you";
+	when IPLAYER:	str = "you (but invisible)";