1 | /* SCCS Id: @(#)cmd.c 3.3 2000/05/05 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 | #include "func_tab.h"
7 | /* #define DEBUG */ /* uncomment for debugging */
8 |
9 | /*
10 | * Some systems may have getchar() return EOF for various reasons, and
11 | * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
12 | */
13 | #if defined(SYSV) || defined(DGUX) || defined(HPUX)
14 | #define NR_OF_EOFS 20
15 | #endif
16 |
17 | #ifdef DEBUG
18 | /*
19 | * only one "wiz_debug_cmd" routine should be available (in whatever
20 | * module you are trying to debug) or things are going to get rather
21 | * hard to link :-)
22 | */
23 | extern void NDECL(wiz_debug_cmd);
24 | #endif
25 |
26 | #ifdef DUMB /* stuff commented out in extern.h, but needed here */
27 | extern int NDECL(doapply); /**/
28 | extern int NDECL(dorub); /**/
29 | extern int NDECL(dojump); /**/
30 | extern int NDECL(doextlist); /**/
31 | extern int NDECL(dodrop); /**/
32 | extern int NDECL(doddrop); /**/
33 | extern int NDECL(dodown); /**/
34 | extern int NDECL(doup); /**/
35 | extern int NDECL(donull); /**/
36 | extern int NDECL(dowipe); /**/
37 | extern int NDECL(do_mname); /**/
38 | extern int NDECL(ddocall); /**/
39 | extern int NDECL(dotakeoff); /**/
40 | extern int NDECL(doremring); /**/
41 | extern int NDECL(dowear); /**/
42 | extern int NDECL(doputon); /**/
43 | extern int NDECL(doddoremarm); /**/
44 | extern int NDECL(dokick); /**/
45 | extern int NDECL(dofire); /**/
46 | extern int NDECL(dothrow); /**/
47 | extern int NDECL(doeat); /**/
48 | extern int NDECL(done2); /**/
49 | extern int NDECL(doengrave); /**/
50 | extern int NDECL(dopickup); /**/
51 | extern int NDECL(ddoinv); /**/
52 | extern int NDECL(dotypeinv); /**/
53 | extern int NDECL(dolook); /**/
54 | extern int NDECL(doprgold); /**/
55 | extern int NDECL(doprwep); /**/
56 | extern int NDECL(doprarm); /**/
57 | extern int NDECL(doprring); /**/
58 | extern int NDECL(dopramulet); /**/
59 | extern int NDECL(doprtool); /**/
60 | extern int NDECL(dosuspend); /**/
61 | extern int NDECL(doforce); /**/
62 | extern int NDECL(doopen); /**/
63 | extern int NDECL(doclose); /**/
64 | extern int NDECL(dosh); /**/
65 | extern int NDECL(dodiscovered); /**/
66 | extern int NDECL(doset); /**/
67 | extern int NDECL(dotogglepickup); /**/
68 | extern int NDECL(dowhatis); /**/
69 | extern int NDECL(doquickwhatis); /**/
70 | extern int NDECL(dowhatdoes); /**/
71 | extern int NDECL(dohelp); /**/
72 | extern int NDECL(dohistory); /**/
73 | extern int NDECL(doloot); /**/
74 | extern int NDECL(dodrink); /**/
75 | extern int NDECL(dodip); /**/
76 | extern int NDECL(dosacrifice); /**/
77 | extern int NDECL(dopray); /**/
78 | extern int NDECL(doturn); /**/
79 | extern int NDECL(doredraw); /**/
80 | extern int NDECL(doread); /**/
81 | extern int NDECL(dosave); /**/
82 | extern int NDECL(dosearch); /**/
83 | extern int NDECL(doidtrap); /**/
84 | extern int NDECL(dopay); /**/
85 | extern int NDECL(dosit); /**/
86 | extern int NDECL(dotalk); /**/
87 | extern int NDECL(docast); /**/
88 | extern int NDECL(dovspell); /**/
89 | extern int NDECL(dotele); /**/
90 | extern int NDECL(dountrap); /**/
91 | extern int NDECL(doversion); /**/
92 | extern int NDECL(doextversion); /**/
93 | extern int NDECL(doswapweapon); /**/
94 | extern int NDECL(dowield); /**/
95 | extern int NDECL(dowieldquiver); /**/
96 | extern int NDECL(dozap); /**/
97 | extern int NDECL(doorganize); /**/
98 | #endif /* DUMB */
99 |
100 | #ifdef OVL1
101 | static int NDECL((*timed_occ_fn));
102 | #endif /* OVL1 */
103 |
104 | STATIC_PTR int NDECL(doprev_message);
105 | STATIC_PTR int NDECL(timed_occupation);
106 | STATIC_PTR int NDECL(doextcmd);
107 | STATIC_PTR int NDECL(domonability);
108 | # ifdef WIZARD
109 | STATIC_PTR int NDECL(wiz_wish);
110 | STATIC_PTR int NDECL(wiz_identify);
111 | STATIC_PTR int NDECL(wiz_map);
112 | STATIC_PTR int NDECL(wiz_genesis);
113 | STATIC_PTR int NDECL(wiz_where);
114 | STATIC_PTR int NDECL(wiz_detect);
115 | STATIC_PTR int NDECL(wiz_level_tele);
116 | STATIC_PTR int NDECL(wiz_show_seenv);
117 | STATIC_PTR int NDECL(wiz_show_vision);
118 | STATIC_PTR int NDECL(wiz_show_wmodes);
119 | #ifdef __BORLANDC__
120 | extern void FDECL(show_borlandc_stats, (winid));
121 | #endif
122 | STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
123 | STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
124 | STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
125 | STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
126 | STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
127 | STATIC_PTR int NDECL(wiz_show_stats);
128 | # endif
129 | STATIC_PTR int NDECL(enter_explore_mode);
130 | STATIC_PTR int NDECL(doattributes);
131 | STATIC_PTR int NDECL(doconduct); /**/
132 | STATIC_PTR void NDECL(minimal_enlightenment);
133 |
134 | #ifdef OVLB
135 | STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
136 | #ifdef UNIX
137 | static void NDECL(end_of_input);
138 | #endif
139 | #endif /* OVLB */
140 |
141 | STATIC_DCL char *NDECL(parse);
142 |
143 | #ifdef OVL1
144 |
145 | STATIC_PTR int
146 | doprev_message()
147 | {
148 | return nh_doprev_message();
149 | }
150 |
151 | /* Count down by decrementing multi */
152 | STATIC_PTR int
153 | timed_occupation()
154 | {
155 | (*timed_occ_fn)();
156 | if (multi > 0)
157 | multi--;
158 | return multi > 0;
159 | }
160 |
161 | /* If you have moved since initially setting some occupations, they
162 | * now shouldn't be able to restart.
163 | *
164 | * The basic rule is that if you are carrying it, you can continue
165 | * since it is with you. If you are acting on something at a distance,
166 | * your orientation to it must have changed when you moved.
167 | *
168 | * The exception to this is taking off items, since they can be taken
169 | * off in a number of ways in the intervening time, screwing up ordering.
170 | *
171 | * Currently: Take off all armor.
172 | * Picking Locks / Forcing Chests.
173 | * Setting traps.
174 | */
175 | void
176 | reset_occupations()
177 | {
178 | reset_remarm();
179 | reset_pick();
180 | reset_trapset();
181 | }
182 |
183 | /* If a time is given, use it to timeout this function, otherwise the
184 | * function times out by its own means.
185 | */
186 | void
187 | set_occupation(fn, txt, xtime)
188 | int NDECL((*fn));
189 | const char *txt;
190 | int xtime;
191 | {
192 | if (xtime) {
193 | occupation = timed_occupation;
194 | timed_occ_fn = fn;
195 | } else
196 | occupation = fn;
197 | occtxt = txt;
198 | occtime = 0;
199 | return;
200 | }
201 |
202 | #ifdef REDO
203 |
204 | static char NDECL(popch);
205 |
206 | /* Provide a means to redo the last command. The flag `in_doagain' is set
207 | * to true while redoing the command. This flag is tested in commands that
208 | * require additional input (like `throw' which requires a thing and a
209 | * direction), and the input prompt is not shown. Also, while in_doagain is
210 | * TRUE, no keystrokes can be saved into the saveq.
211 | */
212 | #define BSIZE 20
213 | static char pushq[BSIZE], saveq[BSIZE];
214 | static NEARDATA int phead, ptail, shead, stail;
215 |
216 | static char
217 | popch() {
218 | /* If occupied, return '\0', letting tgetch know a character should
219 | * be read from the keyboard. If the character read is not the
220 | * ABORT character (as checked in pcmain.c), that character will be
221 | * pushed back on the pushq.
222 | */
223 | if (occupation) return '\0';
224 | if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0');
225 | else return(char)((phead != ptail) ? pushq[ptail++] : '\0');
226 | }
227 |
228 | char
229 | pgetchar() { /* curtesy of aeb@cwi.nl */
230 | register int ch;
231 |
232 | if(!(ch = popch()))
233 | ch = nhgetch();
234 | return((char)ch);
235 | }
236 |
237 | /* A ch == 0 resets the pushq */
238 | void
239 | pushch(ch)
240 | char ch;
241 | {
242 | if (!ch)
243 | phead = ptail = 0;
244 | if (phead < BSIZE)
245 | pushq[phead++] = ch;
246 | return;
247 | }
248 |
249 | /* A ch == 0 resets the saveq. Only save keystrokes when not
250 | * replaying a previous command.
251 | */
252 | void
253 | savech(ch)
254 | char ch;
255 | {
256 | if (!in_doagain) {
257 | if (!ch)
258 | phead = ptail = shead = stail = 0;
259 | else if (shead < BSIZE)
260 | saveq[shead++] = ch;
261 | }
262 | return;
263 | }
264 | #endif /* REDO */
265 |
266 | #endif /* OVL1 */
267 | #ifdef OVLB
268 |
269 | STATIC_PTR int
270 | doextcmd() /* here after # - now read a full-word command */
271 | {
272 | int idx, retval;
273 |
274 | /* keep repeating until we don't run help or quit */
275 | do {
276 | idx = get_ext_cmd();
277 | if (idx < 0) return 0; /* quit */
278 |
279 | retval = (*extcmdlist[idx].ef_funct)();
280 | } while (extcmdlist[idx].ef_funct == doextlist);
281 |
282 | return retval;
283 | }
284 |
285 | int
286 | doextlist() /* here after #? - now list all full-word commands */
287 | {
288 | register const struct ext_func_tab *efp;
289 | char buf[BUFSZ];
290 | winid datawin;
291 |
292 | datawin = create_nhwindow(NHW_TEXT);
293 | putstr(datawin, 0, "");
294 | putstr(datawin, 0, " Extended Commands List");
295 | putstr(datawin, 0, "");
296 | putstr(datawin, 0, " Press '#', then type:");
297 | putstr(datawin, 0, "");
298 |
299 | for(efp = extcmdlist; efp->ef_txt; efp++) {
300 | Sprintf(buf, " %-14s - %s.", efp->ef_txt, efp->ef_desc);
301 | putstr(datawin, 0, buf);
302 | }
303 | display_nhwindow(datawin, FALSE);
304 | destroy_nhwindow(datawin);
305 | return 0;
306 | }
307 |
308 | #ifdef TTY_GRAPHICS
309 | #define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */
310 | /*
311 | * This is currently used only by the tty port and is
312 | * controlled via runtime option 'extmenu'
313 | */
314 | int
315 | extcmd_via_menu() /* here after # - now show pick-list of possible commands */
316 | {
317 | const struct ext_func_tab *efp;
318 | menu_item *pick_list = (menu_item *)0;
319 | winid win;
320 | anything any;
321 | const struct ext_func_tab *choices[MAX_EXT_CMD];
322 | char buf[BUFSZ];
323 | char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
324 | int i, n, nchoices, acount;
325 | int ret, biggest;
326 | int accelerator, prevaccelerator;
327 | int matchlevel = 0;
328 |
329 | ret = 0;
330 | cbuf[0] = '\0';
331 | biggest = 0;
332 | while (!ret) {
333 | i = n = 0;
334 | accelerator = 0;
335 | any.a_void = 0;
336 | /* populate choices */
337 | for(efp = extcmdlist; efp->ef_txt; efp++) {
338 | if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
339 | choices[i++] = efp;
340 | if ((int)strlen(efp->ef_desc) > biggest) {
341 | biggest = strlen(efp->ef_desc);
342 | Sprintf(fmtstr,"%%-%ds", biggest + 15);
343 | }
344 | #ifdef DEBUG
345 | if (i >= MAX_EXT_CMD - 2) {
346 | impossible("Exceeded %d extended commands in doextcmd() menu",
347 | MAX_EXT_CMD - 2);
348 | return 0;
349 | }
350 | #endif
351 | }
352 | }
353 | choices[i] = (struct ext_func_tab *)0;
354 | nchoices = i;
355 | /* if we're down to one, we have our selection so get out of here */
356 | if (nchoices == 1) {
357 | for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
358 | if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
359 | ret = i;
360 | break;
361 | }
362 | break;
363 | }
364 |
365 | /* otherwise... */
366 | win = create_nhwindow(NHW_MENU);
367 | start_menu(win);
368 | prevaccelerator = 0;
369 | acount = 0;
370 | for(i = 0; choices[i]; ++i) {
371 | accelerator = choices[i]->ef_txt[matchlevel];
372 | if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
373 | if (acount) {
374 | /* flush the extended commands for that letter already in buf */
375 | Sprintf(buf, fmtstr, prompt);
376 | any.a_char = prevaccelerator;
377 | add_menu(win, NO_GLYPH, &any, any.a_char, 0,
378 | ATR_NONE, buf, FALSE);
379 | acount = 0;
380 | }
381 | }
382 | prevaccelerator = accelerator;
383 | if (!acount || nchoices < (ROWNO - 3)) {
384 | Sprintf(prompt, "%s [%s]", choices[i]->ef_txt,
385 | choices[i]->ef_desc);
386 | } else if (acount == 1) {
387 | Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt,
388 | choices[i]->ef_txt);
389 | } else {
390 | Strcat(prompt," or ");
391 | Strcat(prompt, choices[i]->ef_txt);
392 | }
393 | ++acount;
394 | }
395 | if (acount) {
396 | /* flush buf */
397 | Sprintf(buf, fmtstr, prompt);
398 | any.a_char = prevaccelerator;
399 | add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE);
400 | }
401 | Sprintf(prompt, "Extended Command: %s", cbuf);
402 | end_menu(win, prompt);
403 | n = select_menu(win, PICK_ONE, &pick_list);
404 | destroy_nhwindow(win);
405 | if (n==1) {
406 | if (matchlevel > (QBUFSZ - 2)) {
407 | free((genericptr_t)pick_list);
408 | #ifdef DEBUG
409 | impossible("Too many characters (%d) entered in extcmd_via_menu()",
410 | matchlevel);
411 | #endif
412 | ret = -1;
413 | } else {
414 | cbuf[matchlevel++] = pick_list[0].item.a_char;
415 | cbuf[matchlevel] = '\0';
416 | free((genericptr_t)pick_list);
417 | }
418 | } else {
419 | if (matchlevel) {
420 | ret = 0;
421 | matchlevel = 0;
422 | } else
423 | ret = -1;
424 | }
425 | }
426 | return ret;
427 | }
428 | #endif
429 |
430 | STATIC_PTR int
431 | domonability()
432 | {
433 | if (can_breathe(youmonst.data)) return dobreathe();
434 | else if (attacktype(youmonst.data, AT_SPIT)) return dospit();
435 | else if (youmonst.data->mlet == S_NYMPH) return doremove();
436 | else if (youmonst.data->mlet == S_UMBER) return doconfuse();
437 | else if (is_were(youmonst.data)) return dosummon();
438 | else if (webmaker(youmonst.data)) return dospinweb();
439 | else if (is_hider(youmonst.data)) return dohide();
440 | else if (is_mind_flayer(youmonst.data)) return domindblast();
441 | else if (u.umonnum == PM_GREMLIN) {
442 | if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
443 | if (split_mon(&youmonst, (struct monst *)0))
444 | dryup(u.ux, u.uy, TRUE);
445 | } else There("is no fountain here.");
446 | } else if (is_unicorn(youmonst.data)) {
447 | use_unicorn_horn((struct obj *)0);
448 | return 1;
449 | } else if (youmonst.data->msound == MS_SHRIEK) {
450 | You("shriek.");
451 | if(u.uburied)
452 | pline("Unfortunately sound does not carry well through rock.");
453 | else aggravate();
454 | } else if (Upolyd)
455 | pline("Any special ability you may have is purely reflexive.");
456 | else You("don't have a special ability in your normal form!");
457 | return 0;
458 | }
459 |
460 | STATIC_PTR int
461 | enter_explore_mode()
462 | {
463 | if(!discover && !wizard) {
464 | pline("Beware! From explore mode there will be no return to normal game.");
465 | if (yn("Do you want to enter explore mode?") == 'y') {
466 | clear_nhwindow(WIN_MESSAGE);
467 | You("are now in non-scoring explore mode.");
468 | discover = TRUE;
469 | }
470 | else {
471 | clear_nhwindow(WIN_MESSAGE);
472 | pline("Resuming normal game.");
473 | }
474 | }
475 | return 0;
476 | }
477 |
478 | #ifdef WIZARD
479 | STATIC_PTR int
480 | wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */
481 | {
482 | if (wizard) {
483 | boolean save_verbose = flags.verbose;
484 |
485 | flags.verbose = FALSE;
486 | makewish();
487 | flags.verbose = save_verbose;
488 | (void) encumber_msg();
489 | } else
490 | pline("Unavailable command '^W'.");
491 | return 0;
492 | }
493 |
494 | STATIC_PTR int
495 | wiz_identify()
496 | {
497 | if (wizard) identify_pack(0);
498 | else pline("Unavailable command '^I'.");
499 | return 0;
500 | }
501 |
502 | /* reveal the level map and any traps on it */
503 | STATIC_PTR int
504 | wiz_map()
505 | {
506 | if (wizard) {
507 | struct trap *t;
508 |
509 | for (t = ftrap; t != 0; t = t->ntrap) {
510 | t->tseen = 1;
511 | map_trap(t, TRUE);
512 | }
513 | do_mapping();
514 | } else
515 | pline("Unavailable command '^F'.");
516 | return 0;
517 | }
518 |
519 | STATIC_PTR int
520 | wiz_genesis()
521 | {
522 | if (wizard) (void) create_particular();
523 | else pline("Unavailable command '^G'.");
524 | return 0;
525 | }
526 |
527 | STATIC_PTR int
528 | wiz_where()
529 | {
530 | if (wizard) print_dungeon();
531 | else pline("Unavailable command '^O'.");
532 | return 0;
533 | }
534 |
535 | STATIC_PTR int
536 | wiz_detect()
537 | {
538 | if(wizard) (void) findit();
539 | else pline("Unavailable command '^E'.");
540 | return 0;
541 | }
542 |
543 | STATIC_PTR int
544 | wiz_level_tele()
545 | {
546 | if (wizard) level_tele();
547 | else pline("Unavailable command '^V'.");
548 | return 0;
549 | }
550 |
551 | STATIC_PTR int
552 | wiz_show_seenv()
553 | {
554 | winid win;
555 | int x, y, v, startx, stopx, curx;
556 | char row[COLNO+1];
557 |
558 | win = create_nhwindow(NHW_TEXT);
559 | /*
560 | * Each seenv description takes up 2 characters, so center
561 | * the seenv display around the hero.
562 | */
563 | startx = max(1, u.ux-(COLNO/4));
564 | stopx = min(startx+(COLNO/2), COLNO);
565 | /* can't have a line exactly 80 chars long */
566 | if (stopx - startx == COLNO/2) startx++;
567 |
568 | for (y = 0; y < ROWNO; y++) {
569 | for (x = startx, curx = 0; x < stopx; x++, curx += 2) {
570 | if (x == u.ux && y == u.uy) {
571 | row[curx] = row[curx+1] = '@';
572 | } else {
573 | v = levl[x][y].seenv & 0xff;
574 | if (v == 0)
575 | row[curx] = row[curx+1] = ' ';
576 | else
577 | Sprintf(&row[curx], "%02x", v);
578 | }
579 | }
580 | /* remove trailing spaces */
581 | for (x = curx-1; x >= 0; x--)
582 | if (row[x] != ' ') break;
583 | row[x+1] = '\0';
584 |
585 | putstr(win, 0, row);
586 | }
587 | display_nhwindow(win, TRUE);
588 | destroy_nhwindow(win);
589 | return 0;
590 | }
591 |
592 | STATIC_PTR int
593 | wiz_show_vision()
594 | {
595 | winid win;
596 | int x, y, v;
597 | char row[COLNO+1];
598 |
599 | win = create_nhwindow(NHW_TEXT);
600 | Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
601 | COULD_SEE, IN_SIGHT, TEMP_LIT);
602 | putstr(win, 0, row);
603 | putstr(win, 0, "");
604 | for (y = 0; y < ROWNO; y++) {
605 | for (x = 1; x < COLNO; x++) {
606 | if (x == u.ux && y == u.uy)
607 | row[x] = '@';
608 | else {
609 | v = viz_array[y][x]; /* data access should be hidden */
610 | if (v == 0)
611 | row[x] = ' ';
612 | else
613 | row[x] = '0' + viz_array[y][x];
614 | }
615 | }
616 | /* remove trailing spaces */
617 | for (x = COLNO-1; x >= 1; x--)
618 | if (row[x] != ' ') break;
619 | row[x+1] = '\0';
620 |
621 | putstr(win, 0, &row[1]);
622 | }
623 | display_nhwindow(win, TRUE);
624 | destroy_nhwindow(win);
625 | return 0;
626 | }
627 |
628 | STATIC_PTR int
629 | wiz_show_wmodes()
630 | {
631 | winid win;
632 | int x,y;
633 | char row[COLNO+1];
634 | struct rm *lev;
635 |
636 | win = create_nhwindow(NHW_TEXT);
637 | for (y = 0; y < ROWNO; y++) {
638 | for (x = 0; x < COLNO; x++) {
639 | lev = &levl[x][y];
640 | if (x == u.ux && y == u.uy)
641 | row[x] = '@';
642 | if (IS_WALL(lev->typ) || lev->typ == SDOOR)
643 | row[x] = '0' + (lev->wall_info & WM_MASK);
644 | else if (lev->typ == CORR)
645 | row[x] = '#';
646 | else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
647 | row[x] = '.';
648 | else
649 | row[x] = 'x';
650 | }
651 | row[COLNO] = '\0';
652 | putstr(win, 0, row);
653 | }
654 | display_nhwindow(win, TRUE);
655 | destroy_nhwindow(win);
656 | return 0;
657 | }
658 |
659 | #endif /* WIZARD */
660 |
661 |
662 | /* -enlightenment and conduct- */
663 | static winid en_win;
664 | static const char
665 | *You_ = "You ",
666 | *are = "are ", *were = "were ",
667 | *have = "have ", *had = "had ",
668 | *can = "can ", *could = "could ";
669 | static const char
670 | *have_been = "have been ",
671 | *have_never = "have never ", *never = "never ";
672 |
673 | #define enl_msg(prefix,present,past,suffix) \
674 | enlght_line(prefix, final ? past : present, suffix)
675 | #define you_are(attr) enl_msg(You_,are,were,attr)
676 | #define you_have(attr) enl_msg(You_,have,had,attr)
677 | #define you_can(attr) enl_msg(You_,can,could,attr)
678 | #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing)
679 | #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing)
680 | #define you_have_X(something) enl_msg(You_,have,(const char *)"",something)
681 |
682 | static void
683 | enlght_line(start, middle, end)
684 | const char *start, *middle, *end;
685 | {
686 | char buf[BUFSZ];
687 |
688 | Sprintf(buf, "%s%s%s.", start, middle, end);
689 | putstr(en_win, 0, buf);
690 | }
691 |
692 | void
693 | enlightenment(final)
694 | int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */
695 | {
696 | int ltmp;
697 | char buf[BUFSZ];
698 |
699 | en_win = create_nhwindow(NHW_MENU);
700 | putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
701 | putstr(en_win, 0, "");
702 |
703 | #ifdef ELBERETH
704 | if (u.uevent.uhand_of_elbereth) {
705 | static const char *hofe_titles[3] = {
706 | "the Hand of Elbereth",
707 | "the Envoy of Balance",
708 | "the Glory of Arioch"
709 | };
710 | you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]);
711 | }
712 | #endif
713 |
714 | /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
715 | if (u.ualign.record >= 20) you_are("piously aligned");
716 | else if (u.ualign.record > 13) you_are("devoutly aligned");
717 | else if (u.ualign.record > 8) you_are("fervently aligned");
718 | else if (u.ualign.record > 3) you_are("stridently aligned");
719 | else if (u.ualign.record == 3) you_are("aligned");
720 | else if (u.ualign.record > 0) you_are("haltingly aligned");
721 | else if (u.ualign.record == 0) you_are("nominally aligned");
722 | else if (u.ualign.record >= -3) you_have("strayed");
723 | else if (u.ualign.record >= -8) you_have("sinned");
724 | else you_have("transgressed");
725 | #ifdef WIZARD
726 | if (wizard) {
727 | Sprintf(buf, " %d", u.ualign.record);
728 | enl_msg("Your alignment ", "is", "was", buf);
729 | }
730 | #endif
731 |
732 | /*** Resistances to troubles ***/
733 | if (Fire_resistance) you_are("fire resistant");
734 | if (Cold_resistance) you_are("cold resistant");
735 | if (Sleep_resistance) you_are("sleep resistant");
736 | if (Disint_resistance) you_are("disintegration-resistant");
737 | if (Shock_resistance) you_are("shock resistant");
738 | if (Poison_resistance) you_are("poison resistant");
739 | if (Drain_resistance) you_are("level-drain resistant");
740 | if (Sick_resistance) you_are("immune to sickness");
741 | if (Antimagic) you_are("magic-protected");
742 | if (Acid_resistance) you_are("acid resistant");
743 | if (Stone_resistance)
744 | you_are("petrification resistant");
745 | if (Invulnerable) you_are("invulnerable");
746 |
747 | /*** Troubles ***/
748 | if (Halluc_resistance)
749 | enl_msg("You resist", "", "ed", " hallucinations");
750 | if (final) {
751 | if (Hallucination) you_are("hallucinating");
752 | if (Stunned) you_are("stunned");
753 | if (Confusion) you_are("confused");
754 | if (Blinded) you_are("blinded");
755 | if (Sick) {
756 | if (u.usick_type & SICK_VOMITABLE)
757 | you_are("sick from food poisoning");
758 | if (u.usick_type & SICK_NONVOMITABLE)
759 | you_are("sick from illness");
760 | }
761 | }
762 | if (Stoned) you_are("turning to stone");
763 | if (Slimed) you_are("turning into slime");
764 | if (Strangled) you_are((u.uburied) ? "buried" : "being strangled");
765 | if (Glib) {
766 | Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
767 | you_have(buf);
768 | }
769 | if (Fumbling) enl_msg("You fumble", "", "d", "");
770 | if (Wounded_legs) {
771 | Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
772 | you_have(buf);
773 | }
774 | if (Sleeping) enl_msg("You ", "fall", "fell", " asleep");
775 | if (Hunger) enl_msg("You hunger", "", "ed", " rapidly");
776 |
777 | /*** Vision and senses ***/
778 | if (See_invisible) enl_msg(You_, "see", "saw", " invisible");
779 | if (Blind_telepat) you_are("telepathic");
780 | if (Warning) you_are("warned");
781 | if (Warn_of_mon && flags.warntype) {
782 | Sprintf(buf, "aware of the presence of %s",
783 | (flags.warntype & M2_ORC) ? "orcs" :
784 | (flags.warntype & M2_DEMON) ? "demons" :
785 | something);
786 | you_are(buf);
787 | }
788 | if (Undead_warning) you_are("warned of undead");
789 | if (Searching) you_have("automatic searching");
790 | if (Clairvoyant) you_are("clairvoyant");
791 | if (Infravision) you_have("infravision");
792 | if (Detect_monsters) you_are("sensing the presence of monsters");
793 |
794 | /*** Appearance and behavior ***/
795 | if (Adornment) you_are("adorned");
796 | if (Invisible) you_are("invisible");
797 | else if (Invis) you_are("invisible to others");
798 | /* ordinarily "visible" is redundant; this is a special case for
799 | the situation when invisibility would be an expected attribute */
800 | else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis)
801 | you_are("visible");
802 | if (Displaced) you_are("displaced");
803 | if (Stealth) you_are("stealthy");
804 | if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
805 | if (Conflict) enl_msg("You cause", "", "d", " conflict");
806 |
807 | /*** Transportation ***/
808 | if (Jumping) you_can("jump");
809 | if (Teleportation) you_can("teleport");
810 | if (Teleport_control) you_have("teleport control");
811 | if (Lev_at_will) you_are("levitating, at will");
812 | else if (Levitation) you_are("levitating"); /* without control */
813 | else if (Flying) you_can("fly");
814 | if (Wwalking) you_can("walk on water");
815 | if (Swimming) you_can("swim");
816 | if (Breathless) you_can("survive without air");
817 | else if (Amphibious) you_can("breathe water");
818 | if (Passes_walls) you_can("walk through walls");
819 | #ifdef STEED
820 | if (u.usteed) {
821 | Sprintf(buf, "riding %s", y_monnam(u.usteed));
822 | you_are(buf);
823 | }
824 | #endif
825 | if (u.uswallow) {
826 | Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
827 | #ifdef WIZARD
828 | if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
829 | #endif
830 | you_are(buf);
831 | } else if (u.ustuck) {
832 | Sprintf(buf, "%s %s",
833 | (Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
834 | a_monnam(u.ustuck));
835 | you_are(buf);
836 | }
837 |
838 | /*** Physical attributes ***/
839 | if (Slow_digestion) you_have("slower digestion");
840 | if (Regeneration) enl_msg("You regenerate", "", "d", "");
841 | if (u.uspellprot || Protection) you_are("protected");
842 | if (Protection_from_shape_changers)
843 | you_are("protected from shape changers");
844 | if (Polymorph) you_are("polymorphing");
845 | if (Polymorph_control) you_have("polymorph control");
846 | if (u.ulycn >= LOW_PM) {
847 | Strcpy(buf, an(mons[u.ulycn].mname));
848 | you_are(buf);
849 | }
850 | if (Upolyd) {
851 | if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form");
852 | else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
853 | #ifdef WIZARD
854 | if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
855 | #endif
856 | you_are(buf);
857 | }
858 | if (Unchanging) you_can("not change from your current form");
859 | if (Fast) you_are(Very_fast ? "very fast" : "fast");
860 | if (Reflecting) you_have("reflection");
861 | if (Free_action) you_have("free action");
862 | if (Fixed_abil) you_have("fixed abilities");
863 | if (Lifesaved)
864 | enl_msg("Your life ", "will be", "would have been", " saved");
865 | if (u.twoweap) you_are("wielding two weapons at once");
866 |
867 | /*** Miscellany ***/
868 | if (Luck) {
869 | ltmp = abs((int)Luck);
870 | Sprintf(buf, "%s%slucky",
871 | ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
872 | Luck < 0 ? "un" : "");
873 | #ifdef WIZARD
874 | if (wizard) Sprintf(eos(buf), " (%d)", Luck);
875 | #endif
876 | you_are(buf);
877 | }
878 | #ifdef WIZARD
879 | else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
880 | #endif
881 | if (u.moreluck > 0) you_have("extra luck");
882 | else if (u.moreluck < 0) you_have("reduced luck");
883 | if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
884 | ltmp = stone_luck(FALSE);
885 | if (ltmp <= 0)
886 | enl_msg("Bad luck ", "does", "did", " not time out for you");
887 | if (ltmp >= 0)
888 | enl_msg("Good luck ", "does", "did", " not time out for you");
889 | }
890 |
891 | if (u.ugangr) {
892 | Sprintf(buf, " %sangry with you",
893 | u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
894 | #ifdef WIZARD
895 | if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
896 | #endif
897 | enl_msg(u_gname(), " is", " was", buf);
898 | } else
899 | /*
900 | * We need to suppress this when the game is over, because death
901 | * can change the value calculated by can_pray(), potentially
902 | * resulting in a false claim that you could have prayed safely.
903 | */
904 | if (!final) {
905 | #if 0
906 | /* "can [not] safely pray" vs "could [not] have safely prayed" */
907 | Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
908 | final ? "have " : "", final ? "ed" : "");
909 | #else
910 | Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
911 | #endif
912 | #ifdef WIZARD
913 | if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
914 | #endif
915 | you_can(buf);
916 | }
917 |
918 | {
919 | const char *p;
920 |
921 | buf[0] = '\0';
922 | if (final < 2) { /* still in progress, or quit/escaped/ascended */
923 | p = "survived after being killed ";
924 | switch (u.umortality) {
925 | case 0: p = !final ? (char *)0 : "survived"; break;
926 | case 1: Strcpy(buf, "once"); break;
927 | case 2: Strcpy(buf, "twice"); break;
928 | case 3: Strcpy(buf, "thrice"); break;
929 | default: Sprintf(buf, "%d times", u.umortality);
930 | break;
931 | }
932 | } else { /* game ended in character's death */
933 | p = "are dead";
934 | switch (u.umortality) {
935 | case 0: impossible("dead without dying?");
936 | case 1: break; /* just "are dead" */
937 | default: Sprintf(buf, " (%d%s time!)", u.umortality,
938 | ordin(u.umortality));
939 | break;
940 | }
941 | }
942 | if (p) enl_msg(You_, "have been killed ", p, buf);
943 | }
944 |
945 | display_nhwindow(en_win, TRUE);
946 | destroy_nhwindow(en_win);
947 | return;
948 | }
949 |
950 | /*
951 | * Courtesy function for non-debug, non-explorer mode players
952 | * to help refresh them about who/what they are.
953 | */
954 | STATIC_OVL void
955 | minimal_enlightenment()
956 | {
957 | winid tmpwin;
958 | menu_item *selected;
959 | anything any;
960 | char buf[BUFSZ], buf2[BUFSZ];
961 | static char fmtstr[] = "%-15s: %-12s";
962 |
963 | any.a_void = 0;
964 | buf[0] = buf2[0] = '\0';
965 | tmpwin = create_nhwindow(NHW_MENU);
966 | start_menu(tmpwin);
967 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Starting", FALSE);
968 |
969 | /* Starting name, race, role, gender */
970 | Sprintf(buf, fmtstr, "name", plname);
971 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
972 | Sprintf(buf, fmtstr, "race", urace.noun);
973 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
974 | Sprintf(buf, fmtstr, "role",
975 | (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m);
976 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
977 | Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj);
978 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
979 |
980 | /* Starting alignment */
981 | Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL]));
982 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
983 |
984 | /* Current name, race, role, gender */
985 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
986 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Current", FALSE);
987 | Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun);
988 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
989 | if (!Upolyd) {
990 | Sprintf(buf, fmtstr, "role",
991 | (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
992 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
993 | }
994 | Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj);
995 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
996 |
997 | if (Upolyd) {
998 | Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
999 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1000 | }
1001 |
1002 | /* Current alignment */
1003 | Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type));
1004 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1005 |
1006 | /* Deity list */
1007 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
1008 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Deities", FALSE);
1009 | Sprintf(buf2, "%-17s%s", align_gname(A_CHAOTIC),
1010 | (u.ualignbase[A_ORIGINAL] == u.ualign.type
1011 | && u.ualign.type == A_CHAOTIC) ? " (s,c)" :
1012 | (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" :
1013 | (u.ualign.type == A_CHAOTIC) ? " (c)" : "");
1014 | Sprintf(buf, fmtstr, "chaotic deity", buf2);
1015 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1016 |
1017 | Sprintf(buf2, "%-17s%s", align_gname(A_NEUTRAL),
1018 | (u.ualignbase[A_ORIGINAL] == u.ualign.type
1019 | && u.ualign.type == A_NEUTRAL) ? " (s,c)" :
1020 | (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" :
1021 | (u.ualign.type == A_NEUTRAL) ? " (c)" : "");
1022 | Sprintf(buf, fmtstr, "neutral deity", buf2);
1023 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1024 |
1025 | Sprintf(buf2, "%-17s%s", align_gname(A_LAWFUL),
1026 | (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" :
1027 | (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" :
1028 | (u.ualign.type == A_LAWFUL) ? " (c)" : "");
1029 | Sprintf(buf, fmtstr, "lawful deity", buf2);
1030 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1031 |
1032 | end_menu(tmpwin, "Base Attributes");
1033 | (void) select_menu(tmpwin, PICK_NONE, &selected);
1034 | destroy_nhwindow(tmpwin);
1035 | }
1036 |
1037 | STATIC_PTR int
1038 | doattributes()
1039 | {
1040 | minimal_enlightenment();
1041 | if (wizard || discover)
1042 | enlightenment(0);
1043 | return 0;
1044 | }
1045 |
1046 | /* KMH, #conduct
1047 | * (shares enlightenment's tense handling)
1048 | */
1049 | STATIC_PTR int
1050 | doconduct()
1051 | {
1052 | show_conduct(0);
1053 | return 0;
1054 | }
1055 |
1056 | void
1057 | show_conduct(final)
1058 | int final;
1059 | {
1060 | char buf[BUFSZ];
1061 | int ngenocided;
1062 |
1063 | /* Create the conduct window */
1064 | en_win = create_nhwindow(NHW_MENU);
1065 | putstr(en_win, 0, "Voluntary challenges:");
1066 | putstr(en_win, 0, "");
1067 |
1068 | if (!u.uconduct.food)
1069 | enl_msg(You_, "have gone", "went", " without food");
1070 | /* But beverages are okay */
1071 | else if (!u.uconduct.unvegan)
1072 | you_have_X("followed a strict vegan diet");
1073 | else if (!u.uconduct.unvegetarian)
1074 | you_have_been("vegetarian");
1075 |
1076 | if (!u.uconduct.gnostic)
1077 | you_have_been("an atheist");
1078 |
1079 | if (!u.uconduct.weaphit)
1080 | you_have_never("hit with a wielded weapon");
1081 | #ifdef WIZARD
1082 | else if (wizard) {
1083 | Sprintf(buf, "used a wielded weapon %ld time%s",
1084 | u.uconduct.weaphit, plur(u.uconduct.weaphit));
1085 | you_have_X(buf);
1086 | }
1087 | #endif
1088 | if (!u.uconduct.killer)
1089 | you_have_been("a pacifist");
1090 |
1091 | if (!u.uconduct.literate)
1092 | you_have_been("illiterate");
1093 | #ifdef WIZARD
1094 | else if (wizard) {
1095 | Sprintf(buf, "read items or engraved %ld time%s",
1096 | u.uconduct.literate, plur(u.uconduct.literate));
1097 | you_have_X(buf);
1098 | }
1099 | #endif
1100 |
1101 | ngenocided = num_genocides();
1102 | if (ngenocided == 0) {
1103 | you_have_never("genocided any monsters");
1104 | } else {
1105 | Sprintf(buf, "genocided %d type%s of monster%s",
1106 | ngenocided, plur(ngenocided), plur(ngenocided));
1107 | you_have_X(buf);
1108 | }
1109 |
1110 | if (!u.uconduct.polypiles)
1111 | you_have_never("polymorphed an object");
1112 | #ifdef WIZARD
1113 | else if (wizard) {
1114 | Sprintf(buf, "polymorphed %ld item%s",
1115 | u.uconduct.polypiles, plur(u.uconduct.polypiles));
1116 | you_have_X(buf);
1117 | }
1118 | #endif
1119 |
1120 | if (!u.uconduct.polyselfs)
1121 | you_have_never("changed form");
1122 | #ifdef WIZARD
1123 | else if (wizard) {
1124 | Sprintf(buf, "changed form %ld time%s",
1125 | u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
1126 | you_have_X(buf);
1127 | }
1128 | #endif
1129 |
1130 | if (!u.uconduct.wishes)
1131 | you_have_X("used no wishes");
1132 | else {
1133 | Sprintf(buf, "used %ld wish%s",
1134 | u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
1135 | you_have_X(buf);
1136 |
1137 | if (!u.uconduct.wisharti)
1138 | enl_msg(You_, "have not wished", "did not wish",
1139 | " for any artifacts");
1140 | }
1141 |
1142 | /* Pop up the window and wait for a key */
1143 | display_nhwindow(en_win, TRUE);
1144 | destroy_nhwindow(en_win);
1145 | }
1146 |
1147 | #endif /* OVLB */
1148 | #ifdef OVL1
1149 |
1150 | #ifndef M
1151 | # ifndef NHSTDC
1152 | # define M(c) (0x80 | (c))
1153 | # else
1154 | # define M(c) ((c) - 128)
1155 | # endif /* NHSTDC */
1156 | #endif
1157 | #ifndef C
1158 | #define C(c) (0x1f & (c))
1159 | #endif
1160 |
1161 | static const struct func_tab cmdlist[] = {
1162 | {C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */
1163 | #ifdef WIZARD
1164 | {C('e'), TRUE, wiz_detect},
1165 | {C('f'), TRUE, wiz_map},
1166 | {C('g'), TRUE, wiz_genesis},
1167 | {C('i'), TRUE, wiz_identify},
1168 | #endif
1169 | {C('l'), TRUE, doredraw}, /* if number_pad is set */
1170 | #ifdef WIZARD
1171 | {C('o'), TRUE, wiz_where},
1172 | #endif
1173 | {C('p'), TRUE, doprev_message},
1174 | {C('r'), TRUE, doredraw},
1175 | {C('t'), TRUE, dotele},
1176 | #ifdef WIZARD
1177 | {C('v'), TRUE, wiz_level_tele},
1178 | {C('w'), TRUE, wiz_wish},
1179 | #endif
1180 | {C('x'), TRUE, doattributes},
1181 | #ifdef SUSPEND
1182 | {C('z'), TRUE, dosuspend},
1183 | #endif
1184 | {'a', FALSE, doapply},
1185 | {'A', FALSE, doddoremarm},
1186 | {M('a'), TRUE, doorganize},
1187 | /* 'b', 'B' : go sw */
1188 | {'c', FALSE, doclose},
1189 | {'C', TRUE, do_mname},
1190 | {M('c'), TRUE, dotalk},
1191 | {'d', FALSE, dodrop},
1192 | {'D', FALSE, doddrop},
1193 | {M('d'), FALSE, dodip},
1194 | {'e', FALSE, doeat},
1195 | {'E', FALSE, doengrave},
1196 | {M('e'), TRUE, enhance_weapon_skill},
1197 | {'f', FALSE, dofire},
1198 | /* 'F' : fight (one time) */
1199 | {M('f'), FALSE, doforce},
1200 | /* 'g', 'G' : multiple go */
1201 | /* 'h', 'H' : go west */
1202 | {'h', TRUE, dohelp}, /* if number_pad is set */
1203 | {'i', TRUE, ddoinv},
1204 | {'I', TRUE, dotypeinv}, /* Robert Viduya */
1205 | {M('i'), TRUE, doinvoke},
1206 | /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
1207 | {'j', FALSE, dojump}, /* if number_pad is on */
1208 | {M('j'), FALSE, dojump},
1209 | {'k', FALSE, dokick}, /* if number_pad is on */
1210 | {'l', FALSE, doloot}, /* if number_pad is on */
1211 | {M('l'), FALSE, doloot},
1212 | /* 'n' prefixes a count if number_pad is on */
1213 | {M('m'), TRUE, domonability},
1214 | {'N', TRUE, ddocall}, /* if number_pad is on */
1215 | {M('n'), TRUE, ddocall},
1216 | {M('N'), TRUE, ddocall},
1217 | {'o', FALSE, doopen},
1218 | {'O', TRUE, doset},
1219 | {M('o'), FALSE, dosacrifice},
1220 | {'p', FALSE, dopay},
1221 | {'P', FALSE, doputon},
1222 | {M('p'), TRUE, dopray},
1223 | {'q', FALSE, dodrink},
1224 | {'Q', FALSE, dowieldquiver},
1225 | {M('q'), TRUE, done2},
1226 | {'r', FALSE, doread},
1227 | {'R', FALSE, doremring},
1228 | {M('r'), FALSE, dorub},
1229 | {'s', TRUE, dosearch, "searching"},
1230 | {'S', TRUE, dosave},
1231 | {M('s'), FALSE, dosit},
1232 | {'t', FALSE, dothrow},
1233 | {'T', FALSE, dotakeoff},
1234 | {M('t'), TRUE, doturn},
1235 | /* 'u', 'U' : go ne */
1236 | {'u', FALSE, dountrap}, /* if number_pad is on */
1237 | {M('u'), FALSE, dountrap},
1238 | {'v', TRUE, doversion},
1239 | {'V', TRUE, dohistory},
1240 | {M('v'), TRUE, doextversion},
1241 | {'w', FALSE, dowield},
1242 | {'W', FALSE, dowear},
1243 | {M('w'), FALSE, dowipe},
1244 | {'x', FALSE, doswapweapon},
1245 | {'X', TRUE, enter_explore_mode},
1246 | /* 'y', 'Y' : go nw */
1247 | {'z', FALSE, dozap},
1248 | {'Z', TRUE, docast},
1249 | {'<', FALSE, doup},
1250 | {'>', FALSE, dodown},
1251 | {'/', TRUE, dowhatis},
1252 | {'&', TRUE, dowhatdoes},
1253 | {'?', TRUE, dohelp},
1254 | {M('?'), TRUE, doextlist},
1255 | #ifdef SHELL
1256 | {'!', TRUE, dosh},
1257 | #endif
1258 | {'.', TRUE, donull, "waiting"},
1259 | {' ', TRUE, donull, "waiting"},
1260 | {',', FALSE, dopickup},
1261 | {':', TRUE, dolook},
1262 | {';', TRUE, doquickwhatis},
1263 | {'^', TRUE, doidtrap},
1264 | {'\\', TRUE, dodiscovered}, /* Robert Viduya */
1265 | {'@', TRUE, dotogglepickup},
1266 | {M('2'), FALSE, dotwoweapon},
1267 | {WEAPON_SYM, TRUE, doprwep},
1268 | {ARMOR_SYM, TRUE, doprarm},
1269 | {RING_SYM, TRUE, doprring},
1270 | {AMULET_SYM, TRUE, dopramulet},
1271 | {TOOL_SYM, TRUE, doprtool},
1272 | {'*', TRUE, doprinuse}, /* inventory of all equipment in use */
1273 | {GOLD_SYM, TRUE, doprgold},
1274 | {SPBOOK_SYM, TRUE, dovspell}, /* Mike Stephenson */
1275 | {'#', TRUE, doextcmd},
1276 | {0,0,0,0}
1277 | };
1278 |
1279 | struct ext_func_tab extcmdlist[] = {
1280 | {"adjust", "adjust inventory letters", doorganize, TRUE},
1281 | {"chat", "talk to someone", dotalk, TRUE}, /* converse? */
1282 | {"conduct", "list which challenges you have adhered to", doconduct, TRUE},
1283 | {"dip", "dip an object into something", dodip, FALSE},
1284 | {"enhance", "advance or check weapons skills", enhance_weapon_skill,
1285 | TRUE},
1286 | {"force", "force a lock", doforce, FALSE},
1287 | {"invoke", "invoke an object's powers", doinvoke, TRUE},
1288 | {"jump", "jump to a location", dojump, FALSE},
1289 | {"loot", "loot a box on the floor", doloot, FALSE},
1290 | {"monster", "use a monster's special ability", domonability, TRUE},
1291 | {"name", "name an item or type of object", ddocall, TRUE},
1292 | {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE},
1293 | {"pray", "pray to the gods for help", dopray, TRUE},
1294 | {"quit", "exit without saving current game", done2, TRUE},
1295 | #ifdef STEED
1296 | {"ride", "ride (or stop riding) a monster", doride, FALSE},
1297 | #endif
1298 | {"rub", "rub a lamp", dorub, FALSE},
1299 | {"sit", "sit down", dosit, FALSE},
1300 | {"turn", "turn undead", doturn, TRUE},
1301 | {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE},
1302 | {"untrap", "untrap something", dountrap, FALSE},
1303 | {"version", "list compile time options for this version of NetHack",
1304 | doextversion, TRUE},
1305 | {"wipe", "wipe off your face", dowipe, FALSE},
1306 | {"?", "get this list of extended commands", doextlist, TRUE},
1307 | #if defined(WIZARD)
1308 | /*
1309 | * There must be a blank entry here for every entry in the table
1310 | * below.
1311 | */
1312 | {(char *)0, (char *)0, donull, TRUE},
1313 | {(char *)0, (char *)0, donull, TRUE},
1314 | {(char *)0, (char *)0, donull, TRUE},
1315 | {(char *)0, (char *)0, donull, TRUE},
1316 | {(char *)0, (char *)0, donull, TRUE},
1317 | #ifdef DEBUG
1318 | {(char *)0, (char *)0, donull, TRUE},
1319 | #endif
1320 | {(char *)0, (char *)0, donull, TRUE},
1321 | #endif
1322 | {(char *)0, (char *)0, donull, TRUE} /* sentinel */
1323 | };
1324 |
1325 | #if defined(WIZARD)
1326 | static const struct ext_func_tab debug_extcmdlist[] = {
1327 | {"light sources", "show mobile light sources", wiz_light_sources, TRUE},
1328 | {"seenv", "show seen vectors", wiz_show_seenv, TRUE},
1329 | {"stats", "show memory statistics", wiz_show_stats, TRUE},
1330 | {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
1331 | {"vision", "show vision array", wiz_show_vision, TRUE},
1332 | #ifdef DEBUG
1333 | {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
1334 | #endif
1335 | {"wmode", "show wall modes", wiz_show_wmodes, TRUE},
1336 | {(char *)0, (char *)0, donull, TRUE}
1337 | };
1338 |
1339 | /*
1340 | * Insert debug commands into the extended command list. This function
1341 | * assumes that the last entry will be the help entry.
1342 | *
1343 | * You must add entries in ext_func_tab every time you add one to the
1344 | * debug_extcmdlist().
1345 | */
1346 | void
1347 | add_debug_extended_commands()
1348 | {
1349 | int i, j, k, n;
1350 |
1351 | /* count the # of help entries */
1352 | for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
1353 | ;
1354 |
1355 | for (i = 0; debug_extcmdlist[i].ef_txt; i++) {
1356 | for (j = 0; j < n; j++)
1357 | if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break;
1358 |
1359 | /* insert i'th debug entry into extcmdlist[j], pushing down */
1360 | for (k = n; k >= j; --k)
1361 | extcmdlist[k+1] = extcmdlist[k];
1362 | extcmdlist[j] = debug_extcmdlist[i];
1363 | n++; /* now an extra entry */
1364 | }
1365 | }
1366 |
1367 |
1368 | static const char *template = "%-18s %4ld %6ld";
1369 | static const char *count_str = " count bytes";
1370 | static const char *separator = "------------------ ----- ------";
1371 |
1372 | STATIC_OVL void
1373 | count_obj(chain, total_count, total_size, top, recurse)
1374 | struct obj *chain;
1375 | long *total_count;
1376 | long *total_size;
1377 | boolean top;
1378 | boolean recurse;
1379 | {
1380 | long count, size;
1381 | struct obj *obj;
1382 |
1383 | for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
1384 | if (top) {
1385 | count++;
1386 | size += sizeof(struct obj) + obj->oxlth + obj->onamelth;
1387 | }
1388 | if (recurse && obj->cobj)
1389 | count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
1390 | }
1391 | *total_count += count;
1392 | *total_size += size;
1393 | }
1394 |
1395 | STATIC_OVL void
1396 | obj_chain(win, src, chain, total_count, total_size)
1397 | winid win;
1398 | const char *src;
1399 | struct obj *chain;
1400 | long *total_count;
1401 | long *total_size;
1402 | {
1403 | char buf[BUFSZ];
1404 | long count = 0, size = 0;
1405 |
1406 | count_obj(chain, &count, &size, TRUE, FALSE);
1407 | *total_count += count;
1408 | *total_size += size;
1409 | Sprintf(buf, template, src, count, size);
1410 | putstr(win, 0, buf);
1411 | }
1412 |
1413 | STATIC_OVL void
1414 | mon_invent_chain(win, src, chain, total_count, total_size)
1415 | winid win;
1416 | const char *src;
1417 | struct monst *chain;
1418 | long *total_count;
1419 | long *total_size;
1420 | {
1421 | char buf[BUFSZ];
1422 | long count = 0, size = 0;
1423 | struct monst *mon;
1424 |
1425 | for (mon = chain; mon; mon = mon->nmon)
1426 | count_obj(mon->minvent, &count, &size, TRUE, FALSE);
1427 | *total_count += count;
1428 | *total_size += size;
1429 | Sprintf(buf, template, src, count, size);
1430 | putstr(win, 0, buf);
1431 | }
1432 |
1433 | STATIC_OVL void
1434 | contained(win, src, total_count, total_size)
1435 | winid win;
1436 | const char *src;
1437 | long *total_count;
1438 | long *total_size;
1439 | {
1440 | char buf[BUFSZ];
1441 | long count = 0, size = 0;
1442 | struct monst *mon;
1443 |
1444 | count_obj(invent, &count, &size, FALSE, TRUE);
1445 | count_obj(fobj, &count, &size, FALSE, TRUE);
1446 | count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE);
1447 | count_obj(migrating_objs, &count, &size, FALSE, TRUE);
1448 | /* DEADMONSTER check not required in this loop since they have no inventory */
1449 | for (mon = fmon; mon; mon = mon->nmon)
1450 | count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1451 | for (mon = migrating_mons; mon; mon = mon->nmon)
1452 | count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1453 |
1454 | *total_count += count; *total_size += size;
1455 |
1456 | Sprintf(buf, template, src, count, size);
1457 | putstr(win, 0, buf);
1458 | }
1459 |
1460 | STATIC_OVL void
1461 | mon_chain(win, src, chain, total_count, total_size)
1462 | winid win;
1463 | const char *src;
1464 | struct monst *chain;
1465 | long *total_count;
1466 | long *total_size;
1467 | {
1468 | char buf[BUFSZ];
1469 | long count, size;
1470 | struct monst *mon;
1471 |
1472 | for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
1473 | count++;
1474 | size += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
1475 | }
1476 | *total_count += count;
1477 | *total_size += size;
1478 | Sprintf(buf, template, src, count, size);
1479 | putstr(win, 0, buf);
1480 | }
1481 |
1482 | /*
1483 | * Display memory usage of all monsters and objects on the level.
1484 | */
1485 | static int
1486 | wiz_show_stats()
1487 | {
1488 | char buf[BUFSZ];
1489 | winid win;
1490 | long total_obj_size = 0, total_obj_count = 0;
1491 | long total_mon_size = 0, total_mon_count = 0;
1492 |
1493 | win = create_nhwindow(NHW_TEXT);
1494 | putstr(win, 0, "Current memory statistics:");
1495 | putstr(win, 0, "");
1496 | Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
1497 | putstr(win, 0, buf);
1498 | putstr(win, 0, "");
1499 | putstr(win, 0, count_str);
1500 |
1501 | obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
1502 | obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
1503 | obj_chain(win, "buried", level.buriedobjlist,
1504 | &total_obj_count, &total_obj_size);
1505 | obj_chain(win, "migrating obj", migrating_objs,
1506 | &total_obj_count, &total_obj_size);
1507 | mon_invent_chain(win, "minvent", fmon,
1508 | &total_obj_count,&total_obj_size);
1509 | mon_invent_chain(win, "migrating minvent", migrating_mons,
1510 | &total_obj_count, &total_obj_size);
1511 |
1512 | contained(win, "contained",
1513 | &total_obj_count, &total_obj_size);
1514 |
1515 | putstr(win, 0, separator);
1516 | Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
1517 | putstr(win, 0, buf);
1518 |
1519 | putstr(win, 0, "");
1520 | putstr(win, 0, "");
1521 | Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
1522 | putstr(win, 0, buf);
1523 | putstr(win, 0, "");
1524 |
1525 | mon_chain(win, "fmon", fmon,
1526 | &total_mon_count, &total_mon_size);
1527 | mon_chain(win, "migrating", migrating_mons,
1528 | &total_mon_count, &total_mon_size);
1529 |
1530 | putstr(win, 0, separator);
1531 | Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
1532 | putstr(win, 0, buf);
1533 |
1534 | #ifdef __BORLANDC__
1535 | show_borlandc_stats(win);
1536 | #endif
1537 |
1538 | display_nhwindow(win, FALSE);
1539 | destroy_nhwindow(win);
1540 | return 0;
1541 | }
1542 |
1543 | void
1544 | sanity_check()
1545 | {
1546 | obj_sanity_check();
1547 | timer_sanity_check();
1548 | }
1549 |
1550 | #endif /* WIZARD */
1551 |
1552 | #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
1553 | #define unmeta(c) (0x7f & (c))
1554 |
1555 |
1556 | void
1557 | rhack(cmd)
1558 | register char *cmd;
1559 | {
1560 | boolean do_walk, do_rush, prefix_seen, bad_command,
1561 | firsttime = (cmd == 0);
1562 |
1563 | if (firsttime) {
1564 | flags.nopick = 0;
1565 | cmd = parse();
1566 | }
1567 | if (*cmd == '\033') {
1568 | flags.move = FALSE;
1569 | return;
1570 | }
1571 | #ifdef REDO
1572 | if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
1573 | in_doagain = TRUE;
1574 | stail = 0;
1575 | rhack((char *)0); /* read and execute command */
1576 | in_doagain = FALSE;
1577 | return;
1578 | }
1579 | /* Special case of *cmd == ' ' handled better below */
1580 | if(!*cmd || *cmd == (char)0377)
1581 | #else
1582 | if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
1583 | #endif
1584 | {
1585 | nhbell();
1586 | flags.move = FALSE;
1587 | return; /* probably we just had an interrupt */
1588 | }
1589 |
1590 | /* handle most movement commands */
1591 | do_walk = do_rush = prefix_seen = FALSE;
1592 | switch (*cmd) {
1593 | case 'g': if (movecmd(cmd[1])) {
1594 | flags.run = 2;
1595 | do_rush = TRUE;
1596 | } else
1597 | prefix_seen = TRUE;
1598 | break;
1599 | case '5': if (!iflags.num_pad) break; /* else FALLTHRU */
1600 | case 'G': if (movecmd(lowc(cmd[1]))) {
1601 | flags.run = 3;
1602 | do_rush = TRUE;
1603 | } else
1604 | prefix_seen = TRUE;
1605 | break;
1606 | case '-': if (!iflags.num_pad) break; /* else FALLTHRU */
1607 | /* Effects of movement commands and invisible monsters:
1608 | * m: always move onto space (even if 'I' remembered)
1609 | * F: always attack space (even if 'I' not remembered)
1610 | * normal movement: attack if 'I', move otherwise
1611 | */
1612 | case 'F': if (movecmd(cmd[1])) {
1613 | flags.forcefight = 1;
1614 | do_walk = TRUE;
1615 | } else
1616 | prefix_seen = TRUE;
1617 | break;
1618 | case 'm': if (movecmd(cmd[1]) || u.dz) {
1619 | flags.run = 0;
1620 | flags.nopick = 1;
1621 | if (!u.dz) do_walk = TRUE;
1622 | else cmd[0] = cmd[1]; /* "m<" or "m>" */
1623 | } else
1624 | prefix_seen = TRUE;
1625 | break;
1626 | case 'M': if (movecmd(lowc(cmd[1]))) {
1627 | flags.run = 1;
1628 | flags.nopick = 1;
1629 | do_rush = TRUE;
1630 | } else
1631 | prefix_seen = TRUE;
1632 | break;
1633 | case '0': if (!iflags.num_pad) break;
1634 | (void)ddoinv(); /* a convenience borrowed from the PC */
1635 | flags.move = FALSE;
1636 | multi = 0;
1637 | return;
1638 | default: if (movecmd(*cmd)) { /* ordinary movement */
1639 | do_walk = TRUE;
1640 | } else if (movecmd(iflags.num_pad ?
1641 | unmeta(*cmd) : lowc(*cmd))) {
1642 | flags.run = 1;
1643 | do_rush = TRUE;
1644 | } else if (movecmd(unctrl(*cmd))) {
1645 | flags.run = 3;
1646 | do_rush = TRUE;
1647 | }
1648 | break;
1649 | }
1650 | if (do_walk) {
1651 | if (multi) flags.mv = TRUE;
1652 | domove();
1653 | flags.forcefight = 0;
1654 | return;
1655 | } else if (do_rush) {
1656 | if (firsttime) {
1657 | if (!multi) multi = max(COLNO,ROWNO);
1658 | u.last_str_turn = 0;
1659 | }
1660 | flags.mv = TRUE;
1661 | domove();
1662 | return;
1663 | } else if (prefix_seen && cmd[1] == '\033') { /* <prefix><escape> */
1664 | /* don't report "unknown command" for change of heart... */
1665 | bad_command = FALSE;
1666 | } else if (*cmd == ' ' && !flags.rest_on_space) {
1667 | bad_command = TRUE; /* skip cmdlist[] loop */
1668 |
1669 | /* handle all other commands */
1670 | } else {
1671 | register const struct func_tab *tlist;
1672 | int res, NDECL((*func));
1673 |
1674 | for (tlist = cmdlist; tlist->f_char; tlist++) {
1675 | if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
1676 |
1677 | if (u.uburied && !tlist->can_if_buried) {
1678 | You_cant("do that while you are buried!");
1679 | res = 0;
1680 | } else {
1681 | /* we discard 'const' because some compilers seem to have
1682 | trouble with the pointer passed to set_occupation() */
1683 | func = ((struct func_tab *)tlist)->f_funct;
1684 | if (tlist->f_text && !occupation && multi)
1685 | set_occupation(func, tlist->f_text, multi);
1686 | res = (*func)(); /* perform the command */
1687 | }
1688 | if (!res) {
1689 | flags.move = FALSE;
1690 | multi = 0;
1691 | }
1692 | return;
1693 | }
1694 | /* if we reach here, cmd wasn't found in cmdlist[] */
1695 | bad_command = TRUE;
1696 | }
1697 |
1698 | if (bad_command) {
1699 | char expcmd[10];
1700 | register char *cp = expcmd;
1701 |
1702 | while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
1703 | if (*cmd >= 040 && *cmd < 0177) {
1704 | *cp++ = *cmd++;
1705 | } else if (*cmd & 0200) {
1706 | *cp++ = 'M';
1707 | *cp++ = '-';
1708 | *cp++ = *cmd++ &= ~0200;
1709 | } else {
1710 | *cp++ = '^';
1711 | *cp++ = *cmd++ ^ 0100;
1712 | }
1713 | }
1714 | *cp = '\0';
1715 | Norep("Unknown command '%s'.", expcmd);
1716 | }
1717 | /* didn't move */
1718 | flags.move = FALSE;
1719 | multi = 0;
1720 | return;
1721 | }
1722 |
1723 | int
1724 | xytod(x, y) /* convert an x,y pair into a direction code */
1725 | schar x, y;
1726 | {
1727 | register int dd;
1728 |
1729 | for(dd = 0; dd < 8; dd++)
1730 | if(x == xdir[dd] && y == ydir[dd]) return dd;
1731 |
1732 | return -1;
1733 | }
1734 |
1735 | void
1736 | dtoxy(cc,dd) /* convert a direction code into an x,y pair */
1737 | coord *cc;
1738 | register int dd;
1739 | {
1740 | cc->x = xdir[dd];
1741 | cc->y = ydir[dd];
1742 | return;
1743 | }
1744 |
1745 | int
1746 | movecmd(sym) /* also sets u.dz, but returns false for <> */
1747 | char sym;
1748 | {
1749 | register const char *dp;
1750 | register const char *sdp;
1751 | if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
1752 |
1753 | u.dz = 0;
1754 | if(!(dp = index(sdp, sym))) return 0;
1755 | u.dx = xdir[dp-sdp];
1756 | u.dy = ydir[dp-sdp];
1757 | u.dz = zdir[dp-sdp];
1758 | if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
1759 | u.dx = u.dy = 0;
1760 | return 0;
1761 | }
1762 | return !u.dz;
1763 | }
1764 |
1765 | int
1766 | getdir(s)
1767 | const char *s;
1768 | {
1769 | char dirsym;
1770 |
1771 | #ifdef REDO
1772 | if(in_doagain)
1773 | dirsym = readchar();
1774 | else
1775 | #endif
1776 | dirsym = yn_function (s ? s : "In what direction?",
1777 | (char *)0, '\0');
1778 | #ifdef REDO
1779 | savech(dirsym);
1780 | #endif
1781 | if(dirsym == '.' || dirsym == 's')
1782 | u.dx = u.dy = u.dz = 0;
1783 | else if(!movecmd(dirsym) && !u.dz) {
1784 | if(!index(quitchars, dirsym))
1785 | pline("What a strange direction!");
1786 | return 0;
1787 | }
1788 | if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
1789 | return 1;
1790 | }
1791 |
1792 | #endif /* OVL1 */
1793 | #ifdef OVLB
1794 |
1795 | void
1796 | confdir()
1797 | {
1798 | register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
1799 | u.dx = xdir[x];
1800 | u.dy = ydir[x];
1801 | return;
1802 | }
1803 |
1804 | #endif /* OVLB */
1805 | #ifdef OVL0
1806 |
1807 | int
1808 | isok(x,y)
1809 | register int x, y;
1810 | {
1811 | /* x corresponds to curx, so x==1 is the first column. Ach. %% */
1812 | return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
1813 | }
1814 |
1815 | static NEARDATA int last_multi;
1816 |
1817 | /*
1818 | * convert a MAP window position into a movecmd
1819 | */
1820 | int
1821 | click_to_cmd(x, y, mod)
1822 | int x, y, mod;
1823 | {
1824 | x -= u.ux;
1825 | y -= u.uy;
1826 | /* convert without using floating point, allowing sloppy clicking */
1827 | if(x > 2*abs(y))
1828 | x = 1, y = 0;
1829 | else if(y > 2*abs(x))
1830 | x = 0, y = 1;
1831 | else if(x < -2*abs(y))
1832 | x = -1, y = 0;
1833 | else if(y < -2*abs(x))
1834 | x = 0, y = -1;
1835 | else
1836 | x = sgn(x), y = sgn(y);
1837 |
1838 | if(x == 0 && y == 0) /* map click on player to "rest" command */
1839 | return '.';
1840 |
1841 | x = xytod(x, y);
1842 | if(mod == CLICK_1) {
1843 | return (iflags.num_pad ? ndir[x] : sdir[x]);
1844 | } else {
1845 | return (iflags.num_pad ? M(ndir[x]) :
1846 | (sdir[x] - 'a' + 'A')); /* run command */
1847 | }
1848 | }
1849 |
1850 | STATIC_OVL char *
1851 | parse()
1852 | {
1853 | #ifdef LINT /* static char in_line[COLNO]; */
1854 | char in_line[COLNO];
1855 | #else
1856 | static char in_line[COLNO];
1857 | #endif
1858 | register int foo;
1859 | boolean prezero = FALSE;
1860 |
1861 | multi = 0;
1862 | flags.move = 1;
1863 | flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
1864 |
1865 | if (!iflags.num_pad || (foo = readchar()) == 'n')
1866 | for (;;) {
1867 | foo = readchar();
1868 | if (foo >= '0' && foo <= '9') {
1869 | multi = 10 * multi + foo - '0';
1870 | if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
1871 | if (multi > 9) {
1872 | clear_nhwindow(WIN_MESSAGE);
1873 | Sprintf(in_line, "Count: %d", multi);
1874 | pline(in_line);
1875 | mark_synch();
1876 | }
1877 | last_multi = multi;
1878 | if (!multi && foo == '0') prezero = TRUE;
1879 | } else break; /* not a digit */
1880 | }
1881 |
1882 | if (foo == '\033') { /* esc cancels count (TH) */
1883 | clear_nhwindow(WIN_MESSAGE);
1884 | multi = last_multi = 0;
1885 | # ifdef REDO
1886 | } else if (foo == DOAGAIN || in_doagain) {
1887 | multi = last_multi;
1888 | } else {
1889 | last_multi = multi;
1890 | savech(0); /* reset input queue */
1891 | savech((char)foo);
1892 | # endif
1893 | }
1894 |
1895 | if (multi) {
1896 | multi--;
1897 | save_cm = in_line;
1898 | } else {
1899 | save_cm = (char *)0;
1900 | }
1901 | in_line[0] = foo;
1902 | in_line[1] = '\0';
1903 | if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
1904 | foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) {
1905 | foo = readchar();
1906 | #ifdef REDO
1907 | savech((char)foo);
1908 | #endif
1909 | in_line[1] = foo;
1910 | in_line[2] = 0;
1911 | }
1912 | clear_nhwindow(WIN_MESSAGE);
1913 | if (prezero) in_line[0] = '\033';
1914 | return(in_line);
1915 | }
1916 |
1917 | #endif /* OVL0 */
1918 | #ifdef OVLB
1919 |
1920 | #ifdef UNIX
1921 | static
1922 | void
1923 | end_of_input()
1924 | {
1925 | exit_nhwindows("End of input?");
1926 | #ifndef NOSAVEONHANGUP
1927 | if (!program_state.done_hup++)
1928 | (void) dosave0();
1929 | #endif
1930 | clearlocks();
1931 | terminate(EXIT_SUCCESS);
1932 | }
1933 | #endif
1934 |
1935 | #endif /* OVLB */
1936 | #ifdef OVL0
1937 |
1938 | char
1939 | readchar()
1940 | {
1941 | register int sym;
1942 | int x = u.ux, y = u.uy, mod = 0;
1943 |
1944 | #ifdef REDO
1945 | sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
1946 | #else
1947 | sym = Getchar();
1948 | #endif
1949 |
1950 | #ifdef UNIX
1951 | # ifdef NR_OF_EOFS
1952 | if (sym == EOF) {
1953 | register int cnt = NR_OF_EOFS;
1954 | /*
1955 | * Some SYSV systems seem to return EOFs for various reasons
1956 | * (?like when one hits break or for interrupted systemcalls?),
1957 | * and we must see several before we quit.
1958 | */
1959 | do {
1960 | clearerr(stdin); /* omit if clearerr is undefined */
1961 | sym = Getchar();
1962 | } while (--cnt && sym == EOF);
1963 | }
1964 | # endif /* NR_OF_EOFS */
1965 | if (sym == EOF)
1966 | end_of_input();
1967 | #endif /* UNIX */
1968 |
1969 | if(sym == 0) /* click event */
1970 | sym = click_to_cmd(x, y, mod);
1971 | return((char) sym);
1972 | }
1973 | #endif /* OVL0 */
1974 |
1975 | /*cmd.c*/