1 /* NetHack 3.6 cmd.c $NHDT-Date: 1451082253 2015/12/25 22:24:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.212 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
9 STATIC_VAR boolean alt_esc
= FALSE
;
12 struct cmd Cmd
= { 0 }; /* flag.h */
14 extern const char *hu_stat
[]; /* hunger status from eat.c */
15 extern const char *enc_stat
[]; /* encumbrance status from botl.c */
19 * Some systems may have getchar() return EOF for various reasons, and
20 * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
22 #if defined(SYSV) || defined(DGUX) || defined(HPUX)
27 #define CMD_TRAVEL (char) 0x90
28 #define CMD_CLICKLOOK (char) 0x8F
31 extern int NDECL(wiz_debug_cmd_bury
);
32 extern int NDECL(wiz_debug_cmd_traveldisplay
);
35 #ifdef DUMB /* stuff commented out in extern.h, but needed here */
36 extern int NDECL(doapply
); /**/
37 extern int NDECL(dorub
); /**/
38 extern int NDECL(dojump
); /**/
39 extern int NDECL(doextlist
); /**/
40 extern int NDECL(enter_explore_mode
); /**/
41 extern int NDECL(dodrop
); /**/
42 extern int NDECL(doddrop
); /**/
43 extern int NDECL(dodown
); /**/
44 extern int NDECL(doup
); /**/
45 extern int NDECL(donull
); /**/
46 extern int NDECL(dowipe
); /**/
47 extern int NDECL(docallcnd
); /**/
48 extern int NDECL(dotakeoff
); /**/
49 extern int NDECL(doremring
); /**/
50 extern int NDECL(dowear
); /**/
51 extern int NDECL(doputon
); /**/
52 extern int NDECL(doddoremarm
); /**/
53 extern int NDECL(dokick
); /**/
54 extern int NDECL(dofire
); /**/
55 extern int NDECL(dothrow
); /**/
56 extern int NDECL(doeat
); /**/
57 extern int NDECL(done2
); /**/
58 extern int NDECL(vanquished
); /**/
59 extern int NDECL(doengrave
); /**/
60 extern int NDECL(dopickup
); /**/
61 extern int NDECL(ddoinv
); /**/
62 extern int NDECL(dotypeinv
); /**/
63 extern int NDECL(dolook
); /**/
64 extern int NDECL(doprgold
); /**/
65 extern int NDECL(doprwep
); /**/
66 extern int NDECL(doprarm
); /**/
67 extern int NDECL(doprring
); /**/
68 extern int NDECL(dopramulet
); /**/
69 extern int NDECL(doprtool
); /**/
70 extern int NDECL(dosuspend
); /**/
71 extern int NDECL(doforce
); /**/
72 extern int NDECL(doopen
); /**/
73 extern int NDECL(doclose
); /**/
74 extern int NDECL(dosh
); /**/
75 extern int NDECL(dodiscovered
); /**/
76 extern int NDECL(doclassdisco
); /**/
77 extern int NDECL(doset
); /**/
78 extern int NDECL(dotogglepickup
); /**/
79 extern int NDECL(dowhatis
); /**/
80 extern int NDECL(doquickwhatis
); /**/
81 extern int NDECL(dowhatdoes
); /**/
82 extern int NDECL(dohelp
); /**/
83 extern int NDECL(dohistory
); /**/
84 extern int NDECL(doloot
); /**/
85 extern int NDECL(dodrink
); /**/
86 extern int NDECL(dodip
); /**/
87 extern int NDECL(dosacrifice
); /**/
88 extern int NDECL(dopray
); /**/
89 extern int NDECL(dotip
); /**/
90 extern int NDECL(doturn
); /**/
91 extern int NDECL(doredraw
); /**/
92 extern int NDECL(doread
); /**/
93 extern int NDECL(dosave
); /**/
94 extern int NDECL(dosearch
); /**/
95 extern int NDECL(doidtrap
); /**/
96 extern int NDECL(dopay
); /**/
97 extern int NDECL(dosit
); /**/
98 extern int NDECL(dotalk
); /**/
99 extern int NDECL(docast
); /**/
100 extern int NDECL(dovspell
); /**/
101 extern int NDECL(dotele
); /**/
102 extern int NDECL(dountrap
); /**/
103 extern int NDECL(doversion
); /**/
104 extern int NDECL(doextversion
); /**/
105 extern int NDECL(doswapweapon
); /**/
106 extern int NDECL(dowield
); /**/
107 extern int NDECL(dowieldquiver
); /**/
108 extern int NDECL(dozap
); /**/
109 extern int NDECL(doorganize
); /**/
112 static int NDECL(dosuspend_core
); /**/
114 static int NDECL((*timed_occ_fn
));
116 STATIC_PTR
int NDECL(doprev_message
);
117 STATIC_PTR
int NDECL(timed_occupation
);
118 STATIC_PTR
int NDECL(doextcmd
);
119 STATIC_PTR
int NDECL(domonability
);
120 STATIC_PTR
int NDECL(dooverview_or_wiz_where
);
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_genesis
);
128 STATIC_PTR
int NDECL(wiz_where
);
129 STATIC_PTR
int NDECL(wiz_detect
);
130 STATIC_PTR
int NDECL(wiz_panic
);
131 STATIC_PTR
int NDECL(wiz_polyself
);
132 STATIC_PTR
int NDECL(wiz_level_tele
);
133 STATIC_PTR
int NDECL(wiz_level_change
);
134 STATIC_PTR
int NDECL(wiz_show_seenv
);
135 STATIC_PTR
int NDECL(wiz_show_vision
);
136 STATIC_PTR
int NDECL(wiz_smell
);
137 STATIC_PTR
int NDECL(wiz_mon_polycontrol
);
138 STATIC_PTR
int NDECL(wiz_show_wmodes
);
139 STATIC_DCL
void NDECL(wiz_map_levltyp
);
140 STATIC_DCL
void NDECL(wiz_levltyp_legend
);
141 #if defined(__BORLANDC__) && !defined(_WIN32)
142 extern void FDECL(show_borlandc_stats
, (winid
));
144 #ifdef DEBUG_MIGRATING_MONS
145 STATIC_PTR
int NDECL(wiz_migrate_mons
);
147 STATIC_DCL
int FDECL(size_monst
, (struct monst
*));
148 STATIC_DCL
int FDECL(size_obj
, (struct obj
*));
149 STATIC_DCL
void FDECL(count_obj
, (struct obj
*, long *, long *,
150 BOOLEAN_P
, BOOLEAN_P
));
151 STATIC_DCL
void FDECL(obj_chain
, (winid
, const char *, struct obj
*,
153 STATIC_DCL
void FDECL(mon_invent_chain
, (winid
, const char *, struct monst
*,
155 STATIC_DCL
void FDECL(mon_chain
, (winid
, const char *, struct monst
*,
157 STATIC_DCL
void FDECL(contained
, (winid
, const char *, long *, long *));
158 STATIC_PTR
int NDECL(wiz_show_stats
);
159 STATIC_DCL boolean
FDECL(accept_menu_prefix
, (int NDECL((*))));
161 STATIC_DCL
int NDECL(wiz_port_debug
);
163 STATIC_PTR
int NDECL(wiz_rumor_check
);
164 STATIC_DCL
char FDECL(cmd_from_func
, (int NDECL((*))));
165 STATIC_PTR
int NDECL(doattributes
);
166 STATIC_PTR
int NDECL(doconduct
); /**/
168 STATIC_DCL
void FDECL(enlght_line
, (const char *, const char *, const char *,
170 STATIC_DCL
char *FDECL(enlght_combatinc
, (const char *, int, int, char *));
171 STATIC_DCL
void FDECL(enlght_halfdmg
, (int, int));
172 STATIC_DCL boolean
NDECL(walking_on_water
);
173 STATIC_DCL boolean
FDECL(cause_known
, (int));
174 STATIC_DCL
char *FDECL(attrval
, (int, int, char *));
175 STATIC_DCL
void FDECL(background_enlightenment
, (int, int));
176 STATIC_DCL
void FDECL(characteristics_enlightenment
, (int, int));
177 STATIC_DCL
void FDECL(one_characteristic
, (int, int, int));
178 STATIC_DCL
void FDECL(status_enlightenment
, (int, int));
179 STATIC_DCL
void FDECL(attributes_enlightenment
, (int, int));
181 static const char *readchar_queue
= "";
182 static coord clicklook_cc
;
184 STATIC_DCL
char *NDECL(parse
);
185 STATIC_DCL boolean
FDECL(help_dir
, (CHAR_P
, const char *));
188 doprev_message(VOID_ARGS
)
190 return nh_doprev_message();
193 /* Count down by decrementing multi */
195 timed_occupation(VOID_ARGS
)
203 /* If you have moved since initially setting some occupations, they
204 * now shouldn't be able to restart.
206 * The basic rule is that if you are carrying it, you can continue
207 * since it is with you. If you are acting on something at a distance,
208 * your orientation to it must have changed when you moved.
210 * The exception to this is taking off items, since they can be taken
211 * off in a number of ways in the intervening time, screwing up ordering.
213 * Currently: Take off all armor.
214 * Picking Locks / Forcing Chests.
225 /* If a time is given, use it to timeout this function, otherwise the
226 * function times out by its own means.
229 set_occupation(fn
, txt
, xtime
)
235 occupation
= timed_occupation
;
244 STATIC_DCL
char NDECL(popch
);
246 /* Provide a means to redo the last command. The flag `in_doagain' is set
247 * to true while redoing the command. This flag is tested in commands that
248 * require additional input (like `throw' which requires a thing and a
249 * direction), and the input prompt is not shown. Also, while in_doagain is
250 * TRUE, no keystrokes can be saved into the saveq.
253 static char pushq
[BSIZE
], saveq
[BSIZE
];
254 static NEARDATA
int phead
, ptail
, shead
, stail
;
259 /* If occupied, return '\0', letting tgetch know a character should
260 * be read from the keyboard. If the character read is not the
261 * ABORT character (as checked in pcmain.c), that character will be
262 * pushed back on the pushq.
267 return (char) ((shead
!= stail
) ? saveq
[stail
++] : '\0');
269 return (char) ((phead
!= ptail
) ? pushq
[ptail
++] : '\0');
273 pgetchar() /* courtesy of aeb@cwi.nl */
282 /* A ch == 0 resets the pushq */
294 /* A ch == 0 resets the saveq. Only save keystrokes when not
295 * replaying a previous command.
303 phead
= ptail
= shead
= stail
= 0;
304 else if (shead
< BSIZE
)
310 /* here after # - now read a full-word command */
317 /* keep repeating until we don't run help or quit */
323 func
= extcmdlist
[idx
].ef_funct
;
324 if (iflags
.menu_requested
&& !accept_menu_prefix(func
)) {
325 pline("'m' prefix has no effect for this command.");
326 iflags
.menu_requested
= FALSE
;
329 } while (func
== doextlist
);
334 /* here after #? - now list all full-word commands */
338 register const struct ext_func_tab
*efp
;
342 datawin
= create_nhwindow(NHW_TEXT
);
343 putstr(datawin
, 0, "");
344 putstr(datawin
, 0, " Extended Commands List");
345 putstr(datawin
, 0, "");
346 putstr(datawin
, 0, " Press '#', then type:");
347 putstr(datawin
, 0, "");
349 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
350 Sprintf(buf
, " %-15s - %s.", efp
->ef_txt
, efp
->ef_desc
);
351 putstr(datawin
, 0, buf
);
353 display_nhwindow(datawin
, FALSE
);
354 destroy_nhwindow(datawin
);
359 #define MAX_EXT_CMD 50 /* Change if we ever have > 50 ext cmds */
362 * This is currently used only by the tty port and is
363 * controlled via runtime option 'extmenu'.
364 * ``# ?'' is counted towards the limit of the number of commands,
365 * so we actually support MAX_EXT_CMD-1 "real" extended commands.
367 * Here after # - now show pick-list of possible commands.
372 const struct ext_func_tab
*efp
;
373 menu_item
*pick_list
= (menu_item
*) 0;
376 const struct ext_func_tab
*choices
[MAX_EXT_CMD
+ 1];
378 char cbuf
[QBUFSZ
], prompt
[QBUFSZ
], fmtstr
[20];
379 int i
, n
, nchoices
, acount
;
381 int accelerator
, prevaccelerator
;
390 /* populate choices */
391 for (efp
= extcmdlist
; efp
->ef_txt
; efp
++) {
392 if (!matchlevel
|| !strncmp(efp
->ef_txt
, cbuf
, matchlevel
)) {
394 if ((int) strlen(efp
->ef_desc
) > biggest
) {
395 biggest
= strlen(efp
->ef_desc
);
396 Sprintf(fmtstr
, "%%-%ds", biggest
+ 15);
398 if (++i
> MAX_EXT_CMD
) {
401 "Exceeded %d extended commands in doextcmd() menu; 'extmenu' disabled.",
409 choices
[i
] = (struct ext_func_tab
*) 0;
411 /* if we're down to one, we have our selection so get out of here */
413 for (i
= 0; extcmdlist
[i
].ef_txt
!= (char *) 0; i
++)
414 if (!strncmpi(extcmdlist
[i
].ef_txt
, cbuf
, matchlevel
)) {
422 win
= create_nhwindow(NHW_MENU
);
424 accelerator
= prevaccelerator
= 0;
426 for (i
= 0; choices
[i
]; ++i
) {
427 accelerator
= choices
[i
]->ef_txt
[matchlevel
];
428 if (accelerator
!= prevaccelerator
|| nchoices
< (ROWNO
- 3)) {
430 /* flush extended cmds for that letter already in buf */
431 Sprintf(buf
, fmtstr
, prompt
);
432 any
.a_char
= prevaccelerator
;
433 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
,
438 prevaccelerator
= accelerator
;
439 if (!acount
|| nchoices
< (ROWNO
- 3)) {
440 Sprintf(prompt
, "%s [%s]", choices
[i
]->ef_txt
,
441 choices
[i
]->ef_desc
);
442 } else if (acount
== 1) {
443 Sprintf(prompt
, "%s or %s", choices
[i
- 1]->ef_txt
,
446 Strcat(prompt
, " or ");
447 Strcat(prompt
, choices
[i
]->ef_txt
);
453 Sprintf(buf
, fmtstr
, prompt
);
454 any
.a_char
= prevaccelerator
;
455 add_menu(win
, NO_GLYPH
, &any
, any
.a_char
, 0, ATR_NONE
, buf
,
458 Sprintf(prompt
, "Extended Command: %s", cbuf
);
459 end_menu(win
, prompt
);
460 n
= select_menu(win
, PICK_ONE
, &pick_list
);
461 destroy_nhwindow(win
);
463 if (matchlevel
> (QBUFSZ
- 2)) {
464 free((genericptr_t
) pick_list
);
466 impossible("Too many chars (%d) entered in extcmd_via_menu()",
471 cbuf
[matchlevel
++] = pick_list
[0].item
.a_char
;
472 cbuf
[matchlevel
] = '\0';
473 free((genericptr_t
) pick_list
);
485 #endif /* TTY_GRAPHICS */
487 /* #monster command - use special monster ability while polymorphed */
489 domonability(VOID_ARGS
)
491 if (can_breathe(youmonst
.data
))
493 else if (attacktype(youmonst
.data
, AT_SPIT
))
495 else if (youmonst
.data
->mlet
== S_NYMPH
)
497 else if (attacktype(youmonst
.data
, AT_GAZE
))
499 else if (is_were(youmonst
.data
))
501 else if (webmaker(youmonst
.data
))
503 else if (is_hider(youmonst
.data
))
505 else if (is_mind_flayer(youmonst
.data
))
506 return domindblast();
507 else if (u
.umonnum
== PM_GREMLIN
) {
508 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
509 if (split_mon(&youmonst
, (struct monst
*) 0))
510 dryup(u
.ux
, u
.uy
, TRUE
);
512 There("is no fountain here.");
513 } else if (is_unicorn(youmonst
.data
)) {
514 use_unicorn_horn((struct obj
*) 0);
516 } else if (youmonst
.data
->msound
== MS_SHRIEK
) {
519 pline("Unfortunately sound does not carry well through rock.");
522 } else if (youmonst
.data
->mlet
== S_VAMPIRE
)
525 pline("Any special ability you may have is purely reflexive.");
527 You("don't have a special ability in your normal form!");
532 enter_explore_mode(VOID_ARGS
)
535 You("are in debug mode.");
536 } else if (discover
) {
537 You("are already in explore mode.");
541 if (!sysopt
.explorers
|| !sysopt
.explorers
[0]
542 || !check_user_string(sysopt
.explorers
)) {
543 You("cannot access explore mode.");
549 "Beware! From explore mode there will be no return to normal game.");
550 if (paranoid_query(ParanoidQuit
,
551 "Do you want to enter explore mode?")) {
552 clear_nhwindow(WIN_MESSAGE
);
553 You("are now in non-scoring explore mode.");
556 clear_nhwindow(WIN_MESSAGE
);
557 pline("Resuming normal game.");
564 dooverview_or_wiz_where(VOID_ARGS
)
573 /* ^W command - wish for something */
575 wiz_wish(VOID_ARGS
) /* Unlimited wishes for debug mode by Paul Polderman */
578 boolean save_verbose
= flags
.verbose
;
580 flags
.verbose
= FALSE
;
582 flags
.verbose
= save_verbose
;
583 (void) encumber_msg();
585 pline("Unavailable command '%s'.",
586 visctrl((int) cmd_from_func(wiz_wish
)));
590 /* ^I command - reveal and optionally identify hero's inventory */
592 wiz_identify(VOID_ARGS
)
595 iflags
.override_ID
= (int) cmd_from_func(wiz_identify
);
596 if (display_inventory((char *) 0, TRUE
) == -1)
597 identify_pack(0, FALSE
);
598 iflags
.override_ID
= 0;
600 pline("Unavailable command '%s'.",
601 visctrl((int) cmd_from_func(wiz_identify
)));
605 /* ^F command - reveal the level map and any traps on it */
611 long save_Hconf
= HConfusion
, save_Hhallu
= HHallucination
;
613 HConfusion
= HHallucination
= 0L;
614 for (t
= ftrap
; t
!= 0; t
= t
->ntrap
) {
619 HConfusion
= save_Hconf
;
620 HHallucination
= save_Hhallu
;
622 pline("Unavailable command '%s'.",
623 visctrl((int) cmd_from_func(wiz_map
)));
627 /* ^G command - generate monster(s); a count prefix will be honored */
629 wiz_genesis(VOID_ARGS
)
632 (void) create_particular();
634 pline("Unavailable command '%s'.",
635 visctrl((int) cmd_from_func(wiz_genesis
)));
639 /* ^O command - display dungeon layout */
644 (void) print_dungeon(FALSE
, (schar
*) 0, (xchar
*) 0);
646 pline("Unavailable command '%s'.",
647 visctrl((int) cmd_from_func(wiz_where
)));
651 /* ^E command - detect unseen (secret doors, traps, hidden monsters) */
653 wiz_detect(VOID_ARGS
)
658 pline("Unavailable command '%s'.",
659 visctrl((int) cmd_from_func(wiz_detect
)));
663 /* ^V command - level teleport */
665 wiz_level_tele(VOID_ARGS
)
670 pline("Unavailable command '%s'.",
671 visctrl((int) cmd_from_func(wiz_level_tele
)));
675 /* #monpolycontrol command - choose new form for shapechangers, polymorphees */
677 wiz_mon_polycontrol(VOID_ARGS
)
679 iflags
.mon_polycontrol
= !iflags
.mon_polycontrol
;
680 pline("Monster polymorph control is %s.",
681 iflags
.mon_polycontrol
? "on" : "off");
685 /* #levelchange command - adjust hero's experience level */
687 wiz_level_change(VOID_ARGS
)
693 getlin("To what experience level do you want to be set?", buf
);
694 (void) mungspaces(buf
);
695 if (buf
[0] == '\033' || buf
[0] == '\0')
698 ret
= sscanf(buf
, "%d", &newlevel
);
704 if (newlevel
== u
.ulevel
) {
705 You("are already that experienced.");
706 } else if (newlevel
< u
.ulevel
) {
708 You("are already as inexperienced as you can get.");
713 while (u
.ulevel
> newlevel
)
714 losexp("#levelchange");
716 if (u
.ulevel
>= MAXULEV
) {
717 You("are already as experienced as you can get.");
720 if (newlevel
> MAXULEV
)
722 while (u
.ulevel
< newlevel
)
725 u
.ulevelmax
= u
.ulevel
;
729 /* #panic command - test program's panic handling */
733 if (yn("Do you want to call panic() and end your game?") == 'y')
734 panic("Crash test.");
738 /* #polyself command - change hero's form */
740 wiz_polyself(VOID_ARGS
)
748 wiz_show_seenv(VOID_ARGS
)
751 int x
, y
, v
, startx
, stopx
, curx
;
754 win
= create_nhwindow(NHW_TEXT
);
756 * Each seenv description takes up 2 characters, so center
757 * the seenv display around the hero.
759 startx
= max(1, u
.ux
- (COLNO
/ 4));
760 stopx
= min(startx
+ (COLNO
/ 2), COLNO
);
761 /* can't have a line exactly 80 chars long */
762 if (stopx
- startx
== COLNO
/ 2)
765 for (y
= 0; y
< ROWNO
; y
++) {
766 for (x
= startx
, curx
= 0; x
< stopx
; x
++, curx
+= 2) {
767 if (x
== u
.ux
&& y
== u
.uy
) {
768 row
[curx
] = row
[curx
+ 1] = '@';
770 v
= levl
[x
][y
].seenv
& 0xff;
772 row
[curx
] = row
[curx
+ 1] = ' ';
774 Sprintf(&row
[curx
], "%02x", v
);
777 /* remove trailing spaces */
778 for (x
= curx
- 1; x
>= 0; x
--)
785 display_nhwindow(win
, TRUE
);
786 destroy_nhwindow(win
);
790 /* #vision command */
792 wiz_show_vision(VOID_ARGS
)
798 win
= create_nhwindow(NHW_TEXT
);
799 Sprintf(row
, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
800 COULD_SEE
, IN_SIGHT
, TEMP_LIT
);
803 for (y
= 0; y
< ROWNO
; y
++) {
804 for (x
= 1; x
< COLNO
; x
++) {
805 if (x
== u
.ux
&& y
== u
.uy
)
808 v
= viz_array
[y
][x
]; /* data access should be hidden */
812 row
[x
] = '0' + viz_array
[y
][x
];
815 /* remove trailing spaces */
816 for (x
= COLNO
- 1; x
>= 1; x
--)
821 putstr(win
, 0, &row
[1]);
823 display_nhwindow(win
, TRUE
);
824 destroy_nhwindow(win
);
830 wiz_show_wmodes(VOID_ARGS
)
836 boolean istty
= !strcmp(windowprocs
.name
, "tty");
838 win
= create_nhwindow(NHW_TEXT
);
840 putstr(win
, 0, ""); /* tty only: blank top line */
841 for (y
= 0; y
< ROWNO
; y
++) {
842 for (x
= 0; x
< COLNO
; x
++) {
844 if (x
== u
.ux
&& y
== u
.uy
)
846 else if (IS_WALL(lev
->typ
) || lev
->typ
== SDOOR
)
847 row
[x
] = '0' + (lev
->wall_info
& WM_MASK
);
848 else if (lev
->typ
== CORR
)
850 else if (IS_ROOM(lev
->typ
) || IS_DOOR(lev
->typ
))
856 /* map column 0, levl[0][], is off the left edge of the screen */
857 putstr(win
, 0, &row
[1]);
859 display_nhwindow(win
, TRUE
);
860 destroy_nhwindow(win
);
864 /* wizard mode variant of #terrain; internal levl[][].typ values in base-36 */
866 wiz_map_levltyp(VOID_ARGS
)
871 boolean istty
= !strcmp(windowprocs
.name
, "tty");
873 win
= create_nhwindow(NHW_TEXT
);
874 /* map row 0, levl[][0], is drawn on the second line of tty screen */
876 putstr(win
, 0, ""); /* tty only: blank top line */
877 for (y
= 0; y
< ROWNO
; y
++) {
878 /* map column 0, levl[0][], is off the left edge of the screen;
879 it should always have terrain type "undiggable stone" */
880 for (x
= 1; x
< COLNO
; x
++) {
881 terrain
= levl
[x
][y
].typ
;
882 /* assumes there aren't more than 10+26+26 terrain types */
883 row
[x
- 1] = (char) ((terrain
== 0 && !may_dig(x
, y
))
889 : 'A' + terrain
- 36);
891 if (levl
[0][y
].typ
!= 0 || may_dig(0, y
))
899 s_level
*slev
= Is_special(&u
.uz
);
901 Sprintf(dsc
, "D:%d,L:%d", u
.uz
.dnum
, u
.uz
.dlevel
);
902 /* [dungeon branch features currently omitted] */
903 /* special level features */
905 Sprintf(eos(dsc
), " \"%s\"", slev
->proto
);
906 /* special level flags (note: dungeon.def doesn't set `maze'
907 or `hell' for any specific levels so those never show up) */
908 if (slev
->flags
.maze_like
)
909 Strcat(dsc
, " mazelike");
910 if (slev
->flags
.hellish
)
911 Strcat(dsc
, " hellish");
912 if (slev
->flags
.town
)
913 Strcat(dsc
, " town");
914 if (slev
->flags
.rogue_like
)
915 Strcat(dsc
, " roguelike");
916 /* alignment currently omitted to save space */
919 if (level
.flags
.nfountains
)
920 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_fountain
].sym
,
921 (int) level
.flags
.nfountains
);
922 if (level
.flags
.nsinks
)
923 Sprintf(eos(dsc
), " %c:%d", defsyms
[S_sink
].sym
,
924 (int) level
.flags
.nsinks
);
925 if (level
.flags
.has_vault
)
926 Strcat(dsc
, " vault");
927 if (level
.flags
.has_shop
)
928 Strcat(dsc
, " shop");
929 if (level
.flags
.has_temple
)
930 Strcat(dsc
, " temple");
931 if (level
.flags
.has_court
)
932 Strcat(dsc
, " throne");
933 if (level
.flags
.has_zoo
)
935 if (level
.flags
.has_morgue
)
936 Strcat(dsc
, " morgue");
937 if (level
.flags
.has_barracks
)
938 Strcat(dsc
, " barracks");
939 if (level
.flags
.has_beehive
)
940 Strcat(dsc
, " hive");
941 if (level
.flags
.has_swamp
)
942 Strcat(dsc
, " swamp");
944 if (level
.flags
.noteleport
)
945 Strcat(dsc
, " noTport");
946 if (level
.flags
.hardfloor
)
947 Strcat(dsc
, " noDig");
948 if (level
.flags
.nommap
)
949 Strcat(dsc
, " noMMap");
950 if (!level
.flags
.hero_memory
)
951 Strcat(dsc
, " noMem");
952 if (level
.flags
.shortsighted
)
953 Strcat(dsc
, " shortsight");
954 if (level
.flags
.graveyard
)
955 Strcat(dsc
, " graveyard");
956 if (level
.flags
.is_maze_lev
)
957 Strcat(dsc
, " maze");
958 if (level
.flags
.is_cavernous_lev
)
959 Strcat(dsc
, " cave");
960 if (level
.flags
.arboreal
)
961 Strcat(dsc
, " tree");
963 Strcat(dsc
, " sokoban-rules");
964 /* non-flag info; probably should include dungeon branching
965 checks (extra stairs and magic portals) here */
966 if (Invocation_lev(&u
.uz
))
967 Strcat(dsc
, " invoke");
968 if (On_W_tower_level(&u
.uz
))
969 Strcat(dsc
, " tower");
970 /* append a branch identifier for completeness' sake */
972 Strcat(dsc
, " dungeon");
973 else if (u
.uz
.dnum
== mines_dnum
)
974 Strcat(dsc
, " mines");
975 else if (In_sokoban(&u
.uz
))
976 Strcat(dsc
, " sokoban");
977 else if (u
.uz
.dnum
== quest_dnum
)
978 Strcat(dsc
, " quest");
979 else if (Is_knox(&u
.uz
))
980 Strcat(dsc
, " ludios");
981 else if (u
.uz
.dnum
== 1)
982 Strcat(dsc
, " gehennom");
983 else if (u
.uz
.dnum
== tower_dnum
)
984 Strcat(dsc
, " vlad");
985 else if (In_endgame(&u
.uz
))
986 Strcat(dsc
, " endgame");
988 /* somebody's added a dungeon branch we're not expecting */
989 const char *brname
= dungeons
[u
.uz
.dnum
].dname
;
991 if (!brname
|| !*brname
)
993 if (!strncmpi(brname
, "the ", 4))
995 Sprintf(eos(dsc
), " %s", brname
);
997 /* limit the line length to map width */
998 if (strlen(dsc
) >= COLNO
)
999 dsc
[COLNO
- 1] = '\0'; /* truncate */
1000 putstr(win
, 0, dsc
);
1003 display_nhwindow(win
, TRUE
);
1004 destroy_nhwindow(win
);
1008 /* temporary? hack, since level type codes aren't the same as screen
1009 symbols and only the latter have easily accessible descriptions */
1010 static const char *levltyp
[] = {
1011 "stone", "vertical wall", "horizontal wall", "top-left corner wall",
1012 "top-right corner wall", "bottom-left corner wall",
1013 "bottom-right corner wall", "cross wall", "tee-up wall", "tee-down wall",
1014 "tee-left wall", "tee-right wall", "drawbridge wall", "tree",
1015 "secret door", "secret corridor", "pool", "moat", "water",
1016 "drawbridge up", "lava pool", "iron bars", "door", "corridor", "room",
1017 "stairs", "ladder", "fountain", "throne", "sink", "grave", "altar", "ice",
1018 "drawbridge down", "air", "cloud",
1019 /* not a real terrain type, but used for undiggable stone
1020 by wiz_map_levltyp() */
1021 "unreachable/undiggable",
1022 /* padding in case the number of entries above is odd */
1026 /* explanation of base-36 output from wiz_map_levltyp() */
1028 wiz_levltyp_legend(VOID_ARGS
)
1032 const char *dsc
, *fmt
;
1035 win
= create_nhwindow(NHW_TEXT
);
1036 putstr(win
, 0, "#terrain encodings:");
1038 fmt
= " %c - %-28s"; /* TODO: include tab-separated variant for win32 */
1040 /* output in pairs, left hand column holds [0],[1],...,[N/2-1]
1041 and right hand column holds [N/2],[N/2+1],...,[N-1];
1042 N ('last') will always be even, and may or may not include
1043 the empty string entry to pad out the final pair, depending
1044 upon how many other entries are present in levltyp[] */
1045 last
= SIZE(levltyp
) & ~1;
1046 for (i
= 0; i
< last
/ 2; ++i
)
1047 for (j
= i
; j
< last
; j
+= last
/ 2) {
1050 : !strncmp(dsc
, "unreachable", 11) ? '*'
1051 /* same int-to-char conversion as wiz_map_levltyp() */
1052 : (j
< 10) ? '0' + j
1053 : (j
< 36) ? 'a' + j
- 10
1055 Sprintf(eos(buf
), fmt
, c
, dsc
);
1057 putstr(win
, 0, buf
);
1061 display_nhwindow(win
, TRUE
);
1062 destroy_nhwindow(win
);
1066 /* #wizsmell command - test usmellmon(). */
1068 wiz_smell(VOID_ARGS
)
1071 int mndx
; /* monster index */
1072 coord cc
; /* screen pos of unknown glyph */
1073 int glyph
; /* glyph at selected position */
1077 mndx
= 0; /* gcc -Wall lint */
1078 if (!olfaction(youmonst
.data
)) {
1079 You("are incapable of detecting odors in your present form.");
1083 pline("You can move the cursor to a monster that you want to smell.");
1085 pline("Pick a monster to smell.");
1086 ans
= getpos(&cc
, TRUE
, "a monster");
1087 if (ans
< 0 || cc
.x
< 0) {
1088 return 0; /* done */
1090 /* Convert the glyph at the selected position to a mndxbol. */
1091 glyph
= glyph_at(cc
.x
, cc
.y
);
1092 if (glyph_is_monster(glyph
))
1093 mndx
= glyph_to_mon(glyph
);
1096 /* Is it a monster? */
1098 if (!usmellmon(&mons
[mndx
]))
1099 pline("That monster seems to give off no smell.");
1101 pline("That is not a monster.");
1106 /* #wizinstrinsic command to set some intrinsics for testing */
1108 wiz_intrinsic(VOID_ARGS
)
1113 int i
, n
, accelerator
;
1114 menu_item
*pick_list
= (menu_item
*) 0;
1116 static const char *const intrinsics
[] = {
1120 win
= create_nhwindow(NHW_MENU
);
1124 for (i
= 0; i
< SIZE(intrinsics
); ++i
) {
1125 accelerator
= intrinsics
[i
][0];
1127 add_menu(win
, NO_GLYPH
, &any
, accelerator
, 0, ATR_NONE
, intrinsics
[i
], FALSE
);
1129 end_menu(win
, "Which intrinsic?");
1130 n
= select_menu(win
, PICK_ONE
, &pick_list
);
1131 destroy_nhwindow(win
);
1134 i
= pick_list
[0].item
.a_int
-1;
1135 free((genericptr_t
) pick_list
);
1140 if (!strcmp(intrinsics
[i
],"deafness")) {
1142 incr_itimeout(&HDeaf
, 30);
1145 pline("Unavailable command '%s'.",
1146 visctrl((int) cmd_from_func(wiz_intrinsic
)));
1150 /* #wizrumorcheck command - verify each rumor access */
1152 wiz_rumor_check(VOID_ARGS
)
1158 /* #terrain command -- show known map, inspired by crawl's '|' command */
1160 doterrain(VOID_ARGS
)
1169 * normal play: choose between known map without mons, obj, and traps
1170 * (to see underlying terrain only), or
1171 * known map without mons and objs (to see traps under mons and objs), or
1172 * known map without mons (to see objects under monsters);
1173 * explore mode: normal choices plus full map (w/o mons, objs, traps);
1174 * wizard mode: normal and explore choices plus
1175 * a dump of the internal levl[][].typ codes w/ level flags, or
1176 * a legend for the levl[][].typ codes dump
1178 men
= create_nhwindow(NHW_MENU
);
1182 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1183 "known map without monsters, objects, and traps",
1186 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1187 "known map without monsters and objects",
1190 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1191 "known map without monsters",
1193 if (discover
|| wizard
) {
1195 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1196 "full map without monsters, objects, and traps",
1200 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1201 "internal levl[][].typ codes in base-36",
1204 add_menu(men
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
,
1205 "legend of base-36 levl[][].typ codes",
1209 end_menu(men
, "View which?");
1211 n
= select_menu(men
, PICK_ONE
, &sel
);
1212 destroy_nhwindow(men
);
1214 * n < 0: player used ESC to cancel;
1215 * n == 0: preselected entry was explicitly chosen and got toggled off;
1216 * n == 1: preselected entry was implicitly chosen via <space>|<enter>;
1217 * n == 2: another entry was explicitly chosen, so skip preselected one.
1219 which
= (n
< 0) ? -1 : (n
== 0) ? 1 : sel
[0].item
.a_int
;
1220 if (n
> 1 && which
== 1)
1221 which
= sel
[1].item
.a_int
;
1223 free((genericptr_t
) sel
);
1226 case 1: reveal_terrain(0, 0); break; /* known map */
1227 case 2: reveal_terrain(0, 1); break; /* known map with traps */
1228 case 3: reveal_terrain(0, 1|2); break; /* known map w/ traps & objs */
1229 case 4: reveal_terrain(1, 0); break; /* full map */
1230 case 5: wiz_map_levltyp(); break; /* map internals */
1231 case 6: wiz_levltyp_legend(); break; /* internal details */
1234 return 0; /* no time elapses */
1237 /* -enlightenment and conduct- */
1238 static winid en_win
= WIN_ERR
;
1239 static const char You_
[] = "You ", are
[] = "are ", were
[] = "were ",
1240 have
[] = "have ", had
[] = "had ", can
[] = "can ",
1242 static const char have_been
[] = "have been ", have_never
[] = "have never ",
1245 #define enl_msg(prefix, present, past, suffix, ps) \
1246 enlght_line(prefix, final ? past : present, suffix, ps)
1247 #define you_are(attr, ps) enl_msg(You_, are, were, attr, ps)
1248 #define you_have(attr, ps) enl_msg(You_, have, had, attr, ps)
1249 #define you_can(attr, ps) enl_msg(You_, can, could, attr, ps)
1250 #define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "")
1251 #define you_have_never(badthing) \
1252 enl_msg(You_, have_never, never, badthing, "")
1253 #define you_have_X(something) \
1254 enl_msg(You_, have, (const char *) "", something, "")
1257 enlght_line(start
, middle
, end
, ps
)
1258 const char *start
, *middle
, *end
, *ps
;
1262 Sprintf(buf
, " %s%s%s%s.", start
, middle
, end
, ps
);
1263 putstr(en_win
, 0, buf
);
1266 /* format increased chance to hit or damage or defense (Protection) */
1268 enlght_combatinc(inctyp
, incamt
, final
, outbuf
)
1273 const char *modif
, *bonus
;
1277 absamt
= abs(incamt
);
1278 /* Protection amount is typically larger than damage or to-hit;
1279 reduce magnitude by a third in order to stretch modifier ranges
1280 (small:1..5, moderate:6..10, large:11..19, huge:20+) */
1281 if (!strcmp(inctyp
, "defense"))
1282 absamt
= (absamt
* 2) / 3;
1286 else if (absamt
<= 6)
1288 else if (absamt
<= 12)
1293 modif
= !incamt
? "no" : an(modif
); /* ("no" case shouldn't happen) */
1294 bonus
= (incamt
>= 0) ? "bonus" : "penalty";
1295 /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
1296 invrt
= strcmp(inctyp
, "to hit") ? TRUE
: FALSE
;
1298 Sprintf(outbuf
, "%s %s %s", modif
, invrt
? inctyp
: bonus
,
1299 invrt
? bonus
: inctyp
);
1300 if (final
|| wizard
)
1301 Sprintf(eos(outbuf
), " (%s%d)", (incamt
> 0) ? "+" : "", incamt
);
1306 /* report half physical or half spell damage */
1308 enlght_halfdmg(category
, final
)
1312 const char *category_name
;
1317 category_name
= "physical";
1320 category_name
= "spell";
1323 category_name
= "unknown";
1326 Sprintf(buf
, " %s %s damage", (final
|| wizard
) ? "half" : "reduced",
1328 enl_msg(You_
, "take", "took", buf
, from_what(category
));
1331 /* is hero actively using water walking capability on water (or lava)? */
1335 if (u
.uinwater
|| Levitation
|| Flying
)
1337 return (boolean
) (Wwalking
1338 && (is_pool(u
.ux
, u
.uy
) || is_lava(u
.ux
, u
.uy
)));
1341 /* check whether hero is wearing something that player definitely knows
1342 confers the target property; item must have been seen and its type
1343 discovered but it doesn't necessarily have to be fully identified */
1345 cause_known(propindx
)
1346 int propindx
; /* index of a property which can be conveyed by worn item */
1348 register struct obj
*o
;
1349 long mask
= W_ARMOR
| W_AMUL
| W_RING
| W_TOOL
;
1351 /* simpler than from_what()/what_gives(); we don't attempt to
1352 handle artifacts and we deliberately ignore wielded items */
1353 for (o
= invent
; o
; o
= o
->nobj
) {
1354 if (!(o
->owornmask
& mask
))
1356 if ((int) objects
[o
->otyp
].oc_oprop
== propindx
1357 && objects
[o
->otyp
].oc_name_known
&& o
->dknown
)
1363 /* format a characteristic value, accommodating Strength's strangeness */
1365 attrval(attrindx
, attrvalue
, resultbuf
)
1366 int attrindx
, attrvalue
;
1367 char resultbuf
[]; /* should be at least [7] to hold "18/100\0" */
1369 if (attrindx
!= A_STR
|| attrvalue
<= 18)
1370 Sprintf(resultbuf
, "%d", attrvalue
);
1371 else if (attrvalue
> STR18(100)) /* 19 to 25 */
1372 Sprintf(resultbuf
, "%d", attrvalue
- 100);
1373 else /* simplify "18/ **" to be "18/100" */
1374 Sprintf(resultbuf
, "18/%02d", attrvalue
- 18);
1379 enlightenment(mode
, final
)
1380 int mode
; /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */
1381 int final
; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
1383 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1385 Strcpy(tmpbuf
, plname
);
1386 *tmpbuf
= highc(*tmpbuf
); /* same adjustment as bottom line */
1387 /* as in background_enlightenment, when poly'd we need to use the saved
1388 gender in u.mfemale rather than the current you-as-monster gender */
1389 Sprintf(buf
, "%s the %s's attributes:", tmpbuf
,
1390 ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1394 en_win
= create_nhwindow(NHW_MENU
);
1396 putstr(en_win
, 0, buf
); /* "Conan the Archeologist's attributes:" */
1397 /* background and characteristics; ^X or end-of-game disclosure */
1398 if (mode
& BASICENLIGHTENMENT
) {
1399 /* role, race, alignment, deities */
1400 background_enlightenment(mode
, final
);
1401 /* strength, dexterity, &c */
1402 characteristics_enlightenment(mode
, final
);
1404 /* expanded status line information, including things which aren't
1405 included there due to space considerations--such as obvious
1406 alternative movement indicators (riding, levitation, &c), and
1407 various troubles (turning to stone, trapped, confusion, &c);
1408 shown for both basic and magic enlightenment */
1409 status_enlightenment(mode
, final
);
1410 /* remaining attributes; shown for potion,&c or wizard mode and
1411 explore mode ^X or end of game disclosure */
1412 if (mode
& MAGICENLIGHTENMENT
) {
1413 /* intrinsics and other traditional enlightenment feedback */
1414 attributes_enlightenment(mode
, final
);
1416 display_nhwindow(en_win
, TRUE
);
1417 destroy_nhwindow(en_win
);
1422 /* display role, race, alignment and such to en_win */
1424 background_enlightenment(unused_mode
, final
)
1425 int unused_mode UNUSED
;
1428 const char *role_titl
, *rank_titl
;
1429 int innategend
, difgend
, difalgn
;
1430 char buf
[BUFSZ
], tmpbuf
[BUFSZ
];
1432 /* note that if poly'd, we need to use u.mfemale instead of flags.female
1433 to access hero's saved gender-as-human/elf/&c rather than current one */
1434 innategend
= (Upolyd
? u
.mfemale
: flags
.female
) ? 1 : 0;
1435 role_titl
= (innategend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
;
1436 rank_titl
= rank_of(u
.ulevel
, Role_switch
, innategend
);
1438 putstr(en_win
, 0, ""); /* separator after title */
1439 putstr(en_win
, 0, "Background:");
1441 /* if polymorphed, report current shape before underlying role;
1442 will be repeated as first status: "you are transformed" and also
1443 among various attributes: "you are in beast form" (after being
1444 told about lycanthropy) or "you are polymorphed into <a foo>"
1445 (with countdown timer appended for wizard mode); we really want
1446 the player to know he's not a samurai at the moment... */
1448 struct permonst
*uasmon
= youmonst
.data
;
1451 /* here we always use current gender, not saved role gender */
1452 if (!is_male(uasmon
) && !is_female(uasmon
) && !is_neuter(uasmon
))
1453 Sprintf(tmpbuf
, "%s ", genders
[flags
.female
? 1 : 0].adj
);
1454 Sprintf(buf
, "%sin %s%s form", !final
? "currently " : "", tmpbuf
,
1459 /* report role; omit gender if it's redundant (eg, "female priestess") */
1462 && ((urole
.allow
& ROLE_GENDMASK
) == (ROLE_MALE
| ROLE_FEMALE
)
1463 || innategend
!= flags
.initgend
))
1464 Sprintf(tmpbuf
, "%s ", genders
[innategend
].adj
);
1467 Strcpy(buf
, "actually "); /* "You are actually a ..." */
1468 if (!strcmpi(rank_titl
, role_titl
)) {
1469 /* omit role when rank title matches it */
1470 Sprintf(eos(buf
), "%s, level %d %s%s", an(rank_titl
), u
.ulevel
,
1471 tmpbuf
, urace
.noun
);
1473 Sprintf(eos(buf
), "%s, a level %d %s%s %s", an(rank_titl
), u
.ulevel
,
1474 tmpbuf
, urace
.adj
, role_titl
);
1478 /* report alignment (bypass you_are() in order to omit ending period) */
1479 Sprintf(buf
, " %s%s%s, %son a mission for %s",
1480 You_
, !final
? are
: were
,
1481 align_str(u
.ualign
.type
),
1482 /* helm of opposite alignment (might hide conversion) */
1483 (u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
]) ? "temporarily "
1484 /* permanent conversion */
1485 : (u
.ualign
.type
!= u
.ualignbase
[A_ORIGINAL
]) ? "now "
1486 /* atheist (ignored in very early game) */
1487 : (!u
.uconduct
.gnostic
&& moves
> 1000L) ? "nominally "
1488 /* lastly, normal case */
1491 putstr(en_win
, 0, buf
);
1492 /* show the rest of this game's pantheon (finishes previous sentence)
1493 [appending "also Moloch" at the end would allow for straightforward
1494 trailing "and" on all three aligned entries but looks too verbose] */
1495 Sprintf(buf
, " who %s opposed by", !final
? "is" : "was");
1496 if (u
.ualign
.type
!= A_LAWFUL
)
1497 Sprintf(eos(buf
), " %s (%s) and", align_gname(A_LAWFUL
),
1498 align_str(A_LAWFUL
));
1499 if (u
.ualign
.type
!= A_NEUTRAL
)
1500 Sprintf(eos(buf
), " %s (%s)%s", align_gname(A_NEUTRAL
),
1501 align_str(A_NEUTRAL
),
1502 (u
.ualign
.type
!= A_CHAOTIC
) ? " and" : "");
1503 if (u
.ualign
.type
!= A_CHAOTIC
)
1504 Sprintf(eos(buf
), " %s (%s)", align_gname(A_CHAOTIC
),
1505 align_str(A_CHAOTIC
));
1506 Strcat(buf
, "."); /* terminate sentence */
1507 putstr(en_win
, 0, buf
);
1509 /* show original alignment,gender,race,role if any have been changed;
1510 giving separate message for temporary alignment change bypasses need
1511 for tricky phrasing otherwise necessitated by possibility of having
1512 helm of opposite alignment mask a permanent alignment conversion */
1513 difgend
= (innategend
!= flags
.initgend
);
1514 difalgn
= (((u
.ualign
.type
!= u
.ualignbase
[A_CURRENT
]) ? 1 : 0)
1515 + ((u
.ualignbase
[A_CURRENT
] != u
.ualignbase
[A_ORIGINAL
])
1517 if (difalgn
& 1) { /* have temporary alignment so report permanent one */
1518 Sprintf(buf
, "actually %s", align_str(u
.ualignbase
[A_CURRENT
]));
1520 difalgn
&= ~1; /* suppress helm from "started out <foo>" message */
1522 if (difgend
|| difalgn
) { /* sex change or perm align change or both */
1523 Sprintf(buf
, " You started out %s%s%s.",
1524 difgend
? genders
[flags
.initgend
].adj
: "",
1525 (difgend
&& difalgn
) ? " and " : "",
1526 difalgn
? align_str(u
.ualignbase
[A_ORIGINAL
]) : "");
1527 putstr(en_win
, 0, buf
);
1531 /* characteristics: expanded version of bottom line strength, dexterity, &c */
1533 characteristics_enlightenment(mode
, final
)
1537 putstr(en_win
, 0, ""); /* separator after background */
1539 final
? "Final Characteristics:" : "Current Characteristics:");
1541 /* bottom line order */
1542 one_characteristic(mode
, final
, A_STR
); /* strength */
1543 one_characteristic(mode
, final
, A_DEX
); /* dexterity */
1544 one_characteristic(mode
, final
, A_CON
); /* constitution */
1545 one_characteristic(mode
, final
, A_INT
); /* intelligence */
1546 one_characteristic(mode
, final
, A_WIS
); /* wisdom */
1547 one_characteristic(mode
, final
, A_CHA
); /* charisma */
1550 /* display one attribute value for characteristics_enlightenment() */
1552 one_characteristic(mode
, final
, attrindx
)
1553 int mode
, final
, attrindx
;
1555 boolean hide_innate_value
= FALSE
, interesting_alimit
;
1556 int acurrent
, abase
, apeak
, alimit
;
1557 const char *attrname
, *paren_pfx
;
1558 char subjbuf
[BUFSZ
], valubuf
[BUFSZ
], valstring
[32];
1560 /* being polymorphed or wearing certain cursed items prevents
1561 hero from reliably tracking changes to characteristics so
1562 we don't show base & peak values then; when the items aren't
1563 cursed, hero could take them off to check underlying values
1564 and we show those in such case so that player doesn't need
1565 to actually resort to doing that */
1567 hide_innate_value
= TRUE
;
1568 } else if (Fixed_abil
) {
1569 if (stuck_ring(uleft
, RIN_SUSTAIN_ABILITY
)
1570 || stuck_ring(uright
, RIN_SUSTAIN_ABILITY
))
1571 hide_innate_value
= TRUE
;
1575 attrname
= "strength";
1576 if (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
&& uarmg
->cursed
)
1577 hide_innate_value
= TRUE
;
1580 attrname
= "dexterity";
1583 attrname
= "constitution";
1586 attrname
= "intelligence";
1587 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1588 hide_innate_value
= TRUE
;
1591 attrname
= "wisdom";
1592 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
&& uarmh
->cursed
)
1593 hide_innate_value
= TRUE
;
1596 attrname
= "charisma";
1599 return; /* impossible */
1601 /* note: final disclosure includes MAGICENLIGHTENTMENT */
1602 if ((mode
& MAGICENLIGHTENMENT
) && !Upolyd
)
1603 hide_innate_value
= FALSE
;
1605 acurrent
= ACURR(attrindx
);
1606 (void) attrval(attrindx
, acurrent
, valubuf
); /* Sprintf(valubuf,"%d",) */
1607 Sprintf(subjbuf
, "Your %s ", attrname
);
1609 if (!hide_innate_value
) {
1610 /* show abase, amax, and/or attrmax if acurr doesn't match abase
1611 (a magic bonus or penalty is in effect) or abase doesn't match
1612 amax (some points have been lost to poison or exercise abuse
1613 and are restorable) or attrmax is different from normal human
1614 (while game is in progress; trying to reduce dependency on
1615 spoilers to keep track of such stuff) or attrmax was different
1616 from abase (at end of game; this attribute wasn't maxed out) */
1617 abase
= ABASE(attrindx
);
1618 apeak
= AMAX(attrindx
);
1619 alimit
= ATTRMAX(attrindx
);
1620 /* criterium for whether the limit is interesting varies */
1621 interesting_alimit
=
1622 final
? TRUE
/* was originally `(abase != alimit)' */
1623 : (alimit
!= (attrindx
!= A_STR
? 18 : STR18(100)));
1624 paren_pfx
= final
? " (" : " (current; ";
1625 if (acurrent
!= abase
) {
1626 Sprintf(eos(valubuf
), "%sbase:%s", paren_pfx
,
1627 attrval(attrindx
, abase
, valstring
));
1630 if (abase
!= apeak
) {
1631 Sprintf(eos(valubuf
), "%speak:%s", paren_pfx
,
1632 attrval(attrindx
, apeak
, valstring
));
1635 if (interesting_alimit
) {
1636 Sprintf(eos(valubuf
), "%s%slimit:%s", paren_pfx
,
1637 /* more verbose if exceeding 'limit' due to magic bonus */
1638 (acurrent
> alimit
) ? "innate " : "",
1639 attrval(attrindx
, alimit
, valstring
));
1640 /* paren_pfx = ", "; */
1642 if (acurrent
!= abase
|| abase
!= apeak
|| interesting_alimit
)
1643 Strcat(valubuf
, ")");
1645 enl_msg(subjbuf
, "is ", "was ", valubuf
, "");
1648 /* status: selected obvious capabilities, assorted troubles */
1650 status_enlightenment(mode
, final
)
1654 boolean magic
= (mode
& MAGICENLIGHTENMENT
) ? TRUE
: FALSE
;
1656 char buf
[BUFSZ
], youtoo
[BUFSZ
];
1657 boolean Riding
= (u
.usteed
1658 /* if hero dies while dismounting, u.usteed will still
1659 be set; we want to ignore steed in that situation */
1660 && !(final
== ENL_GAMEOVERDEAD
1661 && !strcmp(killer
.name
, "riding accident")));
1662 const char *steedname
= (!Riding
? (char *) 0
1663 : x_monnam(u
.usteed
,
1664 u
.usteed
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
,
1666 (SUPPRESS_SADDLE
| SUPPRESS_HALLUCINATION
),
1670 * Status (many are abbreviated on bottom line; others are or
1671 * should be discernible to the hero hence to the player)
1673 putstr(en_win
, 0, ""); /* separator after title or characteristics */
1674 putstr(en_win
, 0, final
? "Final Status:" : "Current Status:");
1676 Strcpy(youtoo
, You_
);
1677 /* not a traditional status but inherently obvious to player; more
1678 detail given below (attributes section) for magic enlightenment */
1680 you_are("transformed", "");
1681 /* not a trouble, but we want to display riding status before maybe
1682 reporting steed as trapped or hero stuck to cursed saddle */
1684 Sprintf(buf
, "riding %s", steedname
);
1686 Sprintf(eos(youtoo
), "and %s ", steedname
);
1688 /* other movement situations that hero should always know */
1690 if (Lev_at_will
&& magic
)
1691 you_are("levitating, at will", "");
1693 enl_msg(youtoo
, are
, were
, "levitating", from_what(LEVITATION
));
1694 } else if (Flying
) { /* can only fly when not levitating */
1695 enl_msg(youtoo
, are
, were
, "flying", from_what(FLYING
));
1698 you_are("underwater", "");
1699 } else if (u
.uinwater
) {
1700 you_are(Swimming
? "swimming" : "in water", from_what(SWIMMING
));
1701 } else if (walking_on_water()) {
1702 /* show active Wwalking here, potential Wwalking elsewhere */
1703 Sprintf(buf
, "walking on %s",
1704 is_pool(u
.ux
, u
.uy
) ? "water"
1705 : is_lava(u
.ux
, u
.uy
) ? "lava"
1706 : surface(u
.ux
, u
.uy
)); /* catchall; shouldn't happen */
1707 you_are(buf
, from_what(WWALKING
));
1709 if (Upolyd
&& (u
.uundetected
|| youmonst
.m_ap_type
!= M_AP_NOTHING
))
1710 youhiding(TRUE
, final
);
1712 /* internal troubles, mostly in the order that prayer ranks them */
1714 you_are("turning to stone", "");
1716 you_are("turning into slime", "");
1719 you_are("buried", "");
1721 Strcpy(buf
, "being strangled");
1723 Sprintf(eos(buf
), " (%ld)", (Strangled
& TIMEOUT
));
1724 you_are(buf
, from_what(STRANGLED
));
1728 /* prayer lumps these together; botl puts Ill before FoodPois */
1729 if (u
.usick_type
& SICK_NONVOMITABLE
)
1730 you_are("terminally sick from illness", "");
1731 if (u
.usick_type
& SICK_VOMITABLE
)
1732 you_are("terminally sick from food poisoning", "");
1735 you_are("nauseated", "");
1737 you_are("stunned", "");
1739 you_are("confused", "");
1741 you_are("hallucinating", "");
1743 /* from_what() (currently wizard-mode only) checks !haseyes()
1744 before u.uroleplay.blind, so we should too */
1745 Sprintf(buf
, "%s blind",
1746 !haseyes(youmonst
.data
) ? "innately"
1747 : u
.uroleplay
.blind
? "permanently"
1748 /* better phrasing desperately wanted... */
1749 : Blindfolded_only
? "deliberately"
1751 if (wizard
&& (Blinded
& TIMEOUT
) != 0L
1752 && !u
.uroleplay
.blind
&& haseyes(youmonst
.data
))
1753 Sprintf(eos(buf
), " (%ld)", (Blinded
& TIMEOUT
));
1754 /* !haseyes: avoid "you are innately blind innately" */
1755 you_are(buf
, !haseyes(youmonst
.data
) ? "" : from_what(BLINDED
));
1758 you_are("deaf", from_what(DEAF
));
1760 /* external troubles, more or less */
1763 Sprintf(buf
, "chained to %s", ansimpleoname(uball
));
1765 impossible("Punished without uball?");
1766 Strcpy(buf
, "punished");
1771 char predicament
[BUFSZ
];
1773 boolean anchored
= (u
.utraptype
== TT_BURIEDBALL
);
1776 Strcpy(predicament
, "tethered to something buried");
1777 } else if (u
.utraptype
== TT_INFLOOR
|| u
.utraptype
== TT_LAVA
) {
1778 Sprintf(predicament
, "stuck in %s", the(surface(u
.ux
, u
.uy
)));
1780 Strcpy(predicament
, "trapped");
1781 if ((t
= t_at(u
.ux
, u
.uy
)) != 0)
1782 Sprintf(eos(predicament
), " in %s",
1783 an(defsyms
[trap_to_defsym(t
->ttyp
)].explanation
));
1785 if (u
.usteed
) { /* not `Riding' here */
1786 Sprintf(buf
, "%s%s ", anchored
? "you and " : "", steedname
);
1788 enl_msg(buf
, (anchored
? "are " : "is "),
1789 (anchored
? "were " : "was "), predicament
, "");
1791 you_are(predicament
, "");
1794 Sprintf(buf
, "swallowed by %s", a_monnam(u
.ustuck
));
1796 Sprintf(eos(buf
), " (%u)", u
.uswldtim
);
1798 } else if (u
.ustuck
) {
1799 Sprintf(buf
, "%s %s",
1800 (Upolyd
&& sticks(youmonst
.data
)) ? "holding" : "held by",
1801 a_monnam(u
.ustuck
));
1805 struct obj
*saddle
= which_armor(u
.usteed
, W_SADDLE
);
1807 if (saddle
&& saddle
->cursed
) {
1808 Sprintf(buf
, "stuck to %s %s", s_suffix(steedname
),
1809 simpleonames(saddle
));
1814 /* when mounted, Wounded_legs applies to steed rather than to
1815 hero; we only report steed's wounded legs in wizard mode */
1816 if (u
.usteed
) { /* not `Riding' here */
1817 if (wizard
&& steedname
) {
1818 Strcpy(buf
, steedname
);
1820 enl_msg(buf
, " has", " had", " wounded legs", "");
1823 Sprintf(buf
, "wounded %s", makeplural(body_part(LEG
)));
1828 Sprintf(buf
, "slippery %s", makeplural(body_part(FINGER
)));
1832 if (magic
|| cause_known(FUMBLING
))
1833 enl_msg(You_
, "fumble", "fumbled", "", from_what(FUMBLING
));
1836 if (magic
|| cause_known(SLEEPY
)) {
1837 Strcpy(buf
, from_what(SLEEPY
));
1839 Sprintf(eos(buf
), " (%ld)", (HSleepy
& TIMEOUT
));
1840 enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf
);
1843 /* hunger/nutrition */
1845 if (magic
|| cause_known(HUNGER
))
1846 enl_msg(You_
, "hunger", "hungered", " rapidly",
1849 Strcpy(buf
, hu_stat
[u
.uhs
]); /* hunger status; omitted if "normal" */
1850 mungspaces(buf
); /* strip trailing spaces */
1852 *buf
= lowc(*buf
); /* override capitalization */
1853 if (!strcmp(buf
, "weak"))
1854 Strcat(buf
, " from severe hunger");
1855 else if (!strncmp(buf
, "faint", 5)) /* fainting, fainted */
1856 Strcat(buf
, " due to starvation");
1860 if ((cap
= near_capacity()) > UNENCUMBERED
) {
1861 const char *adj
= "?_?"; /* (should always get overridden) */
1863 Strcpy(buf
, enc_stat
[cap
]);
1868 break; /* burdened */
1871 break; /* stressed */
1874 break; /* strained */
1877 break; /* overtaxed */
1879 adj
= "not possible";
1882 Sprintf(eos(buf
), "; movement %s %s%s", !final
? "is" : "was", adj
,
1883 (cap
< OVERLOADED
) ? " slowed" : "");
1886 /* last resort entry, guarantees Status section is non-empty
1887 (no longer needed for that purpose since weapon status added;
1888 still useful though) */
1889 you_are("unencumbered", "");
1891 /* report being weaponless; distinguish whether gloves are worn */
1893 you_are(uarmg
? "empty handed" /* gloves imply hands */
1894 : humanoid(youmonst
.data
)
1895 /* hands but no weapon and no gloves */
1897 /* alternate phrasing for paws or lack of hands */
1898 : "not wielding anything",
1900 /* two-weaponing implies a weapon (not other odd stuff) in each hand */
1901 } else if (u
.twoweap
) {
1902 you_are("wielding two weapons at once", "");
1903 /* report most weapons by their skill class (so a katana will be
1904 described as a long sword, for instance; mattock and hook are
1905 exceptions), or wielded non-weapon item by its object class */
1907 const char *what
= weapon_descr(uwep
);
1909 if (!strcmpi(what
, "armor") || !strcmpi(what
, "food")
1910 || !strcmpi(what
, "venom"))
1911 Sprintf(buf
, "wielding some %s", what
);
1913 Sprintf(buf
, "wielding %s",
1914 (uwep
->quan
== 1L) ? an(what
) : makeplural(what
));
1917 /* report 'nudity' */
1918 if (!uarm
&& !uarmu
&& !uarmc
&& !uarmg
&& !uarmf
&& !uarmh
) {
1919 if (u
.uroleplay
.nudist
)
1920 enl_msg(You_
, "do", "did", " not wear any armor", "");
1922 you_are("not wearing any armor", "");
1926 /* attributes: intrinsics and the like, other non-obvious capabilities */
1928 attributes_enlightenment(unused_mode
, final
)
1929 int unused_mode UNUSED
;
1932 static NEARDATA
const char if_surroundings_permitted
[] =
1933 " if surroundings permitted";
1940 putstr(en_win
, 0, "");
1941 putstr(en_win
, 0, final
? "Final Attributes:" : "Current Attributes:");
1943 if (u
.uevent
.uhand_of_elbereth
) {
1944 static const char *const hofe_titles
[3] = { "the Hand of Elbereth",
1945 "the Envoy of Balance",
1946 "the Glory of Arioch" };
1947 you_are(hofe_titles
[u
.uevent
.uhand_of_elbereth
- 1], "");
1950 /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
1951 if (u
.ualign
.record
>= 20)
1952 you_are("piously aligned", "");
1953 else if (u
.ualign
.record
> 13)
1954 you_are("devoutly aligned", "");
1955 else if (u
.ualign
.record
> 8)
1956 you_are("fervently aligned", "");
1957 else if (u
.ualign
.record
> 3)
1958 you_are("stridently aligned", "");
1959 else if (u
.ualign
.record
== 3)
1960 you_are("aligned", "");
1961 else if (u
.ualign
.record
> 0)
1962 you_are("haltingly aligned", "");
1963 else if (u
.ualign
.record
== 0)
1964 you_are("nominally aligned", "");
1965 else if (u
.ualign
.record
>= -3)
1966 you_have("strayed", "");
1967 else if (u
.ualign
.record
>= -8)
1968 you_have("sinned", "");
1970 you_have("transgressed", "");
1972 Sprintf(buf
, " %d", u
.ualign
.record
);
1973 enl_msg("Your alignment ", "is", "was", buf
, "");
1976 /*** Resistances to troubles ***/
1978 you_are("invulnerable", from_what(INVULNERABLE
));
1980 you_are("magic-protected", from_what(ANTIMAGIC
));
1981 if (Fire_resistance
)
1982 you_are("fire resistant", from_what(FIRE_RES
));
1983 if (Cold_resistance
)
1984 you_are("cold resistant", from_what(COLD_RES
));
1985 if (Sleep_resistance
)
1986 you_are("sleep resistant", from_what(SLEEP_RES
));
1987 if (Disint_resistance
)
1988 you_are("disintegration-resistant", from_what(DISINT_RES
));
1989 if (Shock_resistance
)
1990 you_are("shock resistant", from_what(SHOCK_RES
));
1991 if (Poison_resistance
)
1992 you_are("poison resistant", from_what(POISON_RES
));
1993 if (Acid_resistance
)
1994 you_are("acid resistant", from_what(ACID_RES
));
1995 if (Drain_resistance
)
1996 you_are("level-drain resistant", from_what(DRAIN_RES
));
1997 if (Sick_resistance
)
1998 you_are("immune to sickness", from_what(SICK_RES
));
1999 if (Stone_resistance
)
2000 you_are("petrification resistant", from_what(STONE_RES
));
2001 if (Halluc_resistance
)
2002 enl_msg(You_
, "resist", "resisted", " hallucinations",
2003 from_what(HALLUC_RES
));
2005 you_can("recognize detrimental food", "");
2007 /*** Vision and senses ***/
2008 if (!Blind
&& (Blinded
|| !haseyes(youmonst
.data
)))
2009 you_can("see", from_what(-BLINDED
)); /* Eyes of the Overworld */
2010 if (See_invisible
) {
2012 enl_msg(You_
, "see", "saw", " invisible", from_what(SEE_INVIS
));
2014 enl_msg(You_
, "will see", "would have seen",
2015 " invisible when not blind", from_what(SEE_INVIS
));
2018 you_are("telepathic", from_what(TELEPAT
));
2020 you_are("warned", from_what(WARNING
));
2021 if (Warn_of_mon
&& context
.warntype
.obj
) {
2022 Sprintf(buf
, "aware of the presence of %s",
2023 (context
.warntype
.obj
& M2_ORC
) ? "orcs"
2024 : (context
.warntype
.obj
& M2_ELF
) ? "elves"
2025 : (context
.warntype
.obj
& M2_DEMON
) ? "demons" : something
);
2026 you_are(buf
, from_what(WARN_OF_MON
));
2028 if (Warn_of_mon
&& context
.warntype
.polyd
) {
2029 Sprintf(buf
, "aware of the presence of %s",
2030 ((context
.warntype
.polyd
& (M2_HUMAN
| M2_ELF
))
2031 == (M2_HUMAN
| M2_ELF
))
2032 ? "humans and elves"
2033 : (context
.warntype
.polyd
& M2_HUMAN
)
2035 : (context
.warntype
.polyd
& M2_ELF
)
2037 : (context
.warntype
.polyd
& M2_ORC
)
2039 : (context
.warntype
.polyd
& M2_DEMON
)
2041 : "certain monsters");
2044 if (Warn_of_mon
&& context
.warntype
.speciesidx
>= LOW_PM
) {
2045 Sprintf(buf
, "aware of the presence of %s",
2046 makeplural(mons
[context
.warntype
.speciesidx
].mname
));
2047 you_are(buf
, from_what(WARN_OF_MON
));
2050 you_are("warned of undead", from_what(WARN_UNDEAD
));
2052 you_have("automatic searching", from_what(SEARCHING
));
2054 you_are("clairvoyant", from_what(CLAIRVOYANT
));
2055 else if ((HClairvoyant
|| EClairvoyant
) && BClairvoyant
) {
2056 Strcpy(buf
, from_what(-CLAIRVOYANT
));
2057 if (!strncmp(buf
, " because of ", 12))
2058 /* overwrite substring; strncpy doesn't add terminator */
2059 (void) strncpy(buf
, " if not for ", 12);
2060 enl_msg(You_
, "could be", "could have been", " clairvoyant", buf
);
2063 you_have("infravision", from_what(INFRAVISION
));
2064 if (Detect_monsters
)
2065 you_are("sensing the presence of monsters", "");
2067 you_are("going to confuse monsters", "");
2069 /*** Appearance and behavior ***/
2073 if (uleft
&& uleft
->otyp
== RIN_ADORNMENT
)
2074 adorn
+= uleft
->spe
;
2075 if (uright
&& uright
->otyp
== RIN_ADORNMENT
)
2076 adorn
+= uright
->spe
;
2077 /* the sum might be 0 (+0 ring or two which negate each other);
2078 that yields "you are charismatic" (which isn't pointless
2079 because it potentially impacts seduction attacks) */
2080 Sprintf(buf
, "%scharismatic",
2081 (adorn
> 0) ? "more " : (adorn
< 0) ? "less " : "");
2082 you_are(buf
, from_what(ADORNED
));
2085 you_are("invisible", from_what(INVIS
));
2087 you_are("invisible to others", from_what(INVIS
));
2088 /* ordinarily "visible" is redundant; this is a special case for
2089 the situation when invisibility would be an expected attribute */
2090 else if ((HInvis
|| EInvis
) && BInvis
)
2091 you_are("visible", from_what(-INVIS
));
2093 you_are("displaced", from_what(DISPLACED
));
2095 you_are("stealthy", from_what(STEALTH
));
2096 if (Aggravate_monster
)
2097 enl_msg("You aggravate", "", "d", " monsters",
2098 from_what(AGGRAVATE_MONSTER
));
2100 enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT
));
2102 /*** Transportation ***/
2104 you_can("jump", from_what(JUMPING
));
2106 you_can("teleport", from_what(TELEPORT
));
2107 if (Teleport_control
)
2108 you_have("teleport control", from_what(TELEPORT_CONTROL
));
2109 /* actively levitating handled earlier as a status condition */
2110 if (BLevitation
) { /* levitation is blocked */
2111 long save_BLev
= BLevitation
;
2115 enl_msg(You_
, "would levitate", "would have levitated",
2116 if_surroundings_permitted
, "");
2117 BLevitation
= save_BLev
;
2119 /* actively flying handled earlier as a status condition */
2120 if (BFlying
) { /* flight is blocked */
2121 long save_BFly
= BFlying
;
2125 enl_msg(You_
, "would fly", "would have flown",
2127 ? "if you weren't levitating"
2128 : (save_BFly
== FROMOUTSIDE
)
2129 ? if_surroundings_permitted
2130 /* both surroundings and [latent] levitation */
2131 : " if circumstances permitted",
2133 BFlying
= save_BFly
;
2135 /* actively walking on water handled earlier as a status condition */
2136 if (Wwalking
&& !walking_on_water())
2137 you_can("walk on water", from_what(WWALKING
));
2138 /* actively swimming (in water but not under it) handled earlier */
2139 if (Swimming
&& (Underwater
|| !u
.uinwater
))
2140 you_can("swim", from_what(SWIMMING
));
2142 you_can("survive without air", from_what(MAGICAL_BREATHING
));
2143 else if (Amphibious
)
2144 you_can("breathe water", from_what(MAGICAL_BREATHING
));
2146 you_can("walk through walls", from_what(PASSES_WALLS
));
2148 /*** Physical attributes ***/
2150 enl_msg("You regenerate", "", "d", "", from_what(REGENERATION
));
2152 you_have("slower digestion", from_what(SLOW_DIGESTION
));
2154 you_have(enlght_combatinc("to hit", u
.uhitinc
, final
, buf
), "");
2156 you_have(enlght_combatinc("damage", u
.udaminc
, final
, buf
), "");
2157 if (u
.uspellprot
|| Protection
) {
2160 if (uleft
&& uleft
->otyp
== RIN_PROTECTION
)
2162 if (uright
&& uright
->otyp
== RIN_PROTECTION
)
2163 prot
+= uright
->spe
;
2164 if (HProtection
& INTRINSIC
)
2166 prot
+= u
.uspellprot
;
2168 you_have(enlght_combatinc("defense", prot
, final
, buf
), "");
2170 if ((armpro
= magic_negation(&youmonst
)) > 0) {
2171 /* magic cancellation factor, conferred by worn armor */
2172 static const char *const mc_types
[] = {
2173 "" /*ordinary*/, "warded", "guarded", "protected",
2176 if (armpro
>= SIZE(mc_types
))
2177 armpro
= SIZE(mc_types
) - 1;
2178 you_are(mc_types
[armpro
], "");
2180 if (Half_physical_damage
)
2181 enlght_halfdmg(HALF_PHDAM
, final
);
2182 if (Half_spell_damage
)
2183 enlght_halfdmg(HALF_SPDAM
, final
);
2184 /* polymorph and other shape change */
2185 if (Protection_from_shape_changers
)
2186 you_are("protected from shape changers",
2187 from_what(PROT_FROM_SHAPE_CHANGERS
));
2189 const char *what
= 0;
2191 if (!Upolyd
) /* Upolyd handled below after current form */
2192 you_can("not change from your current form",
2193 from_what(UNCHANGING
));
2194 /* blocked shape changes */
2196 what
= !final
? "polymorph" : "have polymorphed";
2197 else if (u
.ulycn
>= LOW_PM
)
2198 what
= !final
? "change shape" : "have changed shape";
2200 Sprintf(buf
, "would %s periodically", what
);
2201 /* omit from_what(UNCHANGING); too verbose */
2202 enl_msg(You_
, buf
, buf
, " if not locked into your current form",
2205 } else if (Polymorph
) {
2206 you_are("polymorphing periodically", from_what(POLYMORPH
));
2208 if (Polymorph_control
)
2209 you_have("polymorph control", from_what(POLYMORPH_CONTROL
));
2210 if (Upolyd
&& u
.umonnum
!= u
.ulycn
) {
2211 /* foreign shape (except were-form which is handled below) */
2212 Sprintf(buf
, "polymorphed into %s", an(youmonst
.data
->mname
));
2214 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2217 if (lays_eggs(youmonst
.data
) && flags
.female
) /* Upolyd */
2218 you_can("lay eggs", "");
2219 if (u
.ulycn
>= LOW_PM
) {
2220 /* "you are a werecreature [in beast form]" */
2221 Strcpy(buf
, an(mons
[u
.ulycn
].mname
));
2222 if (u
.umonnum
== u
.ulycn
) {
2223 Strcat(buf
, " in beast form");
2225 Sprintf(eos(buf
), " (%d)", u
.mtimedone
);
2229 if (Unchanging
&& Upolyd
) /* !Upolyd handled above */
2230 you_can("not change from your current form", from_what(UNCHANGING
));
2232 you_are("harmed by silver", "");
2233 /* movement and non-armor-based protection */
2235 you_are(Very_fast
? "very fast" : "fast", from_what(FAST
));
2237 you_have("reflection", from_what(REFLECTING
));
2239 you_have("free action", from_what(FREE_ACTION
));
2241 you_have("fixed abilities", from_what(FIXED_ABIL
));
2243 enl_msg("Your life ", "will be", "would have been", " saved", "");
2245 /*** Miscellany ***/
2247 ltmp
= abs((int) Luck
);
2248 Sprintf(buf
, "%s%slucky",
2249 ltmp
>= 10 ? "extremely " : ltmp
>= 5 ? "very " : "",
2250 Luck
< 0 ? "un" : "");
2252 Sprintf(eos(buf
), " (%d)", Luck
);
2255 enl_msg("Your luck ", "is", "was", " zero", "");
2257 you_have("extra luck", "");
2258 else if (u
.moreluck
< 0)
2259 you_have("reduced luck", "");
2260 if (carrying(LUCKSTONE
) || stone_luck(TRUE
)) {
2261 ltmp
= stone_luck(0);
2263 enl_msg("Bad luck ", "does", "did", " not time out for you", "");
2265 enl_msg("Good luck ", "does", "did", " not time out for you", "");
2269 Sprintf(buf
, " %sangry with you",
2270 u
.ugangr
> 6 ? "extremely " : u
.ugangr
> 3 ? "very " : "");
2272 Sprintf(eos(buf
), " (%d)", u
.ugangr
);
2273 enl_msg(u_gname(), " is", " was", buf
, "");
2276 * We need to suppress this when the game is over, because death
2277 * can change the value calculated by can_pray(), potentially
2278 * resulting in a false claim that you could have prayed safely.
2282 /* "can [not] safely pray" vs "could [not] have safely prayed" */
2283 Sprintf(buf
, "%s%ssafely pray%s", can_pray(FALSE
) ? "" : "not ",
2284 final
? "have " : "", final
? "ed" : "");
2286 Sprintf(buf
, "%ssafely pray", can_pray(FALSE
) ? "" : "not ");
2289 Sprintf(eos(buf
), " (%d)", u
.ublesscnt
);
2295 /* named fruit debugging (doesn't really belong here...); to enable,
2296 include 'fruit' in DEBUGFILES list (even though it isn't a file...) */
2297 if (wizard
&& explicitdebug("fruit")) {
2302 for (f
= ffruit
; f
; f
= f
->nextf
) {
2303 Sprintf(buf
, "Fruit %d ", ++fcount
);
2304 Sprintf(buf2
, "%s (id %d)", f
->fname
, f
->fid
);
2305 enl_msg(buf
, "is ", "was ", buf2
, "");
2307 enl_msg("The current fruit ", "is ", "was ", pl_fruit
, "");
2308 Sprintf(buf
, "%d", flags
.made_fruit
);
2309 enl_msg("The made fruit flag ", "is ", "was ", buf
, "");
2317 if (final
< 2) { /* still in progress, or quit/escaped/ascended */
2318 p
= "survived after being killed ";
2319 switch (u
.umortality
) {
2321 p
= !final
? (char *) 0 : "survived";
2324 Strcpy(buf
, "once");
2327 Strcpy(buf
, "twice");
2330 Strcpy(buf
, "thrice");
2333 Sprintf(buf
, "%d times", u
.umortality
);
2336 } else { /* game ended in character's death */
2338 switch (u
.umortality
) {
2340 impossible("dead without dying?");
2342 break; /* just "are dead" */
2344 Sprintf(buf
, " (%d%s time!)", u
.umortality
,
2345 ordin(u
.umortality
));
2350 enl_msg(You_
, "have been killed ", p
, buf
, "");
2354 #if 0 /* no longer used */
2355 STATIC_DCL boolean
NDECL(minimal_enlightenment
);
2358 * Courtesy function for non-debug, non-explorer mode players
2359 * to help refresh them about who/what they are.
2360 * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
2363 minimal_enlightenment()
2366 menu_item
*selected
;
2369 char buf
[BUFSZ
], buf2
[BUFSZ
];
2370 static const char untabbed_fmtstr
[] = "%-15s: %-12s";
2371 static const char untabbed_deity_fmtstr
[] = "%-17s%s";
2372 static const char tabbed_fmtstr
[] = "%s:\t%-12s";
2373 static const char tabbed_deity_fmtstr
[] = "%s\t%s";
2374 static const char *fmtstr
;
2375 static const char *deity_fmtstr
;
2377 fmtstr
= iflags
.menu_tab_sep
? tabbed_fmtstr
: untabbed_fmtstr
;
2378 deity_fmtstr
= iflags
.menu_tab_sep
? tabbed_deity_fmtstr
2379 : untabbed_deity_fmtstr
;
2381 buf
[0] = buf2
[0] = '\0';
2382 tmpwin
= create_nhwindow(NHW_MENU
);
2384 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2387 /* Starting name, race, role, gender */
2388 Sprintf(buf
, fmtstr
, "name", plname
);
2389 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2390 Sprintf(buf
, fmtstr
, "race", urace
.noun
);
2391 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2392 Sprintf(buf
, fmtstr
, "role",
2393 (flags
.initgend
&& urole
.name
.f
) ? urole
.name
.f
: urole
.name
.m
);
2394 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2395 Sprintf(buf
, fmtstr
, "gender", genders
[flags
.initgend
].adj
);
2396 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2398 /* Starting alignment */
2399 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualignbase
[A_ORIGINAL
]));
2400 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2402 /* Current name, race, role, gender */
2403 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2404 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2406 Sprintf(buf
, fmtstr
, "race", Upolyd
? youmonst
.data
->mname
: urace
.noun
);
2407 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2409 Sprintf(buf
, fmtstr
, "role (base)",
2410 (u
.mfemale
&& urole
.name
.f
) ? urole
.name
.f
2412 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2414 Sprintf(buf
, fmtstr
, "role",
2415 (flags
.female
&& urole
.name
.f
) ? urole
.name
.f
2417 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2419 /* don't want poly_gender() here; it forces `2' for non-humanoids */
2420 genidx
= is_neuter(youmonst
.data
) ? 2 : flags
.female
;
2421 Sprintf(buf
, fmtstr
, "gender", genders
[genidx
].adj
);
2422 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2423 if (Upolyd
&& (int) u
.mfemale
!= genidx
) {
2424 Sprintf(buf
, fmtstr
, "gender (base)", genders
[u
.mfemale
].adj
);
2425 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2428 /* Current alignment */
2429 Sprintf(buf
, fmtstr
, "alignment", align_str(u
.ualign
.type
));
2430 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2433 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", FALSE
);
2434 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2436 Sprintf(buf2
, deity_fmtstr
, align_gname(A_CHAOTIC
),
2437 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2438 && u
.ualign
.type
== A_CHAOTIC
) ? " (s,c)"
2439 : (u
.ualignbase
[A_ORIGINAL
] == A_CHAOTIC
) ? " (s)"
2440 : (u
.ualign
.type
== A_CHAOTIC
) ? " (c)" : "");
2441 Sprintf(buf
, fmtstr
, "Chaotic", buf2
);
2442 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2444 Sprintf(buf2
, deity_fmtstr
, align_gname(A_NEUTRAL
),
2445 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2446 && u
.ualign
.type
== A_NEUTRAL
) ? " (s,c)"
2447 : (u
.ualignbase
[A_ORIGINAL
] == A_NEUTRAL
) ? " (s)"
2448 : (u
.ualign
.type
== A_NEUTRAL
) ? " (c)" : "");
2449 Sprintf(buf
, fmtstr
, "Neutral", buf2
);
2450 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2452 Sprintf(buf2
, deity_fmtstr
, align_gname(A_LAWFUL
),
2453 (u
.ualignbase
[A_ORIGINAL
] == u
.ualign
.type
2454 && u
.ualign
.type
== A_LAWFUL
) ? " (s,c)"
2455 : (u
.ualignbase
[A_ORIGINAL
] == A_LAWFUL
) ? " (s)"
2456 : (u
.ualign
.type
== A_LAWFUL
) ? " (c)" : "");
2457 Sprintf(buf
, fmtstr
, "Lawful", buf2
);
2458 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, buf
, FALSE
);
2460 end_menu(tmpwin
, "Base Attributes");
2461 n
= select_menu(tmpwin
, PICK_NONE
, &selected
);
2462 destroy_nhwindow(tmpwin
);
2463 return (boolean
) (n
!= -1);
2469 doattributes(VOID_ARGS
)
2471 int mode
= BASICENLIGHTENMENT
;
2473 /* show more--as if final disclosure--for wizard and explore modes */
2474 if (wizard
|| discover
)
2475 mode
|= MAGICENLIGHTENMENT
;
2477 enlightenment(mode
, ENL_GAMEINPROGRESS
);
2482 youhiding(via_enlghtmt
, msgflag
)
2483 boolean via_enlghtmt
; /* englightment line vs topl message */
2484 int msgflag
; /* for variant message phrasing */
2486 char *bp
, buf
[BUFSZ
];
2488 Strcpy(buf
, "hiding");
2489 if (youmonst
.m_ap_type
!= M_AP_NOTHING
) {
2490 /* mimic; hero is only able to mimic a strange object or gold
2491 or hallucinatory alternative to gold, so we skip the details
2492 for the hypothetical furniture and monster cases */
2493 bp
= eos(strcpy(buf
, "mimicking"));
2494 if (youmonst
.m_ap_type
== M_AP_OBJECT
) {
2495 Sprintf(bp
, " %s", an(simple_typename(youmonst
.mappearance
)));
2496 } else if (youmonst
.m_ap_type
== M_AP_FURNITURE
) {
2497 Strcpy(bp
, " something");
2498 } else if (youmonst
.m_ap_type
== M_AP_MONSTER
) {
2499 Strcpy(bp
, " someone");
2501 ; /* something unexpected; leave 'buf' as-is */
2503 } else if (u
.uundetected
) {
2504 bp
= eos(buf
); /* points past "hiding" */
2505 if (youmonst
.data
->mlet
== S_EEL
) {
2506 if (is_pool(u
.ux
, u
.uy
))
2507 Sprintf(bp
, " in the %s", waterbody_name(u
.ux
, u
.uy
));
2508 } else if (hides_under(youmonst
.data
)) {
2509 struct obj
*o
= level
.objects
[u
.ux
][u
.uy
];
2512 Sprintf(bp
, " underneath %s", ansimpleoname(o
));
2513 } else if (is_clinger(youmonst
.data
) || Flying
) {
2514 /* Flying: 'lurker above' hides on ceiling but doesn't cling */
2515 Sprintf(bp
, " on the %s", ceiling(u
.ux
, u
.uy
));
2517 /* on floor; is_hider() but otherwise not special: 'trapper' */
2518 if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
2519 struct trap
*t
= t_at(u
.ux
, u
.uy
);
2521 Sprintf(bp
, " in a %spit",
2522 (t
&& t
->ttyp
== SPIKED_PIT
) ? "spiked " : "");
2524 Sprintf(bp
, " on the %s", surface(u
.ux
, u
.uy
));
2527 ; /* shouldn't happen; will result in generic "you are hiding" */
2531 int final
= msgflag
; /* 'final' is used by you_are() macro */
2535 /* for dohide(), when player uses '#monster' command */
2536 You("are %s %s.", msgflag
? "already" : "now", buf
);
2541 * (shares enlightenment's tense handling)
2544 doconduct(VOID_ARGS
)
2557 /* Create the conduct window */
2558 en_win
= create_nhwindow(NHW_MENU
);
2559 putstr(en_win
, 0, "Voluntary challenges:");
2561 if (u
.uroleplay
.blind
)
2562 you_have_been("blind from birth");
2563 if (u
.uroleplay
.nudist
)
2564 you_have_been("faithfully nudist");
2566 if (!u
.uconduct
.food
)
2567 enl_msg(You_
, "have gone", "went", " without food", "");
2568 /* But beverages are okay */
2569 else if (!u
.uconduct
.unvegan
)
2570 you_have_X("followed a strict vegan diet");
2571 else if (!u
.uconduct
.unvegetarian
)
2572 you_have_been("vegetarian");
2574 if (!u
.uconduct
.gnostic
)
2575 you_have_been("an atheist");
2577 if (!u
.uconduct
.weaphit
) {
2578 you_have_never("hit with a wielded weapon");
2579 } else if (wizard
) {
2580 Sprintf(buf
, "used a wielded weapon %ld time%s", u
.uconduct
.weaphit
,
2581 plur(u
.uconduct
.weaphit
));
2584 if (!u
.uconduct
.killer
)
2585 you_have_been("a pacifist");
2587 if (!u
.uconduct
.literate
) {
2588 you_have_been("illiterate");
2589 } else if (wizard
) {
2590 Sprintf(buf
, "read items or engraved %ld time%s", u
.uconduct
.literate
,
2591 plur(u
.uconduct
.literate
));
2595 ngenocided
= num_genocides();
2596 if (ngenocided
== 0) {
2597 you_have_never("genocided any monsters");
2599 Sprintf(buf
, "genocided %d type%s of monster%s", ngenocided
,
2600 plur(ngenocided
), plur(ngenocided
));
2604 if (!u
.uconduct
.polypiles
) {
2605 you_have_never("polymorphed an object");
2606 } else if (wizard
) {
2607 Sprintf(buf
, "polymorphed %ld item%s", u
.uconduct
.polypiles
,
2608 plur(u
.uconduct
.polypiles
));
2612 if (!u
.uconduct
.polyselfs
) {
2613 you_have_never("changed form");
2614 } else if (wizard
) {
2615 Sprintf(buf
, "changed form %ld time%s", u
.uconduct
.polyselfs
,
2616 plur(u
.uconduct
.polyselfs
));
2620 if (!u
.uconduct
.wishes
) {
2621 you_have_X("used no wishes");
2623 Sprintf(buf
, "used %ld wish%s", u
.uconduct
.wishes
,
2624 (u
.uconduct
.wishes
> 1L) ? "es" : "");
2627 if (!u
.uconduct
.wisharti
)
2628 enl_msg(You_
, "have not wished", "did not wish",
2629 " for any artifacts", "");
2632 /* Pop up the window and wait for a key */
2633 display_nhwindow(en_win
, TRUE
);
2634 destroy_nhwindow(en_win
);
2640 #define M(c) (0x80 | (c))
2642 #define M(c) ((c) -128)
2646 #define C(c) (0x1f & (c))
2649 static const struct func_tab cmdlist
[] = {
2650 { C('d'), FALSE
, dokick
}, /* "D" is for door!...? Msg is in dokick.c */
2651 { C('e'), TRUE
, wiz_detect
},
2652 { C('f'), TRUE
, wiz_map
},
2653 { C('g'), TRUE
, wiz_genesis
},
2654 { C('i'), TRUE
, wiz_identify
},
2655 { C('l'), TRUE
, doredraw
}, /* if number_pad is set */
2656 { C('n'), TRUE
, donamelevel
}, /* if number_pad is set */
2657 { C('o'), TRUE
, dooverview_or_wiz_where
}, /* depends on wizard status */
2658 { C('p'), TRUE
, doprev_message
},
2659 { C('r'), TRUE
, doredraw
},
2660 { C('t'), TRUE
, dotele
},
2661 { C('v'), TRUE
, wiz_level_tele
},
2662 { C('w'), TRUE
, wiz_wish
},
2663 { C('x'), TRUE
, doattributes
},
2664 { C('z'), TRUE
, dosuspend_core
},
2665 { 'a', FALSE
, doapply
},
2666 { 'A', FALSE
, doddoremarm
},
2667 { M('a'), TRUE
, doorganize
},
2668 { M('A'), TRUE
, donamelevel
}, /* #annotate */
2669 /* 'b', 'B' : go sw */
2670 { 'c', FALSE
, doclose
},
2671 { 'C', TRUE
, docallcmd
},
2672 { M('c'), TRUE
, dotalk
},
2673 { M('C'), TRUE
, doconduct
}, /* #conduct */
2674 { 'd', FALSE
, dodrop
},
2675 { 'D', FALSE
, doddrop
},
2676 { M('d'), FALSE
, dodip
},
2677 { 'e', FALSE
, doeat
},
2678 { 'E', FALSE
, doengrave
},
2679 { M('e'), TRUE
, enhance_weapon_skill
},
2680 { 'f', FALSE
, dofire
},
2681 /* 'F' : fight (one time) */
2682 { M('f'), FALSE
, doforce
},
2683 /* 'g', 'G' : multiple go */
2684 /* 'h', 'H' : go west */
2685 { 'h', TRUE
, dohelp
}, /* if number_pad is set */
2686 { 'i', TRUE
, ddoinv
},
2687 { 'I', TRUE
, dotypeinv
}, /* Robert Viduya */
2688 { M('i'), TRUE
, doinvoke
},
2689 /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
2690 { 'j', FALSE
, dojump
}, /* if number_pad is on */
2691 { M('j'), FALSE
, dojump
},
2692 { 'k', FALSE
, dokick
}, /* if number_pad is on */
2693 { 'l', FALSE
, doloot
}, /* if number_pad is on */
2694 { M('l'), FALSE
, doloot
},
2695 /* 'n' prefixes a count if number_pad is on */
2696 { M('m'), TRUE
, domonability
},
2697 { 'N', TRUE
, docallcmd
}, /* if number_pad is on */
2698 { M('n'), TRUE
, docallcmd
},
2699 { M('N'), TRUE
, docallcmd
},
2700 { 'o', FALSE
, doopen
},
2701 { 'O', TRUE
, doset
},
2702 { M('o'), FALSE
, dosacrifice
},
2703 { M('O'), TRUE
, dooverview
}, /* #overview */
2704 { 'p', FALSE
, dopay
},
2705 { 'P', FALSE
, doputon
},
2706 { M('p'), TRUE
, dopray
},
2707 { 'q', FALSE
, dodrink
},
2708 { 'Q', FALSE
, dowieldquiver
},
2709 { M('q'), TRUE
, done2
},
2710 { 'r', FALSE
, doread
},
2711 { 'R', FALSE
, doremring
},
2712 { M('r'), FALSE
, dorub
},
2713 { M('R'), FALSE
, doride
}, /* #ride */
2714 { 's', TRUE
, dosearch
, "searching" },
2715 { 'S', TRUE
, dosave
},
2716 { M('s'), FALSE
, dosit
},
2717 { 't', FALSE
, dothrow
},
2718 { 'T', FALSE
, dotakeoff
},
2719 { M('t'), TRUE
, doturn
},
2720 { M('T'), FALSE
, dotip
}, /* #tip */
2721 /* 'u', 'U' : go ne */
2722 { 'u', FALSE
, dountrap
}, /* if number_pad is on */
2723 { M('u'), FALSE
, dountrap
},
2724 { 'v', TRUE
, doversion
},
2725 { 'V', TRUE
, dohistory
},
2726 { M('v'), TRUE
, doextversion
},
2727 { 'w', FALSE
, dowield
},
2728 { 'W', FALSE
, dowear
},
2729 { M('w'), FALSE
, dowipe
},
2730 { 'x', FALSE
, doswapweapon
},
2731 { 'X', FALSE
, dotwoweapon
},
2732 /* 'y', 'Y' : go nw */
2733 { 'z', FALSE
, dozap
},
2734 { 'Z', TRUE
, docast
},
2735 { '<', FALSE
, doup
},
2736 { '>', FALSE
, dodown
},
2737 { '/', TRUE
, dowhatis
},
2738 { '&', TRUE
, dowhatdoes
},
2739 { '?', TRUE
, dohelp
},
2740 { M('?'), TRUE
, doextlist
},
2742 { '!', TRUE
, dosh
},
2744 { '.', TRUE
, donull
, "waiting" },
2745 { ' ', TRUE
, donull
, "waiting" },
2746 { ',', FALSE
, dopickup
},
2747 { ':', TRUE
, dolook
},
2748 { ';', TRUE
, doquickwhatis
},
2749 { '^', TRUE
, doidtrap
},
2750 { '\\', TRUE
, dodiscovered
}, /* Robert Viduya */
2751 { '`', TRUE
, doclassdisco
},
2752 { '@', TRUE
, dotogglepickup
},
2753 { M('2'), FALSE
, dotwoweapon
},
2754 { WEAPON_SYM
, TRUE
, doprwep
},
2755 { ARMOR_SYM
, TRUE
, doprarm
},
2756 { RING_SYM
, TRUE
, doprring
},
2757 { AMULET_SYM
, TRUE
, dopramulet
},
2758 { TOOL_SYM
, TRUE
, doprtool
},
2759 { '*', TRUE
, doprinuse
}, /* inventory of all equipment in use */
2760 { GOLD_SYM
, TRUE
, doprgold
},
2761 { SPBOOK_SYM
, TRUE
, dovspell
}, /* Mike Stephenson */
2762 { '#', TRUE
, doextcmd
},
2763 { '_', TRUE
, dotravel
},
2767 struct ext_func_tab extcmdlist
[] = {
2768 { "adjust", "adjust inventory letters", doorganize
, TRUE
},
2769 { "annotate", "name current level", donamelevel
, TRUE
},
2770 { "chat", "talk to someone", dotalk
, TRUE
}, /* converse? */
2771 { "conduct", "list voluntary challenges you have maintained", doconduct
,
2773 { "dip", "dip an object into something", dodip
, FALSE
},
2774 { "enhance", "advance or check weapon and spell skills",
2775 enhance_weapon_skill
, TRUE
},
2776 { "exploremode", "enter explore mode", enter_explore_mode
, TRUE
},
2777 { "force", "force a lock", doforce
, FALSE
},
2778 { "invoke", "invoke an object's powers", doinvoke
, TRUE
},
2779 { "jump", "jump to a location", dojump
, FALSE
},
2780 { "loot", "loot a box on the floor", doloot
, FALSE
},
2781 { "monster", "use a monster's special ability", domonability
, TRUE
},
2782 { "name", "name a monster or an object", docallcmd
, TRUE
},
2783 { "offer", "offer a sacrifice to the gods", dosacrifice
, FALSE
},
2784 { "overview", "show an overview of the dungeon", dooverview
, TRUE
},
2785 { "pray", "pray to the gods for help", dopray
, TRUE
},
2786 { "quit", "exit without saving current game", done2
, TRUE
},
2787 { "ride", "ride (or stop riding) a monster", doride
, FALSE
},
2788 { "rub", "rub a lamp or a stone", dorub
, FALSE
},
2789 { "sit", "sit down", dosit
, FALSE
},
2790 { "terrain", "show map without obstructions", doterrain
, TRUE
},
2791 { "tip", "empty a container", dotip
, FALSE
},
2792 { "turn", "turn undead", doturn
, TRUE
},
2793 { "twoweapon", "toggle two-weapon combat", dotwoweapon
, FALSE
},
2794 { "untrap", "untrap something", dountrap
, FALSE
},
2795 { "version", "list compile time options for this version of NetHack",
2796 doextversion
, TRUE
},
2797 { "wipe", "wipe off your face", dowipe
, FALSE
},
2798 { "?", "get this list of extended commands", doextlist
, TRUE
},
2800 * There must be a blank entry here for every entry in the table
2803 { (char *) 0, (char *) 0, donull
, TRUE
}, /* levelchange */
2804 { (char *) 0, (char *) 0, donull
, TRUE
}, /* lightsources */
2805 #ifdef DEBUG_MIGRATING_MONS
2806 { (char *) 0, (char *) 0, donull
, TRUE
}, /* migratemons */
2808 { (char *) 0, (char *) 0, donull
, TRUE
}, /* monpolycontrol */
2809 { (char *) 0, (char *) 0, donull
, TRUE
}, /* panic */
2810 { (char *) 0, (char *) 0, donull
, TRUE
}, /* polyself */
2812 { (char *) 0, (char *) 0, donull
, TRUE
}, /* portdebug */
2814 { (char *) 0, (char *) 0, donull
, TRUE
}, /* seenv */
2815 { (char *) 0, (char *) 0, donull
, TRUE
}, /* stats */
2816 { (char *) 0, (char *) 0, donull
, TRUE
}, /* timeout */
2817 { (char *) 0, (char *) 0, donull
, TRUE
}, /* vanquished */
2818 { (char *) 0, (char *) 0, donull
, TRUE
}, /* vision */
2819 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wizsmell */
2820 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wizintrinsic */
2822 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wizdebug_traveldisplay */
2823 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wizdebug_bury */
2825 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wizrumorcheck */
2826 { (char *) 0, (char *) 0, donull
, TRUE
}, /* wmode */
2827 { (char *) 0, (char *) 0, donull
, TRUE
} /* sentinel */
2830 /* there must be a placeholder in the table above for every entry here */
2831 static const struct ext_func_tab debug_extcmdlist
[] = {
2832 { "levelchange", "change experience level", wiz_level_change
, TRUE
},
2833 { "lightsources", "show mobile light sources", wiz_light_sources
, TRUE
},
2834 #ifdef DEBUG_MIGRATING_MONS
2835 { "migratemons", "migrate n random monsters", wiz_migrate_mons
, TRUE
},
2837 { "monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol
,
2839 { "panic", "test panic routine (fatal to game)", wiz_panic
, TRUE
},
2840 { "polyself", "polymorph self", wiz_polyself
, TRUE
},
2842 { "portdebug", "wizard port debug command", wiz_port_debug
, TRUE
},
2844 { "seenv", "show seen vectors", wiz_show_seenv
, TRUE
},
2845 { "stats", "show memory statistics", wiz_show_stats
, TRUE
},
2846 { "timeout", "look at timeout queue", wiz_timeout_queue
, TRUE
},
2847 { "vanquished", "list vanquished monsters", dovanquished
, TRUE
},
2848 { "vision", "show vision array", wiz_show_vision
, TRUE
},
2849 { "wizsmell", "smell monster", wiz_smell
, TRUE
},
2850 { "wizintrinsic", "set intrinsic", wiz_intrinsic
, TRUE
},
2852 { "wizdebug_traveldisplay", "wizard debug: toggle travel display",
2853 wiz_debug_cmd_traveldisplay
, TRUE
},
2854 { "wizdebug_bury", "wizard debug: bury objs under and around you",
2855 wiz_debug_cmd_bury
, TRUE
},
2857 { "wizrumorcheck", "verify rumor boundaries", wiz_rumor_check
, TRUE
},
2858 { "wmode", "show wall modes", wiz_show_wmodes
, TRUE
},
2859 { (char *) 0, (char *) 0, donull
, TRUE
}
2863 * Insert debug commands into the extended command list. This function
2864 * assumes that the last entry will be the help entry.
2866 * You must add entries in ext_func_tab every time you add one to the
2867 * debug_extcmdlist().
2870 add_debug_extended_commands()
2874 /* count the # of help entries */
2875 for (n
= 0; extcmdlist
[n
].ef_txt
[0] != '?'; n
++)
2878 for (i
= 0; debug_extcmdlist
[i
].ef_txt
; i
++) {
2879 /* need enough room for "?" entry plus terminator */
2880 if (n
+ 2 >= SIZE(extcmdlist
))
2881 panic("Too many debugging commands!");
2882 for (j
= 0; j
< n
; j
++)
2883 if (strcmp(debug_extcmdlist
[i
].ef_txt
, extcmdlist
[j
].ef_txt
) < 0)
2886 /* insert i'th debug entry into extcmdlist[j], pushing down */
2887 for (k
= n
; k
>= j
; --k
)
2888 extcmdlist
[k
+ 1] = extcmdlist
[k
];
2889 extcmdlist
[j
] = debug_extcmdlist
[i
];
2890 n
++; /* now an extra entry */
2899 for (i
= 0; i
< SIZE(cmdlist
); ++i
)
2900 if (cmdlist
[i
].f_funct
== fn
)
2901 return cmdlist
[i
].f_char
;
2905 static const char template[] = "%-18s %4ld %6ld";
2906 static const char count_str
[] = " count bytes";
2907 static const char separator
[] = "------------------ ----- ------";
2913 int sz
= (int) sizeof(struct obj
);
2916 sz
+= (int) sizeof(struct oextra
);
2918 sz
+= (int) strlen(ONAME(otmp
)) + 1;
2920 sz
+= (int) sizeof(struct monst
);
2922 sz
+= (int) sizeof(unsigned);
2924 sz
+= (int) sizeof(long);
2926 sz
+= (int) strlen(OMAILCMD(otmp
)) + 1;
2932 count_obj(chain
, total_count
, total_size
, top
, recurse
)
2942 for (count
= size
= 0, obj
= chain
; obj
; obj
= obj
->nobj
) {
2945 size
+= size_obj(obj
);
2947 if (recurse
&& obj
->cobj
)
2948 count_obj(obj
->cobj
, total_count
, total_size
, TRUE
, TRUE
);
2950 *total_count
+= count
;
2951 *total_size
+= size
;
2955 obj_chain(win
, src
, chain
, total_count
, total_size
)
2963 long count
= 0, size
= 0;
2965 count_obj(chain
, &count
, &size
, TRUE
, FALSE
);
2966 *total_count
+= count
;
2967 *total_size
+= size
;
2968 Sprintf(buf
, template, src
, count
, size
);
2969 putstr(win
, 0, buf
);
2973 mon_invent_chain(win
, src
, chain
, total_count
, total_size
)
2976 struct monst
*chain
;
2981 long count
= 0, size
= 0;
2984 for (mon
= chain
; mon
; mon
= mon
->nmon
)
2985 count_obj(mon
->minvent
, &count
, &size
, TRUE
, FALSE
);
2986 *total_count
+= count
;
2987 *total_size
+= size
;
2988 Sprintf(buf
, template, src
, count
, size
);
2989 putstr(win
, 0, buf
);
2993 contained(win
, src
, total_count
, total_size
)
3000 long count
= 0, size
= 0;
3003 count_obj(invent
, &count
, &size
, FALSE
, TRUE
);
3004 count_obj(fobj
, &count
, &size
, FALSE
, TRUE
);
3005 count_obj(level
.buriedobjlist
, &count
, &size
, FALSE
, TRUE
);
3006 count_obj(migrating_objs
, &count
, &size
, FALSE
, TRUE
);
3007 /* DEADMONSTER check not required in this loop since they have no
3009 for (mon
= fmon
; mon
; mon
= mon
->nmon
)
3010 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3011 for (mon
= migrating_mons
; mon
; mon
= mon
->nmon
)
3012 count_obj(mon
->minvent
, &count
, &size
, FALSE
, TRUE
);
3014 *total_count
+= count
;
3015 *total_size
+= size
;
3017 Sprintf(buf
, template, src
, count
, size
);
3018 putstr(win
, 0, buf
);
3025 int sz
= (int) sizeof(struct monst
);
3028 sz
+= (int) sizeof(struct mextra
);
3030 sz
+= (int) strlen(MNAME(mtmp
)) + 1;
3032 sz
+= (int) sizeof(struct egd
);
3034 sz
+= (int) sizeof(struct epri
);
3036 sz
+= (int) sizeof(struct eshk
);
3038 sz
+= (int) sizeof(struct emin
);
3040 sz
+= (int) sizeof(struct edog
);
3041 /* mextra->mcorpsenm doesn't point to more memory */
3047 mon_chain(win
, src
, chain
, total_count
, total_size
)
3050 struct monst
*chain
;
3058 for (count
= size
= 0, mon
= chain
; mon
; mon
= mon
->nmon
) {
3060 size
+= size_monst(mon
);
3062 *total_count
+= count
;
3063 *total_size
+= size
;
3064 Sprintf(buf
, template, src
, count
, size
);
3065 putstr(win
, 0, buf
);
3069 * Display memory usage of all monsters and objects on the level.
3076 long total_obj_size
= 0, total_obj_count
= 0;
3077 long total_mon_size
= 0, total_mon_count
= 0;
3079 win
= create_nhwindow(NHW_TEXT
);
3080 putstr(win
, 0, "Current memory statistics:");
3082 Sprintf(buf
, "Objects, size %d", (int) sizeof(struct obj
));
3083 putstr(win
, 0, buf
);
3085 putstr(win
, 0, count_str
);
3087 obj_chain(win
, "invent", invent
, &total_obj_count
, &total_obj_size
);
3088 obj_chain(win
, "fobj", fobj
, &total_obj_count
, &total_obj_size
);
3089 obj_chain(win
, "buried", level
.buriedobjlist
, &total_obj_count
,
3091 obj_chain(win
, "migrating obj", migrating_objs
, &total_obj_count
,
3093 mon_invent_chain(win
, "minvent", fmon
, &total_obj_count
, &total_obj_size
);
3094 mon_invent_chain(win
, "migrating minvent", migrating_mons
,
3095 &total_obj_count
, &total_obj_size
);
3097 contained(win
, "contained", &total_obj_count
, &total_obj_size
);
3099 putstr(win
, 0, separator
);
3100 Sprintf(buf
, template, "Total", total_obj_count
, total_obj_size
);
3101 putstr(win
, 0, buf
);
3105 Sprintf(buf
, "Monsters, size %d", (int) sizeof(struct monst
));
3106 putstr(win
, 0, buf
);
3109 mon_chain(win
, "fmon", fmon
, &total_mon_count
, &total_mon_size
);
3110 mon_chain(win
, "migrating", migrating_mons
, &total_mon_count
,
3113 putstr(win
, 0, separator
);
3114 Sprintf(buf
, template, "Total", total_mon_count
, total_mon_size
);
3115 putstr(win
, 0, buf
);
3117 #if defined(__BORLANDC__) && !defined(_WIN32)
3118 show_borlandc_stats(win
);
3121 display_nhwindow(win
, FALSE
);
3122 destroy_nhwindow(win
);
3130 timer_sanity_check();
3132 light_sources_sanity_check();
3135 #ifdef DEBUG_MIGRATING_MONS
3141 struct permonst
*ptr
;
3145 getlin("How many random monsters to migrate? [0]", inbuf
);
3146 if (*inbuf
== '\033')
3148 mcount
= atoi(inbuf
);
3149 if (mcount
< 0 || mcount
> (COLNO
* ROWNO
) || Is_botlevel(&u
.uz
))
3151 while (mcount
> 0) {
3152 if (Is_stronghold(&u
.uz
))
3153 assign_level(&tolevel
, &valley_level
);
3155 get_level(&tolevel
, depth(&u
.uz
) + 1);
3157 mtmp
= makemon(ptr
, 0, 0, NO_MM_FLAGS
);
3159 migrate_to_level(mtmp
, ledger_no(&tolevel
), MIGR_RANDOM
,
3167 #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
3168 #define unmeta(c) (0x7f & (c))
3170 /* called at startup and after number_pad is twiddled */
3172 reset_commands(initial
)
3175 static const char sdir
[] = "hykulnjb><",
3176 sdir_swap_yz
[] = "hzkulnjb><",
3177 ndir
[] = "47896321><",
3178 ndir_phone_layout
[] = "41236987><";
3179 static const int ylist
[] = {
3180 'y', 'Y', C('y'), M('y'), M('Y'), M(C('y'))
3182 const struct func_tab
*cmdtmp
;
3184 int c
, i
, updated
= 0;
3188 for (i
= 0; i
< SIZE(cmdlist
); i
++) {
3189 c
= cmdlist
[i
].f_char
& 0xff;
3190 Cmd
.commands
[c
] = &cmdlist
[i
];
3192 Cmd
.num_pad
= FALSE
;
3193 Cmd
.pcHack_compat
= Cmd
.phone_layout
= Cmd
.swap_yz
= FALSE
;
3196 flagtemp
= iflags
.num_pad
;
3197 if (flagtemp
!= Cmd
.num_pad
) {
3198 Cmd
.num_pad
= flagtemp
;
3201 /* swap_yz mode (only applicable for !num_pad) */
3202 flagtemp
= (iflags
.num_pad_mode
& 1) ? !Cmd
.num_pad
: FALSE
;
3203 if (flagtemp
!= Cmd
.swap_yz
) {
3204 Cmd
.swap_yz
= flagtemp
;
3206 /* Cmd.swap_yz has been toggled;
3207 perform the swap (or reverse previous one) */
3208 for (i
= 0; i
< SIZE(ylist
); i
++) {
3209 c
= ylist
[i
] & 0xff;
3210 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [y] */
3211 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 1]; /* [y] = [z] */
3212 Cmd
.commands
[c
+ 1] = cmdtmp
; /* [z] = tmp */
3215 /* MSDOS compatibility mode (only applicable for num_pad) */
3216 flagtemp
= (iflags
.num_pad_mode
& 1) ? Cmd
.num_pad
: FALSE
;
3217 if (flagtemp
!= Cmd
.pcHack_compat
) {
3218 Cmd
.pcHack_compat
= flagtemp
;
3220 /* pcHack_compat has been toggled */
3222 cmdtmp
= Cmd
.commands
['5'];
3223 Cmd
.commands
['5'] = Cmd
.commands
[c
];
3224 Cmd
.commands
[c
] = cmdtmp
;
3226 Cmd
.commands
[c
] = Cmd
.pcHack_compat
? Cmd
.commands
['I'] : 0;
3228 /* phone keypad layout (only applicable for num_pad) */
3229 flagtemp
= (iflags
.num_pad_mode
& 2) ? Cmd
.num_pad
: FALSE
;
3230 if (flagtemp
!= Cmd
.phone_layout
) {
3231 Cmd
.phone_layout
= flagtemp
;
3233 /* phone_layout has been toggled */
3234 for (i
= 0; i
< 3; i
++) {
3235 c
= '1' + i
; /* 1,2,3 <-> 7,8,9 */
3236 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [1] */
3237 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [1] = [7] */
3238 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [7] = tmp */
3239 c
= (M('1') & 0xff) + i
; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
3240 cmdtmp
= Cmd
.commands
[c
]; /* tmp = [M-1] */
3241 Cmd
.commands
[c
] = Cmd
.commands
[c
+ 6]; /* [M-1] = [M-7] */
3242 Cmd
.commands
[c
+ 6] = cmdtmp
; /* [M-7] = tmp */
3249 Cmd
.dirchars
= !Cmd
.num_pad
3250 ? (!Cmd
.swap_yz
? sdir
: sdir_swap_yz
)
3251 : (!Cmd
.phone_layout
? ndir
: ndir_phone_layout
);
3252 Cmd
.alphadirchars
= !Cmd
.num_pad
? Cmd
.dirchars
: sdir
;
3254 Cmd
.move_W
= Cmd
.dirchars
[0];
3255 Cmd
.move_NW
= Cmd
.dirchars
[1];
3256 Cmd
.move_N
= Cmd
.dirchars
[2];
3257 Cmd
.move_NE
= Cmd
.dirchars
[3];
3258 Cmd
.move_E
= Cmd
.dirchars
[4];
3259 Cmd
.move_SE
= Cmd
.dirchars
[5];
3260 Cmd
.move_S
= Cmd
.dirchars
[6];
3261 Cmd
.move_SW
= Cmd
.dirchars
[7];
3265 accept_menu_prefix(cmd_func
)
3266 int NDECL((*cmd_func
));
3268 if (cmd_func
== dopickup
|| cmd_func
== dotip
3269 || cmd_func
== doextcmd
|| cmd_func
== doextlist
)
3278 boolean do_walk
, do_rush
, prefix_seen
, bad_command
,
3279 firsttime
= (cmd
== 0);
3281 iflags
.menu_requested
= FALSE
;
3283 if (program_state
.done_hup
)
3290 if (*cmd
== '\033') {
3291 context
.move
= FALSE
;
3294 if (*cmd
== DOAGAIN
&& !in_doagain
&& saveq
[0]) {
3297 rhack((char *) 0); /* read and execute command */
3301 /* Special case of *cmd == ' ' handled better below */
3302 if (!*cmd
|| *cmd
== (char) 0377) {
3304 context
.move
= FALSE
;
3305 return; /* probably we just had an interrupt */
3308 /* handle most movement commands */
3309 do_walk
= do_rush
= prefix_seen
= FALSE
;
3310 context
.travel
= context
.travel1
= 0;
3313 if (movecmd(cmd
[1])) {
3321 break; /* else FALLTHRU */
3323 if (movecmd(lowc(cmd
[1]))) {
3331 break; /* else FALLTHRU */
3332 /* Effects of movement commands and invisible monsters:
3333 * m: always move onto space (even if 'I' remembered)
3334 * F: always attack space (even if 'I' not remembered)
3335 * normal movement: attack if 'I', move otherwise.
3338 if (movecmd(cmd
[1])) {
3339 context
.forcefight
= 1;
3345 if (movecmd(cmd
[1]) || u
.dz
) {
3351 cmd
[0] = cmd
[1]; /* "m<" or "m>" */
3356 if (movecmd(lowc(cmd
[1]))) {
3366 (void) ddoinv(); /* a convenience borrowed from the PC */
3367 context
.move
= FALSE
;
3371 if (iflags
.clicklook
) {
3372 context
.move
= FALSE
;
3373 do_look(2, &clicklook_cc
);
3377 if (flags
.travelcmd
) {
3379 context
.travel1
= 1;
3387 if (movecmd(*cmd
)) { /* ordinary movement */
3388 context
.run
= 0; /* only matters here if it was 8 */
3390 } else if (movecmd(Cmd
.num_pad
? unmeta(*cmd
) : lowc(*cmd
))) {
3393 } else if (movecmd(unctrl(*cmd
))) {
3400 /* some special prefix handling */
3401 /* overload 'm' prefix to mean "request a menu" */
3402 if (prefix_seen
&& cmd
[0] == 'm') {
3403 /* (for func_tab cast, see below) */
3404 const struct func_tab
*ft
= Cmd
.commands
[cmd
[1] & 0xff];
3405 int NDECL((*func
)) = ft
? ((struct func_tab
*) ft
)->f_funct
: 0;
3407 if (func
&& accept_menu_prefix(func
)) {
3408 iflags
.menu_requested
= TRUE
;
3413 if ((do_walk
|| do_rush
) && !context
.travel
&& !dxdy_moveok()) {
3414 /* trying to move diagonally as a grid bug;
3415 this used to be treated by movecmd() as not being
3416 a movement attempt, but that didn't provide for any
3417 feedback and led to strangeness if the key pressed
3418 ('u' in particular) was overloaded for num_pad use */
3419 You_cant("get there from here...");
3421 context
.nopick
= context
.forcefight
= FALSE
;
3422 context
.move
= context
.mv
= FALSE
;
3431 context
.forcefight
= 0;
3433 } else if (do_rush
) {
3436 multi
= max(COLNO
, ROWNO
);
3437 u
.last_str_turn
= 0;
3442 } else if (prefix_seen
&& cmd
[1] == '\033') { /* <prefix><escape> */
3443 /* don't report "unknown command" for change of heart... */
3444 bad_command
= FALSE
;
3445 } else if (*cmd
== ' ' && !flags
.rest_on_space
) {
3446 bad_command
= TRUE
; /* skip cmdlist[] loop */
3448 /* handle all other commands */
3450 register const struct func_tab
*tlist
;
3451 int res
, NDECL((*func
));
3453 /* current - use *cmd to directly index cmdlist array */
3454 if ((tlist
= Cmd
.commands
[*cmd
& 0xff]) != 0) {
3455 if (u
.uburied
&& !tlist
->can_if_buried
) {
3456 You_cant("do that while you are buried!");
3459 /* we discard 'const' because some compilers seem to have
3460 trouble with the pointer passed to set_occupation() */
3461 func
= ((struct func_tab
*) tlist
)->f_funct
;
3462 if (tlist
->f_text
&& !occupation
&& multi
)
3463 set_occupation(func
, tlist
->f_text
, multi
);
3464 res
= (*func
)(); /* perform the command */
3467 context
.move
= FALSE
;
3472 /* if we reach here, cmd wasn't found in cmdlist[] */
3477 char expcmd
[20]; /* we expect 'cmd' to point to 1 or 2 chars */
3481 while ((c
= *cmd
++) != '\0')
3482 Strcat(expcmd
, visctrl(c
)); /* add 1..4 chars plus terminator */
3484 if (!prefix_seen
|| !iflags
.cmdassist
3485 || !help_dir(0, "Invalid direction key!"))
3486 Norep("Unknown command '%s'.", expcmd
);
3489 context
.move
= FALSE
;
3494 /* convert an x,y pair into a direction code */
3501 for (dd
= 0; dd
< 8; dd
++)
3502 if (x
== xdir
[dd
] && y
== ydir
[dd
])
3507 /* convert a direction code into an x,y pair */
3518 /* also sets u.dz, but returns false for <> */
3523 register const char *dp
= index(Cmd
.dirchars
, sym
);
3528 u
.dx
= xdir
[dp
- Cmd
.dirchars
];
3529 u
.dy
= ydir
[dp
- Cmd
.dirchars
];
3530 u
.dz
= zdir
[dp
- Cmd
.dirchars
];
3531 #if 0 /* now handled elsewhere */
3532 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
)) {
3540 /* grid bug handling which used to be in movecmd() */
3544 if (u
.dx
&& u
.dy
&& NODIAG(u
.umonnum
))
3546 return u
.dx
|| u
.dy
;
3549 /* decide whether a character (user input keystroke) requests screen repaint */
3554 return (boolean
) (c
== C('r') || (Cmd
.num_pad
&& c
== C('l')));
3558 * uses getdir() but unlike getdir() it specifically
3559 * produces coordinates using the direction from getdir()
3560 * and verifies that those coordinates are ok.
3562 * If the call to getdir() returns 0, Never_mind is displayed.
3563 * If the resulting coordinates are not okay, emsg is displayed.
3565 * Returns non-zero if coordinates in cc are valid.
3568 get_adjacent_loc(prompt
, emsg
, x
, y
, cc
)
3569 const char *prompt
, *emsg
;
3574 if (!getdir(prompt
)) {
3580 if (cc
&& isok(new_x
, new_y
)) {
3599 if (in_doagain
|| *readchar_queue
)
3600 dirsym
= readchar();
3602 dirsym
= yn_function((s
&& *s
!= '^') ? s
: "In what direction?",
3604 /* remove the prompt string so caller won't have to */
3605 clear_nhwindow(WIN_MESSAGE
);
3607 if (redraw_cmd(dirsym
)) { /* ^R */
3608 docrt(); /* redraw */
3613 if (dirsym
== '.' || dirsym
== 's') {
3614 u
.dx
= u
.dy
= u
.dz
= 0;
3615 } else if (!(is_mov
= movecmd(dirsym
)) && !u
.dz
) {
3616 boolean did_help
= FALSE
, help_requested
;
3618 if (!index(quitchars
, dirsym
)) {
3619 help_requested
= (dirsym
== '?');
3620 if (help_requested
|| iflags
.cmdassist
) {
3621 did_help
= help_dir((s
&& *s
== '^') ? dirsym
: 0,
3622 help_requested
? (const char *) 0
3623 : "Invalid direction key!");
3628 pline("What a strange direction!");
3631 } else if (is_mov
&& !dxdy_moveok()) {
3632 You_cant("orient yourself that direction.");
3635 if (!u
.dz
&& (Stunned
|| (Confusion
&& !rn2(5))))
3647 static const char wiz_only_list
[] = "EFGIOVW";
3648 char buf
[BUFSZ
], buf2
[BUFSZ
], *explain
;
3650 win
= create_nhwindow(NHW_TEXT
);
3654 Sprintf(buf
, "cmdassist: %s", msg
);
3655 putstr(win
, 0, buf
);
3660 ctrl
= (sym
- 'A') + 1;
3661 if ((explain
= dowhatdoes_core(ctrl
, buf2
))
3662 && (!index(wiz_only_list
, sym
) || wizard
)) {
3663 Sprintf(buf
, "Are you trying to use ^%c%s?", sym
,
3664 index(wiz_only_list
, sym
)
3666 : " as specified in the Guidebook");
3667 putstr(win
, 0, buf
);
3669 putstr(win
, 0, explain
);
3671 putstr(win
, 0, "To use that command, you press");
3672 Sprintf(buf
, "the <Ctrl> key, and the <%c> key at the same time.",
3674 putstr(win
, 0, buf
);
3678 if (NODIAG(u
.umonnum
)) {
3679 putstr(win
, 0, "Valid direction keys in your current form are:");
3680 Sprintf(buf
, " %c ", Cmd
.move_N
);
3681 putstr(win
, 0, buf
);
3682 putstr(win
, 0, " | ");
3683 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
3684 putstr(win
, 0, buf
);
3685 putstr(win
, 0, " | ");
3686 Sprintf(buf
, " %c ", Cmd
.move_S
);
3687 putstr(win
, 0, buf
);
3689 putstr(win
, 0, "Valid direction keys are:");
3690 Sprintf(buf
, " %c %c %c", Cmd
.move_NW
, Cmd
.move_N
,
3692 putstr(win
, 0, buf
);
3693 putstr(win
, 0, " \\ | / ");
3694 Sprintf(buf
, " %c- . -%c", Cmd
.move_W
, Cmd
.move_E
);
3695 putstr(win
, 0, buf
);
3696 putstr(win
, 0, " / | \\ ");
3697 Sprintf(buf
, " %c %c %c", Cmd
.move_SW
, Cmd
.move_S
,
3699 putstr(win
, 0, buf
);
3702 putstr(win
, 0, " < up");
3703 putstr(win
, 0, " > down");
3704 putstr(win
, 0, " . direct at yourself");
3706 /* non-null msg means that this wasn't an explicit user request */
3709 "(Suppress this message with !cmdassist in config file.)");
3711 display_nhwindow(win
, FALSE
);
3712 destroy_nhwindow(win
);
3719 register int x
= NODIAG(u
.umonnum
) ? 2 * rn2(4) : rn2(8);
3730 static NEARDATA
const char *const dirnames
[] = {
3731 "west", "northwest", "north", "northeast", "east",
3732 "southeast", "south", "southwest", "down", "up",
3735 if (dir
< 0 || dir
>= SIZE(dirnames
))
3737 return dirnames
[dir
];
3744 /* x corresponds to curx, so x==1 is the first column. Ach. %% */
3745 return x
>= 1 && x
<= COLNO
- 1 && y
>= 0 && y
<= ROWNO
- 1;
3748 static NEARDATA
int last_multi
;
3751 * convert a MAP window position into a movecmd
3754 click_to_cmd(x
, y
, mod
)
3761 if (iflags
.clicklook
&& mod
== CLICK_2
) {
3764 cmd
[0] = CMD_CLICKLOOK
;
3771 if (flags
.travelcmd
) {
3772 if (abs(x
) <= 1 && abs(y
) <= 1) {
3773 x
= sgn(x
), y
= sgn(y
);
3777 cmd
[0] = CMD_TRAVEL
;
3781 if (x
== 0 && y
== 0) {
3783 if (IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)
3784 || IS_SINK(levl
[u
.ux
][u
.uy
].typ
)) {
3785 cmd
[0] = mod
== CLICK_1
? 'q' : M('d');
3787 } else if (IS_THRONE(levl
[u
.ux
][u
.uy
].typ
)) {
3790 } else if ((u
.ux
== xupstair
&& u
.uy
== yupstair
)
3791 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
3793 || (u
.ux
== xupladder
&& u
.uy
== yupladder
)) {
3795 } else if ((u
.ux
== xdnstair
&& u
.uy
== ydnstair
)
3796 || (u
.ux
== sstairs
.sx
&& u
.uy
== sstairs
.sy
3798 || (u
.ux
== xdnladder
&& u
.uy
== ydnladder
)) {
3800 } else if (OBJ_AT(u
.ux
, u
.uy
)) {
3802 Is_container(level
.objects
[u
.ux
][u
.uy
]) ? M('l') : ',';
3805 return "."; /* just rest */
3809 /* directional commands */
3813 if (!m_at(u
.ux
+ x
, u
.uy
+ y
)
3814 && !test_move(u
.ux
, u
.uy
, x
, y
, TEST_MOVE
)) {
3815 cmd
[1] = Cmd
.dirchars
[dir
];
3817 if (IS_DOOR(levl
[u
.ux
+ x
][u
.uy
+ y
].typ
)) {
3818 /* slight assistance to the player: choose kick/open for them
3820 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_LOCKED
) {
3824 if (levl
[u
.ux
+ x
][u
.uy
+ y
].doormask
& D_CLOSED
) {
3829 if (levl
[u
.ux
+ x
][u
.uy
+ y
].typ
<= SCORR
) {
3836 /* convert without using floating point, allowing sloppy clicking */
3839 else if (y
> 2 * abs(x
))
3841 else if (x
< -2 * abs(y
))
3843 else if (y
< -2 * abs(x
))
3846 x
= sgn(x
), y
= sgn(y
);
3848 if (x
== 0 && y
== 0) /* map click on player to "rest" command */
3854 /* move, attack, etc. */
3856 if (mod
== CLICK_1
) {
3857 cmd
[0] = Cmd
.dirchars
[dir
];
3859 cmd
[0] = (Cmd
.num_pad
3860 ? M(Cmd
.dirchars
[dir
])
3861 : (Cmd
.dirchars
[dir
] - 'a' + 'A')); /* run command */
3868 get_count(allowchars
, inkey
, max
, count
)
3877 boolean backspaced
= FALSE
;
3886 cnt
= 10L * cnt
+ (long)(key
- '0');
3887 } else if (key
== '\b') {
3890 } else if (key
== '\033') {
3892 } else if (allowchars
) {
3893 if (ret
= index(allowchars
, key
)) {
3901 if (max
&& (cnt
> max
))
3903 if (cnt
> 9 || backspaced
) {
3904 clear_nhwindow(WIN_MESSAGE
);
3905 if (backspaced
&& !cnt
)
3906 Sprintf(qbuf
, "Count: ");
3908 Sprintf(qbuf
, "Count: %d", cnt
);
3921 #ifdef LINT /* static char in_line[COLNO]; */
3922 char in_line
[COLNO
];
3924 static char in_line
[COLNO
];
3927 boolean prezero
= FALSE
;
3928 boolean backspaced
= FALSE
;
3932 flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
3935 alt_esc
= iflags
.altmeta
; /* readchar() hack */
3937 if (!Cmd
.num_pad
|| (foo
= readchar()) == 'n') {
3938 long tmpmulti
= multi
;
3939 foo
= get_count(NULL
, '\0', LARGEST_INT
, &tmpmulti
);
3940 last_multi
= multi
= tmpmulti
;
3943 alt_esc
= FALSE
; /* readchar() reset */
3946 if (foo
== '\033') { /* esc cancels count (TH) */
3947 clear_nhwindow(WIN_MESSAGE
);
3948 multi
= last_multi
= 0;
3949 } else if (foo
== DOAGAIN
|| in_doagain
) {
3953 savech(0); /* reset input queue */
3961 save_cm
= (char *) 0;
3963 /* in 3.4.3 this was in rhack(), where it was too late to handle M-5 */
3964 if (Cmd
.pcHack_compat
) {
3965 /* This handles very old inconsistent DOS/Windows behaviour
3966 in a different way: earlier, the keyboard handler mapped
3967 these, which caused counts to be strange when entered
3968 from the number pad. Now do not map them until here. */
3986 if (foo
== 'g' || foo
== 'G' || foo
== 'm' || foo
== 'M' || foo
== 'F'
3987 || (Cmd
.num_pad
&& (foo
== '5' || foo
== '-'))) {
3993 clear_nhwindow(WIN_MESSAGE
);
3995 in_line
[0] = '\033';
3999 #ifdef HANGUPHANDLING
4000 /* some very old systems, or descendents of such systems, expect signal
4001 handlers to have return type `int', but they don't actually inspect
4002 the return value so we should be safe using `void' unconditionally */
4005 hangup(sig_unused
) /* called as signal() handler, so sent at least one arg */
4006 int sig_unused UNUSED
;
4008 if (program_state
.exiting
)
4009 program_state
.in_moveloop
= 0;
4012 /* When using SAFERHANGUP, the done_hup flag it tested in rhack
4013 and a couple of other places; actual hangup handling occurs then.
4014 This is 'safer' because it disallows certain cheats and also
4015 protects against losing objects in the process of being thrown,
4016 but also potentially riskier because the disconnected program
4017 must continue running longer before attempting a hangup save. */
4018 program_state
.done_hup
++;
4019 /* defer hangup iff game appears to be in progress */
4020 if (program_state
.in_moveloop
&& program_state
.something_worth_saving
)
4022 #endif /* SAFERHANGUP */
4029 #ifdef NOSAVEONHANGUP
4031 if (flags
.ins_chkpt
&& program_state
.something_worth_saving
)
4032 program_statue
.preserve_locks
= 1; /* keep files for recovery */
4034 program_state
.something_worth_saving
= 0; /* don't save */
4038 if (!program_state
.done_hup
++)
4040 if (program_state
.something_worth_saving
)
4042 if (iflags
.window_inited
)
4043 exit_nhwindows((char *) 0);
4045 terminate(EXIT_SUCCESS
);
4046 /*NOTREACHED*/ /* not necessarily true for vms... */
4049 #endif /* HANGUPHANDLING */
4055 int x
= u
.ux
, y
= u
.uy
, mod
= 0;
4057 if (*readchar_queue
)
4058 sym
= *readchar_queue
++;
4060 sym
= in_doagain
? pgetchar() : nh_poskey(&x
, &y
, &mod
);
4064 register int cnt
= NR_OF_EOFS
;
4066 * Some SYSV systems seem to return EOFs for various reasons
4067 * (?like when one hits break or for interrupted systemcalls?),
4068 * and we must see several before we quit.
4071 clearerr(stdin
); /* omit if clearerr is undefined */
4073 } while (--cnt
&& sym
== EOF
);
4075 #endif /* NR_OF_EOFS */
4078 #ifdef HANGUPHANDLING
4079 hangup(0); /* call end_of_input() or set program_state.done_hup */
4083 } else if (sym
== '\033' && alt_esc
) {
4084 /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' */
4085 sym
= *readchar_queue
? *readchar_queue
++ : pgetchar();
4086 if (sym
== EOF
|| sym
== 0)
4088 else if (sym
!= '\033')
4089 sym
|= 0200; /* force 8th bit on */
4091 } else if (sym
== 0) {
4093 readchar_queue
= click_to_cmd(x
, y
, mod
);
4094 sym
= *readchar_queue
++;
4102 /* Keyboard travel command */
4106 if (!flags
.travelcmd
)
4109 cc
.x
= iflags
.travelcc
.x
;
4110 cc
.y
= iflags
.travelcc
.y
;
4111 if (cc
.x
== -1 && cc
.y
== -1) {
4112 /* No cached destination, start attempt from current position */
4116 pline("Where do you want to travel to?");
4117 if (getpos(&cc
, TRUE
, "the desired destination") < 0) {
4118 /* user pressed ESC */
4121 iflags
.travelcc
.x
= u
.tx
= cc
.x
;
4122 iflags
.travelcc
.y
= u
.ty
= cc
.y
;
4123 cmd
[0] = CMD_TRAVEL
;
4124 readchar_queue
= cmd
;
4129 extern void NDECL(win32con_debug_keystrokes
);
4130 extern void NDECL(win32con_handler_info
);
4139 int num_menu_selections
;
4140 struct menu_selection_struct
{
4143 } menu_selections
[] = {
4145 { "test win32 keystrokes (tty only)", win32con_debug_keystrokes
},
4146 { "show keystroke handler information (tty only)",
4147 win32con_handler_info
},
4149 { (char *) 0, (void NDECL((*) )) 0 } /* array terminator */
4152 num_menu_selections
= SIZE(menu_selections
) - 1;
4153 if (num_menu_selections
> 0) {
4154 menu_item
*pick_list
;
4155 win
= create_nhwindow(NHW_MENU
);
4157 for (k
= 0; k
< num_menu_selections
; ++k
) {
4159 add_menu(win
, NO_GLYPH
, &any
, item
++, 0, ATR_NONE
,
4160 menu_selections
[k
].menutext
, MENU_UNSELECTED
);
4162 end_menu(win
, "Which port debugging feature?");
4163 n
= select_menu(win
, PICK_ONE
, &pick_list
);
4164 destroy_nhwindow(win
);
4166 n
= pick_list
[0].item
.a_int
- 1;
4167 free((genericptr_t
) pick_list
);
4168 /* execute the function */
4169 (*menu_selections
[n
].fn
)();
4172 pline("No port-specific debug capability defined.");
4175 #endif /*PORT_DEBUG*/
4178 * Parameter validator for generic yes/no function to prevent
4179 * the core from sending too long a prompt string to the
4180 * window port causing a buffer overflow there.
4183 yn_function(query
, resp
, def
)
4184 const char *query
, *resp
;
4189 iflags
.last_msg
= PLNMSG_UNKNOWN
; /* most recent pline is clobbered */
4191 /* maximum acceptable length is QBUFSZ-1 */
4192 if (strlen(query
) >= QBUFSZ
) {
4193 /* caller shouldn't have passed anything this long */
4194 paniclog("Query truncated: ", query
);
4195 (void) strncpy(qbuf
, query
, QBUFSZ
- 1 - 3);
4196 Strcpy(&qbuf
[QBUFSZ
- 1 - 3], "...");
4199 return (*windowprocs
.win_yn_function
)(query
, resp
, def
);
4202 /* for paranoid_confirm:quit,die,attack prompting */
4204 paranoid_query(be_paranoid
, prompt
)
4205 boolean be_paranoid
;
4208 boolean confirmed_ok
;
4210 /* when paranoid, player must respond with "yes" rather than just 'y'
4211 to give the go-ahead for this query; default is "no" unless the
4212 ParanoidConfirm flag is set in which case there's no default */
4214 char qbuf
[QBUFSZ
], ans
[BUFSZ
];
4215 const char *promptprefix
= "", *responsetype
= ParanoidConfirm
4218 int trylimit
= 6; /* 1 normal, 5 more with "Yes or No:" prefix */
4220 /* in addition to being paranoid about this particular
4221 query, we might be even more paranoid about all paranoia
4222 responses (ie, ParanoidConfirm is set) in which case we
4223 require "no" to reject in addition to "yes" to confirm
4224 (except we won't loop if response is ESC; it means no) */
4226 Sprintf(qbuf
, "%s%s %s", promptprefix
, prompt
, responsetype
);
4228 (void) mungspaces(ans
);
4229 confirmed_ok
= !strcmpi(ans
, "yes");
4230 if (confirmed_ok
|| *ans
== '\033')
4232 promptprefix
= "\"Yes\" or \"No\": ";
4233 } while (ParanoidConfirm
&& strcmpi(ans
, "no") && --trylimit
);
4235 confirmed_ok
= (yn(prompt
) == 'y');
4237 return confirmed_ok
;
4244 /* Does current window system support suspend? */
4245 if ((*windowprocs
.win_can_suspend
)()) {
4246 /* NB: SYSCF SHELLERS handled in port code. */
4250 Norep("Suspend command not available.");