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