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