rogue

Ken Arnold's Rogue
git clone https://git.woozle.org/neale/rogue.git

Neale Pickett  ·  2013-07-18

rwrite.c

  1/*
  2 * Read and execute the user commands
  3 *
  4 * @(#)rwrite.c	4.73 (Berkeley) 08/06/83
  5 */
  6
  7#include <curses.h>
  8#include <ctype.h>
  9#include "netprot.h"
 10
 11/*
 12 * command:
 13 *	Process the user commands
 14 */
 15void
 16command(void)
 17{
 18    char ch;
 19    int ntimes = 1;			/* Number of player moves */
 20    char *fp;
 21    THING *mp;
 22    static char countch, direction, newcount = FALSE;
 23
 24    if (on(Player, ISHASTE))
 25	ntimes++;
 26    /*
 27     * Let the daemons start up
 28     */
 29    do_daemons(BEFORE);
 30    do_fuses(BEFORE);
 31    while (ntimes--)
 32    {
 33	Again = FALSE;
 34	if (Has_hit)
 35	{
 36	    endmsg();
 37	    Has_hit = FALSE;
 38	}
 39	/*
 40	 * these are illegal things for the player to be, so if any are
 41	 * set, someone's been poking in memeory
 42	 */
 43	if (on(Player, ISSLOW|ISGREED|ISINVIS|ISREGEN|ISTARGET))
 44	    exit(1);
 45
 46	look(TRUE);
 47	if (!Running)
 48	    Door_stop = FALSE;
 49	status();
 50	Lastscore = Purse;
 51	move(Hero.y, Hero.x);
 52	if (!((Running || Count) && Jump))
 53	    refresh();			/* Draw screen */
 54	Take = 0;
 55	After = TRUE;
 56	/*
 57	 * Read command or continue run
 58	 */
 59#ifdef MASTER
 60	if (Wizard)
 61	    Noscore = TRUE;
 62#endif
 63	if (!No_command)
 64	{
 65	    if (Running || To_death)
 66		ch = Runch;
 67	    else if (Count)
 68		ch = countch;
 69	    else
 70	    {
 71		ch = readchar();
 72		Move_on = FALSE;
 73		if (Mpos != 0)		/* Erase message if its there */
 74		    msg("");
 75	    }
 76	}
 77	else
 78	    ch = '.';
 79	if (No_command)
 80	{
 81	    if (--No_command == 0)
 82	    {
 83		Player.t_flags |= ISRUN;
 84		msg("you can move again");
 85	    }
 86	}
 87	else
 88	{
 89	    /*
 90	     * check for prefixes
 91	     */
 92	    newcount = FALSE;
 93	    if (isdigit(ch))
 94	    {
 95		Count = 0;
 96		newcount = TRUE;
 97		while (isdigit(ch))
 98		{
 99		    Count = Count * 10 + (ch - '0');
100		    ch = readchar();
101		}
102		countch = ch;
103		/*
104		 * turn off Count for commands which don't make sense
105		 * to repeat
106		 */
107		switch (ch)
108		{
109		    case CTRL('B'): case CTRL('H'): case CTRL('J'):
110		    case CTRL('K'): case CTRL('L'): case CTRL('N'):
111		    case CTRL('U'): case CTRL('Y'):
112		    case '.': case 'a': case 'b': case 'h': case 'j':
113		    case 'k': case 'l': case 'm': case 'n': case 'q':
114		    case 'r': case 's': case 't': case 'u': case 'y':
115		    case 'z': case 'B': case 'C': case 'H': case 'I':
116		    case 'J': case 'K': case 'L': case 'N': case 'U':
117		    case 'Y':
118#ifdef MASTER
119		    case CTRL('D'): case CTRL('A'):
120#endif
121			break;
122		    default:
123			Count = 0;
124		}
125	    }
126	    /*
127	     * execute a command
128	     */
129	    if (Count && !Running)
130		Count--;
131	    if (ch != 'a' && ch != ESCAPE && !(Running || Count || To_death))
132	    {
133		L_last_comm = Last_comm;
134		L_last_dir = Last_dir;
135		L_last_pick = Last_pick;
136		Last_comm = ch;
137		Last_dir = '\0';
138		Last_pick = NULL;
139	    }
140over:
141	    switch (ch)
142	    {
143		when ',': {
144		    THING *obj = NULL;
145		    int found = 0;
146		    for (obj = Lvl_obj; obj != NULL; obj = next(obj))
147    			{
148			    if (obj->o_pos.y == Hero.y && obj->o_pos.x == Hero.x)
149			    {
150				found=1;
151				break;
152			    }
153    			}
154
155		    if (found) {
156			if (levit_check())
157			    ;
158			else
159			    pick_up(obj->o_type);
160		    }
161		    else {
162			if (!Terse)
163			    addmsg("you are ");
164			msg("not standing on any object");
165		    }
166		}
167		when 'h': do_move(0, -1);
168		when 'j': do_move(1, 0);
169		when 'k': do_move(-1, 0);
170		when 'l': do_move(0, 1);
171		when 'y': do_move(-1, -1);
172		when 'u': do_move(-1, 1);
173		when 'b': do_move(1, -1);
174		when 'n': do_move(1, 1);
175		when 'H': do_run('h');
176		when 'J': do_run('j');
177		when 'K': do_run('k');
178		when 'L': do_run('l');
179		when 'Y': do_run('y');
180		when 'U': do_run('u');
181		when 'B': do_run('b');
182		when 'N': do_run('n');
183		when CTRL('H'): case CTRL('J'): case CTRL('K'): case CTRL('L'):
184		case CTRL('Y'): case CTRL('U'): case CTRL('B'): case CTRL('N'):
185		{
186		    if (!on(Player, ISBLIND))
187		    {
188			Door_stop = TRUE;
189			Firstmove = TRUE;
190		    }
191		    if (Count && !newcount)
192			ch = direction;
193		    else
194		    {
195			ch += ('A' - CTRL('A'));
196			direction = ch;
197		    }
198		    goto over;
199		}
200		when 'F':
201		    Kamikaze = TRUE;
202		    /* FALLTHROUGH */
203		case 'f':
204		    if (!get_dir())
205		    {
206			After = FALSE;
207			break;
208		    }
209		    Delta.y += Hero.y;
210		    Delta.x += Hero.x;
211		    if (((mp = moat(Delta.y, Delta.x)) == NULL
212			|| (!see_monst(mp)) && !on(Player, SEEMONST)))
213		    {
214			if (!Terse)
215			    addmsg("I see ");
216			msg("no monster there");
217			After = FALSE;
218		    }
219		    else if (diag_ok(&Hero, &Delta))
220		    {
221			To_death = TRUE;
222			Max_hit = 0;
223			mp->t_flags |= ISTARGET;
224			Runch = ch = Dir_ch;
225			goto over;
226		    }
227		when 't':
228		    if (!get_dir())
229			After = FALSE;
230		    else
231			missile(Delta.y, Delta.x);
232		when 'a':
233		    if (Last_comm == '\0')
234		    {
235			msg("you haven't typed a command yet");
236			After = FALSE;
237		    }
238		    else
239		    {
240			ch = Last_comm;
241			Again = TRUE;
242			goto over;
243		    }
244		when 'q': quaff();
245		when 'Q':
246		    After = FALSE;
247		    Q_comm = TRUE;
248		    quit(0);
249		    Q_comm = FALSE;
250		when 'i': After = FALSE; inventory(Pack, 0);
251		when 'I': After = FALSE; picky_inven();
252		when 'd': drop();
253		when 'r': read_scroll();
254		when 'e': eat();
255		when 'w': wield();
256		when 'W': wear();
257		when 'T': take_off();
258		when 'P': ring_on();
259		when 'R': ring_off();
260		when 'o': option(); After = FALSE;
261		when 'c': call(); After = FALSE;
262		when '>': After = FALSE; d_level();
263		when '<': After = FALSE; u_level();
264		when '?': After = FALSE; help();
265		when '/': After = FALSE; identify();
266		when 's': search();
267		when 'z':
268		    if (get_dir())
269			do_zap();
270		    else
271			After = FALSE;
272		when 'D': After = FALSE; discovered();
273		when CTRL('P'): After = FALSE; msg(Huh);
274		when CTRL('R'):
275		    After = FALSE;
276		    clearok(curscr,TRUE);
277		    wrefresh(curscr);
278		when 'v':
279		    After = FALSE;
280		    msg("version %s. (mctesq was here)", Release);
281		when 'S': 
282		    After = FALSE;
283		    save_game();
284		when '.': ;			/* Rest command */
285		when ' ': After = FALSE;	/* "Legal" illegal command */
286		when '^':
287		    After = FALSE;
288		    if (get_dir()) {
289			Delta.y += Hero.y;
290			Delta.x += Hero.x;
291			fp = &flat(Delta.y, Delta.x);
292			if (chat(Delta.y, Delta.x) != TRAP)
293			    msg("no trap there");
294			else if (on(Player, ISHALU))
295			    msg(Tr_name[rnd(NTRAPS)]);
296			else {
297			    msg(Tr_name[*fp & F_TMASK]);
298			    *fp |= F_SEEN;
299			}
300		    }
301#ifdef MASTER
302		when '+':
303		    After = FALSE;
304		    if (Wizard)
305		    {
306			Wizard = FALSE;
307			turn_see(TRUE);
308			msg("not wizard any more");
309		    }
310		    else
311		    {
312/*			if (Wizard = passwd()) */
313			if (Wizard = 1)
314			{
315			    Noscore = TRUE;
316			    turn_see(FALSE);
317			    msg("you are suddenly as smart as Ken Arnold in dungeon #%d", Dnum);
318			}
319			else
320			    msg("sorry");
321		    }
322#endif
323		when ESCAPE:	/* Escape */
324		    Door_stop = FALSE;
325		    Count = 0;
326		    After = FALSE;
327		    Again = FALSE;
328		when 'm':
329		    Move_on = TRUE;
330		    if (!get_dir())
331			After = FALSE;
332		    else
333		    {
334			ch = Dir_ch;
335			countch = Dir_ch;
336			goto over;
337		    }
338		when ')': current(Cur_weapon, "wielding", NULL);
339		when ']': current(Cur_armor, "wearing", NULL);
340		when '=':
341		    current(Cur_ring[LEFT], "wearing",
342					    Terse ? "(L)" : "on left hand");
343		    current(Cur_ring[RIGHT], "wearing",
344					    Terse ? "(R)" : "on right hand");
345		when '@':
346		    Stat_msg = TRUE;
347		    status();
348		    Stat_msg = FALSE;
349		    After = FALSE;
350		otherwise:
351		    After = FALSE;
352#ifdef MASTER
353		    if (Wizard) switch (ch)
354		    {
355			when '|': msg("@ %d,%d", Hero.y, Hero.x);
356			when 'C': create_obj();
357			when '$': msg("Inpack = %d", Inpack);
358			when CTRL('G'): inventory(Lvl_obj, 0);
359			when CTRL('W'): whatis(FALSE, 0);
360			when CTRL('D'): Level++; new_level();
361			when CTRL('A'): Level--; new_level();
362			when CTRL('F'): show_map();
363			when CTRL('T'): teleport();
364			when CTRL('E'): msg("food left: %d", Food_left);
365			when CTRL('C'): add_pass();
366			when CTRL('X'): turn_see(on(Player, SEEMONST));
367			when CTRL('~'):
368			{
369			    THING *item;
370
371			    if ((item = get_item("charge", STICK)) != NULL)
372				item->o_charges = 10000;
373			}
374			when CTRL('I'):
375			{
376			    int i;
377			    THING *obj;
378
379			    for (i = 0; i < 9; i++)
380				raise_level();
381			    /*
382			     * Give him a sword (+1,+1)
383			     */
384			    obj = new_item();
385			    init_weapon(obj, TWOSWORD);
386			    obj->o_hplus = 1;
387			    obj->o_dplus = 1;
388			    add_pack(obj, TRUE);
389			    Cur_weapon = obj;
390			    /*
391			     * And his suit of armor
392			     */
393			    obj = new_item();
394			    obj->o_type = ARMOR;
395			    obj->o_which = PLATE_MAIL;
396			    obj->o_arm = -5;
397			    obj->o_flags |= ISKNOW;
398			    obj->o_count = 1;
399			    obj->o_group = 0;
400			    Cur_armor = obj;
401			    add_pack(obj, TRUE);
402			}
403			when '*' :
404			    pr_list();
405			otherwise:
406			    illcom(ch);
407		    }
408		    else
409#endif
410			illcom(ch);
411	    }
412	    /*
413	     * turn off flags if no longer needed
414	     */
415	    if (!Running)
416		Door_stop = FALSE;
417	}
418	/*
419	 * If he ran into something to take, let him pick it up.
420	 */
421	if (Take != 0)
422	    pick_up(Take);
423	if (!Running)
424	    Door_stop = FALSE;
425	if (!After)
426	    ntimes++;
427    }
428    do_daemons(AFTER);
429    do_fuses(AFTER);
430    if (ISRING(LEFT, R_SEARCH))
431	search();
432    else if (ISRING(LEFT, R_TELEPORT) && rnd(50) == 0)
433	teleport();
434    if (ISRING(RIGHT, R_SEARCH))
435	search();
436    else if (ISRING(RIGHT, R_TELEPORT) && rnd(50) == 0)
437	teleport();
438}
439
440/*
441 * illcom:
442 *	What to do with an illegal command
443 */
444void
445illcom(char ch)
446{
447    Save_msg = FALSE;
448    Count = 0;
449    msg("illegal command '%s'", unctrl(ch));
450    Save_msg = TRUE;
451}
452
453/*
454 * search:
455 *	Player gropes about him to find hidden things.
456 */
457void
458search(void)
459{
460    int y, x;
461    char *fp;
462    int ey, ex;
463    int probinc;
464    bool found;
465
466    ey = Hero.y + 1;
467    ex = Hero.x + 1;
468    probinc  = (on(Player, ISHALU)  ? 3 : 0);
469    probinc += (on(Player, ISBLIND) ? 2 : 0);
470    found = FALSE;
471    for (y = Hero.y - 1; y <= ey; y++) 
472	for (x = Hero.x - 1; x <= ex; x++)
473	{
474	    if (y == Hero.y && x == Hero.x)
475		continue;
476	    fp = &flat(y, x);
477	    if (!(*fp & F_REAL))
478		switch (chat(y, x))
479		{
480		    case '|':
481		    case '-':
482			if (rnd(5 + probinc) != 0)
483			    break;
484			chat(y, x) = DOOR;
485foundone:
486			found = TRUE;
487			*fp |= F_REAL;
488			Count = FALSE;
489			Running = FALSE;
490			break;
491		    case FLOOR:
492			if (rnd(2 + probinc) != 0)
493			    break;
494			chat(y, x) = TRAP;
495			if (!Terse)
496			    addmsg("you found ");
497			if (on(Player, ISHALU))
498			    msg(Tr_name[rnd(NTRAPS)]);
499			else {
500			    msg(Tr_name[*fp & F_TMASK]);
501			    *fp |= F_SEEN;
502			}
503			goto foundone;
504			break;
505		    case ' ':
506			if (rnd(3 + probinc) != 0)
507			    break;
508			chat(y, x) = PASSAGE;
509			goto foundone;
510		}
511	}
512    if (found)
513	look(FALSE);
514}
515
516/*
517 * help:
518 *	Give single character help, or the whole mess if he wants it
519 */
520void
521help(void)
522{
523    struct h_list *strp;
524    char helpch;
525    unsigned int numprint, cnt;
526
527    msg("character you want help for (* for all): ");
528    helpch = readchar();
529    Mpos = 0;
530    /*
531     * If its not a *, print the right help string
532     * or an error if he typed a funny character.
533     */
534    if (helpch != '*')
535    {
536	move(0, 0);
537	for (strp = Helpstr; strp->h_desc != NULL; strp++)
538	    if (strp->h_ch == helpch)
539	    {
540		Lower_msg = TRUE;
541		msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
542		Lower_msg = FALSE;
543		return;
544	    }
545	msg("unknown character '%s'", unctrl(helpch));
546	return;
547    }
548    /*
549     * Here we print help for everything.
550     * Then wait before we return to command mode
551     */
552    numprint = 0;
553    for (strp = Helpstr; strp->h_desc != NULL; strp++)
554	if (strp->h_print)
555	    numprint++;
556    if (numprint & 01)		/* round odd numbers up */
557	numprint++;
558    numprint /= 2;
559    if (numprint > LINES - 1)
560	numprint = LINES - 1;
561
562    wclear(Hw);
563    cnt = 0;
564    for (strp = Helpstr; strp->h_desc != NULL; strp++)
565	if (strp->h_print)
566	{
567	    wmove(Hw, cnt % numprint, cnt >= numprint ? COLS / 2 : 0);
568	    if (strp->h_ch)
569		waddstr(Hw, unctrl(strp->h_ch));
570	    waddstr(Hw, strp->h_desc);
571	    if (++cnt >= numprint * 2)
572		break;
573	}
574    wmove(Hw, LINES - 1, 0);
575    waddstr(Hw, "--Press space to continue--");
576    wrefresh(Hw);
577    wait_for(' ');
578    clearok(stdscr, TRUE);
579/*
580    refresh();
581*/
582    msg("");
583    touchwin(stdscr);
584    wrefresh(stdscr);
585}
586
587/*
588 * identify:
589 *	Tell the player what a certain thing is.
590 */
591void
592identify(void)
593{
594    int ch;
595    struct h_list *hp;
596    char *str;
597    static struct h_list ident_list[] = {
598	'|',		"wall of a room",		FALSE,
599	'-',		"wall of a room",		FALSE,
600	GOLD,		"gold",				FALSE,
601	STAIRS,		"a staircase",			FALSE,
602	DOOR,		"door",				FALSE,
603	FLOOR,		"room floor",			FALSE,
604	PLAYER,		"you",				FALSE,
605	PASSAGE,	"passage",			FALSE,
606	TRAP,		"trap",				FALSE,
607	POTION,		"potion",			FALSE,
608	SCROLL,		"scroll",			FALSE,
609	FOOD,		"food",				FALSE,
610	WEAPON,		"weapon",			FALSE,
611	' ',		"solid rock",			FALSE,
612	ARMOR,		"armor",			FALSE,
613	AMULET,		"the Amulet of Yendor",		FALSE,
614	RING,		"ring",				FALSE,
615	STICK,		"wand or staff",		FALSE,
616	'\0'
617    };
618
619    msg("what do you want identified? ");
620    ch = readchar();
621    Mpos = 0;
622    if (ch == ESCAPE)
623    {
624	msg("");
625	return;
626    }
627    if (isupper(ch))
628	str = Monsters[ch-'A'].m_name;
629    else
630    {
631	str = "unknown character";
632	for (hp = ident_list; hp->h_ch != '\0'; hp++)
633	    if (hp->h_ch == ch)
634	    {
635		str = hp->h_desc;
636		break;
637	    }
638    }
639    msg("'%s': %s", unctrl(ch), str);
640}
641
642/*
643 * d_level:
644 *	He wants to go down a level
645 */
646void
647d_level(void)
648{
649    if (levit_check())
650	return;
651    if (chat(Hero.y, Hero.x) != STAIRS)
652	msg("I see no way down");
653    else
654    {
655	Level++;
656	Seenstairs = FALSE;
657	new_level();
658    }
659}
660
661/*
662 * u_level:
663 *	He wants to go up a level
664 */
665void
666u_level(void)
667{
668    if (levit_check())
669	return;
670    if (chat(Hero.y, Hero.x) == STAIRS)
671	if (Amulet)
672	{
673	    Level--;
674	    if (Level == 0)
675		total_winner();
676	    new_level();
677	    msg("you feel a wrenching sensation in your gut");
678	}
679	else
680	    msg("your way is magically blocked");
681    else
682	msg("I see no way up");
683}
684
685/*
686 * levit_check:
687 *	Check to see if she's levitating, and if she is, print an
688 *	appropriate message.
689 */
690bool
691levit_check(void)
692{
693    if (!on(Player, ISLEVIT))
694	return FALSE;
695    msg("You can't.  You're floating off the ground!");
696    return TRUE;
697}
698
699/*
700 * call:
701 *	Allow a user to call a potion, scroll, or ring something
702 */
703void
704call(void)
705{
706    THING *obj;
707    struct obj_info *op;
708    char **guess, *elsewise = NULL;
709    bool *know;
710
711    obj = get_item("call", CALLABLE);
712    /*
713     * Make certain that it is somethings that we want to wear
714     */
715    if (obj == NULL)
716	return;
717    switch (obj->o_type)
718    {
719	when RING:
720	    op = &Ring_info[obj->o_which];
721	    elsewise = R_stones[obj->o_which];
722	    goto norm;
723	when POTION:
724	    op = &Pot_info[obj->o_which];
725	    elsewise = P_colors[obj->o_which];
726	    goto norm;
727	when SCROLL:
728	    op = &Scr_info[obj->o_which];
729	    elsewise = S_names[obj->o_which];
730	    goto norm;
731	when STICK:
732	    op = &Ws_info[obj->o_which];
733	    elsewise = Ws_made[obj->o_which];
734norm:
735	    know = &op->oi_know;
736	    guess = &op->oi_guess;
737	    if (*guess != NULL)
738		elsewise = *guess;
739	when FOOD:
740	    msg("you can't call that anything");
741	    return;
742	otherwise:
743	    guess = &obj->o_label;
744	    know = NULL;
745	    elsewise = obj->o_label;
746    }
747    if (know != NULL && *know)
748    {
749	msg("that has already been identified");
750	return;
751    }
752    if (elsewise != NULL && elsewise == op->oi_guess)
753    {
754	if (!Terse)
755	    addmsg("Was ");
756	msg("called \"%s\"", elsewise);
757    }
758    if (Terse)
759	msg("call it: ");
760    else
761	msg("what do you want to call it? ");
762    if (elsewise == NULL)
763	strcpy(Prbuf, "");
764    else
765	strcpy(Prbuf, elsewise);
766    if (get_str(Prbuf, stdscr) == NORM)
767    {
768	if (*guess != NULL)
769	    free(*guess);
770	*guess = malloc((unsigned int) strlen(Prbuf) + 1);
771	strcpy(*guess, Prbuf);
772    }
773}
774
775/*
776 * current:
777 *	Print the current weapon/armor
778 */
779/* VARARGS2 */
780void
781current(THING *cur, char *how, char *where)
782{
783    After = FALSE;
784    if (cur != NULL)
785    {
786	if (!Terse)
787	    addmsg("you are %s (", how);
788	Inv_describe = FALSE;
789	addmsg("%c) %s", cur->o_packch, inv_name(cur, TRUE));
790	Inv_describe = TRUE;
791	if (where)
792	    addmsg(" %s", where);
793	endmsg();
794    }
795    else
796    {
797	if (!Terse)
798	    addmsg("you are ");
799	addmsg("%s nothing", how);
800	if (where)
801	    addmsg(" %s", where);
802	endmsg();
803    }
804}