diff arogue7/command.c @ 125:adfa37e67084

Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Fri, 08 May 2015 15:24:40 -0400
parents
children b786053d2f37
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue7/command.c	Fri May 08 15:24:40 2015 -0400
@@ -0,0 +1,1220 @@
+/*
+ * command.c  -  Read and execute the user commands
+ *
+ * Advanced Rogue
+ * Copyright (C) 1984, 1985, 1986 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.
+ */
+
+/*
+ * Read and execute the user commands
+ *
+ */
+
+#include "curses.h"
+#include <ctype.h>
+#include <signal.h>
+#include "mach_dep.h"
+#include "rogue.h"
+#ifdef PC7300
+#include "sys/window.h"
+extern struct uwdata wdata;
+#endif
+
+/*
+ * command:
+ *	Process the user commands
+ */
+
+command()
+{
+    unsigned char ch;
+    struct linked_list *item;
+    unsigned char countch, direction, newcount = FALSE;
+    int segment = 1;
+    int monst_limit, monst_current;
+
+    monst_limit = monst_current = 1;
+    while (playing) {
+	/*
+	 * Let the daemons start up, but only do them once a round
+	 * (round = 10 segments).
+	 */
+	if (segment >= 10) {
+	    do_daemons(BEFORE);
+	    do_fuses(BEFORE);
+	}
+
+	after = TRUE;
+	do {
+	    /* One more tick of the clock. */
+	    if (segment >= 10 && after && (++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);
+	    }
+
+	    /*
+	     * Don't bother with these updates unless the player's going
+	     * to do something.
+	     */
+	    if (player.t_action == A_NIL && player.t_no_move <= 1) {
+		look(after, FALSE);
+		lastscore = purse;
+		wmove(cw, hero.y, hero.x);
+		if (!((running || count) && jump)) {
+		    status(FALSE);
+		}
+	    }
+
+	    /* Draw the screen */
+	    if (!((running || count) && jump)) {
+		wmove(cw, hero.y, hero.x);
+		draw(cw);
+	    }
+
+	    after = TRUE;
+
+	    /*
+	     * Read command or continue run
+	     */
+	    if (--player.t_no_move <= 0) {
+		take = 0;		/* Nothing here to start with */
+		player.t_no_move = 0;	/* Be sure we don't go too negative */
+		if (!running) door_stop = FALSE;
+
+		/* Was the player being held? */
+		if (player.t_action == A_FREEZE) {
+		    player.t_action = A_NIL;
+		    msg("You can move again.");
+		}
+
+		if (player.t_action != A_NIL) ch = (char) player.t_action;
+		else if (running) {
+		    char scratch;
+
+		    /* If in a corridor or maze, if we are at a turn with
+		     * only one way to go, turn that way.
+		     */
+		    scratch = CCHAR( winat(hero.y, hero.x) );
+		    if ((scratch==PASSAGE||scratch==DOOR||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("");
+		}
+
+		/*
+		 * 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 C_SEARCH: case '.':
+			    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 A_PICKUP:
+			player.t_action = A_NIL;
+			if (add_pack(NULL, FALSE, NULL)) {
+			    char tch;
+
+			    tch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
+			    if (tch != FLOOR && tch != PASSAGE) {
+			        player.t_action = A_PICKUP; /*get more */
+			        player.t_no_move += 2 * movement(&player);
+			    }
+			}
+		    when A_ATTACK:
+			/* Is our attackee still there? */
+			if (isalpha(winat(player.t_newpos.y,
+					  player.t_newpos.x))) {
+			    /* Our friend is still here */
+			    player.t_action = A_NIL;
+			    fight(&player.t_newpos, cur_weapon, FALSE);
+			}
+			else {	/* Our monster has moved */
+			    player.t_action = A_NIL;
+			}
+		    when A_THROW:
+			if (player.t_action == A_NIL) {
+			    item = get_item(pack, "throw", ALL, FALSE, FALSE);
+			    if (item != NULL && get_dir(&player.t_newpos)) {
+				player.t_action = A_THROW;
+				player.t_using = item;
+				player.t_no_move = 2 * movement(&player);
+			    }
+			    else
+				after = FALSE;
+			}
+			else {
+			    missile(player.t_newpos.y, player.t_newpos.x, 
+				    player.t_using, &player);
+			    player.t_action = A_NIL;
+			    player.t_using = 0;
+			}
+		    when 'Q' : after = FALSE; quit(0);
+		    when 'i' : after = FALSE; inventory(pack, ALL);
+		    when 'I' : after = FALSE; picky_inven();
+		    when C_DROP : player.t_action = C_DROP; drop(NULL);
+		    when 'P' :
+			if (levtype != POSTLEV) {
+			    /* We charge 2 movement units per item */
+			    player.t_no_move =
+				2 * grab(hero.y, hero.x) * movement(&player);
+			}
+			else {
+			    /* Let's quote the wise guy a price */
+			    buy_it();
+			    after = FALSE;
+			}
+		    when C_COUNT : count_gold();
+		    when C_QUAFF : quaff(-1, NULL, NULL, TRUE);
+		    when C_READ : read_scroll(-1, NULL, TRUE);
+		    when C_EAT : eat();
+		    when C_WIELD : wield();
+		    when C_WEAR : wear();
+		    when C_TAKEOFF : take_off();
+		    when 'o' : option();
+		    when CTRL('N') : nameit();
+		    when '=' : after = FALSE; display();
+		    when 'm' : nameitem(NULL, TRUE);
+		    when '>' : after = FALSE; d_level();
+		    when '<' : after = FALSE; u_level();
+		    when '?' : after = FALSE; help();
+		    when '/' : after = FALSE; identify(NULL);
+		    when C_USE : use_mm(-1);
+		    when CTRL('T') :
+			if (player.t_action == A_NIL) {
+			    if (get_dir(&player.t_newpos)) {
+				player.t_action = CTRL('T');
+				player.t_no_move = 2 * movement(&player);
+			    }
+			    else
+				after = FALSE;
+			}
+			else {
+			    steal();
+			    player.t_action = A_NIL;
+			}
+		    when C_DIP : dip_it();
+		    when 'G' :
+			if (player.t_action == A_NIL) {
+			    player.t_action = 'G';
+			    player.t_no_move = movement(&player);
+			}
+			else {
+			    gsense();
+			    player.t_action = A_NIL;
+			}
+		    when C_SETTRAP : set_trap(&player, hero.y, hero.x);
+		    when C_SEARCH :
+			if (player.t_action == A_NIL) {
+			    player.t_action = C_SEARCH;
+			    player.t_no_move = 5 * movement(&player);
+			}
+			else {
+			    search(FALSE, FALSE);
+			    player.t_action = A_NIL;
+			}
+		    when C_ZAP : if (!player_zap(NULL, FALSE))
+				    after=FALSE;
+		    when C_PRAY : pray();
+		    when C_CHANT : chant();
+		    when C_CAST : cast();
+		    when 'a' :
+			if (player.t_action == A_NIL) {
+			    if (get_dir(&player.t_newpos)) {
+				player.t_action = 'a';
+				player.t_no_move = 2 * movement(&player);
+			    }
+			    else
+				after = FALSE;
+			}
+			else {
+			    affect();
+			    player.t_action = A_NIL;
+			}
+		    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();
+#ifdef PC7300
+			    endhardwin();
+#endif
+			    exit(0);
+			}
+		    when '.' :
+			player.t_no_move = movement(&player);  /* Rest */
+			player.t_action = A_NIL;
+		    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') : msg("food left: %d\tfood level: %d", 
+						    food_left, foodlev);
+			    when CTRL('A') : activity();
+			    when CTRL('C') : 
+			    {
+				int tlev;
+				prbuf[0] = 0;
+				msg("Which level? ");
+				if(get_str(prbuf,msgw) == 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('G') :
+			    {
+				item=get_item(pack,"charge",STICK,FALSE,FALSE);
+				if (item != NULL) {
+				    (OBJPTR(item))->o_charges=10000;
+				}
+			    }
+			    when CTRL('H') :
+			    {
+				register int i;
+				register struct object *obj;
+
+				for (i = 0; i < 9; i++)
+				    raise_level();
+				/*
+				 * 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);
+				    (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT);
+				}
+				/*
+				 * And his suit of armor
+				 */
+				if (player.t_ctype != C_MONK) {
+				    item = spec_item(ARMOR, PLATE_ARMOR, 10, 0);
+				    obj = OBJPTR(item);
+				    if (player.t_ctype == C_THIEF)
+				        obj->o_which = STUDDED_LEATHER;
+				    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;
+			}
+		}
+
+		/*
+		 * If he ran into something to take, let him pick it up.
+		 * unless it's a trading post
+		 */
+		if (auto_pickup && take != 0 && levtype != POSTLEV) {
+		    /* get ready to pick it up */
+		    player.t_action = A_PICKUP;
+		    player.t_no_move += 2 * movement(&player);
+		}
+	    }
+
+	    /* If he was fighting, let's stop (for now) */
+	    if (player.t_quiet < 0) player.t_quiet = 0;
+
+	    if (!running)
+		door_stop = FALSE;
+
+	    if (after && segment >= 10) {
+		/*
+		 * Kick off the rest if the daemons and fuses
+		 */
+
+		/* 
+		 * If player is infested, take off a hit point 
+		 */
+		if (on(player, HASINFEST)) {
+		    if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION);
+		}
+
+		/*
+		 * The eye of Vecna is a constant drain on the player
+		 */
+		if (cur_relic[EYE_VECNA]) {
+		    if ((--pstats.s_hpt) <= 0) death(D_RELIC);
+		}
+
+		/* 
+		 * 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);
+	    }
+	} while (after == FALSE);
+
+	/* Make the monsters go */
+	if (--monst_current <= 0)
+	    monst_current = monst_limit = runners(monst_limit);
+
+#ifdef NEEDLOOK
+	/* Shall we take a look? */
+	if (player.t_no_move <= 1 &&
+	    !((running || count) && jump))
+	    look(FALSE, FALSE);
+#endif
+
+	if (++segment > 10) segment = 1;
+	t_free_list(monst_dead);
+    }
+}
+
+/*
+ * display
+ * 	tell the player what is at a certain coordinates assuming
+ *	it can be seen.
+ */
+display()
+{
+    coord c;
+    struct linked_list *item;
+    struct thing *tp;
+    int what;
+
+    msg("What do you want to display (* for help)?");
+    c = get_coordinates();
+    mpos = 0;
+    if (!cansee(c.y, c.x)) {
+	msg("You can't see what is there.");
+	return;
+    }
+    what = mvwinch(cw, c.y, c.x);
+    if (isalpha(what)) {
+	item = find_mons(c.y, c.x);
+	tp = THINGPTR(item);
+	msg("%s", monster_name(tp));
+	return;
+    }
+    if ((item = find_obj(c.y, c.x)) != NULL) {
+	msg("%s", inv_name(OBJPTR(item), FALSE));
+	return;
+    }
+    identify(what);
+}
+
+/*
+ * quit:
+ *	Have player make certain, then exit.
+ */
+
+void
+quit(sig)
+int sig;
+{
+    /*
+     * Reset the signal in case we got here via an interrupt
+     */
+    if (signal(SIGINT, quit) != quit)
+	mpos = 0;
+    msg("Really quit? <yes or no> ");
+    draw(cw);
+    prbuf[0] = '\0';
+    if ((get_str(prbuf, msgw) == NORM) && strcmp(prbuf, "yes") == 0) {
+	clear();
+	move(lines-1, 0);
+	draw(stdscr);
+	score(pstats.s_exp + (long) purse, CHICKEN, 0);
+#ifdef PC7300
+	endhardwin();
+#endif
+	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);
+		    /*