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. */
9 STATIC_VAR boolean alt_esc
= FALSE
;
12 struct cmd Cmd
= { 0 }; /* flag.h */
14 extern const char *hu_stat
[]; /* hunger status from eat.c */
15 extern const char *enc_stat
[]; /* encumbrance status from botl.c */
19 * Some systems may have getchar() return EOF for various reasons, and
20 * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
22 #if defined(SYSV) || defined(DGUX) || defined(HPUX)
27 #define CMD_TRAVEL (char) 0x90
28 #define CMD_CLICKLOOK (char) 0x8F
31 extern int NDECL(wiz_debug_cmd_bury
);
32 extern int NDECL(wiz_debug_cmd_traveldisplay
);
35 #ifdef DUMB /* stuff commented out in extern.h, but needed here */
36 extern int NDECL(doapply
); /**/
37 extern int NDECL(dorub
); /**/
38 extern int NDECL(dojump
); /**/
39 extern int NDECL(doextlist
); /**/
40 extern int NDECL(enter_explore_mode
); /**/
41 extern int NDECL(dodrop
); /**/
42 extern int NDECL(doddrop
); /**/
43 extern int NDECL(dodown
); /**/
44 extern int NDECL(doup
); /**/
45 extern int NDECL(donull
); /**/
46 extern int NDECL(dowipe
); /**/
47 extern int NDECL(docallcnd
); /**/
48 extern int NDECL(dotakeoff
); /**/
49 extern int NDECL(doremring
); /**/
50 extern int NDECL(dowear
); /**/
51 extern int NDECL(doputon
); /**/
52 extern int NDECL(doddoremarm
); /**/
53 extern int NDECL(dokick
); /**/
54 extern int NDECL(dofire
); /**/
55 extern int NDECL(dothrow
); /**/
56 extern int NDECL(doeat
); /**/
57 extern int NDECL(done2
); /**/
58 extern int NDECL(vanquished
); /**/
59 extern int NDECL(doengrave
); /**/
60 extern int NDECL(dopickup
); /**/
61 extern int NDECL(ddoinv
); /**/
62 extern int NDECL(dotypeinv
); /**/
63 extern int NDECL(dolook
); /**/
64 extern int NDECL(doprgold
); /**/
65 extern int NDECL(doprwep
); /**/
66 extern int NDECL(doprarm
); /**/
67 extern int NDECL(doprring
); /**/
68 extern int NDECL(dopramulet
); /**/
69 extern int NDECL(doprtool
); /**/
70 extern int NDECL(dosuspend
); /**/
71 extern int NDECL(doforce
); /**/
72 extern int NDECL(doopen
); /**/
73 extern int NDECL(doclose
); /**/
74 extern int NDECL(dosh
); /**/
75 extern int NDECL(dodiscovered
); /**/
76 extern int NDECL(doclassdisco
); /**/
77 extern int NDECL(doset
); /**/
78 extern int NDECL(dotogglepickup
); /**/
79 extern int NDECL(dowhatis
); /**/
80 extern int NDECL(doquickwhatis
); /**/
81 extern int NDECL(dowhatdoes
); /**/
82 extern int NDECL(dohelp
); /**/
83 extern int NDECL(dohistory
); /**/
84 extern int NDECL(doloot
); /**/
85 extern int NDECL(dodrink
); /**/
86 extern int NDECL(dodip
); /**/
87 extern int NDECL(dosacrifice
); /**/
88 extern int NDECL(dopray
); /**/
89 extern int NDECL(dotip
); /**/
90 extern int NDECL(doturn
); /**/
91 extern int NDECL(doredraw
); /**/
92 extern int NDECL(doread
); /**/
93 extern int NDECL(dosave
); /**/
94 extern int NDECL(dosearch
); /**/
95 extern int NDECL(doidtrap
); /**/
96 extern int NDECL(dopay
); /**/
97 extern int NDECL(dosit
); /**/
98 extern int NDECL(dotalk
); /**/
99 extern int NDECL(docast
); /**/
100 extern int NDECL(dovspell
); /**/
101 extern int NDECL(dotele
); /**/
102 extern int NDECL(dountrap
); /**/
103 extern int NDECL(doversion
); /**/
104 extern int NDECL(doextversion
); /**/
105 extern int NDECL(doswapweapon
); /**/
106 extern int NDECL(dowield
); /**/
107 extern int NDECL(dowieldquiver
); /**/
108 extern int NDECL(dozap
); /**/
109 extern int NDECL(doorganize
); /**/
112 static int NDECL(dosuspend_core
); /**/
114 static int NDECL((*timed_occ_fn
));
116 STATIC_PTR
int NDECL(doprev_message
);
117 STATIC_PTR
int NDECL(timed_occupation
);
118 STATIC_PTR
int NDECL(doextcmd
);
119 STATIC_PTR
int NDECL(domonability
);
120 STATIC_PTR
int NDECL(dotravel
);
121 STATIC_PTR
int NDECL(doterrain
);
122 STATIC_PTR
int NDECL(wiz_wish
);
123 STATIC_PTR
int NDECL(wiz_identify
);
124 STATIC_PTR
int NDECL(wiz_intrinsic
);
125 STATIC_PTR
int NDECL(wiz_map
);
126 STATIC_PTR
int NDECL(wiz_genesis
);
127 STATIC_PTR
int NDECL(wiz_where
);
128 STATIC_PTR
int NDECL(wiz_detect
);
129 STATIC_PTR
int NDECL(wiz_panic
);
130 STATIC_PTR
int NDECL(wiz_polyself
);
131 STATIC_PTR
int NDECL(wiz_level_tele
);
132 STATIC_PTR
int NDECL(wiz_level_change
);
133 STATIC_PTR
int NDECL(wiz_show_seenv
);
134 STATIC_PTR
int NDECL(wiz_show_vision
);
135 STATIC_PTR
int NDECL(wiz_smell
);
136 STATIC_PTR
int NDECL(wiz_mon_polycontrol
);
137 STATIC_PTR
int NDECL(wiz_show_wmodes
);
138 STATIC_DCL
void NDECL(wiz_map_levltyp
);
139 STATIC_DCL
void NDECL(wiz_levltyp_legend
);
140 #if defined(__BORLANDC__) && !defined(_WIN32)
141 extern void FDECL(show_borlandc_stats
, (winid
));
143 #ifdef DEBUG_MIGRATING_MONS
144 STATIC_PTR
int NDECL(wiz_migrate_mons
);
146 STATIC_DCL
int FDECL(size_monst
, (struct monst
*, BOOLEAN_P
));
147 STATIC_DCL
int FDECL(size_obj
, (struct obj
*));
148 STATIC_DCL
void FDECL(count_obj
, (struct obj
*, long *, long *,
149 BOOLEAN_P
, BOOLEAN_P
));
150 STATIC_DCL
void FDECL(obj_chain
, (winid
, const char *, struct obj
*,
151 BOOLEAN_P
, long *, long *));
152 STATIC_DCL
void FDECL(mon_invent_chain
, (winid
, const char *, struct monst
*,
154 STATIC_DCL
void FDECL(mon_chain
, (winid
, const char *, struct monst
*,
155 BOOLEAN_P
, long *, long *));
156 STATIC_DCL
void FDECL(contained_stats
, (winid
, const char *, long *, long *));
157 STATIC_DCL
void FDECL(misc_stats
, (winid
, long *, long *));
158 STATIC_PTR
int NDECL(wiz_show_stats
);
159 STATIC_DCL boolean
FDECL(accept_menu_prefix
, (int NDECL((*))));
161 STATIC_DCL
int NDECL(wiz_port_debug
);
163 STATIC_PTR
int NDECL(wiz_rumor_check
);
164 STATIC_DCL
char FDECL(cmd_from_func
, (int NDECL((*))));
165 STATIC_PTR
int NDECL(doattributes
);
166 STATIC_PTR
int NDECL(doconduct
); /**/
168 STATIC_DCL
void FDECL(enlght_line
, (const char *, const char *, const char *,
170 STATIC_DCL
char *FDECL(enlght_combatinc
, (const char *, int, int, char *));
171 STATIC_DCL
void FDECL(enlght_halfdmg
, (int, int));
172 STATIC_DCL boolean
NDECL(walking_on_water
);
173 STATIC_DCL boolean
FDECL(cause_known
, (int));
174 STATIC_DCL
char *FDECL(attrval
, (int, int, char *));
175 STATIC_DCL
void FDECL(background_enlightenment
, (int, int));
176 STATIC_DCL
void FDECL(characteristics_enlightenment
, (int, int));
177 STATIC_DCL
void FDECL(one_characteristic
, (int, int, int));
178 STATIC_DCL
void FDECL(status_enlightenment
, (int, int));
179 STATIC_DCL
void FDECL(attributes_enlightenment
, (int, int));
181 static const char *readchar_queue
= "";
182 static coord clicklook_cc
;
184 STATIC_DCL
char *NDECL(parse
);
185 STATIC_DCL
void FDECL(show_direction_keys
, (winid
, BOOLEAN_P
));
186 STATIC_DCL boolean
FDECL(help_dir
, (CHAR_P
, const char *));
189 doprev_message(VOID_ARGS
)
191 return nh_doprev_message();
194 /* Count down by decrementing multi */
196 timed_occupation(VOID_ARGS
)
204 /* If you have moved since initially setting some occupations, they
205 * now shouldn't be able to restart.
207 * The basic rule is that if you are carrying it, you can continue
208 * since it is with you. If you are acting on something at a distance,
209 * your orientation to it must have changed when you moved.
211 * The exception to this is taking off items, since they can be taken
212 * off in a number of ways in the intervening time, screwing up ordering.
214 * Currently: Take off all armor.
215 * Picking Locks / Forcing Chests.
226 /* If a time is given, use it to timeout this function, otherwise the
227 * function times out by its own means.
230 set_occupation(fn
, txt
, xtime
)
236 occupation
= timed_occupation
;
245 STATIC_DCL
char NDECL(popch
);
247 /* Provide a means to redo the last command. The flag `in_doagain' is set
248 * to true while redoing the command. This flag is tested in commands that
249 * require additional input (like `throw' which requires a thing and a
250 * direction), and the input prompt is not shown. Also, while in_doagain is
251 * TRUE, no keystrokes can be saved into the saveq.
254 static char pushq
[BSIZE
], saveq
[BSIZE
];
255 static NEARDATA
int phead
, ptail
, shead
, stail
;
260 /* If occupied, return '\0', letting tgetch know a character should
261 * be read from the keyboard. If the character read is not the
262 * ABORT character (as checked in pcmain.c), that character will be
263 * pushed back on the pushq.
268 return (char) ((shead
!= stail
) ? saveq
[stail
++] : '\0');
270 return (char) ((phead
!= ptail
) ? pushq
[ptail
++] : '\0');
274 pgetchar() /* courtesy of aeb@cwi.nl */
283 /* A ch == 0 resets the pushq */
295 /* A ch == 0 resets the saveq. Only save keystrokes when not
296 * replaying a previous command.
304 phead
= ptail
= shead
= stail
= 0;
305 else if (shead
< BSIZE
)
311 /* here after # - now read a full-word command */
318 /* keep repeating until we don't run help or quit */
324 func
= extcmdlist
[idx
].ef_funct
;
325 if (!wizard
&& (extcmdlist
[idx
].flags
& WIZMODECMD
)) {
326 You("can't do that.");
329 if (iflags
.menu_requested
&& !accept_menu_prefix(func
)) {
330 pline("'%s' prefix has no effect for this command.",
331 visctrl(Cmd
.spkeys
[NHKF_REQMENU
]));
332 iflags
.menu_requested
= FALSE
;
335 } while (func
== doextlist
);
340 /* here after #? - now list all full-word commands */
344 register const struct ext_func_tab
*efp
;
348 datawin
= create_nhwindow(NHW_TEXT
);
349 putstr(datawin
, 0, "");
350 putstr(datawin
, 0, " Extended Commands List");
351 putstr(datawin
, 0, "");
352 putstr(datawin
, 0, " Press '#', then type:");
353 putstr(datawin
, 0, "");
355 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
356 if (!wizard
&& (efp
->flags
& WIZMODECMD
))
358 Sprintf(buf
, " %-15s %c %s.",
360 (efp
->flags
& AUTOCOMPLETE
) ? '*' : ' ',
362 putstr(datawin
, 0, buf
);
364 putstr(datawin
, 0, "");
365 putstr(datawin
, 0, " Commands marked with a * will be autocompleted.");
366 display_nhwindow(datawin
, FALSE
);
367 destroy_nhwindow(datawin
);
372 #define MAX_EXT_CMD 200 /* Change if we ever have more ext cmds */
375 * This is currently used only by the tty port and is
376 * controlled via runtime option 'extmenu'.
377 * ``# ?'' is counted towards the limit of the number of commands,
378 * so we actually support MAX_EXT_CMD-1 "real" extended commands.
380 * Here after # - now show pick-list of possible commands.
385 const struct ext_func_tab
*efp
;
386 menu_item
*pick_list
= (menu_item
*) 0;
389 const struct ext_func_tab
*choices
[MAX_EXT_CMD
+ 1];
391 char cbuf
[QBUFSZ
], prompt
[QBUFSZ
], fmtstr
[20];
392 int i
, n
, nchoices
, acount
;
394 int accelerator
, prevaccelerator
;
403 /* populate choices */
404 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
405 if (!(efp
->flags
& AUTOCOMPLETE
)
406 || (!wizard
&& (efp
->flags
& WIZMODECMD
)))
408 if (!matchlevel
|| !strncmp(efp
->ef_txt
, cbuf
, matchlevel
)) {
410 if ((int) strlen(efp
->ef_desc
) > biggest
) {
411 biggest
= strlen(efp
->ef_desc
);
412 Sprintf(fmtstr
, "%%-%ds", biggest
+ 15);
414 if (++i
> MAX_EXT_CMD
) {
417 "Exceeded %d extended commands in doextcmd() menu; 'extmenu' disabled.",
425 choices
[i
] = (struct ext_func_tab
*) 0;
427 /* if we're down to one, we have our selection so get out of here */
429 for (i
= 0; extcmdlist
[i
].ef_txt
!= (char *) 0; i
++)
430 if ((extcmdlist
[i
].flags
& AUTOCOMPLETE
)
431 && !(!wizard
&& (extcmdlist
[i
].flags
& WIZMODECMD
))
432 && !strncmpi(extcmdlist
[i
].ef_txt
, cbuf
, matchlevel
)) {
440 win
= create_nhwindow(NHW_MENU
);
442 accelerator
= prevaccelerator
= 0;
444 for (i
= 0; choices
[i
]; ++i
) {
445 accelerator
= choices
[i
]->ef_txt
[matchlevel
];
446 if (accelerator
!= prevaccelerator
|| nchoices
< (ROWNO
- 3)) {
448 /* flush extended cmds for that letter already in buf */
449 Sprintf(buf
, fmtstr
, prompt
);
450 any
.a_char
= prevaccelerator
;
451 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
,
456 prevaccelerator
= accelerator
;
457 if (!acount
|| nchoices
< (ROWNO
- 3)) {
458 Sprintf(prompt
, "%s [%s]", choices
[i
]->ef_txt
,
459 choices
[i
]->ef_desc
);
460 } else if (acount
== 1) {
461 Sprintf(prompt
, "%s or %s", choices
[i
- 1]->ef_txt
,
464 Strcat(prompt
, " or ");
465 Strcat(prompt
, choices
[i
]->ef_txt
);
471 Sprintf(buf
, fmtstr
, prompt
);
472 any
.a_char
= prevaccelerator
;
473 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
, buf
,
476 Sprintf(prompt
, "Extended Command: %s", cbuf
);
477 end_menu(win
, prompt
);
478 n
= select_menu(win
, PICK_ONE
, &pick_list
);
479 destroy_nhwindow(win
);
481 if (matchlevel
> (QBUFSZ
- 2)) {
482 free((genericptr_t
) pick_list
);
484 impossible("Too many chars (%d) entered in extcmd_via_menu()",
489 cbuf
[matchlevel
++] = pick_list
[0].item
.a_char
;
490 cbuf
[matchlevel
] = '\0';
491 free((genericptr_t
) pick_list
);
503 #endif /* TTY_GRAPHICS */
505 /* #monster command - use special monster ability while polymorphed */
507 domonability(VOID_ARGS
)
509 if (can_breathe(youmonst
.data
))
511 else if (attacktype(youmonst
.data
, AT_SPIT
))
513 else if (youmonst
.data
->mlet
== S_NYMPH
)
515 else if (attacktype(youmonst
.data
, AT_GAZE
))
517 else if (is_were(youmonst
.data
))
519 else if (webmaker(youmonst
.data
))
521 else if (is_hider(youmonst
.data
))
523 else if (is_mind_flayer(youmonst
.data
))
524 return domindblast();
525 else if (u
.umonnum
== PM_GREMLIN
) {
526 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
527 if (split_mon(&youmonst
, (struct monst
*) 0))
528 dryup(u
.ux
, u
.uy
, TRUE
);
530 There("is no fountain here.");
531 } else if (is_unicorn(youmonst
.data
)) {
532 use_unicorn_horn((struct obj
*) 0);
534 } else if (youmonst
.data
->msound
== MS_SHRIEK
) {
537 pline("Unfortunately sound does not carry well through rock.");
540 } else if (youmonst
.data
->mlet
== S_VAMPIRE
)
543 pline("Any special ability you may have is purely reflexive.");
545 You("don't have a special ability in your normal form!");
550 enter_explore_mode(VOID_ARGS
)
553 You("are in debug mode.");
554 } else if (discover
) {
555 You("are already in explore mode.");
559 if (!sysopt
.explorers
|| !sysopt
.explorers
[0]
560 || !check_user_string(sysopt
.explorers
)) {
561 You("cannot access explore mode.");
567 "Beware! From explore mode there will be no return to normal game.");
568 if (paranoid_query(ParanoidQuit
,
569 "Do you want to enter explore mode?")) {
570 clear_nhwindow(WIN_MESSAGE
);
571 You("are now in non-scoring explore mode.");
574 clear_nhwindow(WIN_MESSAGE
);
575 pline("Resuming normal game.");
581 /* ^W command - wish for something */
583 wiz_wish(VOID_ARGS
) /* Unlimited wishes for debug mode by Paul Polderman */
586 boolean save_verbose
= flags
.verbose
;
588 flags
.verbose
= FALSE
;
590 flags
.verbose
= save_verbose
;
591 (void) encumber_msg();
593 pline("Unavailable command '%s'.",
594 visctrl((int) cmd_from_func(wiz_wish
)));
598 /* ^I command - reveal and optionally identify hero's inventory */
600 wiz_identify(VOID_ARGS
)
603 iflags
.override_ID
= (int) cmd_from_func(wiz_identify
);
604 if (display_inventory((char *) 0, TRUE
) == -1)
605 identify_pack(0, FALSE
);
606 iflags
.override_ID
= 0;
608 pline("Unavailable command '%s'.",
609 visctrl((int) cmd_from_func(wiz_identify
)));
613 /* ^F command - reveal the level map and any traps on it */
619 long save_Hconf
= HConfusion
, save_Hhallu
= HHallucination
;
621 HConfusion
= HHallucination
= 0L;
622 for (t
= ftrap
; t
!= 0; t
= t
->ntrap
) {
627 HConfusion
= save_Hconf
;
628 HHallucination
= save_Hhallu
;
630 pline("Unavailable command '%s'.",
631 visctrl((int) cmd_from_func(wiz_map
)));
635 /* ^G command - generate monster(s); a count prefix will be honored */
637 wiz_genesis(VOID_ARGS
)
640 (void) create_particular();
642 pline("Unavailable command '%s'.",
643 visctrl((int) cmd_from_func(wiz_genesis
)));
647 /* ^O command - display dungeon layout */
652 (void) print_dungeon(FALSE
, (schar
*) 0, (xchar
*) 0);
654 pline("Unavailable command '%s'.",
655 visctrl((int) cmd_from_func(wiz_where
)));
659 /* ^E command - detect unseen (secret doors, traps, hidden monsters) */
661 wiz_detect(VOID_ARGS
)
666 pline("Unavailable command '%s'.",
667 visctrl((int) cmd_from_func(wiz_detect
)));
671 /* ^V command - level teleport */
673 wiz_level_tele(VOID_ARGS
)
678 pline("Unavailable command '%s'.",
679 visctrl((int) cmd_from_func(wiz_level_tele
)));
683 /* #monpolycontrol command - choose new form for shapechangers, polymorphees */
685 wiz_mon_polycontrol(VOID_ARGS
)
687 iflags
.mon_polycontrol
= !iflags
.mon_polycontrol
;
688 pline("Monster polymorph control is %s.",
689 iflags
.mon_polycontrol
? "on" : "off");
693 /* #levelchange command - adjust hero's experience level */
695 wiz_level_change(VOID_ARGS
)
701 getlin("To what experience level do you want to be set?", buf
);
702 (void) mungspaces(buf
);
703 if (buf
[0] == '\033' || buf
[0] == '\0')
706 ret
= sscanf(buf
, "%d", &newlevel
);
712 if (newlevel
== u
.ulevel
) {
713 You("are already that experienced.");
714 } else if (newlevel
< u
.ulevel
) {
716 You("are already as inexperienced as you can get.");
721 while (u
.ulevel
> newlevel
)
722 losexp("#levelchange");
724 if (u
.ulevel
>= MAXULEV
) {
725 You("are already as experienced as you can get.");
728 if (newlevel
> MAXULEV
)
730 while (u
.ulevel
< newlevel
)
733 u
.ulevelmax
= u
.ulevel
;
737 /* #panic command - test program's panic handling */
741 if (yn("Do you want to call panic() and end your game?") == 'y')
742 panic("Crash test.");
746 /* #polyself command - change hero's form */
748 wiz_polyself(VOID_ARGS
)
756 wiz_show_seenv(VOID_ARGS
)
759 int x
, y
, v
, startx
, stopx
, curx
;
762 win
= create_nhwindow(NHW_TEXT
);
764 * Each seenv description takes up 2 characters, so center
765 * the seenv display around the hero.
767 startx
= max(1, u
.ux
- (COLNO
/ 4));
768 stopx
= min(startx
+ (COLNO
/ 2), COLNO
);
769 /* can't have a line exactly 80 chars long */
770 if (stopx
- startx
== COLNO
/ 2)
773 for (y
= 0; y
< ROWNO
; y
++) {
774 for (x
= startx
, curx
= 0; x
< stopx
; x
++, curx
+= 2) {
775 if (x
== u
.ux
&& y
== u
.uy
) {
776 row
[curx
] = row
[curx
+ 1] = '@';
778 v
= levl
[x
][y
].seenv
& 0xff;
780 row
[curx
] = row
[curx
+ 1] = ' ';
782 Sprintf(&row
[curx
], "%02x", v
);
785 /* remove trailing spaces */
786 for (x
= curx
- 1; x
>= 0; x
--)
793 display_nhwindow(win
, TRUE
);
794 destroy_nhwindow(win
);
798 /* #vision command */
800 wiz_show_vision(VOID_ARGS
)
806 win
= create_nhwindow(NHW_TEXT
);
807 Sprintf(row
, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
808 COULD_SEE
, IN_SIGHT
, TEMP_LIT
);
811 for (y
= 0; y
< ROWNO
; y
++) {
812 for (x
= 1; x
< COLNO
; x
++) {
813 if (x
== u
.ux
&& y
== u
.uy
)
816 v
= viz_array
[y
][x
]; /* data access should be hidden */
820 row
[x
] = '0' + viz_array
[y
][x
];
823 /* remove trailing spaces */
824 for (x
= COLNO
- 1; x
>= 1; x
--)
829 putstr(win
, 0, &row
[1]);
831 display_nhwindow(win
, TRUE
);
832 destroy_nhwindow(win
);
838 wiz_show_wmodes(VOID_ARGS
)
844 boolean istty
= !strcmp(windowprocs
.name
, "tty");
846 win
= create_nhwindow(NHW_TEXT
);
848 putstr(win
, 0, ""); /* tty only: blank top line */
849 for (y
= 0; y
< ROWNO
; y
++) {
850 for (x
= 0; x
< COLNO
; x
++) {
852 if (x
== u
.ux
&& y
== u
.uy
)
854 else if (IS_WALL(lev
->typ
) || lev
->typ
== SDOOR
)
855 row
[x
] = '0' + (lev
->wall_info
& WM_MASK
);
856 else if (lev
->typ
== CORR
)
858 else if (IS_ROOM(lev
->typ
) || IS_DOOR(lev
->typ
))
864 /* map column 0, levl[0][], is off the left edge of the screen */
865 putstr(win
, 0, &row
[1]);
867 display_nhwindow(win
, TRUE
);
868 destroy_nhwindow(win
);
872 /* wizard mode variant of #terrain; internal levl[][].typ values in base-36 */
874 wiz_map_levltyp(VOID_ARGS
)
879 boolean istty
= !strcmp(windowprocs
.name
, "tty");
881 win
= create_nhwindow(NHW_TEXT
);
882 /* map row 0, levl[][0], is drawn on the second line of tty screen */
884 putstr(win
, 0, ""); /* tty only: blank top line */
885 for (y
= 0; y
< ROWNO
; y
++) {
886 /* map column 0, levl[0][], is off the left edge of the screen;
887 it should always have terrain type "undiggable stone" */
888 for (x
= 1; x
< COLNO
; x
++) {
889 terrain
= levl
[x
][y
].typ
;
890 /* assumes there aren't more than 10+26+26 terrain types */
891 row
[x
- 1] = (char) ((terrain
== 0 && !may_dig(x
, y
))
897 : 'A' + terrain
- 36);
899 if (levl
[0][y
].typ
!= 0 || may_dig(0, y
))
907 s_level
*slev
= Is_special(&u
.uz
);
909 Sprintf(dsc
, "D:%d,L:%d", u
.uz
.dnum
, u
.uz
.dlevel
);
910 /* [dungeon branch features currently omitted] */
911 /* special level features */
913 Sprintf(eos(dsc
), " \"%s\"", slev
->proto
);
914 /* special level flags (note: dungeon.def doesn't set `maze'
915 or `hell' for any specific levels so those never show up) */
916 if (slev
->flags
.maze_like
)
917 Strcat(dsc
, " mazelike");
918 if (slev
->flags
.hellish
)
919 Strcat(dsc
, " hellish");
920 if (slev
->flags
.town
)
921 Strcat(dsc
, " town");
922 if (slev
->flags
.rogue_like
)
923 Strcat(dsc
, " roguelike");
924 /* alignment currently omitted to save space */
927 if (level
.flags
.nfountains
)
928 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_fountain
].sym
,
929 (int) level
.flags
.nfountains
);
930 if (level
.flags
.nsinks
)
931 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_sink
].sym
,
932 (int) level
.flags
.nsinks
);
933 if (level
.flags
.has_vault
)
934 Strcat(dsc
, " vault");
935 if (level
.flags
.has_shop
)
936 Strcat(dsc
, " shop");
937 if (level
.flags
.has_temple
)
938 Strcat(dsc
, " temple");
939 if (level
.flags
.has_court
)
940 Strcat(dsc
, " throne");
941 if (level
.flags
.has_zoo
)
943 if (level
.flags
.has_morgue
)
944 Strcat(dsc
, " morgue");
945 if (level
.flags
.has_barracks
)
946 Strcat(dsc
, " barracks");
947 if (level
.flags
.has_beehive
)
948 Strcat(dsc
, " hive");
949 if (level
.flags
.has_swamp
)
950 Strcat(dsc
, " swamp");
952 if (level
.flags
.noteleport
)
953 Strcat(dsc
, " noTport");
954 if (level
.flags
.hardfloor
)
955 Strcat(dsc
, " noDig");
956 if (level
.flags
.nommap
)
957 Strcat(dsc
, " noMMap");
958 if (!level
.flags
.hero_memory
)
959 Strcat(dsc
, " noMem");
960 if (level
.flags
.shortsighted
)
961 Strcat(dsc
, " shortsight");
962 if (level
.flags
.graveyard
)
963 Strcat(dsc
, " graveyard");
964 if (level
.flags
.is_maze_lev
)
965 Strcat(dsc
, " maze");
966 if (level
.flags
.is_cavernous_lev
)
967 Strcat(dsc
, " cave");
968 if (level
.flags
.arboreal
)
969 Strcat(dsc
, " tree");
971 Strcat(dsc
, " sokoban-rules");
972 /* non-flag info; probably should include dungeon branching
973 checks (extra stairs and magic portals) here */
974 if (Invocation_lev(&u
.uz
))
975 Strcat(dsc
, " invoke");
976 if (On_W_tower_level(&u
.uz
))
977 Strcat(dsc
, " tower");
978 /* append a branch identifier for completeness' sake */
980 Strcat(dsc
, " dungeon");
981 else if (u
.uz
.dnum
== mines_dnum
)
982 Strcat(dsc
, " mines");
983 else if (In_sokoban(&u
.uz
))
984 Strcat(dsc
, " sokoban");
985 else if (u
.uz
.dnum
== quest_dnum
)
986 Strcat(dsc
, " quest");
987 else if (Is_knox(&u
.uz
))
988 Strcat(dsc
, " ludios");
989 else if (u
.uz
.dnum
== 1)
990 Strcat(dsc
, " gehennom");
991 else if (u
.uz
.dnum
== tower_dnum
)
992 Strcat(dsc
, " vlad");
993 else if (In_endgame(&u
.uz
))
994 Strcat(dsc
, " endgame");
996 /* somebody's added a dungeon branch we're not expecting */
997 const char *brname
= dungeons
[u
.uz
.dnum
].dname
;
999 if (!brname
|| !*brname
)
1001 if (!strncmpi(brname
, "the ", 4))
1003 Sprintf(eos(dsc
), " %s", brname
);
1005 /* limit the line length to map width */
1006 if (strlen(dsc
) >= COLNO
)
1007 dsc
[COLNO
- 1] = '\0'; /* truncate */
1008 putstr(win
, 0, dsc
);
1011 display_nhwindow(win
, TRUE
);
1012 destroy_nhwindow(win
);
1016 /* temporary? hack, since level type codes aren't the same as screen
1017 symbols and only the latter have easily accessible descriptions */
1018 static const char *levltyp
[] = {
1019 "stone", "vertical wall", "horizontal wall", "top-left corner wall",
1020 "top-right corner wall", "bottom-left corner wall",
1021 "bottom-right corner wall", "cross wall", "tee-up wall", "tee-down wall",
1022 "tee-left wall", "tee-right wall", "drawbridge wall", "tree",
1023 "secret door", "secret corridor", "pool", "moat", "water",
1024 "drawbridge up", "lava pool", "iron bars", "door", "corridor", "room",
1025 "stairs", "ladder", "fountain", "throne", "sink", "grave", "altar", "ice",
1026 "drawbridge down", "air", "cloud",
1027 /* not a real terrain type, but used for undiggable stone
1028 by wiz_map_levltyp() */
1029 "unreachable/undiggable",
1030 /* padding in case the number of entries above is odd */
1034 /* explanation of base-36 output from wiz_map_levltyp() */
1036 wiz_levltyp_legend(VOID_ARGS
)
1040 const char *dsc
, *fmt
;
1043 win
= create_nhwindow(NHW_TEXT
);
1044 putstr(win
, 0, "#terrain encodings:");
1046 fmt
= " %c - %-28s"; /* TODO: include tab-separated variant for win32 */
1048 /* output in pairs, left hand column holds [0],[1],...,[N/2-1]
1049 and right hand column holds [N/2],[N/2+1],...,[N-1];
1050 N ('last') will always be even, and may or may not include
1051 the empty string entry to pad out the final pair, depending
1052 upon how many other entries are present in levltyp[] */
1053 last
= SIZE(levltyp
) & ~1;
1054 for (i
= 0; i
< last
/ 2; ++i
)
1055 for (j
= i
; j
< last
; j
+= last
/ 2) {
1058 : !strncmp(dsc
, "unreachable", 11) ? '*'
1059 /* same int-to-char conversion as wiz_map_levltyp() */
1060 : (j
< 10) ? '0' + j
1061 : (j
< 36) ? 'a' + j
- 10
1063 Sprintf(eos(buf
), fmt
, c
, dsc
);
1065 putstr(win
, 0, buf
);
1069 display_nhwindow(win
, TRUE
);
1070 destroy_nhwindow(win
);
1074 /* #wizsmell command - test usmellmon(). */
1076 wiz_smell(VOID_ARGS
)
1079 int mndx
; /* monster index */
1080 coord cc
; /* screen pos of unknown glyph */
1081 int glyph
; /* glyph at selected position */
1085 mndx
= 0; /* gcc -Wall lint */
1086 if (!olfaction(youmonst
.data
)) {
1087 You("are incapable of detecting odors in your present form.");
1091 pline("You can move the cursor to a monster that you want to smell.");
1093 pline("Pick a monster to smell.");
1094 ans
= getpos(&cc
, TRUE
, "a monster");
1095 if (ans
< 0 || cc
.x
< 0) {
1096 return 0; /* done */
1098 /* Convert the glyph at the selected position to a mndxbol. */
1099 glyph
= glyph_at(cc
.x
, cc
.y
);
1100 if (glyph_is_monster(glyph
))
1101 mndx
= glyph_to_mon(glyph
);
1104 /* Is it a monster? */
1106 if (!usmellmon(&mons
[mndx
]))
1107 pline("That monster seems to give off no smell.");
1109 pline("That is not a monster.");
1114 /* #wizinstrinsic command to set some intrinsics for testing */
1116 wiz_intrinsic(VOID_ARGS
)
1121 int i
, n
, accelerator
;
1122 menu_item
*pick_list
= (menu_item
*) 0;
1124 static const char *const intrinsics
[] = {
1128 win
= create_nhwindow(NHW_MENU
);
1132 for (i
= 0; i
< SIZE(intrinsics
); ++i
) {
1133 accelerator
= intrinsics
[i
][0];
1135 add_menu(win
, NO_GLYPH
, &any
, accelerator
, 0,
1136 ATR_NONE
, intrinsics
[i
], FALSE
);
1138 end_menu(win
, "Which intrinsic?");
1139 n
= select_menu(win
, PICK_ONE
, &pick_list
);
1140 destroy_nhwindow(win
);
1143 i
= pick_list
[0].item
.a_int
-1;
1144 free((genericptr_t
) pick_list
);
1149 if (!strcmp(intrinsics
[i
], "deafness")) {
1151 incr_itimeout(&HDeaf
, 30);
1152 context
.botl
= TRUE
;
1155 pline("Unavailable command '%s'.",
1156 visctrl((int) cmd_from_func(wiz_intrinsic
)));
1160 /* #wizrumorcheck command - verify each rumor access */
1162 wiz_rumor_check(VOID_ARGS
)
1168 /* #terrain command -- show known map, inspired by crawl's '|' command */
1170 doterrain(VOID_ARGS
)
1179 * normal play: choose between known map without mons, obj, and traps
1180 * (to see underlying terrain only), or
1181 * known map without mons and objs (to see traps under mons and objs), or
1182 * known map without mons (to see objects under monsters);
1183 * explore mode: normal choices plus full map (w/o mons, objs, traps);
1184 * wizard mode: normal and explore choices plus
1185 * a dump of the internal levl[][].typ codes w/ level flags, or
1186 * a legend for the levl[][].typ codes dump
1188 men
= create_nhwindow(NHW_MENU
);
1192 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1193 "known map without monsters, objects, and traps",
1196 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1197 "known map without monsters and objects",
1200 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1201 "known map without monsters",
1203 if (discover
|| wizard
) {
1205 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1206 "full map without monsters, objects, and traps",
1210 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1211 "internal levl[][].typ codes in base-36",
1214 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1215 "legend of base-36 levl[][].typ codes",
1219 end_menu(men
, "View which?");
1221 n
= select_menu(men
, PICK_ONE
, &sel
);
1222 destroy_nhwindow(men
);
1224 * n < 0: player used ESC to cancel;
1225 * n == 0: preselected entry was explicitly chosen and got toggled off;
1226 * n == 1: preselected entry was implicitly chosen via <space>|<enter>;
1227 * n == 2: another entry was explicitly chosen, so skip preselected one.
1229 which
= (n
< 0) ? -1 : (n
== 0) ? 1 : sel
[0].item
.a_int
;
1230 if (n
> 1 && which
== 1)
1231 which
= sel
[1].item
.a_int
;
1233 free((genericptr_t
) sel
);
1236 case 1: /* known map */
1237 reveal_terrain(0, TER_MAP
);
1239 case 2: /* known map with known traps */
1240 reveal_terrain(0, TER_MAP
| TER_TRP
);
1242 case 3: /* known map with known traps and objects */
1243 reveal_terrain(0, TER_MAP
| TER_TRP
| TER_OBJ
);
1245 case 4: /* full map */
1246 reveal_terrain(1, TER_MAP
);
1248 case 5: /* map internals */
1251 case 6: /* internal details */
1252 wiz_levltyp_legend();
1257 return 0; /* no time elapses */
1260 /* -enlightenment and conduct- */
1261 static winid en_win
= WIN_ERR
;
1262 static const char You_
[] = "You ", are
[] = "are ", were
[] = "were ",
1263 have
[] = "have ", had
[] = "had ", can
[] = "can ",
1265 static const char have_been
[] = "have been ", have_never
[] = "have never ",
1268 #define enl_msg(prefix, present, past, suffix, ps) \
1269 enlght_line(prefix, final ? past : present, suffix, ps)
1270 #define you_are(attr, ps) enl_msg(You_, are, were, attr, ps)
1271 #define you_have(attr, ps) enl_msg(You_, have, had, attr, ps)
1272 #define you_can(attr, ps) enl_msg(You_, can, could, attr, ps)
1273 #define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "")
1274 #define you_have_never(badthing) \
1275 enl_msg(You_, have_never, never, badthing, "")
1276 #define you_have_X(something) \
1277 enl_msg(You_, have, (const char *) "", something, "")
1280 enlght_line(start
, middle
, end
, ps
)
1281 const char *start
, *middle
, *end
, *ps
;
1285 Sprintf(buf
, " %s%s%s%s.", start
, middle
, end
, ps
);
1286 putstr(en_win
, 0, buf
);
1289 /* format increased chance to hit or damage or defense (Protection) */
1291 enlght_combatinc(inctyp
, incamt
, final
, outbuf
)
1296 const char *modif
, *bonus
;
1300 absamt
= abs(incamt
);
1301 /* Protection amount is typically larger than damage or to-hit;
1302 reduce magnitude by a third in order to stretch modifier ranges
1303 (small:1..5, moderate:6..10, large:11..19, huge:20+) */
1304 if (!strcmp(inctyp
, "defense"))
1305 absamt
= (absamt
* 2) / 3;
1309 else if (absamt
<= 6)
1311 else if (absamt
<= 12)
1316 modif
= !incamt
? "no" : an(modif
); /* ("no" case shouldn't happen) */
1317 bonus
= (incamt
>= 0) ? "bonus" : "penalty";
1318 /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
1319 invrt
= strcmp(inctyp
, "to hit") ? TRUE
: FALSE
;
1321 Sprintf(outbuf
, "%s %s %s", modif
, invrt
? inctyp
: bonus
,
1322 invrt
? bonus
: inctyp
);
1323 if (final
|| wizard
)
1324 Sprintf(eos(outbuf
), " (%s%d)", (incamt
> 0) ? "+" : "", incamt
);
1329 /* report half physical or half spell damage */
1331 enlght_halfdmg(category
, final
)
1335 const char *category_name
;
1340 category_name
= "physical";
1343 category_name
= "spell";
1346 category_name
= "unknown";
1349 Sprintf(buf
, " %s %s damage", (final
|| wizard
) ? "half" : "reduced",
1351 enl_msg(You_
, "take", "took", buf
, from_what(category
));
1354 /* is hero actively using water walking capability on water (or lava)? */
1358 if (u
.uinwater
|| Levitation
|| Flying
)
1360 return (boolean
) (Wwalking
1361 && (is_pool(u
.ux
, u
.uy
) || is_lava(u
.ux
, u
.uy
)));
1364 /* check whether hero is wearing something that player definitely knows
1365 confers the target property; item must have been seen and its type
1366 discovered but it doesn't necessarily have to be fully identified */
1368 cause_known(propindx
)
1369 int propindx
; /* index of a property which can be conveyed by worn item */
1371 register struct obj
*o
;
1372 long mask
= W_ARMOR
| W_AMUL
| W_RING
| W_TOOL
;
1374 /* simpler than from_what()/what_gives(); we don't attempt to
1375 handle artifacts and we deliberately ignore wielded items */
1376 for (o
= invent
; o
; o
= o
->nobj
) {
1377 if (!(o
->owornmask
& mask
))
1379 if ((int) objects
[o
->otyp
].oc_oprop
== propindx
1380 && objects
[o
->otyp
].oc_name_known
&& o
->dknown
)
1386 /* format a characteristic value, accommodating Strength's strangeness */
1388 attrval(attrindx
, attrvalue
, resultbuf
)
1389 int attrindx
, attrvalue
;
1390 char resultbuf
[]; /* should be at least [7] to hold "18/100\0" */
1392 if (attrindx
!= A_STR
|| attrvalue
<= 18)
1393 Sprintf(resultbuf
, "%d", attrvalue
);
1394 else if (attrvalue
> STR18(100)) /* 19 to 25 */
1395 Sprintf(resultbuf
, "%d", attrvalue
- 100);
1396 else /* simplify "18/ **" to be "18/100" */
1397 Sprintf(resultbuf
, "18/%02d", attrvalue
- 18);
1402 enlightenment(mode
, final
)
1403 int mode
; /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */
1404 int final
; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
1406 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1408 Strcpy(tmpbuf
, plname
);
1409 *tmpbuf
= highc(*tmpbuf
); /* same adjustment as bottom line */
1410 /* as in background_enlightenment, when poly'd we need to use the saved
1411 gender in u.mfemale rather than the current you-as-monster gender */
1412 Sprintf(buf
, "%s the %s's attributes:", tmpbuf
,
1413 ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1417 en_win
= create_nhwindow(NHW_MENU
);
1419 putstr(en_win
, 0, buf
); /* "Conan the Archeologist's attributes:" */
1420 /* background and characteristics; ^X or end-of-game disclosure */
1421 if (mode
& BASICENLIGHTENMENT
) {
1422 /* role, race, alignment, deities */
1423 background_enlightenment(mode
, final
);
1424 /* strength, dexterity, &c */
1425 characteristics_enlightenment(mode
, final
);
1427 /* expanded status line information, including things which aren't
1428 included there due to space considerations--such as obvious
1429 alternative movement indicators (riding, levitation, &c), and
1430 various troubles (turning to stone, trapped, confusion, &c);
1431 shown for both basic and magic enlightenment */
1432 status_enlightenment(mode
, final
);
1433 /* remaining attributes; shown for potion,&c or wizard mode and
1434 explore mode ^X or end of game disclosure */
1435 if (mode
& MAGICENLIGHTENMENT
) {
1436 /* intrinsics and other traditional enlightenment feedback */
1437 attributes_enlightenment(mode
, final
);
1439 display_nhwindow(en_win
, TRUE
);
1440 destroy_nhwindow(en_win
);
1445 /* display role, race, alignment and such to en_win */
1447 background_enlightenment(unused_mode
, final
)
1448 int unused_mode UNUSED
;
1451 const char *role_titl
, *rank_titl
;
1452 int innategend
, difgend
, difalgn
;
1453 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1455 /* note that if poly'd, we need to use u.mfemale instead of flags.female
1456 to access hero's saved gender-as-human/elf/&c rather than current one */
1457 innategend
= (Upolyd
? u
.mfemale
: flags
.female
) ? 1 : 0;
1458 role_titl
= (innategend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
;
1459 rank_titl
= rank_of(u
.ulevel
, Role_switch
, innategend
);
1461 putstr(en_win
, 0, ""); /* separator after title */
1462 putstr(en_win
, 0, "Background:");
1464 /* if polymorphed, report current shape before underlying role;
1465 will be repeated as first status: "you are transformed" and also
1466 among various attributes: "you are in beast form" (after being
1467 told about lycanthropy) or "you are polymorphed into <a foo>"
1468 (with countdown timer appended for wizard mode); we really want
1469 the player to know he's not a samurai at the moment... */
1471 struct permonst
*uasmon
= youmonst
.data
;
1474 /* here we always use current gender, not saved role gender */
1475 if (!is_male(uasmon
) && !is_female(uasmon
) && !is_neuter(uasmon
))
1476 Sprintf(tmpbuf
, "%s ", genders
[flags
.female
? 1 : 0].adj
);
1477 Sprintf(buf
, "%sin %s%s form", !final
? "currently " : "", tmpbuf
,
1482 /* report role; omit gender if it's redundant (eg, "female priestess") */
1485 && ((urole
.allow
& ROLE_GENDMASK
) == (ROLE_MALE
| ROLE_FEMALE
)
1486 || innategend
!= flags
.initgend
))
1487 Sprintf(tmpbuf
, "%s ", genders
[innategend
].adj
);
1490 Strcpy(buf
, "actually "); /* "You are actually a ..." */
1491 if (!strcmpi(rank_titl
, role_titl
)) {
1492 /* omit role when rank title matches it */
1493 Sprintf(eos(buf
), "%s, level %d %s%s", an(rank_titl
), u
.ulevel
,
1494 tmpbuf
, urace
.noun
);
1496 Sprintf(eos(buf
), "%s, a level %d %s%s %s", an(rank_titl
), u
.ulevel
,
1497 tmpbuf
, urace
.adj
, role_titl
);
1501 /* report alignment (bypass you_are() in order to omit ending period);
1502 adverb is used to distinguish between temporary change (helm of opp.
1503 alignment), permanent change (one-time conversion), and original */
1504 Sprintf(buf
, " %s%s%s, %son a mission for %s",
1505 You_
, !final
? are
: were
,
1506 align_str(u
.ualign
.type
),
1507 /* helm of opposite alignment (might hide conversion) */
1508 (u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
])
1509 /* what's the past tense of "currently"? if we used "formerly"
1510 it would sound like a reference to the original alignment */
1511 ? (!final
? "currently " : "temporarily ")
1512 /* permanent conversion */
1513 : (u
.ualign
.type
!= u
.ualignbase
[A_ORIGINAL
])
1514 /* and what's the past tense of "now"? certainly not "then"
1515 in a context like this...; "belatedly" == weren't that
1516 way sooner (in other words, didn't start that way) */
1517 ? (!final
? "now " : "belatedly ")
1518 /* atheist (ignored in very early game) */
1519 : (!u
.uconduct
.gnostic
&& moves
> 1000L)
1521 /* lastly, normal case */
1524 putstr(en_win
, 0, buf
);
1525 /* show the rest of this game's pantheon (finishes previous sentence)
1526 [appending "also Moloch" at the end would allow for straightforward
1527 trailing "and" on all three aligned entries but looks too verbose] */
1528 Sprintf(buf
, " who %s opposed by", !final
? "is" : "was");
1529 if (u
.ualign
.type
!= A_LAWFUL
)
1530 Sprintf(eos(buf
), " %s (%s) and", align_gname(A_LAWFUL
),
1531 align_str(A_LAWFUL
));
1532 if (u
.ualign
.type
!= A_NEUTRAL
)
1533 Sprintf(eos(buf
), " %s (%s)%s", align_gname(A_NEUTRAL
),
1534 align_str(A_NEUTRAL
),
1535 (u
.ualign
.type
!= A_CHAOTIC
) ? " and" : "");
1536 if (u
.ualign
.type
!= A_CHAOTIC
)
1537 Sprintf(eos(buf
), " %s (%s)", align_gname(A_CHAOTIC
),
1538 align_str(A_CHAOTIC
));
1539 Strcat(buf
, "."); /* terminate sentence */
1540 putstr(en_win
, 0, buf
);
1542 /* show original alignment,gender,race,role if any have been changed;
1543 giving separate message for temporary alignment change bypasses need
1544 for tricky phrasing otherwise necessitated by possibility of having
1545 helm of opposite alignment mask a permanent alignment conversion */
1546 difgend
= (innategend
!= flags
.initgend
);
1547 difalgn
= (((u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
]) ? 1 : 0)
1548 + ((u
.ualignbase
[A_CURRENT
] != u
.ualignbase
[A_ORIGINAL
])
1550 if (difalgn
& 1) { /* have temporary alignment so report permanent one */
1551 Sprintf(buf
, "actually %s", align_str(u
.ualignbase
[A_CURRENT
]));
1553 difalgn
&= ~1; /* suppress helm from "started out <foo>" message */
1555 if (difgend
|| difalgn
) { /* sex change or perm align change or both */
1556 Sprintf(buf
, " You started out %s%s%s.",
1557 difgend
? genders
[flags
.initgend
].adj
: "",
1558 (difgend
&& difalgn
) ? " and " : "",
1559 difalgn
? align_str(u
.ualignbase
[A_ORIGINAL
]) : "");
1560 putstr(en_win
, 0, buf
);
1564 /* characteristics: expanded version of bottom line strength, dexterity, &c */
1566 characteristics_enlightenment(mode
, final
)
1570 putstr(en_win
, 0, ""); /* separator after background */
1572 final
? "Final Characteristics:" : "Current Characteristics:");
1574 /* bottom line order */
1575 one_characteristic(mode
, final
, A_STR
); /* strength */
1576 one_characteristic(mode
, final
, A_DEX
); /* dexterity */
1577 one_characteristic(mode
, final
, A_CON
); /* constitution */
1578 one_characteristic(mode
, final
, A_INT
); /* intelligence */
1579 one_characteristic(mode
, final
, A_WIS
); /* wisdom */
1580 one_characteristic(mode
, final
, A_CHA
); /* charisma */
1583 /* display one attribute value for characteristics_enlightenment() */
1585 one_characteristic(mode
, final
, attrindx
)
1586 int mode
, final
, attrindx
;
1588 boolean hide_innate_value
= FALSE
, interesting_alimit
;
1589 int acurrent
, abase
, apeak
, alimit
;
1590 const char *attrname
, *paren_pfx
;
1591 char subjbuf
[BUFSZ
], valubuf
[BUFSZ
], valstring
[32];
1593 /* being polymorphed or wearing certain cursed items prevents
1594 hero from reliably tracking changes to characteristics so
1595 we don't show base & peak values then; when the items aren't
1596 cursed, hero could take them off to check underlying values
1597 and we show those in such case so that player doesn't need
1598 to actually resort to doing that */
1600 hide_innate_value
= TRUE
;
1601 } else if (Fixed_abil
) {
1602 if (stuck_ring(uleft
, RIN_SUSTAIN_ABILITY
)
1603 || stuck_ring(uright
, RIN_SUSTAIN_ABILITY
))
1604 hide_innate_value
= TRUE
;
1608 attrname
= "strength";
1609 if (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
&& uarmg
->cursed
)
1610 hide_innate_value
= TRUE
;
1613 attrname
= "dexterity";
1616 attrname
= "constitution";
1619 attrname
= "intelligence";
1620 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1621 hide_innate_value
= TRUE
;
1624 attrname
= "wisdom";
1625 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1626 hide_innate_value
= TRUE
;
1629 attrname
= "charisma";
1632 return; /* impossible */
1634 /* note: final disclosure includes MAGICENLIGHTENTMENT */
1635 if ((mode
& MAGICENLIGHTENMENT
) && !Upolyd
)
1636 hide_innate_value
= FALSE
;
1638 acurrent
= ACURR(attrindx
);
1639 (void) attrval(attrindx
, acurrent
, valubuf
); /* Sprintf(valubuf,"%d",) */
1640 Sprintf(subjbuf
, "Your %s ", attrname
);
1642 if (!hide_innate_value
) {
1643 /* show abase, amax, and/or attrmax if acurr doesn't match abase
1644 (a magic bonus or penalty is in effect) or abase doesn't match
1645 amax (some points have been lost to poison or exercise abuse
1646 and are restorable) or attrmax is different from normal human
1647 (while game is in progress; trying to reduce dependency on
1648 spoilers to keep track of such stuff) or attrmax was different
1649 from abase (at end of game; this attribute wasn't maxed out) */
1650 abase
= ABASE(attrindx
);
1651 apeak
= AMAX(attrindx
);
1652 alimit
= ATTRMAX(attrindx
);
1653 /* criterium for whether the limit is interesting varies */
1654 interesting_alimit
=
1655 final
? TRUE
/* was originally `(abase != alimit)' */
1656 : (alimit
!= (attrindx
!= A_STR
? 18 : STR18(100)));
1657 paren_pfx
= final
? " (" : " (current; ";
1658 if (acurrent
!= abase
) {
1659 Sprintf(eos(valubuf
), "%sbase:%s", paren_pfx
,
1660 attrval(attrindx
, abase
, valstring
));
1663 if (abase
!= apeak
) {
1664 Sprintf(eos(valubuf
), "%speak:%s", paren_pfx
,
1665 attrval(attrindx
, apeak
, valstring
));
1668 if (interesting_alimit
) {
1669 Sprintf(eos(valubuf
), "%s%slimit:%s", paren_pfx
,
1670 /* more verbose if exceeding 'limit' due to magic bonus */
1671 (acurrent
> alimit
) ? "innate " : "",
1672 attrval(attrindx
, alimit
, valstring
));
1673 /* paren_pfx = ", "; */
1675 if (acurrent
!= abase
|| abase
!= apeak
|| interesting_alimit
)
1676 Strcat(valubuf
, ")");
1678 enl_msg(subjbuf
, "is ", "was ", valubuf
, "");
1681 /* status: selected obvious capabilities, assorted troubles */
1683 status_enlightenment(mode
, final
)
1687 boolean magic
= (mode
& MAGICENLIGHTENMENT
) ? TRUE
: FALSE
;
1689 char buf
[BUFSZ
], youtoo
[BUFSZ
];
1690 boolean Riding
= (u
.usteed
1691 /* if hero dies while dismounting, u.usteed will still
1692 be set; we want to ignore steed in that situation */
1693 && !(final
== ENL_GAMEOVERDEAD
1694 && !strcmp(killer
.name
, "riding accident")));
1695 const char *steedname
= (!Riding
? (char *) 0
1696 : x_monnam(u
.usteed
,
1697 u
.usteed
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
,
1699 (SUPPRESS_SADDLE
| SUPPRESS_HALLUCINATION
),
1703 * Status (many are abbreviated on bottom line; others are or
1704 * should be discernible to the hero hence to the player)
1706 putstr(en_win
, 0, ""); /* separator after title or characteristics */
1707 putstr(en_win
, 0, final
? "Final Status:" : "Current Status:");
1709 Strcpy(youtoo
, You_
);
1710 /* not a traditional status but inherently obvious to player; more
1711 detail given below (attributes section) for magic enlightenment */
1713 you_are("transformed", "");
1714 /* not a trouble, but we want to display riding status before maybe
1715 reporting steed as trapped or hero stuck to cursed saddle */
1717 Sprintf(buf
, "riding %s", steedname
);
1719 Sprintf(eos(youtoo
), "and %s ", steedname
);
1721 /* other movement situations that hero should always know */
1723 if (Lev_at_will
&& magic
)
1724 you_are("levitating, at will", "");
1726 enl_msg(youtoo
, are
, were
, "levitating", from_what(LEVITATION
));
1727 } else if (Flying
) { /* can only fly when not levitating */
1728 enl_msg(youtoo
, are
, were
, "flying", from_what(FLYING
));
1731 you_are("underwater", "");
1732 } else if (u
.uinwater
) {
1733 you_are(Swimming
? "swimming" : "in water", from_what(SWIMMING
));
1734 } else if (walking_on_water()) {
1735 /* show active Wwalking here, potential Wwalking elsewhere */
1736 Sprintf(buf
, "walking on %s",
1737 is_pool(u
.ux
, u
.uy
) ? "water"
1738 : is_lava(u
.ux
, u
.uy
) ? "lava"
1739 : surface(u
.ux
, u
.uy
)); /* catchall; shouldn't happen */
1740 you_are(buf
, from_what(WWALKING
));
1742 if (Upolyd
&& (u
.uundetected
|| youmonst
.m_ap_type
!= M_AP_NOTHING
))
1743 youhiding(TRUE
, final
);
1745 /* internal troubles, mostly in the order that prayer ranks them */
1747 you_are("turning to stone", "");
1749 you_are("turning into slime", "");
1752 you_are("buried", "");
1754 Strcpy(buf
, "being strangled");
1756 Sprintf(eos(buf
), " (%ld)", (Strangled
& TIMEOUT
));
1757 you_are(buf
, from_what(STRANGLED
));
1761 /* prayer lumps these together; botl puts Ill before FoodPois */
1762 if (u
.usick_type
& SICK_NONVOMITABLE
)
1763 you_are("terminally sick from illness", "");
1764 if (u
.usick_type
& SICK_VOMITABLE
)
1765 you_are("terminally sick from food poisoning", "");
1768 you_are("nauseated", "");
1770 you_are("stunned", "");
1772 you_are("confused", "");
1774 you_are("hallucinating", "");
1776 /* from_what() (currently wizard-mode only) checks !haseyes()
1777 before u.uroleplay.blind, so we should too */
1778 Sprintf(buf
, "%s blind",
1779 !haseyes(youmonst
.data
) ? "innately"
1780 : u
.uroleplay
.blind
? "permanently"
1781 /* better phrasing desperately wanted... */
1782 : Blindfolded_only
? "deliberately"
1784 if (wizard
&& (Blinded
& TIMEOUT
) != 0L
1785 && !u
.uroleplay
.blind
&& haseyes(youmonst
.data
))
1786 Sprintf(eos(buf
), " (%ld)", (Blinded
& TIMEOUT
));
1787 /* !haseyes: avoid "you are innately blind innately" */
1788 you_are(buf
, !haseyes(youmonst
.data
) ? "" : from_what(BLINDED
));
1791 you_are("deaf", from_what(DEAF
));
1793 /* external troubles, more or less */
1796 Sprintf(buf
, "chained to %s", ansimpleoname(uball
));
1798 impossible("Punished without uball?");
1799 Strcpy(buf
, "punished");
1804 char predicament
[BUFSZ
];
1806 boolean anchored
= (u
.utraptype
== TT_BURIEDBALL
);
1809 Strcpy(predicament
, "tethered to something buried");
1810 } else if (u
.utraptype
== TT_INFLOOR
|| u
.utraptype
== TT_LAVA
) {
1811 Sprintf(predicament
, "stuck in %s", the(surface(u
.ux
, u
.uy
)));
1813 Strcpy(predicament
, "trapped");
1814 if ((t
= t_at(u
.ux
, u
.uy
)) != 0)
1815 Sprintf(eos(predicament
), " in %s",
1816 an(defsyms
[trap_to_defsym(t
->ttyp
)].explanation
));
1818 if (u
.usteed
) { /* not `Riding' here */
1819 Sprintf(buf
, "%s%s ", anchored
? "you and " : "", steedname
);
1821 enl_msg(buf
, (anchored
? "are " : "is "),
1822 (anchored
? "were " : "was "), predicament
, "");
1824 you_are(predicament
, "");
1827 Sprintf(buf
, "swallowed by %s", a_monnam(u
.ustuck
));
1829 Sprintf(eos(buf
), " (%u)", u
.uswldtim
);
1831 } else if (u
.ustuck
) {
1832 Sprintf(buf
, "%s %s",
1833 (Upolyd
&& sticks(youmonst
.data
)) ? "holding" : "held by",
1834 a_monnam(u
.ustuck
));
1838 struct obj
*saddle
= which_armor(u
.usteed
, W_SADDLE
);
1840 if (saddle
&& saddle
->cursed
) {
1841 Sprintf(buf
, "stuck to %s %s", s_suffix(steedname
),
1842 simpleonames(saddle
));
1847 /* when mounted, Wounded_legs applies to steed rather than to
1848 hero; we only report steed's wounded legs in wizard mode */
1849 if (u
.usteed
) { /* not `Riding' here */
1850 if (wizard
&& steedname
) {
1851 Strcpy(buf
, steedname
);
1853 enl_msg(buf
, " has", " had", " wounded legs", "");
1856 Sprintf(buf
, "wounded %s", makeplural(body_part(LEG
)));
1861 Sprintf(buf
, "slippery %s", makeplural(body_part(FINGER
)));
1865 if (magic
|| cause_known(FUMBLING
))
1866 enl_msg(You_
, "fumble", "fumbled", "", from_what(FUMBLING
));
1869 if (magic
|| cause_known(SLEEPY
)) {
1870 Strcpy(buf
, from_what(SLEEPY
));
1872 Sprintf(eos(buf
), " (%ld)", (HSleepy
& TIMEOUT
));
1873 enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf
);
1876 /* hunger/nutrition */
1878 if (magic
|| cause_known(HUNGER
))
1879 enl_msg(You_
, "hunger", "hungered", " rapidly",
1882 Strcpy(buf
, hu_stat
[u
.uhs
]); /* hunger status; omitted if "normal" */
1883 mungspaces(buf
); /* strip trailing spaces */
1885 *buf
= lowc(*buf
); /* override capitalization */
1886 if (!strcmp(buf
, "weak"))
1887 Strcat(buf
, " from severe hunger");
1888 else if (!strncmp(buf
, "faint", 5)) /* fainting, fainted */
1889 Strcat(buf
, " due to starvation");
1893 if ((cap
= near_capacity()) > UNENCUMBERED
) {
1894 const char *adj
= "?_?"; /* (should always get overridden) */
1896 Strcpy(buf
, enc_stat
[cap
]);
1901 break; /* burdened */
1904 break; /* stressed */
1907 break; /* strained */
1910 break; /* overtaxed */
1912 adj
= "not possible";
1915 Sprintf(eos(buf
), "; movement %s %s%s", !final
? "is" : "was", adj
,
1916 (cap
< OVERLOADED
) ? " slowed" : "");
1919 /* last resort entry, guarantees Status section is non-empty
1920 (no longer needed for that purpose since weapon status added;
1921 still useful though) */
1922 you_are("unencumbered", "");
1924 /* report being weaponless; distinguish whether gloves are worn */
1926 you_are(uarmg
? "empty handed" /* gloves imply hands */
1927 : humanoid(youmonst
.data
)
1928 /* hands but no weapon and no gloves */
1930 /* alternate phrasing for paws or lack of hands */
1931 : "not wielding anything",
1933 /* two-weaponing implies a weapon (not other odd stuff) in each hand */
1934 } else if (u
.twoweap
) {
1935 you_are("wielding two weapons at once", "");
1936 /* report most weapons by their skill class (so a katana will be
1937 described as a long sword, for instance; mattock and hook are
1938 exceptions), or wielded non-weapon item by its object class */
1940 const char *what
= weapon_descr(uwep
);
1942 if (!strcmpi(what
, "armor") || !strcmpi(what
, "food")
1943 || !strcmpi(what
, "venom"))
1944 Sprintf(buf
, "wielding some %s", what
);
1946 Sprintf(buf
, "wielding %s",
1947 (uwep
->quan
== 1L) ? an(what
) : makeplural(what
));
1950 /* report 'nudity' */
1951 if (!uarm
&& !uarmu
&& !uarmc
&& !uarmg
&& !uarmf
&& !uarmh
) {
1952 if (u
.uroleplay
.nudist
)
1953 enl_msg(You_
, "do", "did", " not wear any armor", "");
1955 you_are("not wearing any armor", "");
1959 /* attributes: intrinsics and the like, other non-obvious capabilities */
1961 attributes_enlightenment(unused_mode
, final
)
1962 int unused_mode UNUSED
;
1965 static NEARDATA
const char if_surroundings_permitted
[] =
1966 " if surroundings permitted";
1973 putstr(en_win
, 0, "");
1974 putstr(en_win
, 0, final
? "Final Attributes:" : "Current Attributes:");
1976 if (u
.uevent
.uhand_of_elbereth
) {
1977 static const char *const hofe_titles
[3] = { "the Hand of Elbereth",
1978 "the Envoy of Balance",
1979 "the Glory of Arioch" };
1980 you_are(hofe_titles
[u
.uevent
.uhand_of_elbereth
- 1], "");
1983 Sprintf(buf
, "%s", piousness(TRUE
, "aligned"));
1984 if (u
.ualign
.record
>= 0)
1990 Sprintf(buf
, " %d", u
.ualign
.record
);
1991 enl_msg("Your alignment ", "is", "was", buf
, "");
1994 /*** Resistances to troubles ***/
1996 you_are("invulnerable", from_what(INVULNERABLE
));
1998 you_are("magic-protected", from_what(ANTIMAGIC
));
1999 if (Fire_resistance
)
2000 you_are("fire resistant", from_what(FIRE_RES
));
2001 if (Cold_resistance
)
2002 you_are("cold resistant", from_what(COLD_RES
));
2003 if (Sleep_resistance
)
2004 you_are("sleep resistant", from_what(SLEEP_RES
));
2005 if (Disint_resistance
)
2006 you_are("disintegration-resistant", from_what(DISINT_RES
));
2007 if (Shock_resistance
)
2008 you_are("shock resistant", from_what(SHOCK_RES
));
2009 if (Poison_resistance
)
2010 you_are("poison resistant", from_what(POISON_RES
));
2011 if (Acid_resistance
)
2012 you_are("acid resistant", from_what(ACID_RES
));
2013 if (Drain_resistance
)
2014 you_are("level-drain resistant", from_what(DRAIN_RES
));
2015 if (Sick_resistance
)
2016 you_are("immune to sickness", from_what(SICK_RES
));
2017 if (Stone_resistance
)
2018 you_are("petrification resistant", from_what(STONE_RES
));
2019 if (Halluc_resistance
)
2020 enl_msg(You_
, "resist", "resisted", " hallucinations",
2021 from_what(HALLUC_RES
));
2023 you_can("recognize detrimental food", "");
2025 /*** Vision and senses ***/
2026 if (!Blind
&& (Blinded
|| !haseyes(youmonst
.data
)))
2027 you_can("see", from_what(-BLINDED
)); /* Eyes of the Overworld */
2028 if (See_invisible
) {
2030 enl_msg(You_
, "see", "saw", " invisible", from_what(SEE_INVIS
));
2032 enl_msg(You_
, "will see", "would have seen",
2033 " invisible when not blind", from_what(SEE_INVIS
));
2036 you_are("telepathic", from_what(TELEPAT
));
2038 you_are("warned", from_what(WARNING
));
2039 if (Warn_of_mon
&& context
.warntype
.obj
) {
2040 Sprintf(buf
, "aware of the presence of %s",
2041 (context
.warntype
.obj
& M2_ORC
) ? "orcs"
2042 : (context
.warntype
.obj
& M2_ELF
) ? "elves"
2043 : (context
.warntype
.obj
& M2_DEMON
) ? "demons" : something
);
2044 you_are(buf
, from_what(WARN_OF_MON
));
2046 if (Warn_of_mon
&& context
.warntype
.polyd
) {
2047 Sprintf(buf
, "aware of the presence of %s",
2048 ((context
.warntype
.polyd
& (M2_HUMAN
| M2_ELF
))
2049 == (M2_HUMAN
| M2_ELF
))
2050 ? "humans and elves"
2051 : (context
.warntype
.polyd
& M2_HUMAN
)
2053 : (context
.warntype
.polyd
& M2_ELF
)
2055 : (context
.warntype
.polyd
& M2_ORC
)
2057 : (context
.warntype
.polyd
& M2_DEMON
)
2059 : "certain monsters");
2062 if (Warn_of_mon
&& context
.warntype
.speciesidx
>= LOW_PM
) {
2063 Sprintf(buf
, "aware of the presence of %s",
2064 makeplural(mons
[context
.warntype
.speciesidx
].mname
));
2065 you_are(buf
, from_what(WARN_OF_MON
));
2068 you_are("warned of undead", from_what(WARN_UNDEAD
));
2070 you_have("automatic searching", from_what(SEARCHING
));
2072 you_are("clairvoyant", from_what(CLAIRVOYANT
));
2073 else if ((HClairvoyant
|| EClairvoyant
) && BClairvoyant
) {
2074 Strcpy(buf
, from_what(-CLAIRVOYANT
));
2075 if (!strncmp(buf
, " because of ", 12))
2076 /* overwrite substring; strncpy doesn't add terminator */
2077 (void) strncpy(buf
, " if not for ", 12);
2078 enl_msg(You_
, "could be", "could have been", " clairvoyant", buf
);
2081 you_have("infravision", from_what(INFRAVISION
));
2082 if (Detect_monsters
)
2083 you_are("sensing the presence of monsters", "");
2085 you_are("going to confuse monsters", "");
2087 /*** Appearance and behavior ***/
2091 if (uleft
&& uleft
->otyp
== RIN_ADORNMENT
)
2092 adorn
+= uleft
->spe
;
2093 if (uright
&& uright
->otyp
== RIN_ADORNMENT
)
2094 adorn
+= uright
->spe
;
2095 /* the sum might be 0 (+0 ring or two which negate each other);
2096 that yields "you are charismatic" (which isn't pointless
2097 because it potentially impacts seduction attacks) */
2098 Sprintf(buf
, "%scharismatic",
2099 (adorn
> 0) ? "more " : (adorn
< 0) ? "less " : "");
2100 you_are(buf
, from_what(ADORNED
));
2103 you_are("invisible", from_what(INVIS
));
2105 you_are("invisible to others", from_what(INVIS
));
2106 /* ordinarily "visible" is redundant; this is a special case for
2107 the situation when invisibility would be an expected attribute */
2108 else if ((HInvis
|| EInvis
) && BInvis
)
2109 you_are("visible", from_what(-INVIS
));
2111 you_are("displaced", from_what(DISPLACED
));
2113 you_are("stealthy", from_what(STEALTH
));
2114 if (Aggravate_monster
)
2115 enl_msg("You aggravate", "", "d", " monsters",
2116 from_what(AGGRAVATE_MONSTER
));
2118 enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT
));
2120 /*** Transportation ***/
2122 you_can("jump", from_what(JUMPING
));
2124 you_can("teleport", from_what(TELEPORT
));
2125 if (Teleport_control
)
2126 you_have("teleport control", from_what(TELEPORT_CONTROL
));
2127 /* actively levitating handled earlier as a status condition */
2128 if (BLevitation
) { /* levitation is blocked */
2129 long save_BLev
= BLevitation
;
2133 enl_msg(You_
, "would levitate", "would have levitated",
2134 if_surroundings_permitted
, "");
2135 BLevitation
= save_BLev
;
2137 /* actively flying handled earlier as a status condition */
2138 if (BFlying
) { /* flight is blocked */
2139 long save_BFly
= BFlying
;
2143 enl_msg(You_
, "would fly", "would have flown",
2145 ? "if you weren't levitating"
2146 : (save_BFly
== FROMOUTSIDE
)
2147 ? if_surroundings_permitted
2148 /* both surroundings and [latent] levitation */
2149 : " if circumstances permitted",
2151 BFlying
= save_BFly
;
2153 /* actively walking on water handled earlier as a status condition */
2154 if (Wwalking
&& !walking_on_water())
2155 you_can("walk on water", from_what(WWALKING
));
2156 /* actively swimming (in water but not under it) handled earlier */
2157 if (Swimming
&& (Underwater
|| !u
.uinwater
))
2158 you_can("swim", from_what(SWIMMING
));
2160 you_can("survive without air", from_what(MAGICAL_BREATHING
));
2161 else if (Amphibious
)
2162 you_can("breathe water", from_what(MAGICAL_BREATHING
));
2164 you_can("walk through walls", from_what(PASSES_WALLS
));
2166 /*** Physical attributes ***/
2168 enl_msg("You regenerate", "", "d", "", from_what(REGENERATION
));
2170 you_have("slower digestion", from_what(SLOW_DIGESTION
));
2172 you_have(enlght_combatinc("to hit", u
.uhitinc
, final
, buf
), "");
2174 you_have(enlght_combatinc("damage", u
.udaminc
, final
, buf
), "");
2175 if (u
.uspellprot
|| Protection
) {
2178 if (uleft
&& uleft
->otyp
== RIN_PROTECTION
)
2180 if (uright
&& uright
->otyp
== RIN_PROTECTION
)
2181 prot
+= uright
->spe
;
2182 if (HProtection
& INTRINSIC
)
2184 prot
+= u
.uspellprot
;
2186 you_have(enlght_combatinc("defense", prot
, final
, buf
), "");
2188 if ((armpro
= magic_negation(&youmonst
)) > 0) {
2189 /* magic cancellation factor, conferred by worn armor */
2190 static const char *const mc_types
[] = {
2191 "" /*ordinary*/, "warded", "guarded", "protected",
2194 if (armpro
>= SIZE(mc_types
))
2195 armpro
= SIZE(mc_types
) - 1;
2196 you_are(mc_types
[armpro
], "");
2198 if (Half_physical_damage
)
2199 enlght_halfdmg(HALF_PHDAM
, final
);
2200 if (Half_spell_damage
)
2201 enlght_halfdmg(HALF_SPDAM
, final
);
2202 /* polymorph and other shape change */
2203 if (Protection_from_shape_changers
)
2204 you_are("protected from shape changers",
2205 from_what(PROT_FROM_SHAPE_CHANGERS
));
2207 const char *what
= 0;
2209 if (!Upolyd
) /* Upolyd handled below after current form */
2210 you_can("not change from your current form",
2211 from_what(UNCHANGING
));
2212 /* blocked shape changes */
2214 what
= !final
? "polymorph" : "have polymorphed";
2215 else if (u
.ulycn
>= LOW_PM
)
2216 what
= !final
? "change shape" : "have changed shape";
2218 Sprintf(buf
, "would %s periodically", what
);
2219 /* omit from_what(UNCHANGING); too verbose */
2220 enl_msg(You_
, buf
, buf
, " if not locked into your current form",
2223 } else if (Polymorph
) {
2224 you_are("polymorphing periodically", from_what(POLYMORPH
));
2226 if (Polymorph_control
)
2227 you_have("polymorph control", from_what(POLYMORPH_CONTROL
));
2228 if (Upolyd
&& u
.umonnum
!= u
.ulycn
) {
2229 /* foreign shape (except were-form which is handled below) */
2230 Sprintf(buf
, "polymorphed into %s", an(youmonst
.data
->mname
));
2232 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2235 if (lays_eggs(youmonst
.data
) && flags
.female
) /* Upolyd */
2236 you_can("lay eggs", "");
2237 if (u
.ulycn
>= LOW_PM
) {
2238 /* "you are a werecreature [in beast form]" */
2239 Strcpy(buf
, an(mons
[u
.ulycn
].mname
));
2240 if (u
.umonnum
== u
.ulycn
) {
2241 Strcat(buf
, " in beast form");
2243 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2247 if (Unchanging
&& Upolyd
) /* !Upolyd handled above */
2248 you_can("not change from your current form", from_what(UNCHANGING
));
2250 you_are("harmed by silver", "");
2251 /* movement and non-armor-based protection */
2253 you_are(Very_fast
? "very fast" : "fast", from_what(FAST
));
2255 you_have("reflection", from_what(REFLECTING
));
2257 you_have("free action", from_what(FREE_ACTION
));
2259 you_have("fixed abilities", from_what(FIXED_ABIL
));
2261 enl_msg("Your life ", "will be", "would have been", " saved", "");
2263 /*** Miscellany ***/
2265 ltmp
= abs((int) Luck
);
2266 Sprintf(buf
, "%s%slucky",
2267 ltmp
>= 10 ? "extremely " : ltmp
>= 5 ? "very " : "",
2268 Luck
< 0 ? "un" : "");
2270 Sprintf(eos(buf
), " (%d)", Luck
);
2273 enl_msg("Your luck ", "is", "was", " zero", "");
2275 you_have("extra luck", "");
2276 else if (u
.moreluck
< 0)
2277 you_have("reduced luck", "");
2278 if (carrying(LUCKSTONE
) || stone_luck(TRUE
)) {
2279 ltmp
= stone_luck(0);
2281 enl_msg("Bad luck ", "does", "did", " not time out for you", "");
2283 enl_msg("Good luck ", "does", "did", " not time out for you", "");
2287 Sprintf(buf
, " %sangry with you",
2288 u
.ugangr
> 6 ? "extremely " : u
.ugangr
> 3 ? "very " : "");
2290 Sprintf(eos(buf
), " (%d)", u
.ugangr
);
2291 enl_msg(u_gname(), " is", " was", buf
, "");
2294 * We need to suppress this when the game is over, because death
2295 * can change the value calculated by can_pray(), potentially
2296 * resulting in a false claim that you could have prayed safely.
2300 /* "can [not] safely pray" vs "could [not] have safely prayed" */
2301 Sprintf(buf
, "%s%ssafely pray%s", can_pray(FALSE
) ? "" : "not ",
2302 final
? "have " : "", final
? "ed" : "");
2304 Sprintf(buf
, "%ssafely pray", can_pray(FALSE
) ? "" : "not ");
2307 Sprintf(eos(buf
), " (%d)", u
.ublesscnt
);
2313 /* named fruit debugging (doesn't really belong here...); to enable,
2314 include 'fruit' in DEBUGFILES list (even though it isn't a file...) */
2315 if (wizard
&& explicitdebug("fruit")) {
2320 for (f
= ffruit
; f
; f
= f
->nextf
) {
2321 Sprintf(buf
, "Fruit %d ", ++fcount
);
2322 Sprintf(buf2
, "%s (id %d)", f
->fname
, f
->fid
);
2323 enl_msg(buf
, "is ", "was ", buf2
, "");
2325 enl_msg("The current fruit ", "is ", "was ", pl_fruit
, "");
2326 Sprintf(buf
, "%d", flags
.made_fruit
);
2327 enl_msg("The made fruit flag ", "is ", "was ", buf
, "");
2335 if (final
< 2) { /* still in progress, or quit/escaped/ascended */
2336 p
= "survived after being killed ";
2337 switch (u
.umortality
) {
2339 p
= !final
? (char *) 0 : "survived";
2342 Strcpy(buf
, "once");
2345 Strcpy(buf
, "twice");
2348 Strcpy(buf
, "thrice");
2351 Sprintf(buf
, "%d times", u
.umortality
);
2354 } else { /* game ended in character's death */
2356 switch (u
.umortality
) {
2358 impossible("dead without dying?");
2360 break; /* just "are dead" */
2362 Sprintf(buf
, " (%d%s time!)", u
.umortality
,
2363 ordin(u
.umortality
));
2368 enl_msg(You_
, "have been killed ", p
, buf
, "");
2372 #if 0 /* no longer used */
2373 STATIC_DCL boolean
NDECL(minimal_enlightenment
);
2376 * Courtesy function for non-debug, non-explorer mode players
2377 * to help refresh them about who/what they are.
2378 * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
2381 minimal_enlightenment()
2384 menu_item
*selected
;
2387 char buf
[BUFSZ
], buf2
[BUFSZ
];
2388 static const char untabbed_fmtstr
[] = "%-15s: %-12s";
2389 static const char untabbed_deity_fmtstr
[] = "%-17s%s";
2390 static const char tabbed_fmtstr
[] = "%s:\t%-12s";
2391 static const char tabbed_deity_fmtstr
[] = "%s\t%s";
2392 static const char *fmtstr
;
2393 static const char *deity_fmtstr
;
2395 fmtstr
= iflags
.menu_tab_sep
? tabbed_fmtstr
: untabbed_fmtstr
;
2396 deity_fmtstr
= iflags
.menu_tab_sep
? tabbed_deity_fmtstr
2397 : untabbed_deity_fmtstr
;
2399 buf
[0] = buf2
[0] = '\0';
2400 tmpwin
= create_nhwindow(NHW_MENU
);
2402 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2405 /* Starting name, race, role, gender */
2406 Sprintf(buf
, fmtstr
, "name", plname
);
2407 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2408 Sprintf(buf
, fmtstr
, "race", urace
.noun
);
2409 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2410 Sprintf(buf
, fmtstr
, "role",
2411 (flags
.initgend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
);
2412 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2413 Sprintf(buf
, fmtstr
, "gender", genders
[flags
.initgend
].adj
);
2414 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2416 /* Starting alignment */
2417 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualignbase
[A_ORIGINAL
]));
2418 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2420 /* Current name, race, role, gender */
2421 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2422 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2424 Sprintf(buf
, fmtstr
, "race", Upolyd
? youmonst
.data
->mname
: urace
.noun
);
2425 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2427 Sprintf(buf
, fmtstr
, "role (base)",
2428 (u
.mfemale
&& urole
.name
.f
) ? urole
.name
.f
2430 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2432 Sprintf(buf
, fmtstr
, "role",
2433 (flags
.female
&& urole
.name
.f
) ? urole
.name
.f
2435 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2437 /* don't want poly_gender() here; it forces `2' for non-humanoids */
2438 genidx
= is_neuter(youmonst
.data
) ? 2 : flags
.female
;
2439 Sprintf(buf
, fmtstr
, "gender", genders
[genidx
].adj
);
2440 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2441 if (Upolyd
&& (int) u
.mfemale
!= genidx
) {
2442 Sprintf(buf
, fmtstr
, "gender (base)", genders
[u
.mfemale
].adj
);
2443 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2446 /* Current alignment */
2447 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualign
.type
));
2448 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2451 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2452 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2454 Sprintf(buf2
, deity_fmtstr
, align_gname(A_CHAOTIC
),
2455 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2456 && u
.ualign
.type
== A_CHAOTIC
) ? " (s,c)"
2457 : (u
.ualignbase
[A_ORIGINAL
] == A_CHAOTIC
) ? " (s)"
2458 : (u
.ualign
.type
== A_CHAOTIC
) ? " (c)" : "");
2459 Sprintf(buf
, fmtstr
, "Chaotic", buf2
);
2460 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2462 Sprintf(buf2
, deity_fmtstr
, align_gname(A_NEUTRAL
),
2463 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2464 && u
.ualign
.type
== A_NEUTRAL
) ? " (s,c)"
2465 : (u
.ualignbase
[A_ORIGINAL
] == A_NEUTRAL
) ? " (s)"
2466 : (u
.ualign
.type
== A_NEUTRAL
) ? " (c)" : "");
2467 Sprintf(buf
, fmtstr
, "Neutral", buf2
);
2468 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2470 Sprintf(buf2
, deity_fmtstr
, align_gname(A_LAWFUL
),
2471 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2472 && u
.ualign
.type
== A_LAWFUL
) ? " (s,c)"
2473 : (u
.ualignbase
[A_ORIGINAL
] == A_LAWFUL
) ? " (s)"
2474 : (u
.ualign
.type
== A_LAWFUL
) ? " (c)" : "");
2475 Sprintf(buf
, fmtstr
, "Lawful", buf2
);
2476 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2478 end_menu(tmpwin
, "Base Attributes");
2479 n
= select_menu(tmpwin
, PICK_NONE
, &selected
);
2480 destroy_nhwindow(tmpwin
);
2481 return (boolean
) (n
!= -1);
2487 doattributes(VOID_ARGS
)
2489 int mode
= BASICENLIGHTENMENT
;
2491 /* show more--as if final disclosure--for wizard and explore modes */
2492 if (wizard
|| discover
)
2493 mode
|= MAGICENLIGHTENMENT
;
2495 enlightenment(mode
, ENL_GAMEINPROGRESS
);
2500 youhiding(via_enlghtmt
, msgflag
)
2501 boolean via_enlghtmt
; /* englightment line vs topl message */
2502 int msgflag
; /* for variant message phrasing */
2504 char *bp
, buf
[BUFSZ
];
2506 Strcpy(buf
, "hiding");
2507 if (youmonst
.m_ap_type
!= M_AP_NOTHING
) {
2508 /* mimic; hero is only able to mimic a strange object or gold
2509 or hallucinatory alternative to gold, so we skip the details
2510 for the hypothetical furniture and monster cases */
2511 bp
= eos(strcpy(buf
, "mimicking"));
2512 if (youmonst
.m_ap_type
== M_AP_OBJECT
) {
2513 Sprintf(bp
, " %s", an(simple_typename(youmonst
.mappearance
)));
2514 } else if (youmonst
.m_ap_type
== M_AP_FURNITURE
) {
2515 Strcpy(bp
, " something");
2516 } else if (youmonst
.m_ap_type
== M_AP_MONSTER
) {
2517 Strcpy(bp
, " someone");
2519 ; /* something unexpected; leave 'buf' as-is */
2521 } else if (u
.uundetected
) {
2522 bp
= eos(buf
); /* points past "hiding" */
2523 if (youmonst
.data
->mlet
== S_EEL
) {
2524 if (is_pool(u
.ux
, u
.uy
))
2525 Sprintf(bp
, " in the %s", waterbody_name(u
.ux
, u
.uy
));
2526 } else if (hides_under(youmonst
.data
)) {
2527 struct obj
*o
= level
.objects
[u
.ux
][u
.uy
];
2530 Sprintf(bp
, " underneath %s", ansimpleoname(o
));
2531 } else if (is_clinger(youmonst
.data
) || Flying
) {
2532 /* Flying: 'lurker above' hides on ceiling but doesn't cling */
2533 Sprintf(bp
, " on the %s", ceiling(u
.ux
, u
.uy
));
2535 /* on floor; is_hider() but otherwise not special: 'trapper' */
2536 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
2537 struct trap
*t
= t_at(u
.ux
, u
.uy
);
2539 Sprintf(bp
, " in a %spit",
2540 (t
&& t
->ttyp
== SPIKED_PIT
) ? "spiked " : "");
2542 Sprintf(bp
, " on the %s", surface(u
.ux
, u
.uy
));
2545 ; /* shouldn't happen; will result in generic "you are hiding" */
2549 int final
= msgflag
; /* 'final' is used by you_are() macro */
2553 /* for dohide(), when player uses '#monster' command */
2554 You("are %s %s.", msgflag
? "already" : "now", buf
);
2559 * (shares enlightenment's tense handling)
2562 doconduct(VOID_ARGS
)
2575 /* Create the conduct window */
2576 en_win
= create_nhwindow(NHW_MENU
);
2577 putstr(en_win
, 0, "Voluntary challenges:");
2579 if (u
.uroleplay
.blind
)
2580 you_have_been("blind from birth");
2581 if (u
.uroleplay
.nudist
)
2582 you_have_been("faithfully nudist");
2584 if (!u
.uconduct
.food
)
2585 enl_msg(You_
, "have gone", "went", " without food", "");
2586 /* But beverages are okay */
2587 else if (!u
.uconduct
.unvegan
)
2588 you_have_X("followed a strict vegan diet");
2589 else if (!u
.uconduct
.unvegetarian
)
2590 you_have_been("vegetarian");
2592 if (!u
.uconduct
.gnostic
)
2593 you_have_been("an atheist");
2595 if (!u
.uconduct
.weaphit
) {
2596 you_have_never("hit with a wielded weapon");
2597 } else if (wizard
) {
2598 Sprintf(buf
, "used a wielded weapon %ld time%s", u
.uconduct
.weaphit
,
2599 plur(u
.uconduct
.weaphit
));
2602 if (!u
.uconduct
.killer
)
2603 you_have_been("a pacifist");
2605 if (!u
.uconduct
.literate
) {
2606 you_have_been("illiterate");
2607 } else if (wizard
) {
2608 Sprintf(buf
, "read items or engraved %ld time%s", u
.uconduct
.literate
,
2609 plur(u
.uconduct
.literate
));
2613 ngenocided
= num_genocides();
2614 if (ngenocided
== 0) {
2615 you_have_never("genocided any monsters");
2617 Sprintf(buf
, "genocided %d type%s of monster%s", ngenocided
,
2618 plur(ngenocided
), plur(ngenocided
));
2622 if (!u
.uconduct
.polypiles
) {
2623 you_have_never("polymorphed an object");
2624 } else if (wizard
) {
2625 Sprintf(buf
, "polymorphed %ld item%s", u
.uconduct
.polypiles
,
2626 plur(u
.uconduct
.polypiles
));
2630 if (!u
.uconduct
.polyselfs
) {
2631 you_have_never("changed form");
2632 } else if (wizard
) {
2633 Sprintf(buf
, "changed form %ld time%s", u
.uconduct
.polyselfs
,
2634 plur(u
.uconduct
.polyselfs
));
2638 if (!u
.uconduct
.wishes
) {
2639 you_have_X("used no wishes");
2641 Sprintf(buf
, "used %ld wish%s", u
.uconduct
.wishes
,
2642 (u
.uconduct
.wishes
> 1L) ? "es" : "");
2643 if (u
.uconduct
.wisharti
) {
2644 /* if wisharti == wishes
2645 * 1 wish (for an artifact)
2646 * 2 wishes (both for artifacts)
2647 * N wishes (all for artifacts)
2648 * else (N is at least 2 in order to get here; M < N)
2649 * N wishes (1 for an artifact)
2650 * N wishes (M for artifacts)
2652 if (u
.uconduct
.wisharti
== u
.uconduct
.wishes
)
2653 Sprintf(eos(buf
), " (%s",
2654 (u
.uconduct
.wisharti
> 2L) ? "all "
2655 : (u
.uconduct
.wisharti
== 2L) ? "both " : "");
2657 Sprintf(eos(buf
), " (%ld ", u
.uconduct
.wisharti
);
2659 Sprintf(eos(buf
), "for %s)",
2660 (u
.uconduct
.wisharti
== 1L) ? "an artifact"
2665 if (!u
.uconduct
.wisharti
)
2666 enl_msg(You_
, "have not wished", "did not wish",
2667 " for any artifacts", "");
2670 /* Pop up the window and wait for a key */
2671 display_nhwindow(en_win
, TRUE
);
2672 destroy_nhwindow(en_win
);
2676 /* Macros for meta and ctrl modifiers:
2677 * M and C return the meta/ctrl code for the given character;
2678 * e.g., (C('c') is ctrl-c
2679 * ISMETA and ISCTRL return TRUE iff the code is a meta/ctrl code
2680 * UNMETA and UNCTRL are the opposite of M/C and return the key for a given
2681 * meta/ctrl code. */
2684 #define M(c) (0x80 | (c))
2686 #define M(c) ((c) -128)
2689 #define ISMETA(c) (((c) & 0x80) != 0)
2690 #define UNMETA(c) ((c) & 0x7f)
2693 #define C(c) (0x1f & (c))
2695 #define ISCTRL(c) ((uchar)(c) < 0x20)
2696 #define UNCTRL(c) (ISCTRL(c) ? (0x60 | (c)) : (c))
2698 struct ext_func_tab extcmdlist
[] = {
2699 { '#', "#", "perform an extended command", doextcmd
, IFBURIED
|GENERALCMD
},
2700 { M('?'), "?", "get this list of extended commands", doextlist
, IFBURIED
|AUTOCOMPLETE
|GENERALCMD
},
2701 { M('a'), "adjust", "adjust inventory letters", doorganize
, IFBURIED
|AUTOCOMPLETE
},
2702 { M('A'), "annotate", "name current level", donamelevel
, IFBURIED
|AUTOCOMPLETE
},
2703 { 'a', "apply", "apply (use) a tool (pick-axe, key, lamp...)", doapply
},
2704 { C('x'), "attributes", "show your attributes", doattributes
, IFBURIED
},
2705 { '@', "autopickup", "toggle the pickup option on/off", dotogglepickup
, IFBURIED
},
2706 { 'C', "call", "call (name) something", docallcmd
, IFBURIED
},
2707 { 'Z', "cast", "zap (cast) a spell", docast
, IFBURIED
},
2708 { M('c'), "chat", "talk to someone", dotalk
, IFBURIED
|AUTOCOMPLETE
},
2709 { 'c', "close", "close a door", doclose
},
2710 { M('C'), "conduct", "list voluntary challenges you have maintained", doconduct
, IFBURIED
|AUTOCOMPLETE
},
2711 { M('d'), "dip", "dip an object into something", dodip
, AUTOCOMPLETE
},
2712 { '>', "down", "go down a staircase", dodown
},
2713 { 'd', "drop", "drop an item", dodrop
},
2714 { 'D', "droptype", "drop specific item types", doddrop
},
2715 { 'e', "eat", "eat something", doeat
},
2716 { 'E', "engrave", "engrave writing on the floor", doengrave
},
2717 { M('e'), "enhance", "advance or check weapon and spell skills", enhance_weapon_skill
, IFBURIED
|AUTOCOMPLETE
},
2718 { '\0', "exploremode", "enter explore (discovery) mode", enter_explore_mode
, IFBURIED
},
2719 { 'f', "fire", "fire ammunition from quiver", dofire
},
2720 { M('f'), "force", "force a lock", doforce
, AUTOCOMPLETE
},
2721 { ';', "glance", "show what type of thing a map symbol corresponds to", doquickwhatis
, IFBURIED
|GENERALCMD
},
2722 { '?', "help", "give a help message", dohelp
, IFBURIED
|GENERALCMD
},
2723 { 'V', "history", "show long version and game history", dohistory
, IFBURIED
|GENERALCMD
},
2724 { 'i', "inventory", "show your inventory", ddoinv
, IFBURIED
},
2725 { 'I', "inventtype", "inventory specific item types", dotypeinv
, IFBURIED
},
2726 { M('i'), "invoke", "invoke an object's special powers", doinvoke
, IFBURIED
|AUTOCOMPLETE
},
2727 { M('j'), "jump", "jump to another location", dojump
, AUTOCOMPLETE
},
2728 { C('d'), "kick", "kick something", dokick
},
2729 { '\\', "known", "show what object types have been discovered", dodiscovered
, IFBURIED
|GENERALCMD
},
2730 { '`', "knownclass", "show discovered types for one class of objects", doclassdisco
, IFBURIED
|GENERALCMD
},
2731 { '\0', "levelchange", "change experience level", wiz_level_change
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2732 { '\0', "lightsources", "show mobile light sources", wiz_light_sources
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2733 { ':', "look", "look at what is here", dolook
, IFBURIED
},
2734 { M('l'), "loot", "loot a box on the floor", doloot
, AUTOCOMPLETE
},
2735 #ifdef DEBUG_MIGRATING_MONS
2736 { '\0', "migratemons", "migrate n random monsters", wiz_migrate_mons
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2738 { '\0', "monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2739 { M('m'), "monster", "use a monster's special ability", domonability
, IFBURIED
|AUTOCOMPLETE
},
2740 { 'N', "name", "name a monster or an object", docallcmd
, IFBURIED
|AUTOCOMPLETE
},
2741 { M('o'), "offer", "offer a sacrifice to the gods", dosacrifice
, AUTOCOMPLETE
},
2742 { 'o', "open", "open a door", doopen
},
2743 { 'O', "options", "show option settings, possibly change them", doset
, IFBURIED
|GENERALCMD
},
2744 { C('o'), "overview", "show a summary of the explored dungeon", dooverview
, IFBURIED
|AUTOCOMPLETE
},
2745 { '\0', "panic", "test panic routine (fatal to game)", wiz_panic
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2746 { 'p', "pay", "pay your shopping bill", dopay
},
2747 { ',', "pickup", "pick up things at the current location", dopickup
},
2748 { '\0', "polyself", "polymorph self", wiz_polyself
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2750 { '\0', "portdebug", "wizard port debug command", wiz_port_debug
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2752 { M('p'), "pray", "pray to the gods for help", dopray
, IFBURIED
|AUTOCOMPLETE
},
2753 { C('p'), "prevmsg", "toggle through previously displayed game messages", doprev_message
, IFBURIED
|GENERALCMD
},
2754 { 'P', "puton", "put on an accessory (ring, amulet, etc)", doputon
},
2755 { 'q', "quaff", "quaff (drink) something", dodrink
},
2756 { M('q'), "quit", "exit without saving current game", done2
, IFBURIED
|AUTOCOMPLETE
|GENERALCMD
},
2757 { 'Q', "quiver", "select ammunition for quiver", dowieldquiver
},
2758 { 'r', "read", "read a scroll or spellbook", doread
},
2759 { C('r'), "redraw", "redraw screen", doredraw
, IFBURIED
|GENERALCMD
},
2760 { 'R', "remove", "remove an accessory (ring, amulet, etc)", doremring
},
2761 { M('R'), "ride", "mount or dismount a saddled steed", doride
, AUTOCOMPLETE
},
2762 { M('r'), "rub", "rub a lamp or a stone", dorub
, AUTOCOMPLETE
},
2763 { 'S', "save", "save the game", dosave
, IFBURIED
|GENERALCMD
},
2764 { 's', "search", "search for traps and secret doors", dosearch
, IFBURIED
, "searching" },
2765 { '*', "seeall", "show all equipment in use", doprinuse
, IFBURIED
},
2766 { AMULET_SYM
, "seeamulet", "show the amulet currently worn", dopramulet
, IFBURIED
},
2767 { ARMOR_SYM
, "seearmor", "show the armor currently worn", doprarm
, IFBURIED
},
2768 { GOLD_SYM
, "seegold", "count your gold", doprgold
, IFBURIED
},
2769 { '\0', "seenv", "show seen vectors", wiz_show_seenv
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2770 { RING_SYM
, "seerings", "show the ring(s) currently worn", doprring
, IFBURIED
},
2771 { SPBOOK_SYM
, "seespells", "list and reorder known spells", dovspell
, IFBURIED
},
2772 { TOOL_SYM
, "seetools", "show the tools currently in use", doprtool
, IFBURIED
},
2773 { '^', "seetrap", "show the type of a trap", doidtrap
, IFBURIED
},
2774 { WEAPON_SYM
, "seeweapon", "show the weapon currently wielded", doprwep
, IFBURIED
},
2776 { '!', "shell", "do a shell escape", dosh
, IFBURIED
|GENERALCMD
},
2778 { M('s'), "sit", "sit down", dosit
, AUTOCOMPLETE
},
2779 { '\0', "stats", "show memory statistics", wiz_show_stats
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2781 { C('z'), "suspend", "suspend the game", dosuspend_core
, IFBURIED
|GENERALCMD
},
2782 #endif /* SUSPEND */
2783 { 'x', "swap", "swap wielded and secondary weapons", doswapweapon
},
2784 { 'T', "takeoff", "take off one piece of armor", dotakeoff
},
2785 { 'A', "takeoffall", "remove all armor", doddoremarm
},
2786 { C('t'), "teleport", "teleport around the level", dotele
, IFBURIED
},
2787 { '\0', "terrain", "show map without obstructions", doterrain
, IFBURIED
|AUTOCOMPLETE
},
2788 { 't', "throw", "throw something", dothrow
},
2789 { '\0', "timeout", "look at timeout queue", wiz_timeout_queue
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2790 { M('T'), "tip", "empty a container", dotip
, AUTOCOMPLETE
},
2791 { '_', "travel", "travel to a specific location on the map", dotravel
},
2792 { M('t'), "turn", "turn undead away", doturn
, IFBURIED
|AUTOCOMPLETE
},
2793 { 'X', "twoweapon", "toggle two-weapon combat", dotwoweapon
, AUTOCOMPLETE
},
2794 { M('u'), "untrap", "untrap something", dountrap
, AUTOCOMPLETE
},
2795 { '<', "up", "go up a staircase", doup
},
2796 { '\0', "vanquished", "list vanquished monsters", dovanquished
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2797 { M('v'), "version", "list compile time options for this version of NetHack", doextversion
, IFBURIED
|AUTOCOMPLETE
|GENERALCMD
},
2798 { 'v', "versionshort", "show version", doversion
, IFBURIED
|GENERALCMD
},
2799 { '\0', "vision", "show vision array", wiz_show_vision
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2800 { '.', "wait", "rest one move while doing nothing", donull
, IFBURIED
, "waiting" },
2801 { 'W', "wear", "wear a piece of armor", dowear
},
2802 { '&', "whatdoes", "tell what a command does", dowhatdoes
, IFBURIED
},
2803 { '/', "whatis", "show what type of thing a symbol corresponds to", dowhatis
, IFBURIED
|GENERALCMD
},
2804 { 'w', "wield", "wield (put in use) a weapon", dowield
},
2805 { M('w'), "wipe", "wipe off your face", dowipe
, AUTOCOMPLETE
},
2807 { '\0', "wizdebug_bury", "wizard debug: bury objs under and around you", wiz_debug_cmd_bury
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2808 { '\0', "wizdebug_traveldisplay", "wizard debug: toggle travel display", wiz_debug_cmd_traveldisplay
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2810 { C('e'), "wizdetect", "search a room", wiz_detect
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2811 { C('g'), "wizgenesis", "create a monster", wiz_genesis
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2812 { C('i'), "wizidentify", "identify all items in inventory", wiz_identify
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2813 { '\0', "wizintrinsic", "set intrinsic", wiz_intrinsic
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2814 { C('v'), "wizlevelport", "teleport to another level", wiz_level_tele
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2815 { C('f'), "wizmap", "map the level", wiz_map
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2816 { '\0', "wizrumorcheck", "verify rumor boundaries", wiz_rumor_check
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2817 { '\0', "wizsmell", "smell monster", wiz_smell
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2818 { '\0', "wizwhere", "show locations of special levels", wiz_where
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2819 { C('w'), "wizwish", "wish for something", wiz_wish
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2820 { '\0', "wmode", "show wall modes", wiz_show_wmodes
, IFBURIED
|AUTOCOMPLETE
|WIZMODECMD
},
2821 { 'z', "zap", "zap a wand", dozap
},
2823 { '\0', (char *)0, (char *)0, donull
} /* sentinel */
2830 if (Cmd
.commands
[key
] && Cmd
.commands
[key
]->ef_txt
)
2831 return Cmd
.commands
[key
]->ef_desc
;
2836 bind_key(key
, command
)
2840 struct ext_func_tab
* extcmd
;
2842 /* special case: "nothing" is reserved for unbinding */
2843 if (!strcmp(command
, "nothing")) {
2844 Cmd
.commands
[key
] = NULL
;
2848 for(extcmd
= extcmdlist
; extcmd
->ef_txt
; extcmd
++) {
2849 if (strcmp(command
, extcmd
->ef_txt
)) continue;
2850 Cmd
.commands
[key
] = extcmd
;
2854 pline("Bad command %s matched with key %c (ASCII %i). "
2855 "Ignoring command.\n", command
, key
, key
);
2858 /* initialize all keyboard commands */
2862 struct ext_func_tab
*extcmd
;
2864 for (extcmd
= extcmdlist
; extcmd
->ef_txt
; extcmd
++)
2866 Cmd
.commands
[extcmd
->key
] = extcmd
;
2868 bind_key(C('l'), "redraw"); /* if number_pad is set */
2869 /* 'b', 'B' : go sw */
2870 /* 'F' : fight (one time) */
2871 /* 'g', 'G' : multiple go */
2872 /* 'h', 'H' : go west */
2873 bind_key('h', "help"); /* if number_pad is set */
2874 bind_key('j', "jump"); /* if number_pad is on */
2875 /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
2876 bind_key('k', "kick"); /* if number_pad is on */
2877 bind_key('l', "loot"); /* if number_pad is on */
2878 bind_key(C('n'), "annotate"); /* if number_pad is on */
2879 bind_key(M('n'), "name");
2880 bind_key(M('N'), "name");
2881 bind_key('u', "untrap"); /* if number_pad is on */
2884 bind_key(M('O'), "overview");
2885 bind_key(M('2'), "twoweapon");
2888 bind_key(' ', "wait");
2892 dokeylist_putcmds(datawin
, docount
, cmdflags
, exflags
, keys_used
)
2895 int cmdflags
, exflags
;
2896 boolean
*keys_used
; /* boolean keys_used[256] */
2903 for (i
= 0; i
< 256; i
++) {
2904 const struct ext_func_tab
* extcmd
;
2905 uchar key
= (uchar
)i
;
2907 if (keys_used
[i
]) continue;
2908 if (key
== ' ' && !flags
.rest_on_space
) continue;
2909 if ((extcmd
= Cmd
.commands
[i
]) != NULL
) {
2910 if ((cmdflags
&& !(extcmd
->flags
& cmdflags
))
2911 || (exflags
&& (extcmd
->flags
& exflags
)))
2917 Sprintf(buf
, "%-8s %-12s %s", key2txt(key
, buf2
),
2920 putstr(datawin
, 0, buf
);
2921 keys_used
[i
] = TRUE
;
2927 /* list all keys and their bindings, like dat/hh but dynamic */
2929 dokeylist(VOID_ARGS
)
2931 char buf
[BUFSZ
], buf2
[BUFSZ
];
2933 boolean keys_used
[256] = {0};
2941 { NHKF_ESC
, "escape from the current query/action" },
2942 { NHKF_RUSH
, "Prefix: rush until something interesting is seen" },
2943 { NHKF_RUN
, "Prefix: run until something extremely interesting is seen" },
2944 { NHKF_RUN2
, "Prefix: run until something extremely interesting is seen", TRUE
},
2945 { NHKF_FIGHT
, "Prefix: force fight even if you don't see a monster" },
2946 { NHKF_FIGHT2
, "Prefix: force fight even if you don't see a monster", TRUE
},
2947 { NHKF_NOPICKUP
, "Prefix: move without picking up objects/fighting" },
2948 { NHKF_RUN_NOPICKUP
, "Prefix: run without picking up objects/fighting" },
2949 { NHKF_DOINV
, "inventory (same as #inventory)", TRUE
},
2950 { NHKF_REQMENU
, "Prefix: request a menu" },
2952 { NHKF_DOAGAIN
, "redo the previous command" },
2957 datawin
= create_nhwindow(NHW_TEXT
);
2958 putstr(datawin
, 0, "");
2959 putstr(datawin
, 0, " Full Current Key Bindings List");
2961 /* directional keys */
2962 putstr(datawin
, 0, "");
2963 putstr(datawin
, 0, "Directional keys:");
2964 show_direction_keys(datawin
, FALSE
);
2966 keys_used
[(uchar
)Cmd
.move_NW
] = keys_used
[(uchar
)Cmd
.move_N
]
2967 = keys_used
[(uchar
)Cmd
.move_NE
] = keys_used
[(uchar
)Cmd
.move_W
]
2968 = keys_used
[(uchar
)Cmd
.move_E
] = keys_used
[(uchar
)Cmd
.move_SW
]
2969 = keys_used
[(uchar
)Cmd
.move_S
] = keys_used
[(uchar
)Cmd
.move_SE
] = TRUE
;
2971 if (!iflags
.num_pad
) {
2972 keys_used
[(uchar
)highc(Cmd
.move_NW
)]
2973 = keys_used
[(uchar
)highc(Cmd
.move_N
)]
2974 = keys_used
[(uchar
)highc(Cmd
.move_NE
)]
2975 = keys_used
[(uchar
)highc(Cmd
.move_W
)]
2976 = keys_used
[(uchar
)highc(Cmd
.move_E
)]
2977 = keys_used
[(uchar
)highc(Cmd
.move_SW
)]
2978 = keys_used
[(uchar
)highc(Cmd
.move_S
)]
2979 = keys_used
[(uchar
)highc(Cmd
.move_SE
)] = TRUE
;
2980 keys_used
[(uchar
)C(Cmd
.move_NW
)]
2981 = keys_used
[(uchar
)C(Cmd
.move_N
)]
2982 = keys_used
[(uchar
)C(Cmd
.move_NE
)]
2983 = keys_used
[(uchar
)C(Cmd
.move_W
)]
2984 = keys_used
[(uchar
)C(Cmd
.move_E
)]
2985 = keys_used
[(uchar
)C(Cmd
.move_SW
)]
2986 = keys_used
[(uchar
)C(Cmd
.move_S
)]
2987 = keys_used
[(uchar
)C(Cmd
.move_SE
)] = TRUE
;
2988 putstr(datawin
, 0, "");
2990 "Shift-<direction> will move in specified direction until you hit");
2991 putstr(datawin
, 0, " a wall or run into something.");
2993 "Ctrl-<direction> will run in specified direction until something");
2994 putstr(datawin
, 0, " very interesting is seen.");
2997 putstr(datawin
, 0, "");
2998 putstr(datawin
, 0, "Miscellaneous keys:");
2999 for (i
= 0; misc_keys
[i
].desc
; i
++) {
3000 key
= Cmd
.spkeys
[misc_keys
[i
].nhkf
];
3001 if (key
&& ((misc_keys
[i
].numpad
&& iflags
.num_pad
)
3002 || !misc_keys
[i
].numpad
)) {
3003 keys_used
[(uchar
)key
] = TRUE
;
3004 Sprintf(buf
, "%-8s %s", key2txt(key
, buf2
), misc_keys
[i
].desc
);
3005 putstr(datawin
, 0, buf
);
3009 putstr(datawin
, 0, "^c break out of NetHack (SIGINT)");
3010 keys_used
[(uchar
)C('c')] = TRUE
;
3013 if (dokeylist_putcmds(datawin
, TRUE
, GENERALCMD
, WIZMODECMD
, &keys_used
)) {
3014 putstr(datawin
, 0, "");
3015 putstr(datawin
, 0, "General commands:");
3016 (void) dokeylist_putcmds(datawin
, FALSE
, GENERALCMD
, WIZMODECMD
, &keys_used
);
3019 if (dokeylist_putcmds(datawin
, TRUE
, 0, WIZMODECMD
, &keys_used
)) {
3020 putstr(datawin
, 0, "");
3021 putstr(datawin
, 0, "Game commands:");
3022 (void) dokeylist_putcmds(datawin
, FALSE
, 0, WIZMODECMD
, &keys_used
);
3025 if (wizard
&& dokeylist_putcmds(datawin
, TRUE
, WIZMODECMD
, 0, &keys_used
)) {
3026 putstr(datawin
, 0, "");
3027 putstr(datawin
, 0, "Wizard-mode commands:");
3028 (void) dokeylist_putcmds(datawin
, FALSE
, WIZMODECMD
, 0, &keys_used
);
3031 display_nhwindow(datawin
, FALSE
);
3032 destroy_nhwindow(datawin
);
3040 for (i
= 0; i
< 256; ++i
)
3041 if (Cmd
.commands
[i
] && Cmd
.commands
[i
]->ef_funct
== fn
)
3046 static const char template[] = "%-27s %4ld %6ld";
3047 static const char stats_hdr
[] = " count bytes";
3048 static const char stats_sep
[] = "--------------------------- ----- -------";
3054 int sz
= (int) sizeof(struct obj
);
3057 sz
+= (int) sizeof(struct oextra
);
3059 sz
+= (int) strlen(ONAME(otmp
)) + 1;
3061 sz
+= (int) sizeof(struct monst
);
3063 sz
+= (int) sizeof(unsigned);
3065 sz
+= (int) sizeof(long);
3067 sz
+= (int) strlen(OMAILCMD(otmp
)) + 1;
3073 count_obj(chain
, total_count
, total_size
, top
, recurse
)
3083 for (count
= size
= 0, obj
= chain
; obj
; obj
= obj
->nobj
) {
3086 size
+= size_obj(obj
);
3088 if (recurse
&& obj
->cobj
)
3089 count_obj(obj
->cobj
, total_count
, total_size
, TRUE
, TRUE
);
3091 *total_count
+= count
;
3092 *total_size
+= size
;
3096 obj_chain(win
, src
, chain
, force
, total_count
, total_size
)
3105 long count
= 0L, size
= 0L;
3107 count_obj(chain
, &count
, &size
, TRUE
, FALSE
);
3109 if (count
|| size
|| force
) {
3110 *total_count
+= count
;
3111 *total_size
+= size
;
3112 Sprintf(buf
, template, src
, count
, size
);
3113 putstr(win
, 0, buf
);
3118 mon_invent_chain(win
, src
, chain
, total_count
, total_size
)
3121 struct monst
*chain
;
3126 long count
= 0, size
= 0;
3129 for (mon
= chain
; mon
; mon
= mon
->nmon
)
3130 count_obj(mon
->minvent
, &count
, &size
, TRUE
, FALSE
);
3132 if (count
|| size
) {
3133 *total_count
+= count
;
3134 *total_size
+= size
;
3135 Sprintf(buf
, template, src
, count
, size
);
3136 putstr(win
, 0, buf
);
3141 contained_stats(win
, src
, total_count
, total_size
)
3148 long count
= 0, size
= 0;
3151 count_obj(invent
, &count
, &size
, FALSE
, TRUE
);
3152 count_obj(fobj
, &count
, &size
, FALSE
, TRUE
);
3153 count_obj(level
.buriedobjlist
, &count
, &size
, FALSE
, TRUE
);
3154 count_obj(migrating_objs
, &count
, &size
, FALSE
, TRUE
);
3155 /* DEADMONSTER check not required in this loop since they have no
3157 for (mon
= fmon
; mon
; mon
= mon
->nmon
)
3158 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3159 for (mon
= migrating_mons
; mon
; mon
= mon
->nmon
)
3160 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3162 if (count
|| size
) {
3163 *total_count
+= count
;
3164 *total_size
+= size
;
3165 Sprintf(buf
, template, src
, count
, size
);
3166 putstr(win
, 0, buf
);
3171 size_monst(mtmp
, incl_wsegs
)
3175 int sz
= (int) sizeof (struct monst
);
3177 if (mtmp
->wormno
&& incl_wsegs
)
3178 sz
+= size_wseg(mtmp
);
3181 sz
+= (int) sizeof (struct mextra
);
3183 sz
+= (int) strlen(MNAME(mtmp
)) + 1;
3185 sz
+= (int) sizeof (struct egd
);
3187 sz
+= (int) sizeof (struct epri
);
3189 sz
+= (int) sizeof (struct eshk
);
3191 sz
+= (int) sizeof (struct emin
);
3193 sz
+= (int) sizeof (struct edog
);
3194 /* mextra->mcorpsenm doesn't point to more memory */
3200 mon_chain(win
, src
, chain
, force
, total_count
, total_size
)
3203 struct monst
*chain
;
3211 /* mon->wormno means something different for migrating_mons and mydogs */
3212 boolean incl_wsegs
= !strcmpi(src
, "fmon");
3215 for (mon
= chain
; mon
; mon
= mon
->nmon
) {
3217 size
+= size_monst(mon
, incl_wsegs
);
3219 if (count
|| size
|| force
) {
3220 *total_count
+= count
;
3221 *total_size
+= size
;
3222 Sprintf(buf
, template, src
, count
, size
);
3223 putstr(win
, 0, buf
);
3228 misc_stats(win
, total_count
, total_size
)
3233 char buf
[BUFSZ
], hdrbuf
[QBUFSZ
];
3237 struct damage
*sd
; /* shop damage */
3238 struct cemetery
*bi
; /* bones info */
3240 /* traps and engravings are output unconditionally;
3241 * others only if nonzero
3244 for (tt
= ftrap
; tt
; tt
= tt
->ntrap
) {
3246 size
+= (long) sizeof *tt
;
3248 *total_count
+= count
;
3249 *total_size
+= size
;
3250 Sprintf(hdrbuf
, "traps, size %ld", (long) sizeof (struct trap
));
3251 Sprintf(buf
, template, hdrbuf
, count
, size
);
3252 putstr(win
, 0, buf
);
3255 engr_stats("engravings, size %ld+text", hdrbuf
, &count
, &size
);
3256 *total_count
+= count
;
3257 *total_size
+= size
;
3258 Sprintf(buf
, template, hdrbuf
, count
, size
);
3259 putstr(win
, 0, buf
);
3262 light_stats("light sources, size %ld", hdrbuf
, &count
, &size
);
3263 if (count
|| size
) {
3264 *total_count
+= count
;
3265 *total_size
+= size
;
3266 Sprintf(buf
, template, hdrbuf
, count
, size
);
3267 putstr(win
, 0, buf
);
3271 timer_stats("timers, size %ld", hdrbuf
, &count
, &size
);
3272 if (count
|| size
) {
3273 *total_count
+= count
;
3274 *total_size
+= size
;
3275 Sprintf(buf
, template, hdrbuf
, count
, size
);
3276 putstr(win
, 0, buf
);
3280 for (sd
= level
.damagelist
; sd
; sd
= sd
->next
) {
3282 size
+= (long) sizeof *sd
;
3284 if (count
|| size
) {
3285 *total_count
+= count
;
3286 *total_size
+= size
;
3287 Sprintf(hdrbuf
, "shop damage, size %ld",
3288 (long) sizeof (struct damage
));
3289 Sprintf(buf
, template, hdrbuf
, count
, size
);
3290 putstr(win
, 0, buf
);
3294 region_stats("regions, size %ld+%ld*rect+N", hdrbuf
, &count
, &size
);
3295 if (count
|| size
) {
3296 *total_count
+= count
;
3297 *total_size
+= size
;
3298 Sprintf(buf
, template, hdrbuf
, count
, size
);
3299 putstr(win
, 0, buf
);
3303 for (bi
= level
.bonesinfo
; bi
; bi
= bi
->next
) {
3305 size
+= (long) sizeof *bi
;
3307 if (count
|| size
) {
3308 *total_count
+= count
;
3309 *total_size
+= size
;
3310 Sprintf(hdrbuf
, "bones history, size %ld",
3311 (long) sizeof (struct cemetery
));
3312 Sprintf(buf
, template, hdrbuf
, count
, size
);
3313 putstr(win
, 0, buf
);
3317 for (idx
= 0; idx
< NUM_OBJECTS
; ++idx
)
3318 if (objects
[idx
].oc_uname
) {
3320 size
+= (long) (strlen(objects
[idx
].oc_uname
) + 1);
3322 if (count
|| size
) {
3323 *total_count
+= count
;
3324 *total_size
+= size
;
3325 Strcpy(hdrbuf
, "object type names, text");
3326 Sprintf(buf
, template, hdrbuf
, count
, size
);
3327 putstr(win
, 0, buf
);
3332 * Display memory usage of all monsters and objects on the level.
3339 long total_obj_size
, total_obj_count
,
3340 total_mon_size
, total_mon_count
,
3341 total_ovr_size
, total_ovr_count
,
3342 total_misc_size
, total_misc_count
;
3344 win
= create_nhwindow(NHW_TEXT
);
3345 putstr(win
, 0, "Current memory statistics:");
3347 total_obj_count
= total_obj_size
= 0L;
3348 putstr(win
, 0, stats_hdr
);
3349 Sprintf(buf
, " Objects, base size %ld", (long) sizeof (struct obj
));
3350 putstr(win
, 0, buf
);
3351 obj_chain(win
, "invent", invent
, TRUE
, &total_obj_count
, &total_obj_size
);
3352 obj_chain(win
, "fobj", fobj
, TRUE
, &total_obj_count
, &total_obj_size
);
3353 obj_chain(win
, "buried", level
.buriedobjlist
, FALSE
,
3354 &total_obj_count
, &total_obj_size
);
3355 obj_chain(win
, "migrating obj", migrating_objs
, FALSE
,
3356 &total_obj_count
, &total_obj_size
);
3357 obj_chain(win
, "billobjs", billobjs
, FALSE
,
3358 &total_obj_count
, &total_obj_size
);
3359 mon_invent_chain(win
, "minvent", fmon
, &total_obj_count
, &total_obj_size
);
3360 mon_invent_chain(win
, "migrating minvent", migrating_mons
,
3361 &total_obj_count
, &total_obj_size
);
3362 contained_stats(win
, "contained", &total_obj_count
, &total_obj_size
);
3363 putstr(win
, 0, stats_sep
);
3364 Sprintf(buf
, template, " Obj total", total_obj_count
, total_obj_size
);
3365 putstr(win
, 0, buf
);
3367 total_mon_count
= total_mon_size
= 0L;
3369 Sprintf(buf
, " Monsters, base size %ld", (long) sizeof (struct monst
));
3370 putstr(win
, 0, buf
);
3371 mon_chain(win
, "fmon", fmon
, TRUE
, &total_mon_count
, &total_mon_size
);
3372 mon_chain(win
, "migrating", migrating_mons
, FALSE
,
3373 &total_mon_count
, &total_mon_size
);
3374 /* 'mydogs' is only valid during level change or end of game disclosure,
3375 but conceivably we've been called from within debugger at such time */
3376 if (mydogs
) /* monsters accompanying hero */
3377 mon_chain(win
, "mydogs", mydogs
, FALSE
,
3378 &total_mon_count
, &total_mon_size
);
3379 putstr(win
, 0, stats_sep
);
3380 Sprintf(buf
, template, " Mon total", total_mon_count
, total_mon_size
);
3381 putstr(win
, 0, buf
);
3383 total_ovr_count
= total_ovr_size
= 0L;
3385 putstr(win
, 0, " Overview");
3386 overview_stats(win
, template, &total_ovr_count
, &total_ovr_size
);
3387 putstr(win
, 0, stats_sep
);
3388 Sprintf(buf
, template, " Over total", total_ovr_count
, total_ovr_size
);
3389 putstr(win
, 0, buf
);
3391 total_misc_count
= total_misc_size
= 0L;
3393 putstr(win
, 0, " Miscellaneous");
3394 misc_stats(win
, &total_misc_count
, &total_misc_size
);
3395 putstr(win
, 0, stats_sep
);
3396 Sprintf(buf
, template, " Misc total", total_misc_count
, total_misc_size
);
3397 putstr(win
, 0, buf
);
3400 putstr(win
, 0, stats_sep
);
3401 Sprintf(buf
, template, " Grand total",
3402 (total_obj_count
+ total_mon_count
3403 + total_ovr_count
+ total_misc_count
),
3404 (total_obj_size
+ total_mon_size
3405 + total_ovr_size
+ total_misc_size
));
3406 putstr(win
, 0, buf
);
3408 #if defined(__BORLANDC__) && !defined(_WIN32)
3409 show_borlandc_stats(win
);
3412 display_nhwindow(win
, FALSE
);
3413 destroy_nhwindow(win
);
3421 timer_sanity_check();
3423 light_sources_sanity_check();
3426 #ifdef DEBUG_MIGRATING_MONS
3432 struct permonst
*ptr
;
3436 getlin("How many random monsters to migrate? [0]", inbuf
);
3437 if (*inbuf
== '\033')
3439 mcount
= atoi(inbuf
);
3440 if (mcount
< 0 || mcount
> (COLNO
* ROWNO
) || Is_botlevel(&u
.uz
))
3442 while (mcount
> 0) {
3443 if (Is_stronghold(&u
.uz
))
3444 assign_level(&tolevel
, &valley_level
);
3446 get_level(&tolevel
, depth(&u
.uz
) + 1);
3448 mtmp
= makemon(ptr
, 0, 0, NO_MM_FLAGS
);
3450 migrate_to_level(mtmp
, ledger_no(&tolevel
), MIGR_RANDOM
,
3458 #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
3459 #define unmeta(c) (0x7f & (c))
3465 } const spkeys_binds
[] = {
3466 { NHKF_ESC
, '\033', NULL
}, /* no binding */
3467 { NHKF_DOAGAIN
, DOAGAIN
, "repeat" },
3468 { NHKF_REQMENU
, 'm', "reqmenu" },
3469 { NHKF_RUN
, 'G', "run" },
3470 { NHKF_RUN2
, '5', "run.numpad" },
3471 { NHKF_RUSH
, 'g', "rush" },
3472 { NHKF_FIGHT
, 'F', "fight" },
3473 { NHKF_FIGHT2
, '-', "fight.numpad" },
3474 { NHKF_NOPICKUP
, 'm', "nopickup" },
3475 { NHKF_RUN_NOPICKUP
, 'M', "run.nopickup" },
3476 { NHKF_DOINV
, '0', "doinv" },
3477 { NHKF_TRAVEL
, CMD_TRAVEL
, NULL
}, /* no binding */
3478 { NHKF_CLICKLOOK
, CMD_CLICKLOOK
, NULL
}, /* no binding */
3479 { NHKF_REDRAW
, C('r'), "redraw" },
3480 { NHKF_REDRAW2
, C('l'), "redraw.numpad" },
3481 { NHKF_GETDIR_SELF
, '.', "getdir.self" },
3482 { NHKF_GETDIR_SELF2
, 's', "getdir.self2" },
3483 { NHKF_GETDIR_HELP
, '?', "getdir.help" },
3484 { NHKF_COUNT
, 'n', "count" },
3485 { NHKF_GETPOS_SELF
, '@', "getpos.self" },
3486 { NHKF_GETPOS_PICK
, '.', "getpos.pick" },
3487 { NHKF_GETPOS_PICK_Q
, ',', "getpos.pick.quick" },
3488 { NHKF_GETPOS_PICK_O
, ';', "getpos.pick.once" },
3489 { NHKF_GETPOS_PICK_V
, ':', "getpos.pick.verbose" },
3490 { NHKF_GETPOS_SHOWVALID
, '$', "getpos.valid" },
3491 { NHKF_GETPOS_AUTODESC
, '#', "getpos.autodescribe" },
3492 { NHKF_GETPOS_MON_NEXT
, 'm', "getpos.mon.next" },
3493 { NHKF_GETPOS_MON_PREV
, 'M', "getpos.mon.prev" },
3494 { NHKF_GETPOS_OBJ_NEXT
, 'o', "getpos.obj.next" },
3495 { NHKF_GETPOS_OBJ_PREV
, 'O', "getpos.obj.prev" },
3496 { NHKF_GETPOS_DOOR_NEXT
, 'd', "getpos.door.next" },
3497 { NHKF_GETPOS_DOOR_PREV
, 'D', "getpos.door.prev" },
3498 { NHKF_GETPOS_UNEX_NEXT
, 'x', "getpos.unexplored.next" },
3499 { NHKF_GETPOS_UNEX_PREV
, 'X', "getpos.unexplored.prev" },
3500 { NHKF_GETPOS_HELP
, '?', "getpos.help" }
3504 bind_specialkey(key
, command
)
3509 for (i
= 0; i
< SIZE(spkeys_binds
); i
++) {
3510 if (!spkeys_binds
[i
].name
|| strcmp(command
, spkeys_binds
[i
].name
))
3512 Cmd
.spkeys
[spkeys_binds
[i
].nhkf
] = key
;
3518 /* returns a one-byte character from the text (it may massacre the txt
3524 txt
= trimspaces(txt
);
3525 if (!*txt
) return 0;
3527 /* simple character */
3528 if (!txt
[1]) return txt
[0];
3530 /* a few special entries */
3531 if (!strcmp(txt
, "<enter>")) return '\n';
3532 if (!strcmp(txt
, "<space>")) return ' ';
3533 if (!strcmp(txt
, "<esc>")) return '\033';
3535 /* control and meta keys */
3537 case 'm': /* can be mx, Mx, m-x, M-x */
3540 if(*txt
== '-' && txt
[1]) txt
++;
3541 if (txt
[1]) return 0;
3543 case 'c': /* can be cx, Cx, ^x, c-x, C-x, ^-x */
3547 if(*txt
== '-' && txt
[1]) txt
++;
3548 if (txt
[1]) return 0;
3552 /* ascii codes: must be three-digit decimal */
3553 if (*txt
>= '0' && *txt
<= '9') {
3556 for(i
= 0; i
< 3; i
++) {
3557 if(txt
[i
]<'0' || txt
[i
]>'9') return 0;
3558 key
= 10 * key
+ txt
[i
]-'0';
3566 /* returns the text for a one-byte encoding
3567 * must be shorter than a tab for proper formatting */
3571 char* txt
; /* sufficiently long buffer */
3574 Sprintf(txt
, "<space>");
3575 else if (c
== '\033')
3576 Sprintf(txt
, "<esc>");
3578 Sprintf(txt
, "<enter>");
3580 Sprintf(txt
, "^%c", UNCTRL(c
));
3582 Sprintf(txt
, "M-%c", UNMETA(c
));
3583 else if (c
>= 33 && c
<= 126)
3584 Sprintf(txt
, "%c", c
); /* regular keys: ! through ~ */
3586 Sprintf(txt
, "A-%i", c
); /* arbitrary ascii combinations */
3592 parseautocomplete(autocomplete
,condition
)
3596 struct ext_func_tab
*efp
;
3597 register char *autoc
;
3599 /* break off first autocomplete from the rest; parse the rest */
3600 if ((autoc
= index(autocomplete
, ','))
3601 || (autoc
= index(autocomplete
, ':'))) {
3603 parseautocomplete(autoc
, condition
);
3606 /* strip leading and trailing white space */
3607 autocomplete
= trimspaces(autocomplete
);
3609 if (!*autocomplete
) return;
3611 /* take off negation */
3612 if (*autocomplete
== '!') {
3613 /* unlike most options, a leading "no" might actually be a part of
3614 * the extended command. Thus you have to use ! */
3616 autocomplete
= trimspaces(autocomplete
);
3617 condition
= !condition
;
3620 /* find and modify the extended command */
3621 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
3622 if (!strcmp(autocomplete
, efp
->ef_txt
)) {
3624 efp
->flags
|= AUTOCOMPLETE
;
3626 efp
->flags
&= ~AUTOCOMPLETE
;
3631 /* not a real extended command */
3632 raw_printf("Bad autocomplete: invalid extended command '%s'.", autocomplete
);
3636 /* called at startup and after number_pad is twiddled */
3638 reset_commands(initial
)
3641 static const char sdir
[] = "hykulnjb><",
3642 sdir_swap_yz
[] = "hzkulnjb><",
3643 ndir
[] = "47896321><",
3644 ndir_phone_layout
[] = "41236987><";
3645 static const int ylist
[] = {
3646 'y', 'Y', C('y'), M('y'), M('Y'), M(C('y'))
3648 static struct ext_func_tab
*back_dir_cmd
[10];
3649 const struct ext_func_tab
*cmdtmp
;
3651 int c
, i
, updated
= 0;
3652 static boolean backed_dir_cmd
= FALSE
;
3656 Cmd
.num_pad
= FALSE
;
3657 Cmd
.pcHack_compat
= Cmd
.phone_layout
= Cmd
.swap_yz
= FALSE
;
3658 for (i
= 0; i
< SIZE(spkeys_binds
); i
++)
3659 Cmd
.spkeys
[spkeys_binds
[i
].nhkf
] = spkeys_binds
[i
].key
;
3663 if (backed_dir_cmd
) {
3664 for (i
= 0; i
< 10; i
++) {
3665 Cmd
.commands
[(uchar
)Cmd
.dirchars
[i
]] = back_dir_cmd
[i
];
3670 flagtemp
= iflags
.num_pad
;
3671 if (flagtemp
!= Cmd
.num_pad
) {
3672 Cmd
.num_pad
= flagtemp
;
3675 /* swap_yz mode (only applicable for !num_pad); intended for
3676 QWERTZ keyboard used in Central Europe, particularly Germany */
3677 flagtemp
= (iflags
.num_pad_mode
& 1) ? !Cmd
.num_pad
: FALSE
;
3678 if (flagtemp
!= Cmd
.swap_yz
) {
3679 Cmd
.swap_yz
= flagtemp
;
3681 /* Cmd.swap_yz has been toggled;
3682 perform the swap (or reverse previous one) */
3683 for (i
= 0; i
< SIZE(ylist
); i
++) {
3684 c
= ylist
[i
] & 0xff;
3685 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [y] */
3686 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 1]; /* [y] = [z] */
3687 Cmd
.commands
[c
+ 1] = cmdtmp
; /* [z] = tmp */
3690 /* MSDOS compatibility mode (only applicable for num_pad) */
3691 flagtemp
= (iflags
.num_pad_mode
& 1) ? Cmd
.num_pad
: FALSE
;
3692 if (flagtemp
!= Cmd
.pcHack_compat
) {
3693 Cmd
.pcHack_compat
= flagtemp
;
3695 /* pcHack_compat has been toggled */
3697 cmdtmp
= Cmd
.commands
['5'];
3698 Cmd
.commands
['5'] = Cmd
.commands
[c
];
3699 Cmd
.commands
[c
] = cmdtmp
;
3701 Cmd
.commands
[c
] = Cmd
.pcHack_compat
? Cmd
.commands
['I'] : 0;
3703 /* phone keypad layout (only applicable for num_pad) */
3704 flagtemp
= (iflags
.num_pad_mode
& 2) ? Cmd
.num_pad
: FALSE
;
3705 if (flagtemp
!= Cmd
.phone_layout
) {
3706 Cmd
.phone_layout
= flagtemp
;
3708 /* phone_layout has been toggled */
3709 for (i
= 0; i
< 3; i
++) {
3710 c
= '1' + i
; /* 1,2,3 <-> 7,8,9 */
3711 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [1] */
3712 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [1] = [7] */
3713 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [7] = tmp */
3714 c
= (M('1') & 0xff) + i
; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
3715 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [M-1] */
3716 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [M-1] = [M-7] */
3717 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [M-7] = tmp */
3724 Cmd
.dirchars
= !Cmd
.num_pad
3725 ? (!Cmd
.swap_yz
? sdir
: sdir_swap_yz
)
3726 : (!Cmd
.phone_layout
? ndir
: ndir_phone_layout
);
3727 Cmd
.alphadirchars
= !Cmd
.num_pad
? Cmd
.dirchars
: sdir
;
3729 Cmd
.move_W
= Cmd
.dirchars
[0];
3730 Cmd
.move_NW
= Cmd
.dirchars
[1];
3731 Cmd
.move_N
= Cmd
.dirchars
[2];
3732 Cmd
.move_NE
= Cmd
.dirchars
[3];
3733 Cmd
.move_E
= Cmd
.dirchars
[4];
3734 Cmd
.move_SE
= Cmd
.dirchars
[5];
3735 Cmd
.move_S
= Cmd
.dirchars
[6];
3736 Cmd
.move_SW
= Cmd
.dirchars
[7];
3739 for (i
= 0; i
< 10; i
++) {
3741 (struct ext_func_tab
*)Cmd
.commands
[(uchar
)Cmd
.dirchars
[i
]];
3742 Cmd
.commands
[(uchar
)Cmd
.dirchars
[i
]] = NULL
;
3744 backed_dir_cmd
= TRUE
;
3745 for (i
= 0; i
< 8; i
++)
3746 bind_key(Cmd
.dirchars
[i
], "nothing");
3750 /* non-movement commands which accept 'm' prefix to request menu operation */
3752 accept_menu_prefix(cmd_func
)
3753 int NDECL((*cmd_func
));
3755 if (cmd_func
== dopickup
|| cmd_func
== dotip
3756 /* eat, #offer, and apply tinning-kit all use floorfood() to pick
3757 an item on floor or in invent; 'm' skips picking from floor
3758 (ie, inventory only) rather than request use of menu operation */
3759 || cmd_func
== doeat
|| cmd_func
== dosacrifice
|| cmd_func
== doapply
3760 /* 'm' for removing saddle from adjacent monster without checking
3761 for containers at <u.ux,u.uy> */
3762 || cmd_func
== doloot
3763 /* 'm' prefix allowed for some extended commands */
3764 || cmd_func
== doextcmd
|| cmd_func
== doextlist
)
3770 ch2spkeys(c
, start
,end
)
3775 for (i
= start
; i
<= end
; i
++)
3776 if (Cmd
.spkeys
[i
] == c
)
3785 boolean do_walk
, do_rush
, prefix_seen
, bad_command
,
3786 firsttime
= (cmd
== 0);
3788 iflags
.menu_requested
= FALSE
;
3790 if (program_state
.done_hup
)
3797 if (*cmd
== Cmd
.spkeys
[NHKF_ESC
]) {
3798 context
.move
= FALSE
;
3801 if (*cmd
== DOAGAIN
&& !in_doagain
&& saveq
[0]) {
3804 rhack((char *) 0); /* read and execute command */
3808 /* Special case of *cmd == ' ' handled better below */
3809 if (!*cmd
|| *cmd
== (char) 0377) {
3811 context
.move
= FALSE
;
3812 return; /* probably we just had an interrupt */
3815 /* handle most movement commands */
3816 do_walk
= do_rush
= prefix_seen
= FALSE
;
3817 context
.travel
= context
.travel1
= 0;
3818 switch (ch2spkeys(*cmd
, NHKF_RUN
,NHKF_CLICKLOOK
)) {
3820 if (movecmd(cmd
[1])) {
3828 break; /* else FALLTHRU */
3830 if (movecmd(lowc(cmd
[1]))) {
3838 break; /* else FALLTHRU */
3839 /* Effects of movement commands and invisible monsters:
3840 * m: always move onto space (even if 'I' remembered)
3841 * F: always attack space (even if 'I' not remembered)
3842 * normal movement: attack if 'I', move otherwise.
3845 if (movecmd(cmd
[1])) {
3846 context
.forcefight
= 1;
3852 if (movecmd(cmd
[1]) || u
.dz
) {
3858 cmd
[0] = cmd
[1]; /* "m<" or "m>" */
3862 case NHKF_RUN_NOPICKUP
:
3863 if (movecmd(lowc(cmd
[1]))) {
3873 (void) ddoinv(); /* a convenience borrowed from the PC */
3874 context
.move
= FALSE
;
3877 case NHKF_CLICKLOOK
:
3878 if (iflags
.clicklook
) {
3879 context
.move
= FALSE
;
3880 do_look(2, &clicklook_cc
);
3884 if (flags
.travelcmd
) {
3886 context
.travel1
= 1;
3894 if (movecmd(*cmd
)) { /* ordinary movement */
3895 context
.run
= 0; /* only matters here if it was 8 */
3897 } else if (movecmd(Cmd
.num_pad
? unmeta(*cmd
) : lowc(*cmd
))) {
3900 } else if (movecmd(unctrl(*cmd
))) {
3907 /* some special prefix handling */
3908 /* overload 'm' prefix to mean "request a menu" */
3909 if (prefix_seen
&& cmd
[0] == Cmd
.spkeys
[NHKF_REQMENU
]) {
3910 /* (for func_tab cast, see below) */
3911 const struct ext_func_tab
*ft
= Cmd
.commands
[cmd
[1] & 0xff];
3912 int NDECL((*func
)) = ft
? ((struct ext_func_tab
*) ft
)->ef_funct
: 0;
3914 if (func
&& accept_menu_prefix(func
)) {
3915 iflags
.menu_requested
= TRUE
;
3920 if ((do_walk
|| do_rush
) && !context
.travel
&& !dxdy_moveok()) {
3921 /* trying to move diagonally as a grid bug;
3922 this used to be treated by movecmd() as not being
3923 a movement attempt, but that didn't provide for any
3924 feedback and led to strangeness if the key pressed
3925 ('u' in particular) was overloaded for num_pad use */
3926 You_cant("get there from here...");
3928 context
.nopick
= context
.forcefight
= FALSE
;
3929 context
.move
= context
.mv
= FALSE
;
3938 context
.forcefight
= 0;
3940 } else if (do_rush
) {
3943 multi
= max(COLNO
, ROWNO
);
3944 u
.last_str_turn
= 0;
3949 } else if (prefix_seen
&& cmd
[1] == Cmd
.spkeys
[NHKF_ESC
]) {
3950 /* <prefix><escape> */
3951 /* don't report "unknown command" for change of heart... */
3952 bad_command
= FALSE
;
3953 } else if (*cmd
== ' ' && !flags
.rest_on_space
) {
3954 bad_command
= TRUE
; /* skip cmdlist[] loop */
3956 /* handle all other commands */
3958 register const struct ext_func_tab
*tlist
;
3959 int res
, NDECL((*func
));
3961 /* current - use *cmd to directly index cmdlist array */
3962 if ((tlist
= Cmd
.commands
[*cmd
& 0xff]) != 0) {
3963 if (!wizard
&& (tlist
->flags
& WIZMODECMD
)) {
3964 You_cant("do that!");
3966 } else if (u
.uburied
&& !(tlist
->flags
& IFBURIED
)) {
3967 You_cant("do that while you are buried!");
3970 /* we discard 'const' because some compilers seem to have
3971 trouble with the pointer passed to set_occupation() */
3972 func
= ((struct ext_func_tab
*) tlist
)->ef_funct
;
3973 if (tlist
->f_text
&& !occupation
&& multi
)
3974 set_occupation(func
, tlist
->f_text
, multi
);
3975 res
= (*func
)(); /* perform the command */
3978 context
.move
= FALSE
;
3983 /* if we reach here, cmd wasn't found in cmdlist[] */
3988 char expcmd
[20]; /* we expect 'cmd' to point to 1 or 2 chars */
3992 while ((c
= *cmd
++) != '\0')
3993 Strcat(expcmd
, visctrl(c
)); /* add 1..4 chars plus terminator */
3995 if (!prefix_seen
|| !iflags
.cmdassist
3996 || !help_dir(0, "Invalid direction key!"))
3997 Norep("Unknown command '%s'.", expcmd
);
4000 context
.move
= FALSE
;
4005 /* convert an x,y pair into a direction code */
4012 for (dd
= 0; dd
< 8; dd
++)
4013 if (x
== xdir
[dd
] && y
== ydir
[dd
])
4018 /* convert a direction code into an x,y pair */
4029 /* also sets u.dz, but returns false for <> */
4034 register const char *dp
= index(Cmd
.dirchars
, sym
);
4039 u
.dx
= xdir
[dp
- Cmd
.dirchars
];
4040 u
.dy
= ydir
[dp
- Cmd
.dirchars
];
4041 u
.dz
= zdir
[dp
- Cmd
.dirchars
];
4042 #if 0 /* now handled elsewhere */
4043 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
)) {
4051 /* grid bug handling which used to be in movecmd() */
4055 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
))
4057 return u
.dx
|| u
.dy
;
4060 /* decide whether a character (user input keystroke) requests screen repaint */
4065 return (boolean
) (c
== Cmd
.spkeys
[NHKF_REDRAW
]
4066 || (Cmd
.num_pad
&& c
== Cmd
.spkeys
[NHKF_REDRAW2
]));
4073 return (c
== Cmd
.spkeys
[NHKF_RUSH
]
4074 || c
== Cmd
.spkeys
[NHKF_RUN
]
4075 || c
== Cmd
.spkeys
[NHKF_NOPICKUP
]
4076 || c
== Cmd
.spkeys
[NHKF_RUN_NOPICKUP
]
4077 || c
== Cmd
.spkeys
[NHKF_FIGHT
]
4078 || (Cmd
.num_pad
&& (c
== Cmd
.spkeys
[NHKF_RUN2
]
4079 || c
== Cmd
.spkeys
[NHKF_FIGHT2
])));
4083 * uses getdir() but unlike getdir() it specifically
4084 * produces coordinates using the direction from getdir()
4085 * and verifies that those coordinates are ok.
4087 * If the call to getdir() returns 0, Never_mind is displayed.
4088 * If the resulting coordinates are not okay, emsg is displayed.
4090 * Returns non-zero if coordinates in cc are valid.
4093 get_adjacent_loc(prompt
, emsg
, x
, y
, cc
)
4094 const char *prompt
, *emsg
;
4099 if (!getdir(prompt
)) {
4105 if (cc
&& isok(new_x
, new_y
)) {
4124 if (in_doagain
|| *readchar_queue
)
4125 dirsym
= readchar();
4127 dirsym
= yn_function((s
&& *s
!= '^') ? s
: "In what direction?",
4129 /* remove the prompt string so caller won't have to */
4130 clear_nhwindow(WIN_MESSAGE
);
4132 if (redraw_cmd(dirsym
)) { /* ^R */
4133 docrt(); /* redraw */
4138 if (dirsym
== Cmd
.spkeys
[NHKF_GETDIR_SELF
]
4139 || dirsym
== Cmd
.spkeys
[NHKF_GETDIR_SELF2
]) {
4140 u
.dx
= u
.dy
= u
.dz
= 0;
4141 } else if (!(is_mov
= movecmd(dirsym
)) && !u
.dz
) {
4142 boolean did_help
= FALSE
, help_requested
;
4144 if (!index(quitchars
, dirsym
)) {
4145 help_requested
= (dirsym
== Cmd
.spkeys
[NHKF_GETDIR_HELP
]);
4146 if (help_requested
|| iflags
.cmdassist
) {
4147 did_help
= help_dir((s
&& *s
== '^') ? dirsym
: 0,
4148 help_requested
? (const char *) 0
4149 : "Invalid direction key!");
4154 pline("What a strange direction!");
4157 } else if (is_mov
&& !dxdy_moveok()) {
4158 You_cant("orient yourself that direction.");
4161 if (!u
.dz
&& (Stunned
|| (Confusion
&& !rn2(5))))
4167 show_direction_keys(win
, nodiag
)
4174 Sprintf(buf
, " %c ", Cmd
.move_N
);
4175 putstr(win
, 0, buf
);
4176 putstr(win
, 0, " | ");
4177 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
4178 putstr(win
, 0, buf
);
4179 putstr(win
, 0, " | ");
4180 Sprintf(buf
, " %c ", Cmd
.move_S
);
4181 putstr(win
, 0, buf
);
4183 Sprintf(buf
, " %c %c %c", Cmd
.move_NW
, Cmd
.move_N
,
4185 putstr(win
, 0, buf
);
4186 putstr(win
, 0, " \\ | / ");
4187 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
4188 putstr(win
, 0, buf
);
4189 putstr(win
, 0, " / | \\ ");
4190 Sprintf(buf
, " %c %c %c", Cmd
.move_SW
, Cmd
.move_S
,
4192 putstr(win
, 0, buf
);
4202 static const char wiz_only_list
[] = "EFGIVW";
4205 char buf
[BUFSZ
], buf2
[BUFSZ
], *explain
;
4207 win
= create_nhwindow(NHW_TEXT
);
4211 Sprintf(buf
, "cmdassist: %s", msg
);
4212 putstr(win
, 0, buf
);
4215 if (letter(sym
) || sym
== '[') { /* 'dat/cmdhelp' shows ESC as ^[ */
4216 sym
= highc(sym
); /* @A-Z[ (note: letter() accepts '@') */
4217 ctrl
= (sym
- 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */
4218 if ((explain
= dowhatdoes_core(ctrl
, buf2
)) != 0
4219 && (!index(wiz_only_list
, sym
) || wizard
)) {
4220 Sprintf(buf
, "Are you trying to use ^%c%s?", sym
,
4221 index(wiz_only_list
, sym
)
4223 : " as specified in the Guidebook");
4224 putstr(win
, 0, buf
);
4226 putstr(win
, 0, explain
);
4229 "To use that command, hold down the <Ctrl> key as a shift");
4230 Sprintf(buf
, "and press the <%c> key.", sym
);
4231 putstr(win
, 0, buf
);
4236 Sprintf(buf
, "Valid direction keys %sare:",
4237 NODIAG(u
.umonnum
) ? "in your current form " : "");
4238 putstr(win
, 0, buf
);
4239 show_direction_keys(win
, NODIAG(u
.umonnum
));
4242 putstr(win
, 0, " < up");
4243 putstr(win
, 0, " > down");
4244 Sprintf(buf
, " %4s direct at yourself",
4245 visctrl(Cmd
.spkeys
[NHKF_GETDIR_SELF
]));
4246 putstr(win
, 0, buf
);
4248 /* non-null msg means that this wasn't an explicit user request */
4251 "(Suppress this message with !cmdassist in config file.)");
4253 display_nhwindow(win
, FALSE
);
4254 destroy_nhwindow(win
);
4261 register int x
= NODIAG(u
.umonnum
) ? 2 * rn2(4) : rn2(8);
4272 static NEARDATA
const char *const dirnames
[] = {
4273 "west", "northwest", "north", "northeast", "east",
4274 "southeast", "south", "southwest", "down", "up",
4277 if (dir
< 0 || dir
>= SIZE(dirnames
))
4279 return dirnames
[dir
];
4286 /* x corresponds to curx, so x==1 is the first column. Ach. %% */
4287 return x
>= 1 && x
<= COLNO
- 1 && y
>= 0 && y
<= ROWNO
- 1;
4290 static NEARDATA
int last_multi
;
4293 * convert a MAP window position into a movecmd
4296 click_to_cmd(x
, y
, mod
)
4303 if (iflags
.clicklook
&& mod
== CLICK_2
) {
4306 cmd
[0] = Cmd
.spkeys
[NHKF_CLICKLOOK
];
4313 if (flags
.travelcmd
) {
4314 if (abs(x
) <= 1 && abs(y
) <= 1) {
4315 x
= sgn(x
), y
= sgn(y
);
4319 cmd
[0] = Cmd
.spkeys
[NHKF_TRAVEL
];
4323 if (x
== 0 && y
== 0) {
4325 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)
4326 || IS_SINK(levl
[u
.ux
][u
.uy
].typ
)) {
4327 cmd
[0] = cmd_from_func(mod
== CLICK_1
? dodrink
: dodip
);
4329 } else if (IS_THRONE(levl
[u
.ux
][u
.uy
].typ
)) {
4330 cmd
[0] = cmd_from_func(dosit
);
4332 } else if ((u
.ux
== xupstair
&& u
.uy
== yupstair
)
4333 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
4335 || (u
.ux
== xupladder
&& u
.uy
== yupladder
)) {
4336 cmd
[0] = cmd_from_func(doup
);
4338 } else if ((u
.ux
== xdnstair
&& u
.uy
== ydnstair
)
4339 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
4341 || (u
.ux
== xdnladder
&& u
.uy
== ydnladder
)) {
4342 cmd
[0] = cmd_from_func(dodown
);
4344 } else if (OBJ_AT(u
.ux
, u
.uy
)) {
4345 cmd
[0] = cmd_from_func(Is_container(level
.objects
[u
.ux
][u
.uy
])
4346 ? doloot
: dopickup
);
4349 cmd
[0] = cmd_from_func(donull
); /* just rest */
4354 /* directional commands */
4358 if (!m_at(u
.ux
+ x
, u
.uy
+ y
)
4359 && !test_move(u
.ux
, u
.uy
, x
, y
, TEST_MOVE
)) {
4360 cmd
[1] = Cmd
.dirchars
[dir
];
4362 if (IS_DOOR(levl
[u
.ux
+ x
][u
.uy
+ y
].typ
)) {
4363 /* slight assistance to the player: choose kick/open for them
4365 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_LOCKED
) {
4366 cmd
[0] = cmd_from_func(dokick
);
4369 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_CLOSED
) {
4370 cmd
[0] = cmd_from_func(doopen
);
4374 if (levl
[u
.ux
+ x
][u
.uy
+ y
].typ
<= SCORR
) {
4375 cmd
[0] = cmd_from_func(dosearch
);
4381 /* convert without using floating point, allowing sloppy clicking */
4384 else if (y
> 2 * abs(x
))
4386 else if (x
< -2 * abs(y
))
4388 else if (y
< -2 * abs(x
))
4391 x
= sgn(x
), y
= sgn(y
);
4393 if (x
== 0 && y
== 0) {
4394 /* map click on player to "rest" command */
4395 cmd
[0] = cmd_from_func(donull
);
4401 /* move, attack, etc. */
4403 if (mod
== CLICK_1
) {
4404 cmd
[0] = Cmd
.dirchars
[dir
];
4406 cmd
[0] = (Cmd
.num_pad
4407 ? M(Cmd
.dirchars
[dir
])
4408 : (Cmd
.dirchars
[dir
] - 'a' + 'A')); /* run command */
4415 get_count(allowchars
, inkey
, maxcount
, count
)
4424 boolean backspaced
= FALSE
;
4425 /* this should be done in port code so that we have erase_char
4426 and kill_char available; we can at least fake erase_char */
4427 #define STANDBY_erase_char '\177'
4437 cnt
= 10L * cnt
+ (long) (key
- '0');
4440 else if (maxcount
> 0 && cnt
> maxcount
)
4442 } else if (cnt
&& (key
== '\b' || key
== STANDBY_erase_char
)) {
4445 } else if (key
== Cmd
.spkeys
[NHKF_ESC
]) {
4447 } else if (!allowchars
|| index(allowchars
, key
)) {
4452 if (cnt
> 9 || backspaced
) {
4453 clear_nhwindow(WIN_MESSAGE
);
4454 if (backspaced
&& !cnt
) {
4455 Sprintf(qbuf
, "Count: ");
4457 Sprintf(qbuf
, "Count: %ld", cnt
);
4471 #ifdef LINT /* static char in_line[COLNO]; */
4472 char in_line
[COLNO
];
4474 static char in_line
[COLNO
];
4477 boolean prezero
= FALSE
;
4481 flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
4484 alt_esc
= iflags
.altmeta
; /* readchar() hack */
4486 if (!Cmd
.num_pad
|| (foo
= readchar()) == Cmd
.spkeys
[NHKF_COUNT
]) {
4487 long tmpmulti
= multi
;
4489 foo
= get_count(NULL
, '\0', LARGEST_INT
, &tmpmulti
);
4490 last_multi
= multi
= tmpmulti
;
4493 alt_esc
= FALSE
; /* readchar() reset */
4496 if (foo
== Cmd
.spkeys
[NHKF_ESC
]) { /* esc cancels count (TH) */
4497 clear_nhwindow(WIN_MESSAGE
);
4498 multi
= last_multi
= 0;
4499 } else if (foo
== Cmd
.spkeys
[NHKF_DOAGAIN
] || in_doagain
) {
4503 savech(0); /* reset input queue */
4511 save_cm
= (char *) 0;
4513 /* in 3.4.3 this was in rhack(), where it was too late to handle M-5 */
4514 if (Cmd
.pcHack_compat
) {
4515 /* This handles very old inconsistent DOS/Windows behaviour
4516 in a different way: earlier, the keyboard handler mapped
4517 these, which caused counts to be strange when entered
4518 from the number pad. Now do not map them until here. */
4521 foo
= Cmd
.spkeys
[NHKF_RUSH
];
4524 foo
= Cmd
.spkeys
[NHKF_RUN
];
4527 foo
= Cmd
.spkeys
[NHKF_DOINV
];
4536 if (prefix_cmd(foo
)) {
4542 clear_nhwindow(WIN_MESSAGE
);
4544 in_line
[0] = Cmd
.spkeys
[NHKF_ESC
];
4548 #ifdef HANGUPHANDLING
4549 /* some very old systems, or descendents of such systems, expect signal
4550 handlers to have return type `int', but they don't actually inspect
4551 the return value so we should be safe using `void' unconditionally */
4554 hangup(sig_unused
) /* called as signal() handler, so sent at least one arg */
4555 int sig_unused UNUSED
;
4557 if (program_state
.exiting
)
4558 program_state
.in_moveloop
= 0;
4561 /* When using SAFERHANGUP, the done_hup flag it tested in rhack
4562 and a couple of other places; actual hangup handling occurs then.
4563 This is 'safer' because it disallows certain cheats and also
4564 protects against losing objects in the process of being thrown,
4565 but also potentially riskier because the disconnected program
4566 must continue running longer before attempting a hangup save. */
4567 program_state
.done_hup
++;
4568 /* defer hangup iff game appears to be in progress */
4569 if (program_state
.in_moveloop
&& program_state
.something_worth_saving
)
4571 #endif /* SAFERHANGUP */
4578 #ifdef NOSAVEONHANGUP
4580 if (flags
.ins_chkpt
&& program_state
.something_worth_saving
)
4581 program_statue
.preserve_locks
= 1; /* keep files for recovery */
4583 program_state
.something_worth_saving
= 0; /* don't save */
4587 if (!program_state
.done_hup
++)
4589 if (program_state
.something_worth_saving
)
4591 if (iflags
.window_inited
)
4592 exit_nhwindows((char *) 0);
4594 terminate(EXIT_SUCCESS
);
4595 /*NOTREACHED*/ /* not necessarily true for vms... */
4598 #endif /* HANGUPHANDLING */
4604 int x
= u
.ux
, y
= u
.uy
, mod
= 0;
4606 if (*readchar_queue
)
4607 sym
= *readchar_queue
++;
4609 sym
= in_doagain
? pgetchar() : nh_poskey(&x
, &y
, &mod
);
4613 register int cnt
= NR_OF_EOFS
;
4615 * Some SYSV systems seem to return EOFs for various reasons
4616 * (?like when one hits break or for interrupted systemcalls?),
4617 * and we must see several before we quit.
4620 clearerr(stdin
); /* omit if clearerr is undefined */
4622 } while (--cnt
&& sym
== EOF
);
4624 #endif /* NR_OF_EOFS */
4627 #ifdef HANGUPHANDLING
4628 hangup(0); /* call end_of_input() or set program_state.done_hup */
4632 } else if (sym
== '\033' && alt_esc
) {
4633 /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' */
4634 sym
= *readchar_queue
? *readchar_queue
++ : pgetchar();
4635 if (sym
== EOF
|| sym
== 0)
4637 else if (sym
!= '\033')
4638 sym
|= 0200; /* force 8th bit on */
4640 } else if (sym
== 0) {
4642 readchar_queue
= click_to_cmd(x
, y
, mod
);
4643 sym
= *readchar_queue
++;
4651 /* Keyboard travel command */
4655 if (!flags
.travelcmd
)
4658 cc
.x
= iflags
.travelcc
.x
;
4659 cc
.y
= iflags
.travelcc
.y
;
4660 if (cc
.x
== -1 && cc
.y
== -1) {
4661 /* No cached destination, start attempt from current position */
4665 iflags
.getloc_travelmode
= TRUE
;
4666 pline("Where do you want to travel to?");
4667 if (getpos(&cc
, TRUE
, "the desired destination") < 0) {
4668 /* user pressed ESC */
4669 iflags
.getloc_travelmode
= FALSE
;
4672 iflags
.getloc_travelmode
= FALSE
;
4673 iflags
.travelcc
.x
= u
.tx
= cc
.x
;
4674 iflags
.travelcc
.y
= u
.ty
= cc
.y
;
4675 cmd
[0] = Cmd
.spkeys
[NHKF_TRAVEL
];
4676 readchar_queue
= cmd
;
4681 extern void NDECL(win32con_debug_keystrokes
);
4682 extern void NDECL(win32con_handler_info
);
4691 int num_menu_selections
;
4692 struct menu_selection_struct
{
4695 } menu_selections
[] = {
4697 { "test win32 keystrokes (tty only)", win32con_debug_keystrokes
},
4698 { "show keystroke handler information (tty only)",
4699 win32con_handler_info
},
4701 { (char *) 0, (void NDECL((*) )) 0 } /* array terminator */
4704 num_menu_selections
= SIZE(menu_selections
) - 1;
4705 if (num_menu_selections
> 0) {
4706 menu_item
*pick_list
;
4707 win
= create_nhwindow(NHW_MENU
);
4709 for (k
= 0; k
< num_menu_selections
; ++k
) {
4711 add_menu(win
, NO_GLYPH
, &any
, item
++, 0, ATR_NONE
,
4712 menu_selections
[k
].menutext
, MENU_UNSELECTED
);
4714 end_menu(win
, "Which port debugging feature?");
4715 n
= select_menu(win
, PICK_ONE
, &pick_list
);
4716 destroy_nhwindow(win
);
4718 n
= pick_list
[0].item
.a_int
- 1;
4719 free((genericptr_t
) pick_list
);
4720 /* execute the function */
4721 (*menu_selections
[n
].fn
)();
4724 pline("No port-specific debug capability defined.");
4727 #endif /*PORT_DEBUG*/
4730 * Parameter validator for generic yes/no function to prevent
4731 * the core from sending too long a prompt string to the
4732 * window port causing a buffer overflow there.
4735 yn_function(query
, resp
, def
)
4736 const char *query
, *resp
;
4741 iflags
.last_msg
= PLNMSG_UNKNOWN
; /* most recent pline is clobbered */
4743 /* maximum acceptable length is QBUFSZ-1 */
4744 if (strlen(query
) >= QBUFSZ
) {
4745 /* caller shouldn't have passed anything this long */
4746 paniclog("Query truncated: ", query
);
4747 (void) strncpy(qbuf
, query
, QBUFSZ
- 1 - 3);
4748 Strcpy(&qbuf
[QBUFSZ
- 1 - 3], "...");
4751 return (*windowprocs
.win_yn_function
)(query
, resp
, def
);
4754 /* for paranoid_confirm:quit,die,attack prompting */
4756 paranoid_query(be_paranoid
, prompt
)
4757 boolean be_paranoid
;
4760 boolean confirmed_ok
;
4762 /* when paranoid, player must respond with "yes" rather than just 'y'
4763 to give the go-ahead for this query; default is "no" unless the
4764 ParanoidConfirm flag is set in which case there's no default */
4766 char qbuf
[QBUFSZ
], ans
[BUFSZ
];
4767 const char *promptprefix
= "", *responsetype
= ParanoidConfirm
4770 int trylimit
= 6; /* 1 normal, 5 more with "Yes or No:" prefix */
4772 /* in addition to being paranoid about this particular
4773 query, we might be even more paranoid about all paranoia
4774 responses (ie, ParanoidConfirm is set) in which case we
4775 require "no" to reject in addition to "yes" to confirm
4776 (except we won't loop if response is ESC; it means no) */
4778 Sprintf(qbuf
, "%s%s %s", promptprefix
, prompt
, responsetype
);
4780 (void) mungspaces(ans
);
4781 confirmed_ok
= !strcmpi(ans
, "yes");
4782 if (confirmed_ok
|| *ans
== '\033')
4784 promptprefix
= "\"Yes\" or \"No\": ";
4785 } while (ParanoidConfirm
&& strcmpi(ans
, "no") && --trylimit
);
4787 confirmed_ok
= (yn(prompt
) == 'y');
4789 return confirmed_ok
;
4796 /* Does current window system support suspend? */
4797 if ((*windowprocs
.win_can_suspend
)()) {
4798 /* NB: SYSCF SHELLERS handled in port code. */
4802 Norep("Suspend command not available.");