1 /* NetHack 3.6 cmd.c $NHDT-Date: 1457207033 2016/03/05 19:43:53 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.220 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
10 STATIC_VAR boolean alt_esc
= FALSE
;
13 struct cmd Cmd
= { 0 }; /* flag.h */
15 extern const char *hu_stat
[]; /* hunger status from eat.c */
16 extern const char *enc_stat
[]; /* encumbrance status from botl.c */
20 * Some systems may have getchar() return EOF for various reasons, and
21 * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
23 #if defined(SYSV) || defined(DGUX) || defined(HPUX)
28 #define CMD_TRAVEL (char) 0x90
29 #define CMD_CLICKLOOK (char) 0x8F
32 extern int NDECL(wiz_debug_cmd_bury
);
33 extern int NDECL(wiz_debug_cmd_traveldisplay
);
36 #ifdef DUMB /* stuff commented out in extern.h, but needed here */
37 extern int NDECL(doapply
); /**/
38 extern int NDECL(dorub
); /**/
39 extern int NDECL(dojump
); /**/
40 extern int NDECL(doextlist
); /**/
41 extern int NDECL(enter_explore_mode
); /**/
42 extern int NDECL(dodrop
); /**/
43 extern int NDECL(doddrop
); /**/
44 extern int NDECL(dodown
); /**/
45 extern int NDECL(doup
); /**/
46 extern int NDECL(donull
); /**/
47 extern int NDECL(dowipe
); /**/
48 extern int NDECL(docallcnd
); /**/
49 extern int NDECL(dotakeoff
); /**/
50 extern int NDECL(doremring
); /**/
51 extern int NDECL(dowear
); /**/
52 extern int NDECL(doputon
); /**/
53 extern int NDECL(doddoremarm
); /**/
54 extern int NDECL(dokick
); /**/
55 extern int NDECL(dofire
); /**/
56 extern int NDECL(dothrow
); /**/
57 extern int NDECL(doeat
); /**/
58 extern int NDECL(done2
); /**/
59 extern int NDECL(vanquished
); /**/
60 extern int NDECL(doengrave
); /**/
61 extern int NDECL(dopickup
); /**/
62 extern int NDECL(ddoinv
); /**/
63 extern int NDECL(dotypeinv
); /**/
64 extern int NDECL(dolook
); /**/
65 extern int NDECL(doprgold
); /**/
66 extern int NDECL(doprwep
); /**/
67 extern int NDECL(doprarm
); /**/
68 extern int NDECL(doprring
); /**/
69 extern int NDECL(dopramulet
); /**/
70 extern int NDECL(doprtool
); /**/
71 extern int NDECL(dosuspend
); /**/
72 extern int NDECL(doforce
); /**/
73 extern int NDECL(doopen
); /**/
74 extern int NDECL(doclose
); /**/
75 extern int NDECL(dosh
); /**/
76 extern int NDECL(dodiscovered
); /**/
77 extern int NDECL(doclassdisco
); /**/
78 extern int NDECL(doset
); /**/
79 extern int NDECL(dotogglepickup
); /**/
80 extern int NDECL(dowhatis
); /**/
81 extern int NDECL(doquickwhatis
); /**/
82 extern int NDECL(dowhatdoes
); /**/
83 extern int NDECL(dohelp
); /**/
84 extern int NDECL(dohistory
); /**/
85 extern int NDECL(doloot
); /**/
86 extern int NDECL(dodrink
); /**/
87 extern int NDECL(dodip
); /**/
88 extern int NDECL(dosacrifice
); /**/
89 extern int NDECL(dopray
); /**/
90 extern int NDECL(dotip
); /**/
91 extern int NDECL(doturn
); /**/
92 extern int NDECL(doredraw
); /**/
93 extern int NDECL(doread
); /**/
94 extern int NDECL(dosave
); /**/
95 extern int NDECL(dosearch
); /**/
96 extern int NDECL(doidtrap
); /**/
97 extern int NDECL(dopay
); /**/
98 extern int NDECL(dosit
); /**/
99 extern int NDECL(dotalk
); /**/
100 extern int NDECL(docast
); /**/
101 extern int NDECL(dovspell
); /**/
102 extern int NDECL(dotele
); /**/
103 extern int NDECL(dountrap
); /**/
104 extern int NDECL(doversion
); /**/
105 extern int NDECL(doextversion
); /**/
106 extern int NDECL(doswapweapon
); /**/
107 extern int NDECL(dowield
); /**/
108 extern int NDECL(dowieldquiver
); /**/
109 extern int NDECL(dozap
); /**/
110 extern int NDECL(doorganize
); /**/
113 static int NDECL(dosuspend_core
); /**/
115 static int NDECL((*timed_occ_fn
));
117 STATIC_PTR
int NDECL(doprev_message
);
118 STATIC_PTR
int NDECL(timed_occupation
);
119 STATIC_PTR
int NDECL(doextcmd
);
120 STATIC_PTR
int NDECL(domonability
);
121 STATIC_PTR
int NDECL(dotravel
);
122 STATIC_PTR
int NDECL(doterrain
);
123 STATIC_PTR
int NDECL(wiz_wish
);
124 STATIC_PTR
int NDECL(wiz_identify
);
125 STATIC_PTR
int NDECL(wiz_intrinsic
);
126 STATIC_PTR
int NDECL(wiz_map
);
127 STATIC_PTR
int NDECL(wiz_makemap
);
128 STATIC_PTR
int NDECL(wiz_genesis
);
129 STATIC_PTR
int NDECL(wiz_where
);
130 STATIC_PTR
int NDECL(wiz_detect
);
131 STATIC_PTR
int NDECL(wiz_panic
);
132 STATIC_PTR
int NDECL(wiz_polyself
);
133 STATIC_PTR
int NDECL(wiz_level_tele
);
134 STATIC_PTR
int NDECL(wiz_level_change
);
135 STATIC_PTR
int NDECL(wiz_show_seenv
);
136 STATIC_PTR
int NDECL(wiz_show_vision
);
137 STATIC_PTR
int NDECL(wiz_smell
);
138 STATIC_PTR
int NDECL(wiz_mon_polycontrol
);
139 STATIC_PTR
int NDECL(wiz_show_wmodes
);
140 STATIC_DCL
void NDECL(wiz_map_levltyp
);
141 STATIC_DCL
void NDECL(wiz_levltyp_legend
);
142 #if defined(__BORLANDC__) && !defined(_WIN32)
143 extern void FDECL(show_borlandc_stats
, (winid
));
145 #ifdef DEBUG_MIGRATING_MONS
146 STATIC_PTR
int NDECL(wiz_migrate_mons
);
148 STATIC_DCL
int FDECL(size_monst
, (struct monst
*, BOOLEAN_P
));
149 STATIC_DCL
int FDECL(size_obj
, (struct obj
*));
150 STATIC_DCL
void FDECL(count_obj
, (struct obj
*, long *, long *,
151 BOOLEAN_P
, BOOLEAN_P
));
152 STATIC_DCL
void FDECL(obj_chain
, (winid
, const char *, struct obj
*,
153 BOOLEAN_P
, long *, long *));
154 STATIC_DCL
void FDECL(mon_invent_chain
, (winid
, const char *, struct monst
*,
156 STATIC_DCL
void FDECL(mon_chain
, (winid
, const char *, struct monst
*,
157 BOOLEAN_P
, long *, long *));
158 STATIC_DCL
void FDECL(contained_stats
, (winid
, const char *, long *, long *));
159 STATIC_DCL
void FDECL(misc_stats
, (winid
, long *, long *));
160 STATIC_PTR
int NDECL(wiz_show_stats
);
161 STATIC_DCL boolean
FDECL(accept_menu_prefix
, (int NDECL((*))));
163 STATIC_DCL
int NDECL(wiz_port_debug
);
165 STATIC_PTR
int NDECL(wiz_rumor_check
);
166 STATIC_DCL
char FDECL(cmd_from_func
, (int NDECL((*))));
167 STATIC_PTR
int NDECL(doattributes
);
168 STATIC_PTR
int NDECL(doconduct
); /**/
170 STATIC_DCL
void FDECL(enlght_line
, (const char *, const char *, const char *,
172 STATIC_DCL
char *FDECL(enlght_combatinc
, (const char *, int, int, char *));
173 STATIC_DCL
void FDECL(enlght_halfdmg
, (int, int));
174 STATIC_DCL boolean
NDECL(walking_on_water
);
175 STATIC_DCL boolean
FDECL(cause_known
, (int));
176 STATIC_DCL
char *FDECL(attrval
, (int, int, char *));
177 STATIC_DCL
void FDECL(background_enlightenment
, (int, int));
178 STATIC_DCL
void FDECL(characteristics_enlightenment
, (int, int));
179 STATIC_DCL
void FDECL(one_characteristic
, (int, int, int));
180 STATIC_DCL
void FDECL(status_enlightenment
, (int, int));
181 STATIC_DCL
void FDECL(attributes_enlightenment
, (int, int));
183 static const char *readchar_queue
= "";
184 static coord clicklook_cc
;
186 STATIC_DCL
char *NDECL(parse
);
187 STATIC_DCL
void FDECL(show_direction_keys
, (winid
, BOOLEAN_P
));
188 STATIC_DCL boolean
FDECL(help_dir
, (CHAR_P
, const char *));
191 doprev_message(VOID_ARGS
)
193 return nh_doprev_message();
196 /* Count down by decrementing multi */
198 timed_occupation(VOID_ARGS
)
206 /* If you have moved since initially setting some occupations, they
207 * now shouldn't be able to restart.
209 * The basic rule is that if you are carrying it, you can continue
210 * since it is with you. If you are acting on something at a distance,
211 * your orientation to it must have changed when you moved.
213 * The exception to this is taking off items, since they can be taken
214 * off in a number of ways in the intervening time, screwing up ordering.
216 * Currently: Take off all armor.
217 * Picking Locks / Forcing Chests.
228 /* If a time is given, use it to timeout this function, otherwise the
229 * function times out by its own means.
232 set_occupation(fn
, txt
, xtime
)
238 occupation
= timed_occupation
;
247 STATIC_DCL
char NDECL(popch
);
249 /* Provide a means to redo the last command. The flag `in_doagain' is set
250 * to true while redoing the command. This flag is tested in commands that
251 * require additional input (like `throw' which requires a thing and a
252 * direction), and the input prompt is not shown. Also, while in_doagain is
253 * TRUE, no keystrokes can be saved into the saveq.
256 static char pushq
[BSIZE
], saveq
[BSIZE
];
257 static NEARDATA
int phead
, ptail
, shead
, stail
;
262 /* If occupied, return '\0', letting tgetch know a character should
263 * be read from the keyboard. If the character read is not the
264 * ABORT character (as checked in pcmain.c), that character will be
265 * pushed back on the pushq.
270 return (char) ((shead
!= stail
) ? saveq
[stail
++] : '\0');
272 return (char) ((phead
!= ptail
) ? pushq
[ptail
++] : '\0');
276 pgetchar() /* courtesy of aeb@cwi.nl */
285 /* A ch == 0 resets the pushq */
297 /* A ch == 0 resets the saveq. Only save keystrokes when not
298 * replaying a previous command.
306 phead
= ptail
= shead
= stail
= 0;
307 else if (shead
< BSIZE
)
313 /* here after # - now read a full-word command */
320 /* keep repeating until we don't run help or quit */
326 func
= extcmdlist
[idx
].ef_funct
;
327 if (!wizard
&& (extcmdlist
[idx
].flags
& WIZMODECMD
)) {
328 You("can't do that.");
331 if (iflags
.menu_requested
&& !accept_menu_prefix(func
)) {
332 pline("'%s' prefix has no effect for the %s command.",
333 visctrl(Cmd
.spkeys
[NHKF_REQMENU
]),
334 extcmdlist
[idx
].ef_txt
);
335 iflags
.menu_requested
= FALSE
;
338 } while (func
== doextlist
);
343 /* here after #? - now list all full-word commands */
347 register const struct ext_func_tab
*efp
;
350 char ch
= cmd_from_func(doextcmd
);
352 datawin
= create_nhwindow(NHW_TEXT
);
353 putstr(datawin
, 0, "");
354 putstr(datawin
, 0, " Extended Commands List");
355 putstr(datawin
, 0, "");
357 Sprintf(buf
, " Press '%s', then type:",
359 putstr(datawin
, 0, buf
);
360 putstr(datawin
, 0, "");
363 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
364 if (!wizard
&& (efp
->flags
& WIZMODECMD
))
366 Sprintf(buf
, " %-15s %c %s.",
368 (efp
->flags
& AUTOCOMPLETE
) ? '*' : ' ',
370 putstr(datawin
, 0, buf
);
372 putstr(datawin
, 0, "");
373 putstr(datawin
, 0, " Commands marked with a * will be autocompleted.");
374 display_nhwindow(datawin
, FALSE
);
375 destroy_nhwindow(datawin
);
380 #define MAX_EXT_CMD 200 /* Change if we ever have more ext cmds */
383 * This is currently used only by the tty port and is
384 * controlled via runtime option 'extmenu'.
385 * ``# ?'' is counted towards the limit of the number of commands,
386 * so we actually support MAX_EXT_CMD-1 "real" extended commands.
388 * Here after # - now show pick-list of possible commands.
393 const struct ext_func_tab
*efp
;
394 menu_item
*pick_list
= (menu_item
*) 0;
397 const struct ext_func_tab
*choices
[MAX_EXT_CMD
+ 1];
399 char cbuf
[QBUFSZ
], prompt
[QBUFSZ
], fmtstr
[20];
400 int i
, n
, nchoices
, acount
;
402 int accelerator
, prevaccelerator
;
411 /* populate choices */
412 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
413 if (!(efp
->flags
& AUTOCOMPLETE
)
414 || (!wizard
&& (efp
->flags
& WIZMODECMD
)))
416 if (!matchlevel
|| !strncmp(efp
->ef_txt
, cbuf
, matchlevel
)) {
418 if ((int) strlen(efp
->ef_desc
) > biggest
) {
419 biggest
= strlen(efp
->ef_desc
);
420 Sprintf(fmtstr
, "%%-%ds", biggest
+ 15);
422 if (++i
> MAX_EXT_CMD
) {
425 "Exceeded %d extended commands in doextcmd() menu; 'extmenu' disabled.",
433 choices
[i
] = (struct ext_func_tab
*) 0;
435 /* if we're down to one, we have our selection so get out of here */
437 for (i
= 0; extcmdlist
[i
].ef_txt
!= (char *) 0; i
++)
438 if ((extcmdlist
[i
].flags
& AUTOCOMPLETE
)
439 && !(!wizard
&& (extcmdlist
[i
].flags
& WIZMODECMD
))
440 && !strncmpi(extcmdlist
[i
].ef_txt
, cbuf
, matchlevel
)) {
448 win
= create_nhwindow(NHW_MENU
);
450 accelerator
= prevaccelerator
= 0;
452 for (i
= 0; choices
[i
]; ++i
) {
453 accelerator
= choices
[i
]->ef_txt
[matchlevel
];
454 if (accelerator
!= prevaccelerator
|| nchoices
< (ROWNO
- 3)) {
456 /* flush extended cmds for that letter already in buf */
457 Sprintf(buf
, fmtstr
, prompt
);
458 any
.a_char
= prevaccelerator
;
459 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
,
464 prevaccelerator
= accelerator
;
465 if (!acount
|| nchoices
< (ROWNO
- 3)) {
466 Sprintf(prompt
, "%s [%s]", choices
[i
]->ef_txt
,
467 choices
[i
]->ef_desc
);
468 } else if (acount
== 1) {
469 Sprintf(prompt
, "%s or %s", choices
[i
- 1]->ef_txt
,
472 Strcat(prompt
, " or ");
473 Strcat(prompt
, choices
[i
]->ef_txt
);
479 Sprintf(buf
, fmtstr
, prompt
);
480 any
.a_char
= prevaccelerator
;
481 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
, buf
,
484 Sprintf(prompt
, "Extended Command: %s", cbuf
);
485 end_menu(win
, prompt
);
486 n
= select_menu(win
, PICK_ONE
, &pick_list
);
487 destroy_nhwindow(win
);
489 if (matchlevel
> (QBUFSZ
- 2)) {
490 free((genericptr_t
) pick_list
);
492 impossible("Too many chars (%d) entered in extcmd_via_menu()",
497 cbuf
[matchlevel
++] = pick_list
[0].item
.a_char
;
498 cbuf
[matchlevel
] = '\0';
499 free((genericptr_t
) pick_list
);
511 #endif /* TTY_GRAPHICS */
513 /* #monster command - use special monster ability while polymorphed */
515 domonability(VOID_ARGS
)
517 if (can_breathe(youmonst
.data
))
519 else if (attacktype(youmonst
.data
, AT_SPIT
))
521 else if (youmonst
.data
->mlet
== S_NYMPH
)
523 else if (attacktype(youmonst
.data
, AT_GAZE
))
525 else if (is_were(youmonst
.data
))
527 else if (webmaker(youmonst
.data
))
529 else if (is_hider(youmonst
.data
))
531 else if (is_mind_flayer(youmonst
.data
))
532 return domindblast();
533 else if (u
.umonnum
== PM_GREMLIN
) {
534 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
535 if (split_mon(&youmonst
, (struct monst
*) 0))
536 dryup(u
.ux
, u
.uy
, TRUE
);
538 There("is no fountain here.");
539 } else if (is_unicorn(youmonst
.data
)) {
540 use_unicorn_horn((struct obj
*) 0);
542 } else if (youmonst
.data
->msound
== MS_SHRIEK
) {
545 pline("Unfortunately sound does not carry well through rock.");
548 } else if (youmonst
.data
->mlet
== S_VAMPIRE
)
551 pline("Any special ability you may have is purely reflexive.");
553 You("don't have a special ability in your normal form!");
558 enter_explore_mode(VOID_ARGS
)
561 You("are in debug mode.");
562 } else if (discover
) {
563 You("are already in explore mode.");
567 if (!sysopt
.explorers
|| !sysopt
.explorers
[0]
568 || !check_user_string(sysopt
.explorers
)) {
569 You("cannot access explore mode.");
575 "Beware! From explore mode there will be no return to normal game.");
576 if (paranoid_query(ParanoidQuit
,
577 "Do you want to enter explore mode?")) {
578 clear_nhwindow(WIN_MESSAGE
);
579 You("are now in non-scoring explore mode.");
582 clear_nhwindow(WIN_MESSAGE
);
583 pline("Resuming normal game.");
589 /* ^W command - wish for something */
591 wiz_wish(VOID_ARGS
) /* Unlimited wishes for debug mode by Paul Polderman */
594 boolean save_verbose
= flags
.verbose
;
596 flags
.verbose
= FALSE
;
598 flags
.verbose
= save_verbose
;
599 (void) encumber_msg();
601 pline("Unavailable command '%s'.",
602 visctrl((int) cmd_from_func(wiz_wish
)));
606 /* ^I command - reveal and optionally identify hero's inventory */
608 wiz_identify(VOID_ARGS
)
611 iflags
.override_ID
= (int) cmd_from_func(wiz_identify
);
612 if (display_inventory((char *) 0, TRUE
) == -1)
613 identify_pack(0, FALSE
);
614 iflags
.override_ID
= 0;
616 pline("Unavailable command '%s'.",
617 visctrl((int) cmd_from_func(wiz_identify
)));
622 wiz_makemap(VOID_ARGS
)
625 savelev(-1, ledger_no(&u
.uz
), FREE_SAVE
);
629 vision_full_recalc
= 1;
630 (void) safe_teleds(TRUE
);
637 /* ^F command - reveal the level map and any traps on it */
643 long save_Hconf
= HConfusion
, save_Hhallu
= HHallucination
;
645 HConfusion
= HHallucination
= 0L;
646 for (t
= ftrap
; t
!= 0; t
= t
->ntrap
) {
651 HConfusion
= save_Hconf
;
652 HHallucination
= save_Hhallu
;
654 pline("Unavailable command '%s'.",
655 visctrl((int) cmd_from_func(wiz_map
)));
659 /* ^G command - generate monster(s); a count prefix will be honored */
661 wiz_genesis(VOID_ARGS
)
664 (void) create_particular();
666 pline("Unavailable command '%s'.",
667 visctrl((int) cmd_from_func(wiz_genesis
)));
671 /* ^O command - display dungeon layout */
676 (void) print_dungeon(FALSE
, (schar
*) 0, (xchar
*) 0);
678 pline("Unavailable command '%s'.",
679 visctrl((int) cmd_from_func(wiz_where
)));
683 /* ^E command - detect unseen (secret doors, traps, hidden monsters) */
685 wiz_detect(VOID_ARGS
)
690 pline("Unavailable command '%s'.",
691 visctrl((int) cmd_from_func(wiz_detect
)));
695 /* ^V command - level teleport */
697 wiz_level_tele(VOID_ARGS
)
702 pline("Unavailable command '%s'.",
703 visctrl((int) cmd_from_func(wiz_level_tele
)));
707 /* #monpolycontrol command - choose new form for shapechangers, polymorphees */
709 wiz_mon_polycontrol(VOID_ARGS
)
711 iflags
.mon_polycontrol
= !iflags
.mon_polycontrol
;
712 pline("Monster polymorph control is %s.",
713 iflags
.mon_polycontrol
? "on" : "off");
717 /* #levelchange command - adjust hero's experience level */
719 wiz_level_change(VOID_ARGS
)
725 getlin("To what experience level do you want to be set?", buf
);
726 (void) mungspaces(buf
);
727 if (buf
[0] == '\033' || buf
[0] == '\0')
730 ret
= sscanf(buf
, "%d", &newlevel
);
736 if (newlevel
== u
.ulevel
) {
737 You("are already that experienced.");
738 } else if (newlevel
< u
.ulevel
) {
740 You("are already as inexperienced as you can get.");
745 while (u
.ulevel
> newlevel
)
746 losexp("#levelchange");
748 if (u
.ulevel
>= MAXULEV
) {
749 You("are already as experienced as you can get.");
752 if (newlevel
> MAXULEV
)
754 while (u
.ulevel
< newlevel
)
757 u
.ulevelmax
= u
.ulevel
;
761 /* #panic command - test program's panic handling */
765 if (yn("Do you want to call panic() and end your game?") == 'y')
766 panic("Crash test.");
770 /* #polyself command - change hero's form */
772 wiz_polyself(VOID_ARGS
)
780 wiz_show_seenv(VOID_ARGS
)
783 int x
, y
, v
, startx
, stopx
, curx
;
786 win
= create_nhwindow(NHW_TEXT
);
788 * Each seenv description takes up 2 characters, so center
789 * the seenv display around the hero.
791 startx
= max(1, u
.ux
- (COLNO
/ 4));
792 stopx
= min(startx
+ (COLNO
/ 2), COLNO
);
793 /* can't have a line exactly 80 chars long */
794 if (stopx
- startx
== COLNO
/ 2)
797 for (y
= 0; y
< ROWNO
; y
++) {
798 for (x
= startx
, curx
= 0; x
< stopx
; x
++, curx
+= 2) {
799 if (x
== u
.ux
&& y
== u
.uy
) {
800 row
[curx
] = row
[curx
+ 1] = '@';
802 v
= levl
[x
][y
].seenv
& 0xff;
804 row
[curx
] = row
[curx
+ 1] = ' ';
806 Sprintf(&row
[curx
], "%02x", v
);
809 /* remove trailing spaces */
810 for (x
= curx
- 1; x
>= 0; x
--)
817 display_nhwindow(win
, TRUE
);
818 destroy_nhwindow(win
);
822 /* #vision command */
824 wiz_show_vision(VOID_ARGS
)
830 win
= create_nhwindow(NHW_TEXT
);
831 Sprintf(row
, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
832 COULD_SEE
, IN_SIGHT
, TEMP_LIT
);
835 for (y
= 0; y
< ROWNO
; y
++) {
836 for (x
= 1; x
< COLNO
; x
++) {
837 if (x
== u
.ux
&& y
== u
.uy
)
840 v
= viz_array
[y
][x
]; /* data access should be hidden */
844 row
[x
] = '0' + viz_array
[y
][x
];
847 /* remove trailing spaces */
848 for (x
= COLNO
- 1; x
>= 1; x
--)
853 putstr(win
, 0, &row
[1]);
855 display_nhwindow(win
, TRUE
);
856 destroy_nhwindow(win
);
862 wiz_show_wmodes(VOID_ARGS
)
868 boolean istty
= !strcmp(windowprocs
.name
, "tty");
870 win
= create_nhwindow(NHW_TEXT
);
872 putstr(win
, 0, ""); /* tty only: blank top line */
873 for (y
= 0; y
< ROWNO
; y
++) {
874 for (x
= 0; x
< COLNO
; x
++) {
876 if (x
== u
.ux
&& y
== u
.uy
)
878 else if (IS_WALL(lev
->typ
) || lev
->typ
== SDOOR
)
879 row
[x
] = '0' + (lev
->wall_info
& WM_MASK
);
880 else if (lev
->typ
== CORR
)
882 else if (IS_ROOM(lev
->typ
) || IS_DOOR(lev
->typ
))
888 /* map column 0, levl[0][], is off the left edge of the screen */
889 putstr(win
, 0, &row
[1]);
891 display_nhwindow(win
, TRUE
);
892 destroy_nhwindow(win
);
896 /* wizard mode variant of #terrain; internal levl[][].typ values in base-36 */
898 wiz_map_levltyp(VOID_ARGS
)
903 boolean istty
= !strcmp(windowprocs
.name
, "tty");
905 win
= create_nhwindow(NHW_TEXT
);
906 /* map row 0, levl[][0], is drawn on the second line of tty screen */
908 putstr(win
, 0, ""); /* tty only: blank top line */
909 for (y
= 0; y
< ROWNO
; y
++) {
910 /* map column 0, levl[0][], is off the left edge of the screen;
911 it should always have terrain type "undiggable stone" */
912 for (x
= 1; x
< COLNO
; x
++) {
913 terrain
= levl
[x
][y
].typ
;
914 /* assumes there aren't more than 10+26+26 terrain types */
915 row
[x
- 1] = (char) ((terrain
== STONE
&& !may_dig(x
, y
))
921 : 'A' + terrain
- 36);
924 if (levl
[0][y
].typ
!= STONE
|| may_dig(0, y
))
932 s_level
*slev
= Is_special(&u
.uz
);
934 Sprintf(dsc
, "D:%d,L:%d", u
.uz
.dnum
, u
.uz
.dlevel
);
935 /* [dungeon branch features currently omitted] */
936 /* special level features */
938 Sprintf(eos(dsc
), " \"%s\"", slev
->proto
);
939 /* special level flags (note: dungeon.def doesn't set `maze'
940 or `hell' for any specific levels so those never show up) */
941 if (slev
->flags
.maze_like
)
942 Strcat(dsc
, " mazelike");
943 if (slev
->flags
.hellish
)
944 Strcat(dsc
, " hellish");
945 if (slev
->flags
.town
)
946 Strcat(dsc
, " town");
947 if (slev
->flags
.rogue_like
)
948 Strcat(dsc
, " roguelike");
949 /* alignment currently omitted to save space */
952 if (level
.flags
.nfountains
)
953 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_fountain
].sym
,
954 (int) level
.flags
.nfountains
);
955 if (level
.flags
.nsinks
)
956 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_sink
].sym
,
957 (int) level
.flags
.nsinks
);
958 if (level
.flags
.has_vault
)
959 Strcat(dsc
, " vault");
960 if (level
.flags
.has_shop
)
961 Strcat(dsc
, " shop");
962 if (level
.flags
.has_temple
)
963 Strcat(dsc
, " temple");
964 if (level
.flags
.has_court
)
965 Strcat(dsc
, " throne");
966 if (level
.flags
.has_zoo
)
968 if (level
.flags
.has_morgue
)
969 Strcat(dsc
, " morgue");
970 if (level
.flags
.has_barracks
)
971 Strcat(dsc
, " barracks");
972 if (level
.flags
.has_beehive
)
973 Strcat(dsc
, " hive");
974 if (level
.flags
.has_swamp
)
975 Strcat(dsc
, " swamp");
977 if (level
.flags
.noteleport
)
978 Strcat(dsc
, " noTport");
979 if (level
.flags
.hardfloor
)
980 Strcat(dsc
, " noDig");
981 if (level
.flags
.nommap
)
982 Strcat(dsc
, " noMMap");
983 if (!level
.flags
.hero_memory
)
984 Strcat(dsc
, " noMem");
985 if (level
.flags
.shortsighted
)
986 Strcat(dsc
, " shortsight");
987 if (level
.flags
.graveyard
)
988 Strcat(dsc
, " graveyard");
989 if (level
.flags
.is_maze_lev
)
990 Strcat(dsc
, " maze");
991 if (level
.flags
.is_cavernous_lev
)
992 Strcat(dsc
, " cave");
993 if (level
.flags
.arboreal
)
994 Strcat(dsc
, " tree");
996 Strcat(dsc
, " sokoban-rules");
997 /* non-flag info; probably should include dungeon branching
998 checks (extra stairs and magic portals) here */
999 if (Invocation_lev(&u
.uz
))
1000 Strcat(dsc
, " invoke");
1001 if (On_W_tower_level(&u
.uz
))
1002 Strcat(dsc
, " tower");
1003 /* append a branch identifier for completeness' sake */
1005 Strcat(dsc
, " dungeon");
1006 else if (u
.uz
.dnum
== mines_dnum
)
1007 Strcat(dsc
, " mines");
1008 else if (In_sokoban(&u
.uz
))
1009 Strcat(dsc
, " sokoban");
1010 else if (u
.uz
.dnum
== quest_dnum
)
1011 Strcat(dsc
, " quest");
1012 else if (Is_knox(&u
.uz
))
1013 Strcat(dsc
, " ludios");
1014 else if (u
.uz
.dnum
== 1)
1015 Strcat(dsc
, " gehennom");
1016 else if (u
.uz
.dnum
== tower_dnum
)
1017 Strcat(dsc
, " vlad");
1018 else if (In_endgame(&u
.uz
))
1019 Strcat(dsc
, " endgame");
1021 /* somebody's added a dungeon branch we're not expecting */
1022 const char *brname
= dungeons
[u
.uz
.dnum
].dname
;
1024 if (!brname
|| !*brname
)
1026 if (!strncmpi(brname
, "the ", 4))
1028 Sprintf(eos(dsc
), " %s", brname
);
1030 /* limit the line length to map width */
1031 if (strlen(dsc
) >= COLNO
)
1032 dsc
[COLNO
- 1] = '\0'; /* truncate */
1033 putstr(win
, 0, dsc
);
1036 display_nhwindow(win
, TRUE
);
1037 destroy_nhwindow(win
);
1041 /* temporary? hack, since level type codes aren't the same as screen
1042 symbols and only the latter have easily accessible descriptions */
1043 static const char *levltyp
[] = {
1044 "stone", "vertical wall", "horizontal wall", "top-left corner wall",
1045 "top-right corner wall", "bottom-left corner wall",
1046 "bottom-right corner wall", "cross wall", "tee-up wall", "tee-down wall",
1047 "tee-left wall", "tee-right wall", "drawbridge wall", "tree",
1048 "secret door", "secret corridor", "pool", "moat", "water",
1049 "drawbridge up", "lava pool", "iron bars", "door", "corridor", "room",
1050 "stairs", "ladder", "fountain", "throne", "sink", "grave", "altar", "ice",
1051 "drawbridge down", "air", "cloud",
1052 /* not a real terrain type, but used for undiggable stone
1053 by wiz_map_levltyp() */
1054 "unreachable/undiggable",
1055 /* padding in case the number of entries above is odd */
1059 /* explanation of base-36 output from wiz_map_levltyp() */
1061 wiz_levltyp_legend(VOID_ARGS
)
1065 const char *dsc
, *fmt
;
1068 win
= create_nhwindow(NHW_TEXT
);
1069 putstr(win
, 0, "#terrain encodings:");
1071 fmt
= " %c - %-28s"; /* TODO: include tab-separated variant for win32 */
1073 /* output in pairs, left hand column holds [0],[1],...,[N/2-1]
1074 and right hand column holds [N/2],[N/2+1],...,[N-1];
1075 N ('last') will always be even, and may or may not include
1076 the empty string entry to pad out the final pair, depending
1077 upon how many other entries are present in levltyp[] */
1078 last
= SIZE(levltyp
) & ~1;
1079 for (i
= 0; i
< last
/ 2; ++i
)
1080 for (j
= i
; j
< last
; j
+= last
/ 2) {
1083 : !strncmp(dsc
, "unreachable", 11) ? '*'
1084 /* same int-to-char conversion as wiz_map_levltyp() */
1085 : (j
< 10) ? '0' + j
1086 : (j
< 36) ? 'a' + j
- 10
1088 Sprintf(eos(buf
), fmt
, c
, dsc
);
1090 putstr(win
, 0, buf
);
1094 display_nhwindow(win
, TRUE
);
1095 destroy_nhwindow(win
);
1099 /* #wizsmell command - test usmellmon(). */
1101 wiz_smell(VOID_ARGS
)
1104 int mndx
; /* monster index */
1105 coord cc
; /* screen pos of unknown glyph */
1106 int glyph
; /* glyph at selected position */
1110 mndx
= 0; /* gcc -Wall lint */
1111 if (!olfaction(youmonst
.data
)) {
1112 You("are incapable of detecting odors in your present form.");
1116 pline("You can move the cursor to a monster that you want to smell.");
1118 pline("Pick a monster to smell.");
1119 ans
= getpos(&cc
, TRUE
, "a monster");
1120 if (ans
< 0 || cc
.x
< 0) {
1121 return 0; /* done */
1123 /* Convert the glyph at the selected position to a mndxbol. */
1124 glyph
= glyph_at(cc
.x
, cc
.y
);
1125 if (glyph_is_monster(glyph
))
1126 mndx
= glyph_to_mon(glyph
);
1129 /* Is it a monster? */
1131 if (!usmellmon(&mons
[mndx
]))
1132 pline("That monster seems to give off no smell.");
1134 pline("That is not a monster.");
1139 /* #wizinstrinsic command to set some intrinsics for testing */
1141 wiz_intrinsic(VOID_ARGS
)
1146 int i
, n
, accelerator
;
1147 menu_item
*pick_list
= (menu_item
*) 0;
1149 static const char *const intrinsics
[] = {
1153 win
= create_nhwindow(NHW_MENU
);
1157 for (i
= 0; i
< SIZE(intrinsics
); ++i
) {
1158 accelerator
= intrinsics
[i
][0];
1160 add_menu(win
, NO_GLYPH
, &any
, accelerator
, 0,
1161 ATR_NONE
, intrinsics
[i
], FALSE
);
1163 end_menu(win
, "Which intrinsic?");
1164 n
= select_menu(win
, PICK_ONE
, &pick_list
);
1165 destroy_nhwindow(win
);
1168 i
= pick_list
[0].item
.a_int
-1;
1169 free((genericptr_t
) pick_list
);
1174 if (!strcmp(intrinsics
[i
], "deafness")) {
1176 incr_itimeout(&HDeaf
, 30);
1177 context
.botl
= TRUE
;
1180 pline("Unavailable command '%s'.",
1181 visctrl((int) cmd_from_func(wiz_intrinsic
)));
1185 /* #wizrumorcheck command - verify each rumor access */
1187 wiz_rumor_check(VOID_ARGS
)
1193 /* #terrain command -- show known map, inspired by crawl's '|' command */
1195 doterrain(VOID_ARGS
)
1204 * normal play: choose between known map without mons, obj, and traps
1205 * (to see underlying terrain only), or
1206 * known map without mons and objs (to see traps under mons and objs), or
1207 * known map without mons (to see objects under monsters);
1208 * explore mode: normal choices plus full map (w/o mons, objs, traps);
1209 * wizard mode: normal and explore choices plus
1210 * a dump of the internal levl[][].typ codes w/ level flags, or
1211 * a legend for the levl[][].typ codes dump
1213 men
= create_nhwindow(NHW_MENU
);
1217 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1218 "known map without monsters, objects, and traps",
1221 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1222 "known map without monsters and objects",
1225 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1226 "known map without monsters",
1228 if (discover
|| wizard
) {
1230 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1231 "full map without monsters, objects, and traps",
1235 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1236 "internal levl[][].typ codes in base-36",
1239 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1240 "legend of base-36 levl[][].typ codes",
1244 end_menu(men
, "View which?");
1246 n
= select_menu(men
, PICK_ONE
, &sel
);
1247 destroy_nhwindow(men
);
1249 * n < 0: player used ESC to cancel;
1250 * n == 0: preselected entry was explicitly chosen and got toggled off;
1251 * n == 1: preselected entry was implicitly chosen via <space>|<enter>;
1252 * n == 2: another entry was explicitly chosen, so skip preselected one.
1254 which
= (n
< 0) ? -1 : (n
== 0) ? 1 : sel
[0].item
.a_int
;
1255 if (n
> 1 && which
== 1)
1256 which
= sel
[1].item
.a_int
;
1258 free((genericptr_t
) sel
);
1261 case 1: /* known map */
1262 reveal_terrain(0, TER_MAP
);
1264 case 2: /* known map with known traps */
1265 reveal_terrain(0, TER_MAP
| TER_TRP
);
1267 case 3: /* known map with known traps and objects */
1268 reveal_terrain(0, TER_MAP
| TER_TRP
| TER_OBJ
);
1270 case 4: /* full map */
1271 reveal_terrain(1, TER_MAP
);
1273 case 5: /* map internals */
1276 case 6: /* internal details */
1277 wiz_levltyp_legend();
1282 return 0; /* no time elapses */
1285 /* -enlightenment and conduct- */
1286 static winid en_win
= WIN_ERR
;
1287 static const char You_
[] = "You ", are
[] = "are ", were
[] = "were ",
1288 have
[] = "have ", had
[] = "had ", can
[] = "can ",
1290 static const char have_been
[] = "have been ", have_never
[] = "have never ",
1293 #define enl_msg(prefix, present, past, suffix, ps) \
1294 enlght_line(prefix, final ? past : present, suffix, ps)
1295 #define you_are(attr, ps) enl_msg(You_, are, were, attr, ps)
1296 #define you_have(attr, ps) enl_msg(You_, have, had, attr, ps)
1297 #define you_can(attr, ps) enl_msg(You_, can, could, attr, ps)
1298 #define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "")
1299 #define you_have_never(badthing) \
1300 enl_msg(You_, have_never, never, badthing, "")
1301 #define you_have_X(something) \
1302 enl_msg(You_, have, (const char *) "", something, "")
1305 enlght_line(start
, middle
, end
, ps
)
1306 const char *start
, *middle
, *end
, *ps
;
1310 Sprintf(buf
, " %s%s%s%s.", start
, middle
, end
, ps
);
1311 putstr(en_win
, 0, buf
);
1314 /* format increased chance to hit or damage or defense (Protection) */
1316 enlght_combatinc(inctyp
, incamt
, final
, outbuf
)
1321 const char *modif
, *bonus
;
1325 absamt
= abs(incamt
);
1326 /* Protection amount is typically larger than damage or to-hit;
1327 reduce magnitude by a third in order to stretch modifier ranges
1328 (small:1..5, moderate:6..10, large:11..19, huge:20+) */
1329 if (!strcmp(inctyp
, "defense"))
1330 absamt
= (absamt
* 2) / 3;
1334 else if (absamt
<= 6)
1336 else if (absamt
<= 12)
1341 modif
= !incamt
? "no" : an(modif
); /* ("no" case shouldn't happen) */
1342 bonus
= (incamt
>= 0) ? "bonus" : "penalty";
1343 /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
1344 invrt
= strcmp(inctyp
, "to hit") ? TRUE
: FALSE
;
1346 Sprintf(outbuf
, "%s %s %s", modif
, invrt
? inctyp
: bonus
,
1347 invrt
? bonus
: inctyp
);
1348 if (final
|| wizard
)
1349 Sprintf(eos(outbuf
), " (%s%d)", (incamt
> 0) ? "+" : "", incamt
);
1354 /* report half physical or half spell damage */
1356 enlght_halfdmg(category
, final
)
1360 const char *category_name
;
1365 category_name
= "physical";
1368 category_name
= "spell";
1371 category_name
= "unknown";
1374 Sprintf(buf
, " %s %s damage", (final
|| wizard
) ? "half" : "reduced",
1376 enl_msg(You_
, "take", "took", buf
, from_what(category
));
1379 /* is hero actively using water walking capability on water (or lava)? */
1383 if (u
.uinwater
|| Levitation
|| Flying
)
1385 return (boolean
) (Wwalking
1386 && (is_pool(u
.ux
, u
.uy
) || is_lava(u
.ux
, u
.uy
)));
1389 /* check whether hero is wearing something that player definitely knows
1390 confers the target property; item must have been seen and its type
1391 discovered but it doesn't necessarily have to be fully identified */
1393 cause_known(propindx
)
1394 int propindx
; /* index of a property which can be conveyed by worn item */
1396 register struct obj
*o
;
1397 long mask
= W_ARMOR
| W_AMUL
| W_RING
| W_TOOL
;
1399 /* simpler than from_what()/what_gives(); we don't attempt to
1400 handle artifacts and we deliberately ignore wielded items */
1401 for (o
= invent
; o
; o
= o
->nobj
) {
1402 if (!(o
->owornmask
& mask
))
1404 if ((int) objects
[o
->otyp
].oc_oprop
== propindx
1405 && objects
[o
->otyp
].oc_name_known
&& o
->dknown
)
1411 /* format a characteristic value, accommodating Strength's strangeness */
1413 attrval(attrindx
, attrvalue
, resultbuf
)
1414 int attrindx
, attrvalue
;
1415 char resultbuf
[]; /* should be at least [7] to hold "18/100\0" */
1417 if (attrindx
!= A_STR
|| attrvalue
<= 18)
1418 Sprintf(resultbuf
, "%d", attrvalue
);
1419 else if (attrvalue
> STR18(100)) /* 19 to 25 */
1420 Sprintf(resultbuf
, "%d", attrvalue
- 100);
1421 else /* simplify "18/ **" to be "18/100" */
1422 Sprintf(resultbuf
, "18/%02d", attrvalue
- 18);
1427 enlightenment(mode
, final
)
1428 int mode
; /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */
1429 int final
; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
1431 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1433 Strcpy(tmpbuf
, plname
);
1434 *tmpbuf
= highc(*tmpbuf
); /* same adjustment as bottom line */
1435 /* as in background_enlightenment, when poly'd we need to use the saved
1436 gender in u.mfemale rather than the current you-as-monster gender */
1437 Sprintf(buf
, "%s the %s's attributes:", tmpbuf
,
1438 ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1442 en_win
= create_nhwindow(NHW_MENU
);
1444 putstr(en_win
, 0, buf
); /* "Conan the Archeologist's attributes:" */
1445 /* background and characteristics; ^X or end-of-game disclosure */
1446 if (mode
& BASICENLIGHTENMENT
) {
1447 /* role, race, alignment, deities */
1448 background_enlightenment(mode
, final
);
1449 /* strength, dexterity, &c */
1450 characteristics_enlightenment(mode
, final
);
1452 /* expanded status line information, including things which aren't
1453 included there due to space considerations--such as obvious
1454 alternative movement indicators (riding, levitation, &c), and
1455 various troubles (turning to stone, trapped, confusion, &c);
1456 shown for both basic and magic enlightenment */
1457 status_enlightenment(mode
, final
);
1458 /* remaining attributes; shown for potion,&c or wizard mode and
1459 explore mode ^X or end of game disclosure */
1460 if (mode
& MAGICENLIGHTENMENT
) {
1461 /* intrinsics and other traditional enlightenment feedback */
1462 attributes_enlightenment(mode
, final
);
1464 display_nhwindow(en_win
, TRUE
);
1465 destroy_nhwindow(en_win
);
1470 /* display role, race, alignment and such to en_win */
1472 background_enlightenment(unused_mode
, final
)
1473 int unused_mode UNUSED
;
1476 const char *role_titl
, *rank_titl
;
1477 int innategend
, difgend
, difalgn
;
1478 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1480 /* note that if poly'd, we need to use u.mfemale instead of flags.female
1481 to access hero's saved gender-as-human/elf/&c rather than current one */
1482 innategend
= (Upolyd
? u
.mfemale
: flags
.female
) ? 1 : 0;
1483 role_titl
= (innategend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
;
1484 rank_titl
= rank_of(u
.ulevel
, Role_switch
, innategend
);
1486 putstr(en_win
, 0, ""); /* separator after title */
1487 putstr(en_win
, 0, "Background:");
1489 /* if polymorphed, report current shape before underlying role;
1490 will be repeated as first status: "you are transformed" and also
1491 among various attributes: "you are in beast form" (after being
1492 told about lycanthropy) or "you are polymorphed into <a foo>"
1493 (with countdown timer appended for wizard mode); we really want
1494 the player to know he's not a samurai at the moment... */
1496 struct permonst
*uasmon
= youmonst
.data
;
1499 /* here we always use current gender, not saved role gender */
1500 if (!is_male(uasmon
) && !is_female(uasmon
) && !is_neuter(uasmon
))
1501 Sprintf(tmpbuf
, "%s ", genders
[flags
.female
? 1 : 0].adj
);
1502 Sprintf(buf
, "%sin %s%s form", !final
? "currently " : "", tmpbuf
,
1507 /* report role; omit gender if it's redundant (eg, "female priestess") */
1510 && ((urole
.allow
& ROLE_GENDMASK
) == (ROLE_MALE
| ROLE_FEMALE
)
1511 || innategend
!= flags
.initgend
))
1512 Sprintf(tmpbuf
, "%s ", genders
[innategend
].adj
);
1515 Strcpy(buf
, "actually "); /* "You are actually a ..." */
1516 if (!strcmpi(rank_titl
, role_titl
)) {
1517 /* omit role when rank title matches it */
1518 Sprintf(eos(buf
), "%s, level %d %s%s", an(rank_titl
), u
.ulevel
,
1519 tmpbuf
, urace
.noun
);
1521 Sprintf(eos(buf
), "%s, a level %d %s%s %s", an(rank_titl
), u
.ulevel
,
1522 tmpbuf
, urace
.adj
, role_titl
);
1526 /* report alignment (bypass you_are() in order to omit ending period);
1527 adverb is used to distinguish between temporary change (helm of opp.
1528 alignment), permanent change (one-time conversion), and original */
1529 Sprintf(buf
, " %s%s%s, %son a mission for %s",
1530 You_
, !final
? are
: were
,
1531 align_str(u
.ualign
.type
),
1532 /* helm of opposite alignment (might hide conversion) */
1533 (u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
])
1534 /* what's the past tense of "currently"? if we used "formerly"
1535 it would sound like a reference to the original alignment */
1536 ? (!final
? "currently " : "temporarily ")
1537 /* permanent conversion */
1538 : (u
.ualign
.type
!= u
.ualignbase
[A_ORIGINAL
])
1539 /* and what's the past tense of "now"? certainly not "then"
1540 in a context like this...; "belatedly" == weren't that
1541 way sooner (in other words, didn't start that way) */
1542 ? (!final
? "now " : "belatedly ")
1543 /* atheist (ignored in very early game) */
1544 : (!u
.uconduct
.gnostic
&& moves
> 1000L)
1546 /* lastly, normal case */
1549 putstr(en_win
, 0, buf
);
1550 /* show the rest of this game's pantheon (finishes previous sentence)
1551 [appending "also Moloch" at the end would allow for straightforward
1552 trailing "and" on all three aligned entries but looks too verbose] */
1553 Sprintf(buf
, " who %s opposed by", !final
? "is" : "was");
1554 if (u
.ualign
.type
!= A_LAWFUL
)
1555 Sprintf(eos(buf
), " %s (%s) and", align_gname(A_LAWFUL
),
1556 align_str(A_LAWFUL
));
1557 if (u
.ualign
.type
!= A_NEUTRAL
)
1558 Sprintf(eos(buf
), " %s (%s)%s", align_gname(A_NEUTRAL
),
1559 align_str(A_NEUTRAL
),
1560 (u
.ualign
.type
!= A_CHAOTIC
) ? " and" : "");
1561 if (u
.ualign
.type
!= A_CHAOTIC
)
1562 Sprintf(eos(buf
), " %s (%s)", align_gname(A_CHAOTIC
),
1563 align_str(A_CHAOTIC
));
1564 Strcat(buf
, "."); /* terminate sentence */
1565 putstr(en_win
, 0, buf
);
1567 /* show original alignment,gender,race,role if any have been changed;
1568 giving separate message for temporary alignment change bypasses need
1569 for tricky phrasing otherwise necessitated by possibility of having
1570 helm of opposite alignment mask a permanent alignment conversion */
1571 difgend
= (innategend
!= flags
.initgend
);
1572 difalgn
= (((u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
]) ? 1 : 0)
1573 + ((u
.ualignbase
[A_CURRENT
] != u
.ualignbase
[A_ORIGINAL
])
1575 if (difalgn
& 1) { /* have temporary alignment so report permanent one */
1576 Sprintf(buf
, "actually %s", align_str(u
.ualignbase
[A_CURRENT
]));
1578 difalgn
&= ~1; /* suppress helm from "started out <foo>" message */
1580 if (difgend
|| difalgn
) { /* sex change or perm align change or both */
1581 Sprintf(buf
, " You started out %s%s%s.",
1582 difgend
? genders
[flags
.initgend
].adj
: "",
1583 (difgend
&& difalgn
) ? " and " : "",
1584 difalgn
? align_str(u
.ualignbase
[A_ORIGINAL
]) : "");
1585 putstr(en_win
, 0, buf
);
1589 /* characteristics: expanded version of bottom line strength, dexterity, &c */
1591 characteristics_enlightenment(mode
, final
)
1596 int hp
= Upolyd
? u
.mh
: u
.uhp
;
1597 int hpmax
= Upolyd
? u
.mhmax
: u
.uhpmax
;
1599 putstr(en_win
, 0, ""); /* separator after background */
1601 final
? "Final Characteristics:" : "Current Characteristics:");
1605 Sprintf(buf
, "%d hit points (max:%d)", hp
, hpmax
);
1608 Sprintf(buf
, "%d magic power (max:%d)", u
.uen
, u
.uenmax
);
1611 Sprintf(buf
, "%d", u
.uac
);
1612 enl_msg("Your armor class ", "is ", "was ", buf
, "");
1615 Sprintf(buf
, "%d hit dice", mons
[u
.umonnum
].mlevel
);
1617 /* flags.showexp does not matter */
1618 /* experience level is already shown in the Background section */
1619 Sprintf(buf
, "%-1ld experience point%s",
1620 u
.uexp
, u
.uexp
== 1 ? "" : "s");
1624 Sprintf(buf
, " You entered the dungeon %ld turn%s ago",
1625 moves
, moves
== 1 ? "" : "s");
1626 putstr(en_win
, 0, buf
);
1628 #ifdef SCORE_ON_BOTL
1629 Sprintf(buf
, "%ld", botl_score());
1630 enl_msg("Your score ", "is ", "was ", buf
, "");
1633 /* bottom line order */
1634 one_characteristic(mode
, final
, A_STR
); /* strength */
1635 one_characteristic(mode
, final
, A_DEX
); /* dexterity */
1636 one_characteristic(mode
, final
, A_CON
); /* constitution */
1637 one_characteristic(mode
, final
, A_INT
); /* intelligence */
1638 one_characteristic(mode
, final
, A_WIS
); /* wisdom */
1639 one_characteristic(mode
, final
, A_CHA
); /* charisma */
1642 /* display one attribute value for characteristics_enlightenment() */
1644 one_characteristic(mode
, final
, attrindx
)
1645 int mode
, final
, attrindx
;
1647 boolean hide_innate_value
= FALSE
, interesting_alimit
;
1648 int acurrent
, abase
, apeak
, alimit
;
1649 const char *attrname
, *paren_pfx
;
1650 char subjbuf
[BUFSZ
], valubuf
[BUFSZ
], valstring
[32];
1652 /* being polymorphed or wearing certain cursed items prevents
1653 hero from reliably tracking changes to characteristics so
1654 we don't show base & peak values then; when the items aren't
1655 cursed, hero could take them off to check underlying values
1656 and we show those in such case so that player doesn't need
1657 to actually resort to doing that */
1659 hide_innate_value
= TRUE
;
1660 } else if (Fixed_abil
) {
1661 if (stuck_ring(uleft
, RIN_SUSTAIN_ABILITY
)
1662 || stuck_ring(uright
, RIN_SUSTAIN_ABILITY
))
1663 hide_innate_value
= TRUE
;
1667 attrname
= "strength";
1668 if (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
&& uarmg
->cursed
)
1669 hide_innate_value
= TRUE
;
1672 attrname
= "dexterity";
1675 attrname
= "constitution";
1676 if (uwep
&& uwep
->oartifact
== ART_OGRESMASHER
&& uwep
->cursed
)
1677 hide_innate_value
= TRUE
;
1680 attrname
= "intelligence";
1681 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1682 hide_innate_value
= TRUE
;
1685 attrname
= "wisdom";
1686 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1687 hide_innate_value
= TRUE
;
1690 attrname
= "charisma";
1693 return; /* impossible */
1695 /* note: final disclosure includes MAGICENLIGHTENTMENT */
1696 if ((mode
& MAGICENLIGHTENMENT
) && !Upolyd
)
1697 hide_innate_value
= FALSE
;
1699 acurrent
= ACURR(attrindx
);
1700 (void) attrval(attrindx
, acurrent
, valubuf
); /* Sprintf(valubuf,"%d",) */
1701 Sprintf(subjbuf
, "Your %s ", attrname
);
1703 if (!hide_innate_value
) {
1704 /* show abase, amax, and/or attrmax if acurr doesn't match abase
1705 (a magic bonus or penalty is in effect) or abase doesn't match
1706 amax (some points have been lost to poison or exercise abuse
1707 and are restorable) or attrmax is different from normal human
1708 (while game is in progress; trying to reduce dependency on
1709 spoilers to keep track of such stuff) or attrmax was different
1710 from abase (at end of game; this attribute wasn't maxed out) */
1711 abase
= ABASE(attrindx
);
1712 apeak
= AMAX(attrindx
);
1713 alimit
= ATTRMAX(attrindx
);
1714 /* criterium for whether the limit is interesting varies */
1715 interesting_alimit
=
1716 final
? TRUE
/* was originally `(abase != alimit)' */
1717 : (alimit
!= (attrindx
!= A_STR
? 18 : STR18(100)));
1718 paren_pfx
= final
? " (" : " (current; ";
1719 if (acurrent
!= abase
) {
1720 Sprintf(eos(valubuf
), "%sbase:%s", paren_pfx
,
1721 attrval(attrindx
, abase
, valstring
));
1724 if (abase
!= apeak
) {
1725 Sprintf(eos(valubuf
), "%speak:%s", paren_pfx
,
1726 attrval(attrindx
, apeak
, valstring
));
1729 if (interesting_alimit
) {
1730 Sprintf(eos(valubuf
), "%s%slimit:%s", paren_pfx
,
1731 /* more verbose if exceeding 'limit' due to magic bonus */
1732 (acurrent
> alimit
) ? "innate " : "",
1733 attrval(attrindx
, alimit
, valstring
));
1734 /* paren_pfx = ", "; */
1736 if (acurrent
!= abase
|| abase
!= apeak
|| interesting_alimit
)
1737 Strcat(valubuf
, ")");
1739 enl_msg(subjbuf
, "is ", "was ", valubuf
, "");
1742 /* status: selected obvious capabilities, assorted troubles */
1744 status_enlightenment(mode
, final
)
1748 boolean magic
= (mode
& MAGICENLIGHTENMENT
) ? TRUE
: FALSE
;
1750 char buf
[BUFSZ
], youtoo
[BUFSZ
];
1751 boolean Riding
= (u
.usteed
1752 /* if hero dies while dismounting, u.usteed will still
1753 be set; we want to ignore steed in that situation */
1754 && !(final
== ENL_GAMEOVERDEAD
1755 && !strcmp(killer
.name
, "riding accident")));
1756 const char *steedname
= (!Riding
? (char *) 0
1757 : x_monnam(u
.usteed
,
1758 u
.usteed
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
,
1760 (SUPPRESS_SADDLE
| SUPPRESS_HALLUCINATION
),
1764 * Status (many are abbreviated on bottom line; others are or
1765 * should be discernible to the hero hence to the player)
1767 putstr(en_win
, 0, ""); /* separator after title or characteristics */
1768 putstr(en_win
, 0, final
? "Final Status:" : "Current Status:");
1770 Strcpy(youtoo
, You_
);
1771 /* not a traditional status but inherently obvious to player; more
1772 detail given below (attributes section) for magic enlightenment */
1774 you_are("transformed", "");
1775 /* not a trouble, but we want to display riding status before maybe
1776 reporting steed as trapped or hero stuck to cursed saddle */
1778 Sprintf(buf
, "riding %s", steedname
);
1780 Sprintf(eos(youtoo
), "and %s ", steedname
);
1782 /* other movement situations that hero should always know */
1784 if (Lev_at_will
&& magic
)
1785 you_are("levitating, at will", "");
1787 enl_msg(youtoo
, are
, were
, "levitating", from_what(LEVITATION
));
1788 } else if (Flying
) { /* can only fly when not levitating */
1789 enl_msg(youtoo
, are
, were
, "flying", from_what(FLYING
));
1792 you_are("underwater", "");
1793 } else if (u
.uinwater
) {
1794 you_are(Swimming
? "swimming" : "in water", from_what(SWIMMING
));
1795 } else if (walking_on_water()) {
1796 /* show active Wwalking here, potential Wwalking elsewhere */
1797 Sprintf(buf
, "walking on %s",
1798 is_pool(u
.ux
, u
.uy
) ? "water"
1799 : is_lava(u
.ux
, u
.uy
) ? "lava"
1800 : surface(u
.ux
, u
.uy
)); /* catchall; shouldn't happen */
1801 you_are(buf
, from_what(WWALKING
));
1803 if (Upolyd
&& (u
.uundetected
|| youmonst
.m_ap_type
!= M_AP_NOTHING
))
1804 youhiding(TRUE
, final
);
1806 /* internal troubles, mostly in the order that prayer ranks them */
1808 you_are("turning to stone", "");
1810 you_are("turning into slime", "");
1813 you_are("buried", "");
1815 Strcpy(buf
, "being strangled");
1817 Sprintf(eos(buf
), " (%ld)", (Strangled
& TIMEOUT
));
1818 you_are(buf
, from_what(STRANGLED
));
1822 /* prayer lumps these together; botl puts Ill before FoodPois */
1823 if (u
.usick_type
& SICK_NONVOMITABLE
)
1824 you_are("terminally sick from illness", "");
1825 if (u
.usick_type
& SICK_VOMITABLE
)
1826 you_are("terminally sick from food poisoning", "");
1829 you_are("nauseated", "");
1831 you_are("stunned", "");
1833 you_are("confused", "");
1835 you_are("hallucinating", "");
1837 /* from_what() (currently wizard-mode only) checks !haseyes()
1838 before u.uroleplay.blind, so we should too */
1839 Sprintf(buf
, "%s blind",
1840 !haseyes(youmonst
.data
) ? "innately"
1841 : u
.uroleplay
.blind
? "permanently"
1842 /* better phrasing desperately wanted... */
1843 : Blindfolded_only
? "deliberately"
1845 if (wizard
&& (Blinded
& TIMEOUT
) != 0L
1846 && !u
.uroleplay
.blind
&& haseyes(youmonst
.data
))
1847 Sprintf(eos(buf
), " (%ld)", (Blinded
& TIMEOUT
));
1848 /* !haseyes: avoid "you are innately blind innately" */
1849 you_are(buf
, !haseyes(youmonst
.data
) ? "" : from_what(BLINDED
));
1852 you_are("deaf", from_what(DEAF
));
1854 /* external troubles, more or less */
1857 Sprintf(buf
, "chained to %s", ansimpleoname(uball
));
1859 impossible("Punished without uball?");
1860 Strcpy(buf
, "punished");
1865 char predicament
[BUFSZ
];
1867 boolean anchored
= (u
.utraptype
== TT_BURIEDBALL
);
1870 Strcpy(predicament
, "tethered to something buried");
1871 } else if (u
.utraptype
== TT_INFLOOR
|| u
.utraptype
== TT_LAVA
) {
1872 Sprintf(predicament
, "stuck in %s", the(surface(u
.ux
, u
.uy
)));
1874 Strcpy(predicament
, "trapped");
1875 if ((t
= t_at(u
.ux
, u
.uy
)) != 0)
1876 Sprintf(eos(predicament
), " in %s",
1877 an(defsyms
[trap_to_defsym(t
->ttyp
)].explanation
));
1879 if (u
.usteed
) { /* not `Riding' here */
1880 Sprintf(buf
, "%s%s ", anchored
? "you and " : "", steedname
);
1882 enl_msg(buf
, (anchored
? "are " : "is "),
1883 (anchored
? "were " : "was "), predicament
, "");
1885 you_are(predicament
, "");
1888 Sprintf(buf
, "swallowed by %s", a_monnam(u
.ustuck
));
1890 Sprintf(eos(buf
), " (%u)", u
.uswldtim
);
1892 } else if (u
.ustuck
) {
1893 Sprintf(buf
, "%s %s",
1894 (Upolyd
&& sticks(youmonst
.data
)) ? "holding" : "held by",
1895 a_monnam(u
.ustuck
));
1899 struct obj
*saddle
= which_armor(u
.usteed
, W_SADDLE
);
1901 if (saddle
&& saddle
->cursed
) {
1902 Sprintf(buf
, "stuck to %s %s", s_suffix(steedname
),
1903 simpleonames(saddle
));
1908 /* when mounted, Wounded_legs applies to steed rather than to
1909 hero; we only report steed's wounded legs in wizard mode */
1910 if (u
.usteed
) { /* not `Riding' here */
1911 if (wizard
&& steedname
) {
1912 Strcpy(buf
, steedname
);
1914 enl_msg(buf
, " has", " had", " wounded legs", "");
1917 Sprintf(buf
, "wounded %s", makeplural(body_part(LEG
)));
1922 Sprintf(buf
, "slippery %s", makeplural(body_part(FINGER
)));
1926 if (magic
|| cause_known(FUMBLING
))
1927 enl_msg(You_
, "fumble", "fumbled", "", from_what(FUMBLING
));
1930 if (magic
|| cause_known(SLEEPY
)) {
1931 Strcpy(buf
, from_what(SLEEPY
));
1933 Sprintf(eos(buf
), " (%ld)", (HSleepy
& TIMEOUT
));
1934 enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf
);
1937 /* hunger/nutrition */
1939 if (magic
|| cause_known(HUNGER
))
1940 enl_msg(You_
, "hunger", "hungered", " rapidly",
1943 Strcpy(buf
, hu_stat
[u
.uhs
]); /* hunger status; omitted if "normal" */
1944 mungspaces(buf
); /* strip trailing spaces */
1946 *buf
= lowc(*buf
); /* override capitalization */
1947 if (!strcmp(buf
, "weak"))
1948 Strcat(buf
, " from severe hunger");
1949 else if (!strncmp(buf
, "faint", 5)) /* fainting, fainted */
1950 Strcat(buf
, " due to starvation");
1954 if ((cap
= near_capacity()) > UNENCUMBERED
) {
1955 const char *adj
= "?_?"; /* (should always get overridden) */
1957 Strcpy(buf
, enc_stat
[cap
]);
1962 break; /* burdened */
1965 break; /* stressed */
1968 break; /* strained */
1971 break; /* overtaxed */
1973 adj
= "not possible";
1976 Sprintf(eos(buf
), "; movement %s %s%s", !final
? "is" : "was", adj
,
1977 (cap
< OVERLOADED
) ? " slowed" : "");
1980 /* last resort entry, guarantees Status section is non-empty
1981 (no longer needed for that purpose since weapon status added;
1982 still useful though) */
1983 you_are("unencumbered", "");
1985 /* report being weaponless; distinguish whether gloves are worn */
1987 you_are(uarmg
? "empty handed" /* gloves imply hands */
1988 : humanoid(youmonst
.data
)
1989 /* hands but no weapon and no gloves */
1991 /* alternate phrasing for paws or lack of hands */
1992 : "not wielding anything",
1994 /* two-weaponing implies a weapon (not other odd stuff) in each hand */
1995 } else if (u
.twoweap
) {
1996 you_are("wielding two weapons at once", "");
1997 /* report most weapons by their skill class (so a katana will be
1998 described as a long sword, for instance; mattock and hook are
1999 exceptions), or wielded non-weapon item by its object class */
2001 const char *what
= weapon_descr(uwep
);
2003 if (!strcmpi(what
, "armor") || !strcmpi(what
, "food")
2004 || !strcmpi(what
, "venom"))
2005 Sprintf(buf
, "wielding some %s", what
);
2007 Sprintf(buf
, "wielding %s",
2008 (uwep
->quan
== 1L) ? an(what
) : makeplural(what
));
2011 /* report 'nudity' */
2012 if (!uarm
&& !uarmu
&& !uarmc
&& !uarmg
&& !uarmf
&& !uarmh
) {
2013 if (u
.uroleplay
.nudist
)
2014 enl_msg(You_
, "do", "did", " not wear any armor", "");
2016 you_are("not wearing any armor", "");
2020 /* attributes: intrinsics and the like, other non-obvious capabilities */
2022 attributes_enlightenment(unused_mode
, final
)
2023 int unused_mode UNUSED
;
2026 static NEARDATA
const char if_surroundings_permitted
[] =
2027 " if surroundings permitted";
2034 putstr(en_win
, 0, "");
2035 putstr(en_win
, 0, final
? "Final Attributes:" : "Current Attributes:");
2037 if (u
.uevent
.uhand_of_elbereth
) {
2038 static const char *const hofe_titles
[3] = { "the Hand of Elbereth",
2039 "the Envoy of Balance",
2040 "the Glory of Arioch" };
2041 you_are(hofe_titles
[u
.uevent
.uhand_of_elbereth
- 1], "");
2044 Sprintf(buf
, "%s", piousness(TRUE
, "aligned"));
2045 if (u
.ualign
.record
>= 0)
2051 Sprintf(buf
, " %d", u
.ualign
.record
);
2052 enl_msg("Your alignment ", "is", "was", buf
, "");
2055 /*** Resistances to troubles ***/
2057 you_are("invulnerable", from_what(INVULNERABLE
));
2059 you_are("magic-protected", from_what(ANTIMAGIC
));
2060 if (Fire_resistance
)
2061 you_are("fire resistant", from_what(FIRE_RES
));
2062 if (Cold_resistance
)
2063 you_are("cold resistant", from_what(COLD_RES
));
2064 if (Sleep_resistance
)
2065 you_are("sleep resistant", from_what(SLEEP_RES
));
2066 if (Disint_resistance
)
2067 you_are("disintegration-resistant", from_what(DISINT_RES
));
2068 if (Shock_resistance
)
2069 you_are("shock resistant", from_what(SHOCK_RES
));
2070 if (Poison_resistance
)
2071 you_are("poison resistant", from_what(POISON_RES
));
2072 if (Acid_resistance
)
2073 you_are("acid resistant", from_what(ACID_RES
));
2074 if (Drain_resistance
)
2075 you_are("level-drain resistant", from_what(DRAIN_RES
));
2076 if (Sick_resistance
)
2077 you_are("immune to sickness", from_what(SICK_RES
));
2078 if (Stone_resistance
)
2079 you_are("petrification resistant", from_what(STONE_RES
));
2080 if (Halluc_resistance
)
2081 enl_msg(You_
, "resist", "resisted", " hallucinations",
2082 from_what(HALLUC_RES
));
2084 you_can("recognize detrimental food", "");
2086 /*** Vision and senses ***/
2087 if (!Blind
&& (Blinded
|| !haseyes(youmonst
.data
)))
2088 you_can("see", from_what(-BLINDED
)); /* Eyes of the Overworld */
2089 if (See_invisible
) {
2091 enl_msg(You_
, "see", "saw", " invisible", from_what(SEE_INVIS
));
2093 enl_msg(You_
, "will see", "would have seen",
2094 " invisible when not blind", from_what(SEE_INVIS
));
2097 you_are("telepathic", from_what(TELEPAT
));
2099 you_are("warned", from_what(WARNING
));
2100 if (Warn_of_mon
&& context
.warntype
.obj
) {
2101 Sprintf(buf
, "aware of the presence of %s",
2102 (context
.warntype
.obj
& M2_ORC
) ? "orcs"
2103 : (context
.warntype
.obj
& M2_ELF
) ? "elves"
2104 : (context
.warntype
.obj
& M2_DEMON
) ? "demons" : something
);
2105 you_are(buf
, from_what(WARN_OF_MON
));
2107 if (Warn_of_mon
&& context
.warntype
.polyd
) {
2108 Sprintf(buf
, "aware of the presence of %s",
2109 ((context
.warntype
.polyd
& (M2_HUMAN
| M2_ELF
))
2110 == (M2_HUMAN
| M2_ELF
))
2111 ? "humans and elves"
2112 : (context
.warntype
.polyd
& M2_HUMAN
)
2114 : (context
.warntype
.polyd
& M2_ELF
)
2116 : (context
.warntype
.polyd
& M2_ORC
)
2118 : (context
.warntype
.polyd
& M2_DEMON
)
2120 : "certain monsters");
2123 if (Warn_of_mon
&& context
.warntype
.speciesidx
>= LOW_PM
) {
2124 Sprintf(buf
, "aware of the presence of %s",
2125 makeplural(mons
[context
.warntype
.speciesidx
].mname
));
2126 you_are(buf
, from_what(WARN_OF_MON
));
2129 you_are("warned of undead", from_what(WARN_UNDEAD
));
2131 you_have("automatic searching", from_what(SEARCHING
));
2133 you_are("clairvoyant", from_what(CLAIRVOYANT
));
2134 else if ((HClairvoyant
|| EClairvoyant
) && BClairvoyant
) {
2135 Strcpy(buf
, from_what(-CLAIRVOYANT
));
2136 if (!strncmp(buf
, " because of ", 12))
2137 /* overwrite substring; strncpy doesn't add terminator */
2138 (void) strncpy(buf
, " if not for ", 12);
2139 enl_msg(You_
, "could be", "could have been", " clairvoyant", buf
);
2142 you_have("infravision", from_what(INFRAVISION
));
2143 if (Detect_monsters
)
2144 you_are("sensing the presence of monsters", "");
2146 you_are("going to confuse monsters", "");
2148 /*** Appearance and behavior ***/
2152 if (uleft
&& uleft
->otyp
== RIN_ADORNMENT
)
2153 adorn
+= uleft
->spe
;
2154 if (uright
&& uright
->otyp
== RIN_ADORNMENT
)
2155 adorn
+= uright
->spe
;
2156 /* the sum might be 0 (+0 ring or two which negate each other);
2157 that yields "you are charismatic" (which isn't pointless
2158 because it potentially impacts seduction attacks) */
2159 Sprintf(buf
, "%scharismatic",
2160 (adorn
> 0) ? "more " : (adorn
< 0) ? "less " : "");
2161 you_are(buf
, from_what(ADORNED
));
2164 you_are("invisible", from_what(INVIS
));
2166 you_are("invisible to others", from_what(INVIS
));
2167 /* ordinarily "visible" is redundant; this is a special case for
2168 the situation when invisibility would be an expected attribute */
2169 else if ((HInvis
|| EInvis
) && BInvis
)
2170 you_are("visible", from_what(-INVIS
));
2172 you_are("displaced", from_what(DISPLACED
));
2174 you_are("stealthy", from_what(STEALTH
));
2175 if (Aggravate_monster
)
2176 enl_msg("You aggravate", "", "d", " monsters",
2177 from_what(AGGRAVATE_MONSTER
));
2179 enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT
));
2181 /*** Transportation ***/
2183 you_can("jump", from_what(JUMPING
));
2185 you_can("teleport", from_what(TELEPORT
));
2186 if (Teleport_control
)
2187 you_have("teleport control", from_what(TELEPORT_CONTROL
));
2188 /* actively levitating handled earlier as a status condition */
2189 if (BLevitation
) { /* levitation is blocked */
2190 long save_BLev
= BLevitation
;
2194 enl_msg(You_
, "would levitate", "would have levitated",
2195 if_surroundings_permitted
, "");
2196 BLevitation
= save_BLev
;
2198 /* actively flying handled earlier as a status condition */
2199 if (BFlying
) { /* flight is blocked */
2200 long save_BFly
= BFlying
;
2204 enl_msg(You_
, "would fly", "would have flown",
2206 ? "if you weren't levitating"
2207 : (save_BFly
== FROMOUTSIDE
)
2208 ? if_surroundings_permitted
2209 /* both surroundings and [latent] levitation */
2210 : " if circumstances permitted",
2212 BFlying
= save_BFly
;
2214 /* actively walking on water handled earlier as a status condition */
2215 if (Wwalking
&& !walking_on_water())
2216 you_can("walk on water", from_what(WWALKING
));
2217 /* actively swimming (in water but not under it) handled earlier */
2218 if (Swimming
&& (Underwater
|| !u
.uinwater
))
2219 you_can("swim", from_what(SWIMMING
));
2221 you_can("survive without air", from_what(MAGICAL_BREATHING
));
2222 else if (Amphibious
)
2223 you_can("breathe water", from_what(MAGICAL_BREATHING
));
2225 you_can("walk through walls", from_what(PASSES_WALLS
));
2227 /*** Physical attributes ***/
2229 enl_msg("You regenerate", "", "d", "", from_what(REGENERATION
));
2231 you_have("slower digestion", from_what(SLOW_DIGESTION
));
2233 you_have(enlght_combatinc("to hit", u
.uhitinc
, final
, buf
), "");
2235 you_have(enlght_combatinc("damage", u
.udaminc
, final
, buf
), "");
2236 if (u
.uspellprot
|| Protection
) {
2239 if (uleft
&& uleft
->otyp
== RIN_PROTECTION
)
2241 if (uright
&& uright
->otyp
== RIN_PROTECTION
)
2242 prot
+= uright
->spe
;
2243 if (HProtection
& INTRINSIC
)
2245 prot
+= u
.uspellprot
;
2247 you_have(enlght_combatinc("defense", prot
, final
, buf
), "");
2249 if ((armpro
= magic_negation(&youmonst
)) > 0) {
2250 /* magic cancellation factor, conferred by worn armor */
2251 static const char *const mc_types
[] = {
2252 "" /*ordinary*/, "warded", "guarded", "protected",
2255 if (armpro
>= SIZE(mc_types
))
2256 armpro
= SIZE(mc_types
) - 1;
2257 you_are(mc_types
[armpro
], "");
2259 if (Half_physical_damage
)
2260 enlght_halfdmg(HALF_PHDAM
, final
);
2261 if (Half_spell_damage
)
2262 enlght_halfdmg(HALF_SPDAM
, final
);
2263 /* polymorph and other shape change */
2264 if (Protection_from_shape_changers
)
2265 you_are("protected from shape changers",
2266 from_what(PROT_FROM_SHAPE_CHANGERS
));
2268 const char *what
= 0;
2270 if (!Upolyd
) /* Upolyd handled below after current form */
2271 you_can("not change from your current form",
2272 from_what(UNCHANGING
));
2273 /* blocked shape changes */
2275 what
= !final
? "polymorph" : "have polymorphed";
2276 else if (u
.ulycn
>= LOW_PM
)
2277 what
= !final
? "change shape" : "have changed shape";
2279 Sprintf(buf
, "would %s periodically", what
);
2280 /* omit from_what(UNCHANGING); too verbose */
2281 enl_msg(You_
, buf
, buf
, " if not locked into your current form",
2284 } else if (Polymorph
) {
2285 you_are("polymorphing periodically", from_what(POLYMORPH
));
2287 if (Polymorph_control
)
2288 you_have("polymorph control", from_what(POLYMORPH_CONTROL
));
2289 if (Upolyd
&& u
.umonnum
!= u
.ulycn
) {
2290 /* foreign shape (except were-form which is handled below) */
2291 Sprintf(buf
, "polymorphed into %s", an(youmonst
.data
->mname
));
2293 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2296 if (lays_eggs(youmonst
.data
) && flags
.female
) /* Upolyd */
2297 you_can("lay eggs", "");
2298 if (u
.ulycn
>= LOW_PM
) {
2299 /* "you are a werecreature [in beast form]" */
2300 Strcpy(buf
, an(mons
[u
.ulycn
].mname
));
2301 if (u
.umonnum
== u
.ulycn
) {
2302 Strcat(buf
, " in beast form");
2304 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2308 if (Unchanging
&& Upolyd
) /* !Upolyd handled above */
2309 you_can("not change from your current form", from_what(UNCHANGING
));
2311 you_are("harmed by silver", "");
2312 /* movement and non-armor-based protection */
2314 you_are(Very_fast
? "very fast" : "fast", from_what(FAST
));
2316 you_have("reflection", from_what(REFLECTING
));
2318 you_have("free action", from_what(FREE_ACTION
));
2320 you_have("fixed abilities", from_what(FIXED_ABIL
));
2322 enl_msg("Your life ", "will be", "would have been", " saved", "");
2324 /*** Miscellany ***/
2326 ltmp
= abs((int) Luck
);
2327 Sprintf(buf
, "%s%slucky",
2328 ltmp
>= 10 ? "extremely " : ltmp
>= 5 ? "very " : "",
2329 Luck
< 0 ? "un" : "");
2331 Sprintf(eos(buf
), " (%d)", Luck
);
2334 enl_msg("Your luck ", "is", "was", " zero", "");
2336 you_have("extra luck", "");
2337 else if (u
.moreluck
< 0)
2338 you_have("reduced luck", "");
2339 if (carrying(LUCKSTONE
) || stone_luck(TRUE
)) {
2340 ltmp
= stone_luck(0);
2342 enl_msg("Bad luck ", "does", "did", " not time out for you", "");
2344 enl_msg("Good luck ", "does", "did", " not time out for you", "");
2348 Sprintf(buf
, " %sangry with you",
2349 u
.ugangr
> 6 ? "extremely " : u
.ugangr
> 3 ? "very " : "");
2351 Sprintf(eos(buf
), " (%d)", u
.ugangr
);
2352 enl_msg(u_gname(), " is", " was", buf
, "");
2355 * We need to suppress this when the game is over, because death
2356 * can change the value calculated by can_pray(), potentially
2357 * resulting in a false claim that you could have prayed safely.
2361 /* "can [not] safely pray" vs "could [not] have safely prayed" */
2362 Sprintf(buf
, "%s%ssafely pray%s", can_pray(FALSE
) ? "" : "not ",
2363 final
? "have " : "", final
? "ed" : "");
2365 Sprintf(buf
, "%ssafely pray", can_pray(FALSE
) ? "" : "not ");
2368 Sprintf(eos(buf
), " (%d)", u
.ublesscnt
);
2374 /* named fruit debugging (doesn't really belong here...); to enable,
2375 include 'fruit' in DEBUGFILES list (even though it isn't a file...) */
2376 if (wizard
&& explicitdebug("fruit")) {
2381 for (f
= ffruit
; f
; f
= f
->nextf
) {
2382 Sprintf(buf
, "Fruit %d ", ++fcount
);
2383 Sprintf(buf2
, "%s (id %d)", f
->fname
, f
->fid
);
2384 enl_msg(buf
, "is ", "was ", buf2
, "");
2386 enl_msg("The current fruit ", "is ", "was ", pl_fruit
, "");
2387 Sprintf(buf
, "%d", flags
.made_fruit
);
2388 enl_msg("The made fruit flag ", "is ", "was ", buf
, "");
2396 if (final
< 2) { /* still in progress, or quit/escaped/ascended */
2397 p
= "survived after being killed ";
2398 switch (u
.umortality
) {
2400 p
= !final
? (char *) 0 : "survived";
2403 Strcpy(buf
, "once");
2406 Strcpy(buf
, "twice");
2409 Strcpy(buf
, "thrice");
2412 Sprintf(buf
, "%d times", u
.umortality
);
2415 } else { /* game ended in character's death */
2417 switch (u
.umortality
) {
2419 impossible("dead without dying?");
2421 break; /* just "are dead" */
2423 Sprintf(buf
, " (%d%s time!)", u
.umortality
,
2424 ordin(u
.umortality
));
2429 enl_msg(You_
, "have been killed ", p
, buf
, "");
2433 #if 0 /* no longer used */
2434 STATIC_DCL boolean
NDECL(minimal_enlightenment
);
2437 * Courtesy function for non-debug, non-explorer mode players
2438 * to help refresh them about who/what they are.
2439 * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
2442 minimal_enlightenment()
2445 menu_item
*selected
;
2448 char buf
[BUFSZ
], buf2
[BUFSZ
];
2449 static const char untabbed_fmtstr
[] = "%-15s: %-12s";
2450 static const char untabbed_deity_fmtstr
[] = "%-17s%s";
2451 static const char tabbed_fmtstr
[] = "%s:\t%-12s";
2452 static const char tabbed_deity_fmtstr
[] = "%s\t%s";
2453 static const char *fmtstr
;
2454 static const char *deity_fmtstr
;
2456 fmtstr
= iflags
.menu_tab_sep
? tabbed_fmtstr
: untabbed_fmtstr
;
2457 deity_fmtstr
= iflags
.menu_tab_sep
? tabbed_deity_fmtstr
2458 : untabbed_deity_fmtstr
;
2460 buf
[0] = buf2
[0] = '\0';
2461 tmpwin
= create_nhwindow(NHW_MENU
);
2463 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2466 /* Starting name, race, role, gender */
2467 Sprintf(buf
, fmtstr
, "name", plname
);
2468 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2469 Sprintf(buf
, fmtstr
, "race", urace
.noun
);
2470 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2471 Sprintf(buf
, fmtstr
, "role",
2472 (flags
.initgend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
);
2473 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2474 Sprintf(buf
, fmtstr
, "gender", genders
[flags
.initgend
].adj
);
2475 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2477 /* Starting alignment */
2478 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualignbase
[A_ORIGINAL
]));
2479 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2481 /* Current name, race, role, gender */
2482 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2483 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2485 Sprintf(buf
, fmtstr
, "race", Upolyd
? youmonst
.data
->mname
: urace
.noun
);
2486 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2488 Sprintf(buf
, fmtstr
, "role (base)",
2489 (u
.mfemale
&& urole
.name
.f
) ? urole
.name
.f
2491 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2493 Sprintf(buf
, fmtstr
, "role",
2494 (flags
.female
&& urole
.name
.f
) ? urole
.name
.f
2496 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2498 /* don't want poly_gender() here; it forces `2' for non-humanoids */
2499 genidx
= is_neuter(youmonst
.data
) ? 2 : flags
.female
;
2500 Sprintf(buf
, fmtstr
, "gender", genders
[genidx
].adj
);
2501 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2502 if (Upolyd
&& (int) u
.mfemale
!= genidx
) {
2503 Sprintf(buf
, fmtstr
, "gender (base)", genders
[u
.mfemale
].adj
);
2504 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2507 /* Current alignment */
2508 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualign
.type
));
2509 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2512 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2513 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2515 Sprintf(buf2
, deity_fmtstr
, align_gname(A_CHAOTIC
),
2516 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2517 && u
.ualign
.type
== A_CHAOTIC
) ? " (s,c)"
2518 : (u
.ualignbase
[A_ORIGINAL
] == A_CHAOTIC
) ? " (s)"
2519 : (u
.ualign
.type
== A_CHAOTIC
) ? " (c)" : "");
2520 Sprintf(buf
, fmtstr
, "Chaotic", buf2
);
2521 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2523 Sprintf(buf2
, deity_fmtstr
, align_gname(A_NEUTRAL
),
2524 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2525 && u
.ualign
.type
== A_NEUTRAL
) ? " (s,c)"
2526 : (u
.ualignbase
[A_ORIGINAL
] == A_NEUTRAL
) ? " (s)"
2527 : (u
.ualign
.type
== A_NEUTRAL
) ? " (c)" : "");
2528 Sprintf(buf
, fmtstr
, "Neutral", buf2
);
2529 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2531 Sprintf(buf2
, deity_fmtstr
, align_gname(A_LAWFUL
),
2532 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2533 && u
.ualign
.type
== A_LAWFUL
) ? " (s,c)"
2534 : (u
.ualignbase
[A_ORIGINAL
] == A_LAWFUL
) ? " (s)"
2535 : (u
.ualign
.type
== A_LAWFUL
) ? " (c)" : "");
2536 Sprintf(buf
, fmtstr
, "Lawful", buf2
);
2537 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2539 end_menu(tmpwin
, "Base Attributes");
2540 n
= select_menu(tmpwin
, PICK_NONE
, &selected
);
2541 destroy_nhwindow(tmpwin
);
2542 return (boolean
) (n
!= -1);
2548 doattributes(VOID_ARGS
)
2550 int mode
= BASICENLIGHTENMENT
;
2552 /* show more--as if final disclosure--for wizard and explore modes */
2553 if (wizard
|| discover
)
2554 mode
|= MAGICENLIGHTENMENT
;
2556 enlightenment(mode
, ENL_GAMEINPROGRESS
);
2561 youhiding(via_enlghtmt
, msgflag
)
2562 boolean via_enlghtmt
; /* englightment line vs topl message */
2563 int msgflag
; /* for variant message phrasing */
2565 char *bp
, buf
[BUFSZ
];
2567 Strcpy(buf
, "hiding");
2568 if (youmonst
.m_ap_type
!= M_AP_NOTHING
) {
2569 /* mimic; hero is only able to mimic a strange object or gold
2570 or hallucinatory alternative to gold, so we skip the details
2571 for the hypothetical furniture and monster cases */
2572 bp
= eos(strcpy(buf
, "mimicking"));
2573 if (youmonst
.m_ap_type
== M_AP_OBJECT
) {
2574 Sprintf(bp
, " %s", an(simple_typename(youmonst
.mappearance
)));
2575 } else if (youmonst
.m_ap_type
== M_AP_FURNITURE
) {
2576 Strcpy(bp
, " something");
2577 } else if (youmonst
.m_ap_type
== M_AP_MONSTER
) {
2578 Strcpy(bp
, " someone");
2580 ; /* something unexpected; leave 'buf' as-is */
2582 } else if (u
.uundetected
) {
2583 bp
= eos(buf
); /* points past "hiding" */
2584 if (youmonst
.data
->mlet
== S_EEL
) {
2585 if (is_pool(u
.ux
, u
.uy
))
2586 Sprintf(bp
, " in the %s", waterbody_name(u
.ux
, u
.uy
));
2587 } else if (hides_under(youmonst
.data
)) {
2588 struct obj
*o
= level
.objects
[u
.ux
][u
.uy
];
2591 Sprintf(bp
, " underneath %s", ansimpleoname(o
));
2592 } else if (is_clinger(youmonst
.data
) || Flying
) {
2593 /* Flying: 'lurker above' hides on ceiling but doesn't cling */
2594 Sprintf(bp
, " on the %s", ceiling(u
.ux
, u
.uy
));
2596 /* on floor; is_hider() but otherwise not special: 'trapper' */
2597 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
2598 struct trap
*t
= t_at(u
.ux
, u
.uy
);
2600 Sprintf(bp
, " in a %spit",
2601 (t
&& t
->ttyp
== SPIKED_PIT
) ? "spiked " : "");
2603 Sprintf(bp
, " on the %s", surface(u
.ux
, u
.uy
));
2606 ; /* shouldn't happen; will result in generic "you are hiding" */
2610 int final
= msgflag
; /* 'final' is used by you_are() macro */
2614 /* for dohide(), when player uses '#monster' command */
2615 You("are %s %s.", msgflag
? "already" : "now", buf
);
2620 * (shares enlightenment's tense handling)
2623 doconduct(VOID_ARGS
)
2636 /* Create the conduct window */
2637 en_win
= create_nhwindow(NHW_MENU
);
2638 putstr(en_win
, 0, "Voluntary challenges:");
2640 if (u
.uroleplay
.blind
)
2641 you_have_been("blind from birth");
2642 if (u
.uroleplay
.nudist
)
2643 you_have_been("faithfully nudist");
2645 if (!u
.uconduct
.food
)
2646 enl_msg(You_
, "have gone", "went", " without food", "");
2647 /* But beverages are okay */
2648 else if (!u
.uconduct
.unvegan
)
2649 you_have_X("followed a strict vegan diet");
2650 else if (!u
.uconduct
.unvegetarian
)
2651 you_have_been("vegetarian");
2653 if (!u
.uconduct
.gnostic
)
2654 you_have_been("an atheist");
2656 if (!u
.uconduct
.weaphit
) {
2657 you_have_never("hit with a wielded weapon");
2658 } else if (wizard
) {
2659 Sprintf(buf
, "used a wielded weapon %ld time%s", u
.uconduct
.weaphit
,
2660 plur(u
.uconduct
.weaphit
));
2663 if (!u
.uconduct
.killer
)
2664 you_have_been("a pacifist");
2666 if (!u
.uconduct
.literate
) {
2667 you_have_been("illiterate");
2668 } else if (wizard
) {
2669 Sprintf(buf
, "read items or engraved %ld time%s", u
.uconduct
.literate
,
2670 plur(u
.uconduct
.literate
));
2674 ngenocided
= num_genocides();
2675 if (ngenocided
== 0) {
2676 you_have_never("genocided any monsters");
2678 Sprintf(buf
, "genocided %d type%s of monster%s", ngenocided
,
2679 plur(ngenocided
), plur(ngenocided
));
2683 if (!u
.uconduct
.polypiles
) {
2684 you_have_never("polymorphed an object");
2685 } else if (wizard
) {
2686 Sprintf(buf
, "polymorphed %ld item%s", u
.uconduct
.polypiles
,
2687 plur(u
.uconduct
.polypiles
));
2691 if (!u
.uconduct
.polyselfs
) {
2692 you_have_never("changed form");
2693 } else if (wizard
) {
2694 Sprintf(buf
, "changed form %ld time%s", u
.uconduct
.polyselfs
,
2695 plur(u
.uconduct
.polyselfs
));
2699 if (!u
.uconduct
.wishes
) {
2700 you_have_X("used no wishes");
2702 Sprintf(buf
, "used %ld wish%s", u
.uconduct
.wishes
,
2703 (u
.uconduct
.wishes
> 1L) ? "es" : "");
2704 if (u
.uconduct
.wisharti
) {
2705 /* if wisharti == wishes
2706 * 1 wish (for an artifact)
2707 * 2 wishes (both for artifacts)
2708 * N wishes (all for artifacts)
2709 * else (N is at least 2 in order to get here; M < N)
2710 * N wishes (1 for an artifact)
2711 * N wishes (M for artifacts)
2713 if (u
.uconduct
.wisharti
== u
.uconduct
.wishes
)
2714 Sprintf(eos(buf
), " (%s",
2715 (u
.uconduct
.wisharti
> 2L) ? "all "
2716 : (u
.uconduct
.wisharti
== 2L) ? "both " : "");
2718 Sprintf(eos(buf
), " (%ld ", u
.uconduct
.wisharti
);
2720 Sprintf(eos(buf
), "for %s)",
2721 (u
.uconduct
.wisharti
== 1L) ? "an artifact"
2726 if (!u
.uconduct
.wisharti
)
2727 enl_msg(You_
, "have not wished", "did not wish",
2728 " for any artifacts", "");
2731 /* Pop up the window and wait for a key */
2732 display_nhwindow(en_win
, TRUE
);
2733 destroy_nhwindow(en_win
);
2737 /* Macros for meta and ctrl modifiers:
2738 * M and C return the meta/ctrl code for the given character;
2739 * e.g., (C('c') is ctrl-c
2740 * ISMETA and ISCTRL return TRUE iff the code is a meta/ctrl code
2741 * UNMETA and UNCTRL are the opposite of M/C and return the key for a given
2742 * meta/ctrl code. */
2745 #define M(c) (0x80 | (c))
2747 #define M(c) ((c) -128)
2750 #define ISMETA(c) (((c) & 0x80) != 0)
2751 #define UNMETA(c) ((c) & 0x7f)
2754 #define C(c) (0x1f & (c))
2756 #define ISCTRL(c) ((uchar)(c) < 0x20)
2757 #define UNCTRL(c) (ISCTRL(c) ? (0x60 | (c)) : (c))
2759 /* ordered by command name */
2760 struct ext_func_tab extcmdlist
[] = {
2761 { '#', "#", "perform an extended command",
2762 doextcmd
, IFBURIED
| GENERALCMD
},
2763 { M('?'), "?", "get this list of extended commands",
2764 doextlist
, IFBURIED
| AUTOCOMPLETE
| GENERALCMD
},
2765 { M('a'), "adjust", "adjust inventory letters",
2766 doorganize
, IFBURIED
| AUTOCOMPLETE
},
2767 { M('A'), "annotate", "name current level",
2768 donamelevel
, IFBURIED
| AUTOCOMPLETE
},
2769 { 'a', "apply", "apply (use) a tool (pick-axe, key, lamp...)",
2771 { C('x'), "attributes", "show your attributes",
2772 doattributes
, IFBURIED
},
2773 { '@', "autopickup", "toggle the pickup option on/off",
2774 dotogglepickup
, IFBURIED
},
2775 { 'C', "call", "call (name) something", docallcmd
, IFBURIED
},
2776 { 'Z', "cast", "zap (cast) a spell", docast
, IFBURIED
},
2777 { M('c'), "chat", "talk to someone", dotalk
, IFBURIED
| AUTOCOMPLETE
},
2778 { 'c', "close", "close a door", doclose
},
2779 { M('C'), "conduct", "list voluntary challenges you have maintained",
2780 doconduct
, IFBURIED
| AUTOCOMPLETE
},
2781 { M('d'), "dip", "dip an object into something", dodip
, AUTOCOMPLETE
},
2782 { '>', "down", "go down a staircase", dodown
},
2783 { 'd', "drop", "drop an item", dodrop
},
2784 { 'D', "droptype", "drop specific item types", doddrop
},
2785 { 'e', "eat", "eat something", doeat
},
2786 { 'E', "engrave", "engrave writing on the floor", doengrave
},
2787 { M('e'), "enhance", "advance or check weapon and spell skills",
2788 enhance_weapon_skill
, IFBURIED
| AUTOCOMPLETE
},
2789 { '\0', "exploremode", "enter explore (discovery) mode",
2790 enter_explore_mode
, IFBURIED
},
2791 { 'f', "fire", "fire ammunition from quiver", dofire
},
2792 { M('f'), "force", "force a lock", doforce
, AUTOCOMPLETE
},
2793 { ';', "glance", "show what type of thing a map symbol corresponds to",
2794 doquickwhatis
, IFBURIED
| GENERALCMD
},
2795 { '?', "help", "give a help message", dohelp
, IFBURIED
| GENERALCMD
},
2796 { 'V', "history", "show long version and game history",
2797 dohistory
, IFBURIED
| GENERALCMD
},
2798 { 'i', "inventory", "show your inventory", ddoinv
, IFBURIED
},
2799 { 'I', "inventtype", "inventory specific item types",
2800 dotypeinv
, IFBURIED
},
2801 { M('i'), "invoke", "invoke an object's special powers",
2802 doinvoke
, IFBURIED
| AUTOCOMPLETE
},
2803 { M('j'), "jump", "jump to another location", dojump
, AUTOCOMPLETE
},
2804 { C('d'), "kick", "kick something", dokick
},
2805 { '\\', "known", "show what object types have been discovered",
2806 dodiscovered
, IFBURIED
| GENERALCMD
},
2807 { '`', "knownclass", "show discovered types for one class of objects",
2808 doclassdisco
, IFBURIED
|GENERALCMD
},
2809 { '\0', "levelchange", "change experience level",
2810 wiz_level_change
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2811 { '\0', "lightsources", "show mobile light sources",
2812 wiz_light_sources
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2813 { ':', "look", "look at what is here", dolook
, IFBURIED
},
2814 { M('l'), "loot", "loot a box on the floor", doloot
, AUTOCOMPLETE
},
2815 #ifdef DEBUG_MIGRATING_MONS
2816 { '\0', "migratemons", "migrate N random monsters",
2817 wiz_migrate_mons
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2819 { '\0', "monpolycontrol", "control monster polymorphs",
2820 wiz_mon_polycontrol
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2821 { M('m'), "monster", "use monster's special ability",
2822 domonability
, IFBURIED
| AUTOCOMPLETE
},
2823 { 'N', "name", "name a monster or an object",
2824 docallcmd
, IFBURIED
| AUTOCOMPLETE
},
2825 { M('o'), "offer", "offer a sacrifice to the gods",
2826 dosacrifice
, AUTOCOMPLETE
},
2827 { 'o', "open", "open a door", doopen
},
2828 { 'O', "options", "show option settings, possibly change them",
2829 doset
, IFBURIED
|GENERALCMD
},
2830 { C('o'), "overview", "show a summary of the explored dungeon",
2831 dooverview
, IFBURIED
|AUTOCOMPLETE
},
2832 { '\0', "panic", "test panic routine (fatal to game)",
2833 wiz_panic
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2834 { 'p', "pay", "pay your shopping bill", dopay
},
2835 { ',', "pickup", "pick up things at the current location", dopickup
},
2836 { '\0', "polyself", "polymorph self",
2837 wiz_polyself
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2839 { '\0', "portdebug", "wizard port debug command",
2840 wiz_port_debug
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2842 { M('p'), "pray", "pray to the gods for help",
2843 dopray
, IFBURIED
| AUTOCOMPLETE
},
2844 { C('p'), "prevmsg", "view recent game messages",
2845 doprev_message
, IFBURIED
|GENERALCMD
},
2846 { 'P', "puton", "put on an accessory (ring, amulet, etc)", doputon
},
2847 { 'q', "quaff", "quaff (drink) something", dodrink
},
2848 { M('q'), "quit", "exit without saving current game",
2849 done2
, IFBURIED
| AUTOCOMPLETE
| GENERALCMD
},
2850 { 'Q', "quiver", "select ammunition for quiver", dowieldquiver
},
2851 { 'r', "read", "read a scroll or spellbook", doread
},
2852 { C('r'), "redraw", "redraw screen", doredraw
, IFBURIED
| GENERALCMD
},
2853 { 'R', "remove", "remove an accessory (ring, amulet, etc)", doremring
},
2854 { M('R'), "ride", "mount or dismount a saddled steed",
2855 doride
, AUTOCOMPLETE
},
2856 { M('r'), "rub", "rub a lamp or a stone", dorub
, AUTOCOMPLETE
},
2857 { 'S', "save", "save the game and exit", dosave
, IFBURIED
| GENERALCMD
},
2858 { 's', "search", "search for traps and secret doors",
2859 dosearch
, IFBURIED
, "searching" },
2860 { '*', "seeall", "show all equipment in use", doprinuse
, IFBURIED
},
2861 { AMULET_SYM
, "seeamulet", "show the amulet currently worn",
2862 dopramulet
, IFBURIED
},
2863 { ARMOR_SYM
, "seearmor", "show the armor currently worn",
2864 doprarm
, IFBURIED
},
2865 { GOLD_SYM
, "seegold", "count your gold", doprgold
, IFBURIED
},
2866 { '\0', "seenv", "show seen vectors",
2867 wiz_show_seenv
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2868 { RING_SYM
, "seerings", "show the ring(s) currently worn",
2869 doprring
, IFBURIED
},
2870 { SPBOOK_SYM
, "seespells", "list and reorder known spells",
2871 dovspell
, IFBURIED
},
2872 { TOOL_SYM
, "seetools", "show the tools currently in use",
2873 doprtool
, IFBURIED
},
2874 { '^', "seetrap", "show the type of adjacent trap", doidtrap
, IFBURIED
},
2875 { WEAPON_SYM
, "seeweapon", "show the weapon currently wielded",
2876 doprwep
, IFBURIED
},
2878 { '!', "shell", "do a shell escape", dosh
, IFBURIED
| GENERALCMD
},
2880 { M('s'), "sit", "sit down", dosit
, AUTOCOMPLETE
},
2881 { '\0', "stats", "show memory statistics",
2882 wiz_show_stats
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2884 { C('z'), "suspend", "suspend the game",
2885 dosuspend_core
, IFBURIED
| GENERALCMD
},
2886 #endif /* SUSPEND */
2887 { 'x', "swap", "swap wielded and secondary weapons", doswapweapon
},
2888 { 'T', "takeoff", "take off one piece of armor", dotakeoff
},
2889 { 'A', "takeoffall", "remove all armor", doddoremarm
},
2890 { C('t'), "teleport", "teleport around the level", dotele
, IFBURIED
},
2891 { '\0', "terrain", "show map without obstructions",
2892 doterrain
, IFBURIED
| AUTOCOMPLETE
},
2893 { 't', "throw", "throw something", dothrow
},
2894 { '\0', "timeout", "look at timeout queue",
2895 wiz_timeout_queue
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2896 { M('T'), "tip", "empty a container", dotip
, AUTOCOMPLETE
},
2897 { '_', "travel", "travel to a specific location on the map", dotravel
},
2898 { M('t'), "turn", "turn undead away", doturn
, IFBURIED
| AUTOCOMPLETE
},
2899 { 'X', "twoweapon", "toggle two-weapon combat",
2900 dotwoweapon
, AUTOCOMPLETE
},
2901 { M('u'), "untrap", "untrap something", dountrap
, AUTOCOMPLETE
},
2902 { '<', "up", "go up a staircase", doup
},
2903 { '\0', "vanquished", "list vanquished monsters",
2904 dovanquished
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2905 { M('v'), "version",
2906 "list compile time options for this version of NetHack",
2907 doextversion
, IFBURIED
| AUTOCOMPLETE
| GENERALCMD
},
2908 { 'v', "versionshort", "show version", doversion
, IFBURIED
| GENERALCMD
},
2909 { '\0', "vision", "show vision array",
2910 wiz_show_vision
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2911 { '.', "wait", "rest one move while doing nothing",
2912 donull
, IFBURIED
, "waiting" },
2913 { 'W', "wear", "wear a piece of armor", dowear
},
2914 { '&', "whatdoes", "tell what a command does", dowhatdoes
, IFBURIED
},
2915 { '/', "whatis", "show what type of thing a symbol corresponds to",
2916 dowhatis
, IFBURIED
| GENERALCMD
},
2917 { 'w', "wield", "wield (put in use) a weapon", dowield
},
2918 { M('w'), "wipe", "wipe off your face", dowipe
, AUTOCOMPLETE
},
2920 { '\0', "wizdebug_bury", "wizard debug: bury objs under and around you",
2921 wiz_debug_cmd_bury
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2922 { '\0', "wizdebug_traveldisplay", "wizard debug: toggle travel display",
2923 wiz_debug_cmd_traveldisplay
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2925 { C('e'), "wizdetect", "reveal hidden things within a small radius",
2926 wiz_detect
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2927 { C('g'), "wizgenesis", "create a monster",
2928 wiz_genesis
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2929 { C('i'), "wizidentify", "identify all items in inventory",
2930 wiz_identify
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2931 { '\0', "wizintrinsic", "set an intrinsic",
2932 wiz_intrinsic
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2933 { C('v'), "wizlevelport", "teleport to another level",
2934 wiz_level_tele
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2935 { '\0', "wizmakemap", "recreate the current level",
2936 wiz_makemap
, IFBURIED
| WIZMODECMD
},
2937 { C('f'), "wizmap", "map the level",
2938 wiz_map
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2939 { '\0', "wizrumorcheck", "verify rumor boundaries",
2940 wiz_rumor_check
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2941 { '\0', "wizsmell", "smell monster",
2942 wiz_smell
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2943 { '\0', "wizwhere", "show locations of special levels",
2944 wiz_where
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2945 { C('w'), "wizwish", "wish for something",
2946 wiz_wish
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2947 { '\0', "wmode", "show wall modes",
2948 wiz_show_wmodes
, IFBURIED
| AUTOCOMPLETE
| WIZMODECMD
},
2949 { 'z', "zap", "zap a wand", dozap
},
2950 { '\0', (char *) 0, (char *) 0, donull
, 0, (char *) 0 } /* sentinel */
2957 if (Cmd
.commands
[key
] && Cmd
.commands
[key
]->ef_txt
)
2958 return Cmd
.commands
[key
]->ef_desc
;
2963 bind_key(key
, command
)
2965 const char *command
;
2967 struct ext_func_tab
*extcmd
;
2969 /* special case: "nothing" is reserved for unbinding */
2970 if (!strcmp(command
, "nothing")) {
2971 Cmd
.commands
[key
] = (struct ext_func_tab
*) 0;
2975 for (extcmd
= extcmdlist
; extcmd
->ef_txt
; extcmd
++) {
2976 if (strcmp(command
, extcmd
->ef_txt
))
2978 Cmd
.commands
[key
] = extcmd
;
2983 "Bad command %s matched with key %c (ASCII %i). Ignoring command.\n",
2987 /* initialize all keyboard commands */
2991 struct ext_func_tab
*extcmd
;
2993 for (extcmd
= extcmdlist
; extcmd
->ef_txt
; extcmd
++)
2995 Cmd
.commands
[extcmd
->key
] = extcmd
;
2997 bind_key(C('l'), "redraw"); /* if number_pad is set */
2998 /* 'b', 'B' : go sw */
2999 /* 'F' : fight (one time) */
3000 /* 'g', 'G' : multiple go */
3001 /* 'h', 'H' : go west */
3002 bind_key('h', "help"); /* if number_pad is set */
3003 bind_key('j', "jump"); /* if number_pad is on */
3004 /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' move commands */
3005 bind_key('k', "kick"); /* if number_pad is on */
3006 bind_key('l', "loot"); /* if number_pad is on */
3007 bind_key(C('n'), "annotate"); /* if number_pad is on */
3008 bind_key(M('n'), "name");
3009 bind_key(M('N'), "name");
3010 bind_key('u', "untrap"); /* if number_pad is on */
3013 bind_key(M('O'), "overview");
3014 bind_key(M('2'), "twoweapon");
3017 bind_key(' ', "wait");
3021 dokeylist_putcmds(datawin
, docount
, cmdflags
, exflags
, keys_used
)
3024 int cmdflags
, exflags
;
3025 boolean
*keys_used
; /* boolean keys_used[256] */
3032 for (i
= 0; i
< 256; i
++) {
3033 const struct ext_func_tab
*extcmd
;
3034 uchar key
= (uchar
) i
;
3038 if (key
== ' ' && !flags
.rest_on_space
)
3040 if ((extcmd
= Cmd
.commands
[i
]) != (struct ext_func_tab
*) 0) {
3041 if ((cmdflags
&& !(extcmd
->flags
& cmdflags
))
3042 || (exflags
&& (extcmd
->flags
& exflags
)))
3048 Sprintf(buf
, "%-8s %-12s %s", key2txt(key
, buf2
),
3051 putstr(datawin
, 0, buf
);
3052 keys_used
[i
] = TRUE
;
3058 /* list all keys and their bindings, like dat/hh but dynamic */
3060 dokeylist(VOID_ARGS
)
3062 char buf
[BUFSZ
], buf2
[BUFSZ
];
3064 boolean keys_used
[256] = {0};
3072 { NHKF_ESC
, "escape from the current query/action", FALSE
},
3074 "Prefix: rush until something interesting is seen", FALSE
},
3076 "Prefix: run until something extremely interesting is seen", FALSE
},
3078 "Prefix: run until something extremely interesting is seen", TRUE
},
3080 "Prefix: force fight even if you don't see a monster", FALSE
},
3082 "Prefix: force fight even if you don't see a monster", TRUE
},
3084 "Prefix: move without picking up objects/fighting", FALSE
},
3085 { NHKF_RUN_NOPICKUP
,
3086 "Prefix: run without picking up objects/fighting", FALSE
},
3087 { NHKF_DOINV
, "inventory (same as #inventory)", TRUE
},
3088 { NHKF_REQMENU
, "Prefix: request a menu", FALSE
},
3090 { NHKF_DOAGAIN
, "redo the previous command", FALSE
},
3092 { 0, (const char *) 0, FALSE
}
3095 datawin
= create_nhwindow(NHW_TEXT
);
3096 putstr(datawin
, 0, "");
3097 putstr(datawin
, 0, " Full Current Key Bindings List");
3099 /* directional keys */
3100 putstr(datawin
, 0, "");
3101 putstr(datawin
, 0, "Directional keys:");
3102 show_direction_keys(datawin
, FALSE
);
3104 keys_used
[(uchar
) Cmd
.move_NW
] = keys_used
[(uchar
) Cmd
.move_N
]
3105 = keys_used
[(uchar
) Cmd
.move_NE
] = keys_used
[(uchar
) Cmd
.move_W
]
3106 = keys_used
[(uchar
) Cmd
.move_E
] = keys_used
[(uchar
) Cmd
.move_SW
]
3107 = keys_used
[(uchar
) Cmd
.move_S
] = keys_used
[(uchar
) Cmd
.move_SE
]
3110 if (!iflags
.num_pad
) {
3111 keys_used
[(uchar
) highc(Cmd
.move_NW
)]
3112 = keys_used
[(uchar
) highc(Cmd
.move_N
)]
3113 = keys_used
[(uchar
) highc(Cmd
.move_NE
)]
3114 = keys_used
[(uchar
) highc(Cmd
.move_W
)]
3115 = keys_used
[(uchar
) highc(Cmd
.move_E
)]
3116 = keys_used
[(uchar
) highc(Cmd
.move_SW
)]
3117 = keys_used
[(uchar
) highc(Cmd
.move_S
)]
3118 = keys_used
[(uchar
) highc(Cmd
.move_SE
)] = TRUE
;
3119 keys_used
[(uchar
) C(Cmd
.move_NW
)]
3120 = keys_used
[(uchar
) C(Cmd
.move_N
)]
3121 = keys_used
[(uchar
) C(Cmd
.move_NE
)]
3122 = keys_used
[(uchar
) C(Cmd
.move_W
)]
3123 = keys_used
[(uchar
) C(Cmd
.move_E
)]
3124 = keys_used
[(uchar
) C(Cmd
.move_SW
)]
3125 = keys_used
[(uchar
) C(Cmd
.move_S
)]
3126 = keys_used
[(uchar
) C(Cmd
.move_SE
)] = TRUE
;
3127 putstr(datawin
, 0, "");
3129 "Shift-<direction> will move in specified direction until you hit");
3130 putstr(datawin
, 0, " a wall or run into something.");
3132 "Ctrl-<direction> will run in specified direction until something");
3133 putstr(datawin
, 0, " very interesting is seen.");
3136 putstr(datawin
, 0, "");
3137 putstr(datawin
, 0, "Miscellaneous keys:");
3138 for (i
= 0; misc_keys
[i
].desc
; i
++) {
3139 key
= Cmd
.spkeys
[misc_keys
[i
].nhkf
];
3140 if (key
&& ((misc_keys
[i
].numpad
&& iflags
.num_pad
)
3141 || !misc_keys
[i
].numpad
)) {
3142 keys_used
[(uchar
) key
] = TRUE
;
3143 Sprintf(buf
, "%-8s %s", key2txt(key
, buf2
), misc_keys
[i
].desc
);
3144 putstr(datawin
, 0, buf
);
3148 putstr(datawin
, 0, "^c break out of NetHack (SIGINT)");
3149 keys_used
[(uchar
) C('c')] = TRUE
;
3152 putstr(datawin
, 0, "");
3153 show_menu_controls(datawin
, TRUE
);
3155 if (dokeylist_putcmds(datawin
, TRUE
, GENERALCMD
, WIZMODECMD
, keys_used
)) {
3156 putstr(datawin
, 0, "");
3157 putstr(datawin
, 0, "General commands:");
3158 (void) dokeylist_putcmds(datawin
, FALSE
, GENERALCMD
, WIZMODECMD
,
3162 if (dokeylist_putcmds(datawin
, TRUE
, 0, WIZMODECMD
, keys_used
)) {
3163 putstr(datawin
, 0, "");
3164 putstr(datawin
, 0, "Game commands:");
3165 (void) dokeylist_putcmds(datawin
, FALSE
, 0, WIZMODECMD
, keys_used
);
3169 && dokeylist_putcmds(datawin
, TRUE
, WIZMODECMD
, 0, keys_used
)) {
3170 putstr(datawin
, 0, "");
3171 putstr(datawin
, 0, "Wizard-mode commands:");
3172 (void) dokeylist_putcmds(datawin
, FALSE
, WIZMODECMD
, 0, keys_used
);
3175 display_nhwindow(datawin
, FALSE
);
3176 destroy_nhwindow(datawin
);
3185 for (i
= 0; i
< 256; ++i
)
3186 if (Cmd
.commands
[i
] && Cmd
.commands
[i
]->ef_funct
== fn
)
3192 * wizard mode sanity_check code
3195 static const char template[] = "%-27s %4ld %6ld";
3196 static const char stats_hdr
[] = " count bytes";
3197 static const char stats_sep
[] = "--------------------------- ----- -------";
3203 int sz
= (int) sizeof(struct obj
);
3206 sz
+= (int) sizeof(struct oextra
);
3208 sz
+= (int) strlen(ONAME(otmp
)) + 1;
3210 sz
+= (int) sizeof(struct monst
);
3212 sz
+= (int) sizeof(unsigned);
3214 sz
+= (int) sizeof(long);
3216 sz
+= (int) strlen(OMAILCMD(otmp
)) + 1;
3222 count_obj(chain
, total_count
, total_size
, top
, recurse
)
3232 for (count
= size
= 0, obj
= chain
; obj
; obj
= obj
->nobj
) {
3235 size
+= size_obj(obj
);
3237 if (recurse
&& obj
->cobj
)
3238 count_obj(obj
->cobj
, total_count
, total_size
, TRUE
, TRUE
);
3240 *total_count
+= count
;
3241 *total_size
+= size
;
3245 obj_chain(win
, src
, chain
, force
, total_count
, total_size
)
3254 long count
= 0L, size
= 0L;
3256 count_obj(chain
, &count
, &size
, TRUE
, FALSE
);
3258 if (count
|| size
|| force
) {
3259 *total_count
+= count
;
3260 *total_size
+= size
;
3261 Sprintf(buf
, template, src
, count
, size
);
3262 putstr(win
, 0, buf
);
3267 mon_invent_chain(win
, src
, chain
, total_count
, total_size
)
3270 struct monst
*chain
;
3275 long count
= 0, size
= 0;
3278 for (mon
= chain
; mon
; mon
= mon
->nmon
)
3279 count_obj(mon
->minvent
, &count
, &size
, TRUE
, FALSE
);
3281 if (count
|| size
) {
3282 *total_count
+= count
;
3283 *total_size
+= size
;
3284 Sprintf(buf
, template, src
, count
, size
);
3285 putstr(win
, 0, buf
);
3290 contained_stats(win
, src
, total_count
, total_size
)
3297 long count
= 0, size
= 0;
3300 count_obj(invent
, &count
, &size
, FALSE
, TRUE
);
3301 count_obj(fobj
, &count
, &size
, FALSE
, TRUE
);
3302 count_obj(level
.buriedobjlist
, &count
, &size
, FALSE
, TRUE
);
3303 count_obj(migrating_objs
, &count
, &size
, FALSE
, TRUE
);
3304 /* DEADMONSTER check not required in this loop since they have no
3306 for (mon
= fmon
; mon
; mon
= mon
->nmon
)
3307 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3308 for (mon
= migrating_mons
; mon
; mon
= mon
->nmon
)
3309 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3311 if (count
|| size
) {
3312 *total_count
+= count
;
3313 *total_size
+= size
;
3314 Sprintf(buf
, template, src
, count
, size
);
3315 putstr(win
, 0, buf
);
3320 size_monst(mtmp
, incl_wsegs
)
3324 int sz
= (int) sizeof (struct monst
);
3326 if (mtmp
->wormno
&& incl_wsegs
)
3327 sz
+= size_wseg(mtmp
);
3330 sz
+= (int) sizeof (struct mextra
);
3332 sz
+= (int) strlen(MNAME(mtmp
)) + 1;
3334 sz
+= (int) sizeof (struct egd
);
3336 sz
+= (int) sizeof (struct epri
);
3338 sz
+= (int) sizeof (struct eshk
);
3340 sz
+= (int) sizeof (struct emin
);
3342 sz
+= (int) sizeof (struct edog
);
3343 /* mextra->mcorpsenm doesn't point to more memory */
3349 mon_chain(win
, src
, chain
, force
, total_count
, total_size
)
3352 struct monst
*chain
;
3360 /* mon->wormno means something different for migrating_mons and mydogs */
3361 boolean incl_wsegs
= !strcmpi(src
, "fmon");
3364 for (mon
= chain
; mon
; mon
= mon
->nmon
) {
3366 size
+= size_monst(mon
, incl_wsegs
);
3368 if (count
|| size
|| force
) {
3369 *total_count
+= count
;
3370 *total_size
+= size
;
3371 Sprintf(buf
, template, src
, count
, size
);
3372 putstr(win
, 0, buf
);
3377 misc_stats(win
, total_count
, total_size
)
3382 char buf
[BUFSZ
], hdrbuf
[QBUFSZ
];
3386 struct damage
*sd
; /* shop damage */
3387 struct cemetery
*bi
; /* bones info */
3389 /* traps and engravings are output unconditionally;
3390 * others only if nonzero
3393 for (tt
= ftrap
; tt
; tt
= tt
->ntrap
) {
3395 size
+= (long) sizeof *tt
;
3397 *total_count
+= count
;
3398 *total_size
+= size
;
3399 Sprintf(hdrbuf
, "traps, size %ld", (long) sizeof (struct trap
));
3400 Sprintf(buf
, template, hdrbuf
, count
, size
);
3401 putstr(win
, 0, buf
);
3404 engr_stats("engravings, size %ld+text", hdrbuf
, &count
, &size
);
3405 *total_count
+= count
;
3406 *total_size
+= size
;
3407 Sprintf(buf
, template, hdrbuf
, count
, size
);
3408 putstr(win
, 0, buf
);
3411 light_stats("light sources, size %ld", hdrbuf
, &count
, &size
);
3412 if (count
|| size
) {
3413 *total_count
+= count
;
3414 *total_size
+= size
;
3415 Sprintf(buf
, template, hdrbuf
, count
, size
);
3416 putstr(win
, 0, buf
);
3420 timer_stats("timers, size %ld", hdrbuf
, &count
, &size
);
3421 if (count
|| size
) {
3422 *total_count
+= count
;
3423 *total_size
+= size
;
3424 Sprintf(buf
, template, hdrbuf
, count
, size
);
3425 putstr(win
, 0, buf
);
3429 for (sd
= level
.damagelist
; sd
; sd
= sd
->next
) {
3431 size
+= (long) sizeof *sd
;
3433 if (count
|| size
) {
3434 *total_count
+= count
;
3435 *total_size
+= size
;
3436 Sprintf(hdrbuf
, "shop damage, size %ld",
3437 (long) sizeof (struct damage
));
3438 Sprintf(buf
, template, hdrbuf
, count
, size
);
3439 putstr(win
, 0, buf
);
3443 region_stats("regions, size %ld+%ld*rect+N", hdrbuf
, &count
, &size
);
3444 if (count
|| size
) {
3445 *total_count
+= count
;
3446 *total_size
+= size
;
3447 Sprintf(buf
, template, hdrbuf
, count
, size
);
3448 putstr(win
, 0, buf
);
3452 for (bi
= level
.bonesinfo
; bi
; bi
= bi
->next
) {
3454 size
+= (long) sizeof *bi
;
3456 if (count
|| size
) {
3457 *total_count
+= count
;
3458 *total_size
+= size
;
3459 Sprintf(hdrbuf
, "bones history, size %ld",
3460 (long) sizeof (struct cemetery
));
3461 Sprintf(buf
, template, hdrbuf
, count
, size
);
3462 putstr(win
, 0, buf
);
3466 for (idx
= 0; idx
< NUM_OBJECTS
; ++idx
)
3467 if (objects
[idx
].oc_uname
) {
3469 size
+= (long) (strlen(objects
[idx
].oc_uname
) + 1);
3471 if (count
|| size
) {
3472 *total_count
+= count
;
3473 *total_size
+= size
;
3474 Strcpy(hdrbuf
, "object type names, text");
3475 Sprintf(buf
, template, hdrbuf
, count
, size
);
3476 putstr(win
, 0, buf
);
3481 * Display memory usage of all monsters and objects on the level.
3488 long total_obj_size
, total_obj_count
,
3489 total_mon_size
, total_mon_count
,
3490 total_ovr_size
, total_ovr_count
,
3491 total_misc_size
, total_misc_count
;
3493 win
= create_nhwindow(NHW_TEXT
);
3494 putstr(win
, 0, "Current memory statistics:");
3496 total_obj_count
= total_obj_size
= 0L;
3497 putstr(win
, 0, stats_hdr
);
3498 Sprintf(buf
, " Objects, base size %ld", (long) sizeof (struct obj
));
3499 putstr(win
, 0, buf
);
3500 obj_chain(win
, "invent", invent
, TRUE
, &total_obj_count
, &total_obj_size
);
3501 obj_chain(win
, "fobj", fobj
, TRUE
, &total_obj_count
, &total_obj_size
);
3502 obj_chain(win
, "buried", level
.buriedobjlist
, FALSE
,
3503 &total_obj_count
, &total_obj_size
);
3504 obj_chain(win
, "migrating obj", migrating_objs
, FALSE
,
3505 &total_obj_count
, &total_obj_size
);
3506 obj_chain(win
, "billobjs", billobjs
, FALSE
,
3507 &total_obj_count
, &total_obj_size
);
3508 mon_invent_chain(win
, "minvent", fmon
, &total_obj_count
, &total_obj_size
);
3509 mon_invent_chain(win
, "migrating minvent", migrating_mons
,
3510 &total_obj_count
, &total_obj_size
);
3511 contained_stats(win
, "contained", &total_obj_count
, &total_obj_size
);
3512 putstr(win
, 0, stats_sep
);
3513 Sprintf(buf
, template, " Obj total", total_obj_count
, total_obj_size
);
3514 putstr(win
, 0, buf
);
3516 total_mon_count
= total_mon_size
= 0L;
3518 Sprintf(buf
, " Monsters, base size %ld", (long) sizeof (struct monst
));
3519 putstr(win
, 0, buf
);
3520 mon_chain(win
, "fmon", fmon
, TRUE
, &total_mon_count
, &total_mon_size
);
3521 mon_chain(win
, "migrating", migrating_mons
, FALSE
,
3522 &total_mon_count
, &total_mon_size
);
3523 /* 'mydogs' is only valid during level change or end of game disclosure,
3524 but conceivably we've been called from within debugger at such time */
3525 if (mydogs
) /* monsters accompanying hero */
3526 mon_chain(win
, "mydogs", mydogs
, FALSE
,
3527 &total_mon_count
, &total_mon_size
);
3528 putstr(win
, 0, stats_sep
);
3529 Sprintf(buf
, template, " Mon total", total_mon_count
, total_mon_size
);
3530 putstr(win
, 0, buf
);
3532 total_ovr_count
= total_ovr_size
= 0L;
3534 putstr(win
, 0, " Overview");
3535 overview_stats(win
, template, &total_ovr_count
, &total_ovr_size
);
3536 putstr(win
, 0, stats_sep
);
3537 Sprintf(buf
, template, " Over total", total_ovr_count
, total_ovr_size
);
3538 putstr(win
, 0, buf
);
3540 total_misc_count
= total_misc_size
= 0L;
3542 putstr(win
, 0, " Miscellaneous");
3543 misc_stats(win
, &total_misc_count
, &total_misc_size
);
3544 putstr(win
, 0, stats_sep
);
3545 Sprintf(buf
, template, " Misc total", total_misc_count
, total_misc_size
);
3546 putstr(win
, 0, buf
);
3549 putstr(win
, 0, stats_sep
);
3550 Sprintf(buf
, template, " Grand total",
3551 (total_obj_count
+ total_mon_count
3552 + total_ovr_count
+ total_misc_count
),
3553 (total_obj_size
+ total_mon_size
3554 + total_ovr_size
+ total_misc_size
));
3555 putstr(win
, 0, buf
);
3557 #if defined(__BORLANDC__) && !defined(_WIN32)
3558 show_borlandc_stats(win
);
3561 display_nhwindow(win
, FALSE
);
3562 destroy_nhwindow(win
);
3570 timer_sanity_check();
3572 light_sources_sanity_check();
3575 #ifdef DEBUG_MIGRATING_MONS
3581 struct permonst
*ptr
;
3585 getlin("How many random monsters to migrate? [0]", inbuf
);
3586 if (*inbuf
== '\033')
3588 mcount
= atoi(inbuf
);
3589 if (mcount
< 0 || mcount
> (COLNO
* ROWNO
) || Is_botlevel(&u
.uz
))
3591 while (mcount
> 0) {
3592 if (Is_stronghold(&u
.uz
))
3593 assign_level(&tolevel
, &valley_level
);
3595 get_level(&tolevel
, depth(&u
.uz
) + 1);
3597 mtmp
= makemon(ptr
, 0, 0, NO_MM_FLAGS
);
3599 migrate_to_level(mtmp
, ledger_no(&tolevel
), MIGR_RANDOM
,
3607 #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
3608 #define unmeta(c) (0x7f & (c))
3614 } const spkeys_binds
[] = {
3615 { NHKF_ESC
, '\033', (char *) 0 }, /* no binding */
3616 { NHKF_DOAGAIN
, DOAGAIN
, "repeat" },
3617 { NHKF_REQMENU
, 'm', "reqmenu" },
3618 { NHKF_RUN
, 'G', "run" },
3619 { NHKF_RUN2
, '5', "run.numpad" },
3620 { NHKF_RUSH
, 'g', "rush" },
3621 { NHKF_FIGHT
, 'F', "fight" },
3622 { NHKF_FIGHT2
, '-', "fight.numpad" },
3623 { NHKF_NOPICKUP
, 'm', "nopickup" },
3624 { NHKF_RUN_NOPICKUP
, 'M', "run.nopickup" },
3625 { NHKF_DOINV
, '0', "doinv" },
3626 { NHKF_TRAVEL
, CMD_TRAVEL
, (char *) 0 }, /* no binding */
3627 { NHKF_CLICKLOOK
, CMD_CLICKLOOK
, (char *) 0 }, /* no binding */
3628 { NHKF_REDRAW
, C('r'), "redraw" },
3629 { NHKF_REDRAW2
, C('l'), "redraw.numpad" },
3630 { NHKF_GETDIR_SELF
, '.', "getdir.self" },
3631 { NHKF_GETDIR_SELF2
, 's', "getdir.self2" },
3632 { NHKF_GETDIR_HELP
, '?', "getdir.help" },
3633 { NHKF_COUNT
, 'n', "count" },
3634 { NHKF_GETPOS_SELF
, '@', "getpos.self" },
3635 { NHKF_GETPOS_PICK
, '.', "getpos.pick" },
3636 { NHKF_GETPOS_PICK_Q
, ',', "getpos.pick.quick" },
3637 { NHKF_GETPOS_PICK_O
, ';', "getpos.pick.once" },
3638 { NHKF_GETPOS_PICK_V
, ':', "getpos.pick.verbose" },
3639 { NHKF_GETPOS_SHOWVALID
, '$', "getpos.valid" },
3640 { NHKF_GETPOS_AUTODESC
, '#', "getpos.autodescribe" },
3641 { NHKF_GETPOS_MON_NEXT
, 'm', "getpos.mon.next" },
3642 { NHKF_GETPOS_MON_PREV
, 'M', "getpos.mon.prev" },
3643 { NHKF_GETPOS_OBJ_NEXT
, 'o', "getpos.obj.next" },
3644 { NHKF_GETPOS_OBJ_PREV
, 'O', "getpos.obj.prev" },
3645 { NHKF_GETPOS_DOOR_NEXT
, 'd', "getpos.door.next" },
3646 { NHKF_GETPOS_DOOR_PREV
, 'D', "getpos.door.prev" },
3647 { NHKF_GETPOS_UNEX_NEXT
, 'x', "getpos.unexplored.next" },
3648 { NHKF_GETPOS_UNEX_PREV
, 'X', "getpos.unexplored.prev" },
3649 { NHKF_GETPOS_INTERESTING_NEXT
, 'a', "getpos.all.next" },
3650 { NHKF_GETPOS_INTERESTING_PREV
, 'A', "getpos.all.prev" },
3651 { NHKF_GETPOS_HELP
, '?', "getpos.help" },
3652 { NHKF_GETPOS_LIMITVIEW
, '"', "getpos.inview" },
3653 { NHKF_GETPOS_MENU
, '!', "getpos.menu" }
3657 bind_specialkey(key
, command
)
3659 const char *command
;
3662 for (i
= 0; i
< SIZE(spkeys_binds
); i
++) {
3663 if (!spkeys_binds
[i
].name
|| strcmp(command
, spkeys_binds
[i
].name
))
3665 Cmd
.spkeys
[spkeys_binds
[i
].nhkf
] = key
;
3671 /* returns a one-byte character from the text (it may massacre the txt
3677 txt
= trimspaces(txt
);
3681 /* simple character */
3685 /* a few special entries */
3686 if (!strcmp(txt
, "<enter>"))
3688 if (!strcmp(txt
, "<space>"))
3690 if (!strcmp(txt
, "<esc>"))
3693 /* control and meta keys */
3695 case 'm': /* can be mx, Mx, m-x, M-x */
3698 if (*txt
== '-' && txt
[1])
3703 case 'c': /* can be cx, Cx, ^x, c-x, C-x, ^-x */
3707 if (*txt
== '-' && txt
[1])
3714 /* ascii codes: must be three-digit decimal */
3715 if (*txt
>= '0' && *txt
<= '9') {
3719 for (i
= 0; i
< 3; i
++) {
3720 if (txt
[i
] < '0' || txt
[i
] > '9')
3722 key
= 10 * key
+ txt
[i
] - '0';
3730 /* returns the text for a one-byte encoding
3731 * must be shorter than a tab for proper formatting */
3735 char *txt
; /* sufficiently long buffer */
3738 Sprintf(txt
, "<space>");
3739 else if (c
== '\033')
3740 Sprintf(txt
, "<esc>");
3742 Sprintf(txt
, "<enter>");
3744 Sprintf(txt
, "^%c", highc(UNCTRL(c
)));
3746 Sprintf(txt
, "M-%c", UNMETA(c
));
3747 else if (c
>= 33 && c
<= 126)
3748 Sprintf(txt
, "%c", c
); /* regular keys: ! through ~ */
3750 Sprintf(txt
, "A-%i", c
); /* arbitrary ascii combinations */
3756 parseautocomplete(autocomplete
, condition
)
3760 struct ext_func_tab
*efp
;
3761 register char *autoc
;
3763 /* break off first autocomplete from the rest; parse the rest */
3764 if ((autoc
= index(autocomplete
, ',')) != 0
3765 || (autoc
= index(autocomplete
, ':')) != 0) {
3767 parseautocomplete(autoc
, condition
);
3770 /* strip leading and trailing white space */
3771 autocomplete
= trimspaces(autocomplete
);
3776 /* take off negation */
3777 if (*autocomplete
== '!') {
3778 /* unlike most options, a leading "no" might actually be a part of
3779 * the extended command. Thus you have to use ! */
3781 autocomplete
= trimspaces(autocomplete
);
3782 condition
= !condition
;
3785 /* find and modify the extended command */
3786 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
3787 if (!strcmp(autocomplete
, efp
->ef_txt
)) {
3789 efp
->flags
|= AUTOCOMPLETE
;
3791 efp
->flags
&= ~AUTOCOMPLETE
;
3796 /* not a real extended command */
3797 raw_printf("Bad autocomplete: invalid extended command '%s'.",
3802 /* called at startup and after number_pad is twiddled */
3804 reset_commands(initial
)
3807 static const char sdir
[] = "hykulnjb><",
3808 sdir_swap_yz
[] = "hzkulnjb><",
3809 ndir
[] = "47896321><",
3810 ndir_phone_layout
[] = "41236987><";
3811 static const int ylist
[] = {
3812 'y', 'Y', C('y'), M('y'), M('Y'), M(C('y'))
3814 static struct ext_func_tab
*back_dir_cmd
[8];
3815 const struct ext_func_tab
*cmdtmp
;
3817 int c
, i
, updated
= 0;
3818 static boolean backed_dir_cmd
= FALSE
;
3822 Cmd
.num_pad
= FALSE
;
3823 Cmd
.pcHack_compat
= Cmd
.phone_layout
= Cmd
.swap_yz
= FALSE
;
3824 for (i
= 0; i
< SIZE(spkeys_binds
); i
++)
3825 Cmd
.spkeys
[spkeys_binds
[i
].nhkf
] = spkeys_binds
[i
].key
;
3829 if (backed_dir_cmd
) {
3830 for (i
= 0; i
< 8; i
++) {
3831 Cmd
.commands
[(uchar
) Cmd
.dirchars
[i
]] = back_dir_cmd
[i
];
3836 flagtemp
= iflags
.num_pad
;
3837 if (flagtemp
!= Cmd
.num_pad
) {
3838 Cmd
.num_pad
= flagtemp
;
3841 /* swap_yz mode (only applicable for !num_pad); intended for
3842 QWERTZ keyboard used in Central Europe, particularly Germany */
3843 flagtemp
= (iflags
.num_pad_mode
& 1) ? !Cmd
.num_pad
: FALSE
;
3844 if (flagtemp
!= Cmd
.swap_yz
) {
3845 Cmd
.swap_yz
= flagtemp
;
3847 /* Cmd.swap_yz has been toggled;
3848 perform the swap (or reverse previous one) */
3849 for (i
= 0; i
< SIZE(ylist
); i
++) {
3850 c
= ylist
[i
] & 0xff;
3851 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [y] */
3852 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 1]; /* [y] = [z] */
3853 Cmd
.commands
[c
+ 1] = cmdtmp
; /* [z] = tmp */
3856 /* MSDOS compatibility mode (only applicable for num_pad) */
3857 flagtemp
= (iflags
.num_pad_mode
& 1) ? Cmd
.num_pad
: FALSE
;
3858 if (flagtemp
!= Cmd
.pcHack_compat
) {
3859 Cmd
.pcHack_compat
= flagtemp
;
3861 /* pcHack_compat has been toggled */
3863 cmdtmp
= Cmd
.commands
['5'];
3864 Cmd
.commands
['5'] = Cmd
.commands
[c
];
3865 Cmd
.commands
[c
] = cmdtmp
;
3867 Cmd
.commands
[c
] = Cmd
.pcHack_compat
? Cmd
.commands
['I'] : 0;
3869 /* phone keypad layout (only applicable for num_pad) */
3870 flagtemp
= (iflags
.num_pad_mode
& 2) ? Cmd
.num_pad
: FALSE
;
3871 if (flagtemp
!= Cmd
.phone_layout
) {
3872 Cmd
.phone_layout
= flagtemp
;
3874 /* phone_layout has been toggled */
3875 for (i
= 0; i
< 3; i
++) {
3876 c
= '1' + i
; /* 1,2,3 <-> 7,8,9 */
3877 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [1] */
3878 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [1] = [7] */
3879 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [7] = tmp */
3880 c
= (M('1') & 0xff) + i
; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
3881 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [M-1] */
3882 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [M-1] = [M-7] */
3883 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [M-7] = tmp */
3890 Cmd
.dirchars
= !Cmd
.num_pad
3891 ? (!Cmd
.swap_yz
? sdir
: sdir_swap_yz
)
3892 : (!Cmd
.phone_layout
? ndir
: ndir_phone_layout
);
3893 Cmd
.alphadirchars
= !Cmd
.num_pad
? Cmd
.dirchars
: sdir
;
3895 Cmd
.move_W
= Cmd
.dirchars
[0];
3896 Cmd
.move_NW
= Cmd
.dirchars
[1];
3897 Cmd
.move_N
= Cmd
.dirchars
[2];
3898 Cmd
.move_NE
= Cmd
.dirchars
[3];
3899 Cmd
.move_E
= Cmd
.dirchars
[4];
3900 Cmd
.move_SE
= Cmd
.dirchars
[5];
3901 Cmd
.move_S
= Cmd
.dirchars
[6];
3902 Cmd
.move_SW
= Cmd
.dirchars
[7];
3905 for (i
= 0; i
< 8; i
++) {
3907 (struct ext_func_tab
*) Cmd
.commands
[(uchar
) Cmd
.dirchars
[i
]];
3908 Cmd
.commands
[(uchar
) Cmd
.dirchars
[i
]] = (struct ext_func_tab
*) 0;
3910 backed_dir_cmd
= TRUE
;
3911 for (i
= 0; i
< 8; i
++)
3912 bind_key(Cmd
.dirchars
[i
], "nothing");
3916 /* non-movement commands which accept 'm' prefix to request menu operation */
3918 accept_menu_prefix(cmd_func
)
3919 int NDECL((*cmd_func
));
3921 if (cmd_func
== dopickup
|| cmd_func
== dotip
3922 /* eat, #offer, and apply tinning-kit all use floorfood() to pick
3923 an item on floor or in invent; 'm' skips picking from floor
3924 (ie, inventory only) rather than request use of menu operation */
3925 || cmd_func
== doeat
|| cmd_func
== dosacrifice
|| cmd_func
== doapply
3926 /* 'm' for removing saddle from adjacent monster without checking
3927 for containers at <u.ux,u.uy> */
3928 || cmd_func
== doloot
3929 /* travel: pop up a menu of interesting targets in view */
3930 || cmd_func
== dotravel
3931 /* 'm' prefix allowed for some extended commands */
3932 || cmd_func
== doextcmd
|| cmd_func
== doextlist
)
3938 ch2spkeys(c
, start
,end
)
3943 for (i
= start
; i
<= end
; i
++)
3944 if (Cmd
.spkeys
[i
] == c
)
3953 boolean do_walk
, do_rush
, prefix_seen
, bad_command
,
3954 firsttime
= (cmd
== 0);
3956 iflags
.menu_requested
= FALSE
;
3958 if (program_state
.done_hup
)
3965 if (*cmd
== Cmd
.spkeys
[NHKF_ESC
]) {
3966 context
.move
= FALSE
;
3969 if (*cmd
== DOAGAIN
&& !in_doagain
&& saveq
[0]) {
3972 rhack((char *) 0); /* read and execute command */
3976 /* Special case of *cmd == ' ' handled better below */
3977 if (!*cmd
|| *cmd
== (char) 0377) {
3979 context
.move
= FALSE
;
3980 return; /* probably we just had an interrupt */
3983 /* handle most movement commands */
3984 do_walk
= do_rush
= prefix_seen
= FALSE
;
3985 context
.travel
= context
.travel1
= 0;
3986 switch (ch2spkeys(*cmd
, NHKF_RUN
,NHKF_CLICKLOOK
)) {
3988 if (movecmd(cmd
[1])) {
3996 break; /* else FALLTHRU */
3998 if (movecmd(lowc(cmd
[1]))) {
4006 break; /* else FALLTHRU */
4007 /* Effects of movement commands and invisible monsters:
4008 * m: always move onto space (even if 'I' remembered)
4009 * F: always attack space (even if 'I' not remembered)
4010 * normal movement: attack if 'I', move otherwise.
4013 if (movecmd(cmd
[1])) {
4014 context
.forcefight
= 1;
4020 if (movecmd(cmd
[1]) || u
.dz
) {
4026 cmd
[0] = cmd
[1]; /* "m<" or "m>" */
4030 case NHKF_RUN_NOPICKUP
:
4031 if (movecmd(lowc(cmd
[1]))) {
4041 (void) ddoinv(); /* a convenience borrowed from the PC */
4042 context
.move
= FALSE
;
4045 case NHKF_CLICKLOOK
:
4046 if (iflags
.clicklook
) {
4047 context
.move
= FALSE
;
4048 do_look(2, &clicklook_cc
);
4052 if (flags
.travelcmd
) {
4054 context
.travel1
= 1;
4062 if (movecmd(*cmd
)) { /* ordinary movement */
4063 context
.run
= 0; /* only matters here if it was 8 */
4065 } else if (movecmd(Cmd
.num_pad
? unmeta(*cmd
) : lowc(*cmd
))) {
4068 } else if (movecmd(unctrl(*cmd
))) {
4075 /* some special prefix handling */
4076 /* overload 'm' prefix to mean "request a menu" */
4077 if (prefix_seen
&& cmd
[0] == Cmd
.spkeys
[NHKF_REQMENU
]) {
4078 /* (for func_tab cast, see below) */
4079 const struct ext_func_tab
*ft
= Cmd
.commands
[cmd
[1] & 0xff];
4080 int NDECL((*func
)) = ft
? ((struct ext_func_tab
*) ft
)->ef_funct
: 0;
4082 if (func
&& accept_menu_prefix(func
)) {
4083 iflags
.menu_requested
= TRUE
;
4088 if ((do_walk
|| do_rush
) && !context
.travel
&& !dxdy_moveok()) {
4089 /* trying to move diagonally as a grid bug;
4090 this used to be treated by movecmd() as not being
4091 a movement attempt, but that didn't provide for any
4092 feedback and led to strangeness if the key pressed
4093 ('u' in particular) was overloaded for num_pad use */
4094 You_cant("get there from here...");
4096 context
.nopick
= context
.forcefight
= FALSE
;
4097 context
.move
= context
.mv
= FALSE
;
4106 context
.forcefight
= 0;
4108 } else if (do_rush
) {
4111 multi
= max(COLNO
, ROWNO
);
4112 u
.last_str_turn
= 0;
4117 } else if (prefix_seen
&& cmd
[1] == Cmd
.spkeys
[NHKF_ESC
]) {
4118 /* <prefix><escape> */
4119 /* don't report "unknown command" for change of heart... */
4120 bad_command
= FALSE
;
4121 } else if (*cmd
== ' ' && !flags
.rest_on_space
) {
4122 bad_command
= TRUE
; /* skip cmdlist[] loop */
4124 /* handle all other commands */
4126 register const struct ext_func_tab
*tlist
;
4127 int res
, NDECL((*func
));
4129 /* current - use *cmd to directly index cmdlist array */
4130 if ((tlist
= Cmd
.commands
[*cmd
& 0xff]) != 0) {
4131 if (!wizard
&& (tlist
->flags
& WIZMODECMD
)) {
4132 You_cant("do that!");
4134 } else if (u
.uburied
&& !(tlist
->flags
& IFBURIED
)) {
4135 You_cant("do that while you are buried!");
4138 /* we discard 'const' because some compilers seem to have
4139 trouble with the pointer passed to set_occupation() */
4140 func
= ((struct ext_func_tab
*) tlist
)->ef_funct
;
4141 if (tlist
->f_text
&& !occupation
&& multi
)
4142 set_occupation(func
, tlist
->f_text
, multi
);
4143 res
= (*func
)(); /* perform the command */
4146 context
.move
= FALSE
;
4151 /* if we reach here, cmd wasn't found in cmdlist[] */
4156 char expcmd
[20]; /* we expect 'cmd' to point to 1 or 2 chars */
4160 while ((c
= *cmd
++) != '\0')
4161 Strcat(expcmd
, visctrl(c
)); /* add 1..4 chars plus terminator */
4163 if (!prefix_seen
|| !iflags
.cmdassist
4164 || !help_dir(0, "Invalid direction key!"))
4165 Norep("Unknown command '%s'.", expcmd
);
4168 context
.move
= FALSE
;
4173 /* convert an x,y pair into a direction code */
4180 for (dd
= 0; dd
< 8; dd
++)
4181 if (x
== xdir
[dd
] && y
== ydir
[dd
])
4186 /* convert a direction code into an x,y pair */
4197 /* also sets u.dz, but returns false for <> */
4202 register const char *dp
= index(Cmd
.dirchars
, sym
);
4207 u
.dx
= xdir
[dp
- Cmd
.dirchars
];
4208 u
.dy
= ydir
[dp
- Cmd
.dirchars
];
4209 u
.dz
= zdir
[dp
- Cmd
.dirchars
];
4210 #if 0 /* now handled elsewhere */
4211 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
)) {
4219 /* grid bug handling which used to be in movecmd() */
4223 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
))
4225 return u
.dx
|| u
.dy
;
4228 /* decide whether a character (user input keystroke) requests screen repaint */
4233 return (boolean
) (c
== Cmd
.spkeys
[NHKF_REDRAW
]
4234 || (Cmd
.num_pad
&& c
== Cmd
.spkeys
[NHKF_REDRAW2
]));
4241 return (c
== Cmd
.spkeys
[NHKF_RUSH
]
4242 || c
== Cmd
.spkeys
[NHKF_RUN
]
4243 || c
== Cmd
.spkeys
[NHKF_NOPICKUP
]
4244 || c
== Cmd
.spkeys
[NHKF_RUN_NOPICKUP
]
4245 || c
== Cmd
.spkeys
[NHKF_FIGHT
]
4246 || (Cmd
.num_pad
&& (c
== Cmd
.spkeys
[NHKF_RUN2
]
4247 || c
== Cmd
.spkeys
[NHKF_FIGHT2
])));
4251 * uses getdir() but unlike getdir() it specifically
4252 * produces coordinates using the direction from getdir()
4253 * and verifies that those coordinates are ok.
4255 * If the call to getdir() returns 0, Never_mind is displayed.
4256 * If the resulting coordinates are not okay, emsg is displayed.
4258 * Returns non-zero if coordinates in cc are valid.
4261 get_adjacent_loc(prompt
, emsg
, x
, y
, cc
)
4262 const char *prompt
, *emsg
;
4267 if (!getdir(prompt
)) {
4273 if (cc
&& isok(new_x
, new_y
)) {
4292 if (in_doagain
|| *readchar_queue
)
4293 dirsym
= readchar();
4295 dirsym
= yn_function((s
&& *s
!= '^') ? s
: "In what direction?",
4297 /* remove the prompt string so caller won't have to */
4298 clear_nhwindow(WIN_MESSAGE
);
4300 if (redraw_cmd(dirsym
)) { /* ^R */
4301 docrt(); /* redraw */
4306 if (dirsym
== Cmd
.spkeys
[NHKF_GETDIR_SELF
]
4307 || dirsym
== Cmd
.spkeys
[NHKF_GETDIR_SELF2
]) {
4308 u
.dx
= u
.dy
= u
.dz
= 0;
4309 } else if (!(is_mov
= movecmd(dirsym
)) && !u
.dz
) {
4310 boolean did_help
= FALSE
, help_requested
;
4312 if (!index(quitchars
, dirsym
)) {
4313 help_requested
= (dirsym
== Cmd
.spkeys
[NHKF_GETDIR_HELP
]);
4314 if (help_requested
|| iflags
.cmdassist
) {
4315 did_help
= help_dir((s
&& *s
== '^') ? dirsym
: 0,
4316 help_requested
? (const char *) 0
4317 : "Invalid direction key!");
4322 pline("What a strange direction!");
4325 } else if (is_mov
&& !dxdy_moveok()) {
4326 You_cant("orient yourself that direction.");
4329 if (!u
.dz
&& (Stunned
|| (Confusion
&& !rn2(5))))
4335 show_direction_keys(win
, nodiag
)
4342 Sprintf(buf
, " %c ", Cmd
.move_N
);
4343 putstr(win
, 0, buf
);
4344 putstr(win
, 0, " | ");
4345 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
4346 putstr(win
, 0, buf
);
4347 putstr(win
, 0, " | ");
4348 Sprintf(buf
, " %c ", Cmd
.move_S
);
4349 putstr(win
, 0, buf
);
4351 Sprintf(buf
, " %c %c %c", Cmd
.move_NW
, Cmd
.move_N
,
4353 putstr(win
, 0, buf
);
4354 putstr(win
, 0, " \\ | / ");
4355 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
4356 putstr(win
, 0, buf
);
4357 putstr(win
, 0, " / | \\ ");
4358 Sprintf(buf
, " %c %c %c", Cmd
.move_SW
, Cmd
.move_S
,
4360 putstr(win
, 0, buf
);
4369 static const char wiz_only_list
[] = "EFGIVW";
4372 char buf
[BUFSZ
], buf2
[BUFSZ
], *explain
;
4374 win
= create_nhwindow(NHW_TEXT
);
4378 Sprintf(buf
, "cmdassist: %s", msg
);
4379 putstr(win
, 0, buf
);
4382 if (letter(sym
) || sym
== '[') { /* 'dat/cmdhelp' shows ESC as ^[ */
4383 sym
= highc(sym
); /* @A-Z[ (note: letter() accepts '@') */
4384 ctrl
= (sym
- 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */
4385 if ((explain
= dowhatdoes_core(ctrl
, buf2
)) != 0
4386 && (!index(wiz_only_list
, sym
) || wizard
)) {
4387 Sprintf(buf
, "Are you trying to use ^%c%s?", sym
,
4388 index(wiz_only_list
, sym
)
4390 : " as specified in the Guidebook");
4391 putstr(win
, 0, buf
);
4393 putstr(win
, 0, explain
);
4396 "To use that command, hold down the <Ctrl> key as a shift");
4397 Sprintf(buf
, "and press the <%c> key.", sym
);
4398 putstr(win
, 0, buf
);
4403 Sprintf(buf
, "Valid direction keys %sare:",
4404 NODIAG(u
.umonnum
) ? "in your current form " : "");
4405 putstr(win
, 0, buf
);
4406 show_direction_keys(win
, NODIAG(u
.umonnum
));
4409 putstr(win
, 0, " < up");
4410 putstr(win
, 0, " > down");
4411 Sprintf(buf
, " %4s direct at yourself",
4412 visctrl(Cmd
.spkeys
[NHKF_GETDIR_SELF
]));
4413 putstr(win
, 0, buf
);
4415 /* non-null msg means that this wasn't an explicit user request */
4418 "(Suppress this message with !cmdassist in config file.)");
4420 display_nhwindow(win
, FALSE
);
4421 destroy_nhwindow(win
);
4428 register int x
= NODIAG(u
.umonnum
) ? 2 * rn2(4) : rn2(8);
4439 static NEARDATA
const char *const dirnames
[] = {
4440 "west", "northwest", "north", "northeast", "east",
4441 "southeast", "south", "southwest", "down", "up",
4444 if (dir
< 0 || dir
>= SIZE(dirnames
))
4446 return dirnames
[dir
];
4453 /* x corresponds to curx, so x==1 is the first column. Ach. %% */
4454 return x
>= 1 && x
<= COLNO
- 1 && y
>= 0 && y
<= ROWNO
- 1;
4457 static NEARDATA
int last_multi
;
4460 * convert a MAP window position into a movecmd
4463 click_to_cmd(x
, y
, mod
)
4470 if (iflags
.clicklook
&& mod
== CLICK_2
) {
4473 cmd
[0] = Cmd
.spkeys
[NHKF_CLICKLOOK
];
4480 if (flags
.travelcmd
) {
4481 if (abs(x
) <= 1 && abs(y
) <= 1) {
4482 x
= sgn(x
), y
= sgn(y
);
4486 cmd
[0] = Cmd
.spkeys
[NHKF_TRAVEL
];
4490 if (x
== 0 && y
== 0) {
4492 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)
4493 || IS_SINK(levl
[u
.ux
][u
.uy
].typ
)) {
4494 cmd
[0] = cmd_from_func(mod
== CLICK_1
? dodrink
: dodip
);
4496 } else if (IS_THRONE(levl
[u
.ux
][u
.uy
].typ
)) {
4497 cmd
[0] = cmd_from_func(dosit
);
4499 } else if ((u
.ux
== xupstair
&& u
.uy
== yupstair
)
4500 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
4502 || (u
.ux
== xupladder
&& u
.uy
== yupladder
)) {
4503 cmd
[0] = cmd_from_func(doup
);
4505 } else if ((u
.ux
== xdnstair
&& u
.uy
== ydnstair
)
4506 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
4508 || (u
.ux
== xdnladder
&& u
.uy
== ydnladder
)) {
4509 cmd
[0] = cmd_from_func(dodown
);
4511 } else if (OBJ_AT(u
.ux
, u
.uy
)) {
4512 cmd
[0] = cmd_from_func(Is_container(level
.objects
[u
.ux
][u
.uy
])
4513 ? doloot
: dopickup
);
4516 cmd
[0] = cmd_from_func(donull
); /* just rest */
4521 /* directional commands */
4525 if (!m_at(u
.ux
+ x
, u
.uy
+ y
)
4526 && !test_move(u
.ux
, u
.uy
, x
, y
, TEST_MOVE
)) {
4527 cmd
[1] = Cmd
.dirchars
[dir
];
4529 if (IS_DOOR(levl
[u
.ux
+ x
][u
.uy
+ y
].typ
)) {
4530 /* slight assistance to the player: choose kick/open for them
4532 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_LOCKED
) {
4533 cmd
[0] = cmd_from_func(dokick
);
4536 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_CLOSED
) {
4537 cmd
[0] = cmd_from_func(doopen
);
4541 if (levl
[u
.ux
+ x
][u
.uy
+ y
].typ
<= SCORR
) {
4542 cmd
[0] = cmd_from_func(dosearch
);
4548 /* convert without using floating point, allowing sloppy clicking */
4551 else if (y
> 2 * abs(x
))
4553 else if (x
< -2 * abs(y
))
4555 else if (y
< -2 * abs(x
))
4558 x
= sgn(x
), y
= sgn(y
);
4560 if (x
== 0 && y
== 0) {
4561 /* map click on player to "rest" command */
4562 cmd
[0] = cmd_from_func(donull
);
4568 /* move, attack, etc. */
4570 if (mod
== CLICK_1
) {
4571 cmd
[0] = Cmd
.dirchars
[dir
];
4573 cmd
[0] = (Cmd
.num_pad
4574 ? M(Cmd
.dirchars
[dir
])
4575 : (Cmd
.dirchars
[dir
] - 'a' + 'A')); /* run command */
4582 get_count(allowchars
, inkey
, maxcount
, count
)
4591 boolean backspaced
= FALSE
;
4592 /* this should be done in port code so that we have erase_char
4593 and kill_char available; we can at least fake erase_char */
4594 #define STANDBY_erase_char '\177'
4604 cnt
= 10L * cnt
+ (long) (key
- '0');
4607 else if (maxcount
> 0 && cnt
> maxcount
)
4609 } else if (cnt
&& (key
== '\b' || key
== STANDBY_erase_char
)) {
4612 } else if (key
== Cmd
.spkeys
[NHKF_ESC
]) {
4614 } else if (!allowchars
|| index(allowchars
, key
)) {
4619 if (cnt
> 9 || backspaced
) {
4620 clear_nhwindow(WIN_MESSAGE
);
4621 if (backspaced
&& !cnt
) {
4622 Sprintf(qbuf
, "Count: ");
4624 Sprintf(qbuf
, "Count: %ld", cnt
);
4638 #ifdef LINT /* static char in_line[COLNO]; */
4639 char in_line
[COLNO
];
4641 static char in_line
[COLNO
];
4644 boolean prezero
= FALSE
;
4648 flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
4651 alt_esc
= iflags
.altmeta
; /* readchar() hack */
4653 if (!Cmd
.num_pad
|| (foo
= readchar()) == Cmd
.spkeys
[NHKF_COUNT
]) {
4654 long tmpmulti
= multi
;
4656 foo
= get_count((char *) 0, '\0', LARGEST_INT
, &tmpmulti
);
4657 last_multi
= multi
= tmpmulti
;
4660 alt_esc
= FALSE
; /* readchar() reset */
4663 if (foo
== Cmd
.spkeys
[NHKF_ESC
]) { /* esc cancels count (TH) */
4664 clear_nhwindow(WIN_MESSAGE
);
4665 multi
= last_multi
= 0;
4666 } else if (foo
== Cmd
.spkeys
[NHKF_DOAGAIN
] || in_doagain
) {
4670 savech(0); /* reset input queue */
4678 save_cm
= (char *) 0;
4680 /* in 3.4.3 this was in rhack(), where it was too late to handle M-5 */
4681 if (Cmd
.pcHack_compat
) {
4682 /* This handles very old inconsistent DOS/Windows behaviour
4683 in a different way: earlier, the keyboard handler mapped
4684 these, which caused counts to be strange when entered
4685 from the number pad. Now do not map them until here. */
4688 foo
= Cmd
.spkeys
[NHKF_RUSH
];
4691 foo
= Cmd
.spkeys
[NHKF_RUN
];
4694 foo
= Cmd
.spkeys
[NHKF_DOINV
];
4703 if (prefix_cmd(foo
)) {
4709 clear_nhwindow(WIN_MESSAGE
);
4711 in_line
[0] = Cmd
.spkeys
[NHKF_ESC
];
4715 #ifdef HANGUPHANDLING
4716 /* some very old systems, or descendents of such systems, expect signal
4717 handlers to have return type `int', but they don't actually inspect
4718 the return value so we should be safe using `void' unconditionally */
4721 hangup(sig_unused
) /* called as signal() handler, so sent at least one arg */
4722 int sig_unused UNUSED
;
4724 if (program_state
.exiting
)
4725 program_state
.in_moveloop
= 0;
4728 /* When using SAFERHANGUP, the done_hup flag it tested in rhack
4729 and a couple of other places; actual hangup handling occurs then.
4730 This is 'safer' because it disallows certain cheats and also
4731 protects against losing objects in the process of being thrown,
4732 but also potentially riskier because the disconnected program
4733 must continue running longer before attempting a hangup save. */
4734 program_state
.done_hup
++;
4735 /* defer hangup iff game appears to be in progress */
4736 if (program_state
.in_moveloop
&& program_state
.something_worth_saving
)
4738 #endif /* SAFERHANGUP */
4745 #ifdef NOSAVEONHANGUP
4747 if (flags
.ins_chkpt
&& program_state
.something_worth_saving
)
4748 program_statue
.preserve_locks
= 1; /* keep files for recovery */
4750 program_state
.something_worth_saving
= 0; /* don't save */
4754 if (!program_state
.done_hup
++)
4756 if (program_state
.something_worth_saving
)
4758 if (iflags
.window_inited
)
4759 exit_nhwindows((char *) 0);
4761 terminate(EXIT_SUCCESS
);
4762 /*NOTREACHED*/ /* not necessarily true for vms... */
4765 #endif /* HANGUPHANDLING */
4771 int x
= u
.ux
, y
= u
.uy
, mod
= 0;
4773 if (*readchar_queue
)
4774 sym
= *readchar_queue
++;
4776 sym
= in_doagain
? pgetchar() : nh_poskey(&x
, &y
, &mod
);
4780 register int cnt
= NR_OF_EOFS
;
4782 * Some SYSV systems seem to return EOFs for various reasons
4783 * (?like when one hits break or for interrupted systemcalls?),
4784 * and we must see several before we quit.
4787 clearerr(stdin
); /* omit if clearerr is undefined */
4789 } while (--cnt
&& sym
== EOF
);
4791 #endif /* NR_OF_EOFS */
4794 #ifdef HANGUPHANDLING
4795 hangup(0); /* call end_of_input() or set program_state.done_hup */
4799 } else if (sym
== '\033' && alt_esc
) {
4800 /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' */
4801 sym
= *readchar_queue
? *readchar_queue
++ : pgetchar();
4802 if (sym
== EOF
|| sym
== 0)
4804 else if (sym
!= '\033')
4805 sym
|= 0200; /* force 8th bit on */
4807 } else if (sym
== 0) {
4809 readchar_queue
= click_to_cmd(x
, y
, mod
);
4810 sym
= *readchar_queue
++;
4818 /* Keyboard travel command */
4822 if (!flags
.travelcmd
)
4825 cc
.x
= iflags
.travelcc
.x
;
4826 cc
.y
= iflags
.travelcc
.y
;
4827 if (cc
.x
== -1 && cc
.y
== -1) {
4828 /* No cached destination, start attempt from current position */
4832 iflags
.getloc_travelmode
= TRUE
;
4833 if (iflags
.menu_requested
) {
4834 if (!getpos_menu(&cc
, TRUE
, GLOC_INTERESTING
)) {
4835 iflags
.getloc_travelmode
= FALSE
;
4839 pline("Where do you want to travel to?");
4840 if (getpos(&cc
, TRUE
, "the desired destination") < 0) {
4841 /* user pressed ESC */
4842 iflags
.getloc_travelmode
= FALSE
;
4846 iflags
.getloc_travelmode
= FALSE
;
4847 iflags
.travelcc
.x
= u
.tx
= cc
.x
;
4848 iflags
.travelcc
.y
= u
.ty
= cc
.y
;
4849 cmd
[0] = Cmd
.spkeys
[NHKF_TRAVEL
];
4850 readchar_queue
= cmd
;
4855 extern void NDECL(win32con_debug_keystrokes
);
4856 extern void NDECL(win32con_handler_info
);
4865 int num_menu_selections
;
4866 struct menu_selection_struct
{
4869 } menu_selections
[] = {
4871 { "test win32 keystrokes (tty only)", win32con_debug_keystrokes
},
4872 { "show keystroke handler information (tty only)",
4873 win32con_handler_info
},
4875 { (char *) 0, (void NDECL((*))) 0 } /* array terminator */
4878 num_menu_selections
= SIZE(menu_selections
) - 1;
4879 if (num_menu_selections
> 0) {
4880 menu_item
*pick_list
;
4881 win
= create_nhwindow(NHW_MENU
);
4883 for (k
= 0; k
< num_menu_selections
; ++k
) {
4885 add_menu(win
, NO_GLYPH
, &any
, item
++, 0, ATR_NONE
,
4886 menu_selections
[k
].menutext
, MENU_UNSELECTED
);
4888 end_menu(win
, "Which port debugging feature?");
4889 n
= select_menu(win
, PICK_ONE
, &pick_list
);
4890 destroy_nhwindow(win
);
4892 n
= pick_list
[0].item
.a_int
- 1;
4893 free((genericptr_t
) pick_list
);
4894 /* execute the function */
4895 (*menu_selections
[n
].fn
)();
4898 pline("No port-specific debug capability defined.");
4901 #endif /*PORT_DEBUG*/
4904 * Parameter validator for generic yes/no function to prevent
4905 * the core from sending too long a prompt string to the
4906 * window port causing a buffer overflow there.
4909 yn_function(query
, resp
, def
)
4910 const char *query
, *resp
;
4915 iflags
.last_msg
= PLNMSG_UNKNOWN
; /* most recent pline is clobbered */
4917 /* maximum acceptable length is QBUFSZ-1 */
4918 if (strlen(query
) >= QBUFSZ
) {
4919 /* caller shouldn't have passed anything this long */
4920 paniclog("Query truncated: ", query
);
4921 (void) strncpy(qbuf
, query
, QBUFSZ
- 1 - 3);
4922 Strcpy(&qbuf
[QBUFSZ
- 1 - 3], "...");
4925 return (*windowprocs
.win_yn_function
)(query
, resp
, def
);
4928 /* for paranoid_confirm:quit,die,attack prompting */
4930 paranoid_query(be_paranoid
, prompt
)
4931 boolean be_paranoid
;
4934 boolean confirmed_ok
;
4936 /* when paranoid, player must respond with "yes" rather than just 'y'
4937 to give the go-ahead for this query; default is "no" unless the
4938 ParanoidConfirm flag is set in which case there's no default */
4940 char qbuf
[QBUFSZ
], ans
[BUFSZ
];
4941 const char *promptprefix
= "", *responsetype
= ParanoidConfirm
4944 int trylimit
= 6; /* 1 normal, 5 more with "Yes or No:" prefix */
4946 /* in addition to being paranoid about this particular
4947 query, we might be even more paranoid about all paranoia
4948 responses (ie, ParanoidConfirm is set) in which case we
4949 require "no" to reject in addition to "yes" to confirm
4950 (except we won't loop if response is ESC; it means no) */
4952 Sprintf(qbuf
, "%s%s %s", promptprefix
, prompt
, responsetype
);
4954 (void) mungspaces(ans
);
4955 confirmed_ok
= !strcmpi(ans
, "yes");
4956 if (confirmed_ok
|| *ans
== '\033')
4958 promptprefix
= "\"Yes\" or \"No\": ";
4959 } while (ParanoidConfirm
&& strcmpi(ans
, "no") && --trylimit
);
4961 confirmed_ok
= (yn(prompt
) == 'y');
4963 return confirmed_ok
;
4970 /* Does current window system support suspend? */
4971 if ((*windowprocs
.win_can_suspend
)()) {
4972 /* NB: SYSCF SHELLERS handled in port code. */
4976 Norep("Suspend command not available.");