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