1 | /* SCCS Id: @(#)cmd.c 3.3 2000/05/05 */ 2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | #include "hack.h" 6 | #include "func_tab.h" 7 | /* #define DEBUG */ /* uncomment for debugging */ 8 | 9 | /* 10 | * Some systems may have getchar() return EOF for various reasons, and 11 | * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. 12 | */ 13 | #if defined(SYSV) || defined(DGUX) || defined(HPUX) 14 | #define NR_OF_EOFS 20 15 | #endif 16 | 17 | #ifdef DEBUG 18 | /* 19 | * only one "wiz_debug_cmd" routine should be available (in whatever 20 | * module you are trying to debug) or things are going to get rather 21 | * hard to link :-) 22 | */ 23 | extern void NDECL(wiz_debug_cmd); 24 | #endif 25 | 26 | #ifdef DUMB /* stuff commented out in extern.h, but needed here */ 27 | extern int NDECL(doapply); /**/ 28 | extern int NDECL(dorub); /**/ 29 | extern int NDECL(dojump); /**/ 30 | extern int NDECL(doextlist); /**/ 31 | extern int NDECL(dodrop); /**/ 32 | extern int NDECL(doddrop); /**/ 33 | extern int NDECL(dodown); /**/ 34 | extern int NDECL(doup); /**/ 35 | extern int NDECL(donull); /**/ 36 | extern int NDECL(dowipe); /**/ 37 | extern int NDECL(do_mname); /**/ 38 | extern int NDECL(ddocall); /**/ 39 | extern int NDECL(dotakeoff); /**/ 40 | extern int NDECL(doremring); /**/ 41 | extern int NDECL(dowear); /**/ 42 | extern int NDECL(doputon); /**/ 43 | extern int NDECL(doddoremarm); /**/ 44 | extern int NDECL(dokick); /**/ 45 | extern int NDECL(dofire); /**/ 46 | extern int NDECL(dothrow); /**/ 47 | extern int NDECL(doeat); /**/ 48 | extern int NDECL(done2); /**/ 49 | extern int NDECL(doengrave); /**/ 50 | extern int NDECL(dopickup); /**/ 51 | extern int NDECL(ddoinv); /**/ 52 | extern int NDECL(dotypeinv); /**/ 53 | extern int NDECL(dolook); /**/ 54 | extern int NDECL(doprgold); /**/ 55 | extern int NDECL(doprwep); /**/ 56 | extern int NDECL(doprarm); /**/ 57 | extern int NDECL(doprring); /**/ 58 | extern int NDECL(dopramulet); /**/ 59 | extern int NDECL(doprtool); /**/ 60 | extern int NDECL(dosuspend); /**/ 61 | extern int NDECL(doforce); /**/ 62 | extern int NDECL(doopen); /**/ 63 | extern int NDECL(doclose); /**/ 64 | extern int NDECL(dosh); /**/ 65 | extern int NDECL(dodiscovered); /**/ 66 | extern int NDECL(doset); /**/ 67 | extern int NDECL(dotogglepickup); /**/ 68 | extern int NDECL(dowhatis); /**/ 69 | extern int NDECL(doquickwhatis); /**/ 70 | extern int NDECL(dowhatdoes); /**/ 71 | extern int NDECL(dohelp); /**/ 72 | extern int NDECL(dohistory); /**/ 73 | extern int NDECL(doloot); /**/ 74 | extern int NDECL(dodrink); /**/ 75 | extern int NDECL(dodip); /**/ 76 | extern int NDECL(dosacrifice); /**/ 77 | extern int NDECL(dopray); /**/ 78 | extern int NDECL(doturn); /**/ 79 | extern int NDECL(doredraw); /**/ 80 | extern int NDECL(doread); /**/ 81 | extern int NDECL(dosave); /**/ 82 | extern int NDECL(dosearch); /**/ 83 | extern int NDECL(doidtrap); /**/ 84 | extern int NDECL(dopay); /**/ 85 | extern int NDECL(dosit); /**/ 86 | extern int NDECL(dotalk); /**/ 87 | extern int NDECL(docast); /**/ 88 | extern int NDECL(dovspell); /**/ 89 | extern int NDECL(dotele); /**/ 90 | extern int NDECL(dountrap); /**/ 91 | extern int NDECL(doversion); /**/ 92 | extern int NDECL(doextversion); /**/ 93 | extern int NDECL(doswapweapon); /**/ 94 | extern int NDECL(dowield); /**/ 95 | extern int NDECL(dowieldquiver); /**/ 96 | extern int NDECL(dozap); /**/ 97 | extern int NDECL(doorganize); /**/ 98 | #endif /* DUMB */ 99 | 100 | #ifdef OVL1 101 | static int NDECL((*timed_occ_fn)); 102 | #endif /* OVL1 */ 103 | 104 | STATIC_PTR int NDECL(doprev_message); 105 | STATIC_PTR int NDECL(timed_occupation); 106 | STATIC_PTR int NDECL(doextcmd); 107 | STATIC_PTR int NDECL(domonability); 108 | # ifdef WIZARD 109 | STATIC_PTR int NDECL(wiz_wish); 110 | STATIC_PTR int NDECL(wiz_identify); 111 | STATIC_PTR int NDECL(wiz_map); 112 | STATIC_PTR int NDECL(wiz_genesis); 113 | STATIC_PTR int NDECL(wiz_where); 114 | STATIC_PTR int NDECL(wiz_detect); 115 | STATIC_PTR int NDECL(wiz_level_tele); 116 | STATIC_PTR int NDECL(wiz_show_seenv); 117 | STATIC_PTR int NDECL(wiz_show_vision); 118 | STATIC_PTR int NDECL(wiz_show_wmodes); 119 | #ifdef __BORLANDC__ 120 | extern void FDECL(show_borlandc_stats, (winid)); 121 | #endif 122 | STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P)); 123 | STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *)); 124 | STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *)); 125 | STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *)); 126 | STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *)); 127 | STATIC_PTR int NDECL(wiz_show_stats); 128 | # endif 129 | STATIC_PTR int NDECL(enter_explore_mode); 130 | STATIC_PTR int NDECL(doattributes); 131 | STATIC_PTR int NDECL(doconduct); /**/ 132 | STATIC_PTR void NDECL(minimal_enlightenment); 133 | 134 | #ifdef OVLB 135 | STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *)); 136 | #ifdef UNIX 137 | static void NDECL(end_of_input); 138 | #endif 139 | #endif /* OVLB */ 140 | 141 | STATIC_DCL char *NDECL(parse); 142 | 143 | #ifdef OVL1 144 | 145 | STATIC_PTR int 146 | doprev_message() 147 | { 148 | return nh_doprev_message(); 149 | } 150 | 151 | /* Count down by decrementing multi */ 152 | STATIC_PTR int 153 | timed_occupation() 154 | { 155 | (*timed_occ_fn)(); 156 | if (multi > 0) 157 | multi--; 158 | return multi > 0; 159 | } 160 | 161 | /* If you have moved since initially setting some occupations, they 162 | * now shouldn't be able to restart. 163 | * 164 | * The basic rule is that if you are carrying it, you can continue 165 | * since it is with you. If you are acting on something at a distance, 166 | * your orientation to it must have changed when you moved. 167 | * 168 | * The exception to this is taking off items, since they can be taken 169 | * off in a number of ways in the intervening time, screwing up ordering. 170 | * 171 | * Currently: Take off all armor. 172 | * Picking Locks / Forcing Chests. 173 | * Setting traps. 174 | */ 175 | void 176 | reset_occupations() 177 | { 178 | reset_remarm(); 179 | reset_pick(); 180 | reset_trapset(); 181 | } 182 | 183 | /* If a time is given, use it to timeout this function, otherwise the 184 | * function times out by its own means. 185 | */ 186 | void 187 | set_occupation(fn, txt, xtime) 188 | int NDECL((*fn)); 189 | const char *txt; 190 | int xtime; 191 | { 192 | if (xtime) { 193 | occupation = timed_occupation; 194 | timed_occ_fn = fn; 195 | } else 196 | occupation = fn; 197 | occtxt = txt; 198 | occtime = 0; 199 | return; 200 | } 201 | 202 | #ifdef REDO 203 | 204 | static char NDECL(popch); 205 | 206 | /* Provide a means to redo the last command. The flag `in_doagain' is set 207 | * to true while redoing the command. This flag is tested in commands that 208 | * require additional input (like `throw' which requires a thing and a 209 | * direction), and the input prompt is not shown. Also, while in_doagain is 210 | * TRUE, no keystrokes can be saved into the saveq. 211 | */ 212 | #define BSIZE 20 213 | static char pushq[BSIZE], saveq[BSIZE]; 214 | static NEARDATA int phead, ptail, shead, stail; 215 | 216 | static char 217 | popch() { 218 | /* If occupied, return '\0', letting tgetch know a character should 219 | * be read from the keyboard. If the character read is not the 220 | * ABORT character (as checked in pcmain.c), that character will be 221 | * pushed back on the pushq. 222 | */ 223 | if (occupation) return '\0'; 224 | if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0'); 225 | else return(char)((phead != ptail) ? pushq[ptail++] : '\0'); 226 | } 227 | 228 | char 229 | pgetchar() { /* curtesy of aeb@cwi.nl */ 230 | register int ch; 231 | 232 | if(!(ch = popch())) 233 | ch = nhgetch(); 234 | return((char)ch); 235 | } 236 | 237 | /* A ch == 0 resets the pushq */ 238 | void 239 | pushch(ch) 240 | char ch; 241 | { 242 | if (!ch) 243 | phead = ptail = 0; 244 | if (phead < BSIZE) 245 | pushq[phead++] = ch; 246 | return; 247 | } 248 | 249 | /* A ch == 0 resets the saveq. Only save keystrokes when not 250 | * replaying a previous command. 251 | */ 252 | void 253 | savech(ch) 254 | char ch; 255 | { 256 | if (!in_doagain) { 257 | if (!ch) 258 | phead = ptail = shead = stail = 0; 259 | else if (shead < BSIZE) 260 | saveq[shead++] = ch; 261 | } 262 | return; 263 | } 264 | #endif /* REDO */ 265 | 266 | #endif /* OVL1 */ 267 | #ifdef OVLB 268 | 269 | STATIC_PTR int 270 | doextcmd() /* here after # - now read a full-word command */ 271 | { 272 | int idx, retval; 273 | 274 | /* keep repeating until we don't run help or quit */ 275 | do { 276 | idx = get_ext_cmd(); 277 | if (idx < 0) return 0; /* quit */ 278 | 279 | retval = (*extcmdlist[idx].ef_funct)(); 280 | } while (extcmdlist[idx].ef_funct == doextlist); 281 | 282 | return retval; 283 | } 284 | 285 | int 286 | doextlist() /* here after #? - now list all full-word commands */ 287 | { 288 | register const struct ext_func_tab *efp; 289 | char buf[BUFSZ]; 290 | winid datawin; 291 | 292 | datawin = create_nhwindow(NHW_TEXT); 293 | putstr(datawin, 0, ""); 294 | putstr(datawin, 0, " Extended Commands List"); 295 | putstr(datawin, 0, ""); 296 | putstr(datawin, 0, " Press '#', then type:"); 297 | putstr(datawin, 0, ""); 298 | 299 | for(efp = extcmdlist; efp->ef_txt; efp++) { 300 | Sprintf(buf, " %-14s - %s.", efp->ef_txt, efp->ef_desc); 301 | putstr(datawin, 0, buf); 302 | } 303 | display_nhwindow(datawin, FALSE); 304 | destroy_nhwindow(datawin); 305 | return 0; 306 | } 307 | 308 | #ifdef TTY_GRAPHICS 309 | #define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */ 310 | /* 311 | * This is currently used only by the tty port and is 312 | * controlled via runtime option 'extmenu' 313 | */ 314 | int 315 | extcmd_via_menu() /* here after # - now show pick-list of possible commands */ 316 | { 317 | const struct ext_func_tab *efp; 318 | menu_item *pick_list = (menu_item *)0; 319 | winid win; 320 | anything any; 321 | const struct ext_func_tab *choices[MAX_EXT_CMD]; 322 | char buf[BUFSZ]; 323 | char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20]; 324 | int i, n, nchoices, acount; 325 | int ret, biggest; 326 | int accelerator, prevaccelerator; 327 | int matchlevel = 0; 328 | 329 | ret = 0; 330 | cbuf[0] = '\0'; 331 | biggest = 0; 332 | while (!ret) { 333 | i = n = 0; 334 | accelerator = 0; 335 | any.a_void = 0; 336 | /* populate choices */ 337 | for(efp = extcmdlist; efp->ef_txt; efp++) { 338 | if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) { 339 | choices[i++] = efp; 340 | if ((int)strlen(efp->ef_desc) > biggest) { 341 | biggest = strlen(efp->ef_desc); 342 | Sprintf(fmtstr,"%%-%ds", biggest + 15); 343 | } 344 | #ifdef DEBUG 345 | if (i >= MAX_EXT_CMD - 2) { 346 | impossible("Exceeded %d extended commands in doextcmd() menu", 347 | MAX_EXT_CMD - 2); 348 | return 0; 349 | } 350 | #endif 351 | } 352 | } 353 | choices[i] = (struct ext_func_tab *)0; 354 | nchoices = i; 355 | /* if we're down to one, we have our selection so get out of here */ 356 | if (nchoices == 1) { 357 | for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) 358 | if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) { 359 | ret = i; 360 | break; 361 | } 362 | break; 363 | } 364 | 365 | /* otherwise... */ 366 | win = create_nhwindow(NHW_MENU); 367 | start_menu(win); 368 | prevaccelerator = 0; 369 | acount = 0; 370 | for(i = 0; choices[i]; ++i) { 371 | accelerator = choices[i]->ef_txt[matchlevel]; 372 | if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) { 373 | if (acount) { 374 | /* flush the extended commands for that letter already in buf */ 375 | Sprintf(buf, fmtstr, prompt); 376 | any.a_char = prevaccelerator; 377 | add_menu(win, NO_GLYPH, &any, any.a_char, 0, 378 | ATR_NONE, buf, FALSE); 379 | acount = 0; 380 | } 381 | } 382 | prevaccelerator = accelerator; 383 | if (!acount || nchoices < (ROWNO - 3)) { 384 | Sprintf(prompt, "%s [%s]", choices[i]->ef_txt, 385 | choices[i]->ef_desc); 386 | } else if (acount == 1) { 387 | Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt, 388 | choices[i]->ef_txt); 389 | } else { 390 | Strcat(prompt," or "); 391 | Strcat(prompt, choices[i]->ef_txt); 392 | } 393 | ++acount; 394 | } 395 | if (acount) { 396 | /* flush buf */ 397 | Sprintf(buf, fmtstr, prompt); 398 | any.a_char = prevaccelerator; 399 | add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); 400 | } 401 | Sprintf(prompt, "Extended Command: %s", cbuf); 402 | end_menu(win, prompt); 403 | n = select_menu(win, PICK_ONE, &pick_list); 404 | destroy_nhwindow(win); 405 | if (n==1) { 406 | if (matchlevel > (QBUFSZ - 2)) { 407 | free((genericptr_t)pick_list); 408 | #ifdef DEBUG 409 | impossible("Too many characters (%d) entered in extcmd_via_menu()", 410 | matchlevel); 411 | #endif 412 | ret = -1; 413 | } else { 414 | cbuf[matchlevel++] = pick_list[0].item.a_char; 415 | cbuf[matchlevel] = '\0'; 416 | free((genericptr_t)pick_list); 417 | } 418 | } else { 419 | if (matchlevel) { 420 | ret = 0; 421 | matchlevel = 0; 422 | } else 423 | ret = -1; 424 | } 425 | } 426 | return ret; 427 | } 428 | #endif 429 | 430 | STATIC_PTR int 431 | domonability() 432 | { 433 | if (can_breathe(youmonst.data)) return dobreathe(); 434 | else if (attacktype(youmonst.data, AT_SPIT)) return dospit(); 435 | else if (youmonst.data->mlet == S_NYMPH) return doremove(); 436 | else if (youmonst.data->mlet == S_UMBER) return doconfuse(); 437 | else if (is_were(youmonst.data)) return dosummon(); 438 | else if (webmaker(youmonst.data)) return dospinweb(); 439 | else if (is_hider(youmonst.data)) return dohide(); 440 | else if (is_mind_flayer(youmonst.data)) return domindblast(); 441 | else if (u.umonnum == PM_GREMLIN) { 442 | if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { 443 | if (split_mon(&youmonst, (struct monst *)0)) 444 | dryup(u.ux, u.uy, TRUE); 445 | } else There("is no fountain here."); 446 | } else if (is_unicorn(youmonst.data)) { 447 | use_unicorn_horn((struct obj *)0); 448 | return 1; 449 | } else if (youmonst.data->msound == MS_SHRIEK) { 450 | You("shriek."); 451 | if(u.uburied) 452 | pline("Unfortunately sound does not carry well through rock."); 453 | else aggravate(); 454 | } else if (Upolyd) 455 | pline("Any special ability you may have is purely reflexive."); 456 | else You("don't have a special ability in your normal form!"); 457 | return 0; 458 | } 459 | 460 | STATIC_PTR int 461 | enter_explore_mode() 462 | { 463 | if(!discover && !wizard) { 464 | pline("Beware! From explore mode there will be no return to normal game."); 465 | if (yn("Do you want to enter explore mode?") == 'y') { 466 | clear_nhwindow(WIN_MESSAGE); 467 | You("are now in non-scoring explore mode."); 468 | discover = TRUE; 469 | } 470 | else { 471 | clear_nhwindow(WIN_MESSAGE); 472 | pline("Resuming normal game."); 473 | } 474 | } 475 | return 0; 476 | } 477 | 478 | #ifdef WIZARD 479 | STATIC_PTR int 480 | wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */ 481 | { 482 | if (wizard) { 483 | boolean save_verbose = flags.verbose; 484 | 485 | flags.verbose = FALSE; 486 | makewish(); 487 | flags.verbose = save_verbose; 488 | (void) encumber_msg(); 489 | } else 490 | pline("Unavailable command '^W'."); 491 | return 0; 492 | } 493 | 494 | STATIC_PTR int 495 | wiz_identify() 496 | { 497 | if (wizard) identify_pack(0); 498 | else pline("Unavailable command '^I'."); 499 | return 0; 500 | } 501 | 502 | /* reveal the level map and any traps on it */ 503 | STATIC_PTR int 504 | wiz_map() 505 | { 506 | if (wizard) { 507 | struct trap *t; 508 | 509 | for (t = ftrap; t != 0; t = t->ntrap) { 510 | t->tseen = 1; 511 | map_trap(t, TRUE); 512 | } 513 | do_mapping(); 514 | } else 515 | pline("Unavailable command '^F'."); 516 | return 0; 517 | } 518 | 519 | STATIC_PTR int 520 | wiz_genesis() 521 | { 522 | if (wizard) (void) create_particular(); 523 | else pline("Unavailable command '^G'."); 524 | return 0; 525 | } 526 | 527 | STATIC_PTR int 528 | wiz_where() 529 | { 530 | if (wizard) print_dungeon(); 531 | else pline("Unavailable command '^O'."); 532 | return 0; 533 | } 534 | 535 | STATIC_PTR int 536 | wiz_detect() 537 | { 538 | if(wizard) (void) findit(); 539 | else pline("Unavailable command '^E'."); 540 | return 0; 541 | } 542 | 543 | STATIC_PTR int 544 | wiz_level_tele() 545 | { 546 | if (wizard) level_tele(); 547 | else pline("Unavailable command '^V'."); 548 | return 0; 549 | } 550 | 551 | STATIC_PTR int 552 | wiz_show_seenv() 553 | { 554 | winid win; 555 | int x, y, v, startx, stopx, curx; 556 | char row[COLNO+1]; 557 | 558 | win = create_nhwindow(NHW_TEXT); 559 | /* 560 | * Each seenv description takes up 2 characters, so center 561 | * the seenv display around the hero. 562 | */ 563 | startx = max(1, u.ux-(COLNO/4)); 564 | stopx = min(startx+(COLNO/2), COLNO); 565 | /* can't have a line exactly 80 chars long */ 566 | if (stopx - startx == COLNO/2) startx++; 567 | 568 | for (y = 0; y < ROWNO; y++) { 569 | for (x = startx, curx = 0; x < stopx; x++, curx += 2) { 570 | if (x == u.ux && y == u.uy) { 571 | row[curx] = row[curx+1] = '@'; 572 | } else { 573 | v = levl[x][y].seenv & 0xff; 574 | if (v == 0) 575 | row[curx] = row[curx+1] = ' '; 576 | else 577 | Sprintf(&row[curx], "%02x", v); 578 | } 579 | } 580 | /* remove trailing spaces */ 581 | for (x = curx-1; x >= 0; x--) 582 | if (row[x] != ' ') break; 583 | row[x+1] = '\0'; 584 | 585 | putstr(win, 0, row); 586 | } 587 | display_nhwindow(win, TRUE); 588 | destroy_nhwindow(win); 589 | return 0; 590 | } 591 | 592 | STATIC_PTR int 593 | wiz_show_vision() 594 | { 595 | winid win; 596 | int x, y, v; 597 | char row[COLNO+1]; 598 | 599 | win = create_nhwindow(NHW_TEXT); 600 | Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit", 601 | COULD_SEE, IN_SIGHT, TEMP_LIT); 602 | putstr(win, 0, row); 603 | putstr(win, 0, ""); 604 | for (y = 0; y < ROWNO; y++) { 605 | for (x = 1; x < COLNO; x++) { 606 | if (x == u.ux && y == u.uy) 607 | row[x] = '@'; 608 | else { 609 | v = viz_array[y][x]; /* data access should be hidden */ 610 | if (v == 0) 611 | row[x] = ' '; 612 | else 613 | row[x] = '0' + viz_array[y][x]; 614 | } 615 | } 616 | /* remove trailing spaces */ 617 | for (x = COLNO-1; x >= 1; x--) 618 | if (row[x] != ' ') break; 619 | row[x+1] = '\0'; 620 | 621 | putstr(win, 0, &row[1]); 622 | } 623 | display_nhwindow(win, TRUE); 624 | destroy_nhwindow(win); 625 | return 0; 626 | } 627 | 628 | STATIC_PTR int 629 | wiz_show_wmodes() 630 | { 631 | winid win; 632 | int x,y; 633 | char row[COLNO+1]; 634 | struct rm *lev; 635 | 636 | win = create_nhwindow(NHW_TEXT); 637 | for (y = 0; y < ROWNO; y++) { 638 | for (x = 0; x < COLNO; x++) { 639 | lev = &levl[x][y]; 640 | if (x == u.ux && y == u.uy) 641 | row[x] = '@'; 642 | if (IS_WALL(lev->typ) || lev->typ == SDOOR) 643 | row[x] = '0' + (lev->wall_info & WM_MASK); 644 | else if (lev->typ == CORR) 645 | row[x] = '#'; 646 | else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ)) 647 | row[x] = '.'; 648 | else 649 | row[x] = 'x'; 650 | } 651 | row[COLNO] = '\0'; 652 | putstr(win, 0, row); 653 | } 654 | display_nhwindow(win, TRUE); 655 | destroy_nhwindow(win); 656 | return 0; 657 | } 658 | 659 | #endif /* WIZARD */ 660 | 661 | 662 | /* -enlightenment and conduct- */ 663 | static winid en_win; 664 | static const char 665 | *You_ = "You ", 666 | *are = "are ", *were = "were ", 667 | *have = "have ", *had = "had ", 668 | *can = "can ", *could = "could "; 669 | static const char 670 | *have_been = "have been ", 671 | *have_never = "have never ", *never = "never "; 672 | 673 | #define enl_msg(prefix,present,past,suffix) \ 674 | enlght_line(prefix, final ? past : present, suffix) 675 | #define you_are(attr) enl_msg(You_,are,were,attr) 676 | #define you_have(attr) enl_msg(You_,have,had,attr) 677 | #define you_can(attr) enl_msg(You_,can,could,attr) 678 | #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing) 679 | #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing) 680 | #define you_have_X(something) enl_msg(You_,have,(const char *)"",something) 681 | 682 | static void 683 | enlght_line(start, middle, end) 684 | const char *start, *middle, *end; 685 | { 686 | char buf[BUFSZ]; 687 | 688 | Sprintf(buf, "%s%s%s.", start, middle, end); 689 | putstr(en_win, 0, buf); 690 | } 691 | 692 | void 693 | enlightenment(final) 694 | int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */ 695 | { 696 | int ltmp; 697 | char buf[BUFSZ]; 698 | 699 | en_win = create_nhwindow(NHW_MENU); 700 | putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:"); 701 | putstr(en_win, 0, ""); 702 | 703 | #ifdef ELBERETH 704 | if (u.uevent.uhand_of_elbereth) { 705 | static const char *hofe_titles[3] = { 706 | "the Hand of Elbereth", 707 | "the Envoy of Balance", 708 | "the Glory of Arioch" 709 | }; 710 | you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]); 711 | } 712 | #endif 713 | 714 | /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */ 715 | if (u.ualign.record >= 20) you_are("piously aligned"); 716 | else if (u.ualign.record > 13) you_are("devoutly aligned"); 717 | else if (u.ualign.record > 8) you_are("fervently aligned"); 718 | else if (u.ualign.record > 3) you_are("stridently aligned"); 719 | else if (u.ualign.record == 3) you_are("aligned"); 720 | else if (u.ualign.record > 0) you_are("haltingly aligned"); 721 | else if (u.ualign.record == 0) you_are("nominally aligned"); 722 | else if (u.ualign.record >= -3) you_have("strayed"); 723 | else if (u.ualign.record >= -8) you_have("sinned"); 724 | else you_have("transgressed"); 725 | #ifdef WIZARD 726 | if (wizard) { 727 | Sprintf(buf, " %d", u.ualign.record); 728 | enl_msg("Your alignment ", "is", "was", buf); 729 | } 730 | #endif 731 | 732 | /*** Resistances to troubles ***/ 733 | if (Fire_resistance) you_are("fire resistant"); 734 | if (Cold_resistance) you_are("cold resistant"); 735 | if (Sleep_resistance) you_are("sleep resistant"); 736 | if (Disint_resistance) you_are("disintegration-resistant"); 737 | if (Shock_resistance) you_are("shock resistant"); 738 | if (Poison_resistance) you_are("poison resistant"); 739 | if (Drain_resistance) you_are("level-drain resistant"); 740 | if (Sick_resistance) you_are("immune to sickness"); 741 | if (Antimagic) you_are("magic-protected"); 742 | if (Acid_resistance) you_are("acid resistant"); 743 | if (Stone_resistance) 744 | you_are("petrification resistant"); 745 | if (Invulnerable) you_are("invulnerable"); 746 | 747 | /*** Troubles ***/ 748 | if (Halluc_resistance) 749 | enl_msg("You resist", "", "ed", " hallucinations"); 750 | if (final) { 751 | if (Hallucination) you_are("hallucinating"); 752 | if (Stunned) you_are("stunned"); 753 | if (Confusion) you_are("confused"); 754 | if (Blinded) you_are("blinded"); 755 | if (Sick) { 756 | if (u.usick_type & SICK_VOMITABLE) 757 | you_are("sick from food poisoning"); 758 | if (u.usick_type & SICK_NONVOMITABLE) 759 | you_are("sick from illness"); 760 | } 761 | } 762 | if (Stoned) you_are("turning to stone"); 763 | if (Slimed) you_are("turning into slime"); 764 | if (Strangled) you_are((u.uburied) ? "buried" : "being strangled"); 765 | if (Glib) { 766 | Sprintf(buf, "slippery %s", makeplural(body_part(FINGER))); 767 | you_have(buf); 768 | } 769 | if (Fumbling) enl_msg("You fumble", "", "d", ""); 770 | if (Wounded_legs) { 771 | Sprintf(buf, "wounded %s", makeplural(body_part(LEG))); 772 | you_have(buf); 773 | } 774 | if (Sleeping) enl_msg("You ", "fall", "fell", " asleep"); 775 | if (Hunger) enl_msg("You hunger", "", "ed", " rapidly"); 776 | 777 | /*** Vision and senses ***/ 778 | if (See_invisible) enl_msg(You_, "see", "saw", " invisible"); 779 | if (Blind_telepat) you_are("telepathic"); 780 | if (Warning) you_are("warned"); 781 | if (Warn_of_mon && flags.warntype) { 782 | Sprintf(buf, "aware of the presence of %s", 783 | (flags.warntype & M2_ORC) ? "orcs" : 784 | (flags.warntype & M2_DEMON) ? "demons" : 785 | something); 786 | you_are(buf); 787 | } 788 | if (Undead_warning) you_are("warned of undead"); 789 | if (Searching) you_have("automatic searching"); 790 | if (Clairvoyant) you_are("clairvoyant"); 791 | if (Infravision) you_have("infravision"); 792 | if (Detect_monsters) you_are("sensing the presence of monsters"); 793 | 794 | /*** Appearance and behavior ***/ 795 | if (Adornment) you_are("adorned"); 796 | if (Invisible) you_are("invisible"); 797 | else if (Invis) you_are("invisible to others"); 798 | /* ordinarily "visible" is redundant; this is a special case for 799 | the situation when invisibility would be an expected attribute */ 800 | else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis) 801 | you_are("visible"); 802 | if (Displaced) you_are("displaced"); 803 | if (Stealth) you_are("stealthy"); 804 | if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters"); 805 | if (Conflict) enl_msg("You cause", "", "d", " conflict"); 806 | 807 | /*** Transportation ***/ 808 | if (Jumping) you_can("jump"); 809 | if (Teleportation) you_can("teleport"); 810 | if (Teleport_control) you_have("teleport control"); 811 | if (Lev_at_will) you_are("levitating, at will"); 812 | else if (Levitation) you_are("levitating"); /* without control */ 813 | else if (Flying) you_can("fly"); 814 | if (Wwalking) you_can("walk on water"); 815 | if (Swimming) you_can("swim"); 816 | if (Breathless) you_can("survive without air"); 817 | else if (Amphibious) you_can("breathe water"); 818 | if (Passes_walls) you_can("walk through walls"); 819 | #ifdef STEED 820 | if (u.usteed) { 821 | Sprintf(buf, "riding %s", y_monnam(u.usteed)); 822 | you_are(buf); 823 | } 824 | #endif 825 | if (u.uswallow) { 826 | Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck)); 827 | #ifdef WIZARD 828 | if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim); 829 | #endif 830 | you_are(buf); 831 | } else if (u.ustuck) { 832 | Sprintf(buf, "%s %s", 833 | (Upolyd && sticks(youmonst.data)) ? "holding" : "held by", 834 | a_monnam(u.ustuck)); 835 | you_are(buf); 836 | } 837 | 838 | /*** Physical attributes ***/ 839 | if (Slow_digestion) you_have("slower digestion"); 840 | if (Regeneration) enl_msg("You regenerate", "", "d", ""); 841 | if (u.uspellprot || Protection) you_are("protected"); 842 | if (Protection_from_shape_changers) 843 | you_are("protected from shape changers"); 844 | if (Polymorph) you_are("polymorphing"); 845 | if (Polymorph_control) you_have("polymorph control"); 846 | if (u.ulycn >= LOW_PM) { 847 | Strcpy(buf, an(mons[u.ulycn].mname)); 848 | you_are(buf); 849 | } 850 | if (Upolyd) { 851 | if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form"); 852 | else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname)); 853 | #ifdef WIZARD 854 | if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); 855 | #endif 856 | you_are(buf); 857 | } 858 | if (Unchanging) you_can("not change from your current form"); 859 | if (Fast) you_are(Very_fast ? "very fast" : "fast"); 860 | if (Reflecting) you_have("reflection"); 861 | if (Free_action) you_have("free action"); 862 | if (Fixed_abil) you_have("fixed abilities"); 863 | if (Lifesaved) 864 | enl_msg("Your life ", "will be", "would have been", " saved"); 865 | if (u.twoweap) you_are("wielding two weapons at once"); 866 | 867 | /*** Miscellany ***/ 868 | if (Luck) { 869 | ltmp = abs((int)Luck); 870 | Sprintf(buf, "%s%slucky", 871 | ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "", 872 | Luck < 0 ? "un" : ""); 873 | #ifdef WIZARD 874 | if (wizard) Sprintf(eos(buf), " (%d)", Luck); 875 | #endif 876 | you_are(buf); 877 | } 878 | #ifdef WIZARD 879 | else if (wizard) enl_msg("Your luck ", "is", "was", " zero"); 880 | #endif 881 | if (u.moreluck > 0) you_have("extra luck"); 882 | else if (u.moreluck < 0) you_have("reduced luck"); 883 | if (carrying(LUCKSTONE) || stone_luck(TRUE)) { 884 | ltmp = stone_luck(FALSE); 885 | if (ltmp <= 0) 886 | enl_msg("Bad luck ", "does", "did", " not time out for you"); 887 | if (ltmp >= 0) 888 | enl_msg("Good luck ", "does", "did", " not time out for you"); 889 | } 890 | 891 | if (u.ugangr) { 892 | Sprintf(buf, " %sangry with you", 893 | u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : ""); 894 | #ifdef WIZARD 895 | if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr); 896 | #endif 897 | enl_msg(u_gname(), " is", " was", buf); 898 | } else 899 | /* 900 | * We need to suppress this when the game is over, because death 901 | * can change the value calculated by can_pray(), potentially 902 | * resulting in a false claim that you could have prayed safely. 903 | */ 904 | if (!final) { 905 | #if 0 906 | /* "can [not] safely pray" vs "could [not] have safely prayed" */ 907 | Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ", 908 | final ? "have " : "", final ? "ed" : ""); 909 | #else 910 | Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not "); 911 | #endif 912 | #ifdef WIZARD 913 | if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt); 914 | #endif 915 | you_can(buf); 916 | } 917 | 918 | { 919 | const char *p; 920 | 921 | buf[0] = '\0'; 922 | if (final < 2) { /* still in progress, or quit/escaped/ascended */ 923 | p = "survived after being killed "; 924 | switch (u.umortality) { 925 | case 0: p = !final ? (char *)0 : "survived"; break; 926 | case 1: Strcpy(buf, "once"); break; 927 | case 2: Strcpy(buf, "twice"); break; 928 | case 3: Strcpy(buf, "thrice"); break; 929 | default: Sprintf(buf, "%d times", u.umortality); 930 | break; 931 | } 932 | } else { /* game ended in character's death */ 933 | p = "are dead"; 934 | switch (u.umortality) { 935 | case 0: impossible("dead without dying?"); 936 | case 1: break; /* just "are dead" */ 937 | default: Sprintf(buf, " (%d%s time!)", u.umortality, 938 | ordin(u.umortality)); 939 | break; 940 | } 941 | } 942 | if (p) enl_msg(You_, "have been killed ", p, buf); 943 | } 944 | 945 | display_nhwindow(en_win, TRUE); 946 | destroy_nhwindow(en_win); 947 | return; 948 | } 949 | 950 | /* 951 | * Courtesy function for non-debug, non-explorer mode players 952 | * to help refresh them about who/what they are. 953 | */ 954 | STATIC_OVL void 955 | minimal_enlightenment() 956 | { 957 | winid tmpwin; 958 | menu_item *selected; 959 | anything any; 960 | char buf[BUFSZ], buf2[BUFSZ]; 961 | static char fmtstr[] = "%-15s: %-12s"; 962 | 963 | any.a_void = 0; 964 | buf[0] = buf2[0] = '\0'; 965 | tmpwin = create_nhwindow(NHW_MENU); 966 | start_menu(tmpwin); 967 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Starting", FALSE); 968 | 969 | /* Starting name, race, role, gender */ 970 | Sprintf(buf, fmtstr, "name", plname); 971 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 972 | Sprintf(buf, fmtstr, "race", urace.noun); 973 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 974 | Sprintf(buf, fmtstr, "role", 975 | (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m); 976 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 977 | Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj); 978 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 979 | 980 | /* Starting alignment */ 981 | Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL])); 982 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 983 | 984 | /* Current name, race, role, gender */ 985 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); 986 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Current", FALSE); 987 | Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun); 988 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 989 | if (!Upolyd) { 990 | Sprintf(buf, fmtstr, "role", 991 | (flags.female && urole.name.f) ? urole.name.f : urole.name.m); 992 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 993 | } 994 | Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj); 995 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 996 | 997 | if (Upolyd) { 998 | Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); 999 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 1000 | } 1001 | 1002 | /* Current alignment */ 1003 | Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type)); 1004 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 1005 | 1006 | /* Deity list */ 1007 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); 1008 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Deities", FALSE); 1009 | Sprintf(buf2, "%-17s%s", align_gname(A_CHAOTIC), 1010 | (u.ualignbase[A_ORIGINAL] == u.ualign.type 1011 | && u.ualign.type == A_CHAOTIC) ? " (s,c)" : 1012 | (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" : 1013 | (u.ualign.type == A_CHAOTIC) ? " (c)" : ""); 1014 | Sprintf(buf, fmtstr, "chaotic deity", buf2); 1015 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 1016 | 1017 | Sprintf(buf2, "%-17s%s", align_gname(A_NEUTRAL), 1018 | (u.ualignbase[A_ORIGINAL] == u.ualign.type 1019 | && u.ualign.type == A_NEUTRAL) ? " (s,c)" : 1020 | (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" : 1021 | (u.ualign.type == A_NEUTRAL) ? " (c)" : ""); 1022 | Sprintf(buf, fmtstr, "neutral deity", buf2); 1023 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 1024 | 1025 | Sprintf(buf2, "%-17s%s", align_gname(A_LAWFUL), 1026 | (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" : 1027 | (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" : 1028 | (u.ualign.type == A_LAWFUL) ? " (c)" : ""); 1029 | Sprintf(buf, fmtstr, "lawful deity", buf2); 1030 | add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); 1031 | 1032 | end_menu(tmpwin, "Base Attributes"); 1033 | (void) select_menu(tmpwin, PICK_NONE, &selected); 1034 | destroy_nhwindow(tmpwin); 1035 | } 1036 | 1037 | STATIC_PTR int 1038 | doattributes() 1039 | { 1040 | minimal_enlightenment(); 1041 | if (wizard || discover) 1042 | enlightenment(0); 1043 | return 0; 1044 | } 1045 | 1046 | /* KMH, #conduct 1047 | * (shares enlightenment's tense handling) 1048 | */ 1049 | STATIC_PTR int 1050 | doconduct() 1051 | { 1052 | show_conduct(0); 1053 | return 0; 1054 | } 1055 | 1056 | void 1057 | show_conduct(final) 1058 | int final; 1059 | { 1060 | char buf[BUFSZ]; 1061 | int ngenocided; 1062 | 1063 | /* Create the conduct window */ 1064 | en_win = create_nhwindow(NHW_MENU); 1065 | putstr(en_win, 0, "Voluntary challenges:"); 1066 | putstr(en_win, 0, ""); 1067 | 1068 | if (!u.uconduct.food) 1069 | enl_msg(You_, "have gone", "went", " without food"); 1070 | /* But beverages are okay */ 1071 | else if (!u.uconduct.unvegan) 1072 | you_have_X("followed a strict vegan diet"); 1073 | else if (!u.uconduct.unvegetarian) 1074 | you_have_been("vegetarian"); 1075 | 1076 | if (!u.uconduct.gnostic) 1077 | you_have_been("an atheist"); 1078 | 1079 | if (!u.uconduct.weaphit) 1080 | you_have_never("hit with a wielded weapon"); 1081 | #ifdef WIZARD 1082 | else if (wizard) { 1083 | Sprintf(buf, "used a wielded weapon %ld time%s", 1084 | u.uconduct.weaphit, plur(u.uconduct.weaphit)); 1085 | you_have_X(buf); 1086 | } 1087 | #endif 1088 | if (!u.uconduct.killer) 1089 | you_have_been("a pacifist"); 1090 | 1091 | if (!u.uconduct.literate) 1092 | you_have_been("illiterate"); 1093 | #ifdef WIZARD 1094 | else if (wizard) { 1095 | Sprintf(buf, "read items or engraved %ld time%s", 1096 | u.uconduct.literate, plur(u.uconduct.literate)); 1097 | you_have_X(buf); 1098 | } 1099 | #endif 1100 | 1101 | ngenocided = num_genocides(); 1102 | if (ngenocided == 0) { 1103 | you_have_never("genocided any monsters"); 1104 | } else { 1105 | Sprintf(buf, "genocided %d type%s of monster%s", 1106 | ngenocided, plur(ngenocided), plur(ngenocided)); 1107 | you_have_X(buf); 1108 | } 1109 | 1110 | if (!u.uconduct.polypiles) 1111 | you_have_never("polymorphed an object"); 1112 | #ifdef WIZARD 1113 | else if (wizard) { 1114 | Sprintf(buf, "polymorphed %ld item%s", 1115 | u.uconduct.polypiles, plur(u.uconduct.polypiles)); 1116 | you_have_X(buf); 1117 | } 1118 | #endif 1119 | 1120 | if (!u.uconduct.polyselfs) 1121 | you_have_never("changed form"); 1122 | #ifdef WIZARD 1123 | else if (wizard) { 1124 | Sprintf(buf, "changed form %ld time%s", 1125 | u.uconduct.polyselfs, plur(u.uconduct.polyselfs)); 1126 | you_have_X(buf); 1127 | } 1128 | #endif 1129 | 1130 | if (!u.uconduct.wishes) 1131 | you_have_X("used no wishes"); 1132 | else { 1133 | Sprintf(buf, "used %ld wish%s", 1134 | u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : ""); 1135 | you_have_X(buf); 1136 | 1137 | if (!u.uconduct.wisharti) 1138 | enl_msg(You_, "have not wished", "did not wish", 1139 | " for any artifacts"); 1140 | } 1141 | 1142 | /* Pop up the window and wait for a key */ 1143 | display_nhwindow(en_win, TRUE); 1144 | destroy_nhwindow(en_win); 1145 | } 1146 | 1147 | #endif /* OVLB */ 1148 | #ifdef OVL1 1149 | 1150 | #ifndef M 1151 | # ifndef NHSTDC 1152 | # define M(c) (0x80 | (c)) 1153 | # else 1154 | # define M(c) ((c) - 128) 1155 | # endif /* NHSTDC */ 1156 | #endif 1157 | #ifndef C 1158 | #define C(c) (0x1f & (c)) 1159 | #endif 1160 | 1161 | static const struct func_tab cmdlist[] = { 1162 | {C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */ 1163 | #ifdef WIZARD 1164 | {C('e'), TRUE, wiz_detect}, 1165 | {C('f'), TRUE, wiz_map}, 1166 | {C('g'), TRUE, wiz_genesis}, 1167 | {C('i'), TRUE, wiz_identify}, 1168 | #endif 1169 | {C('l'), TRUE, doredraw}, /* if number_pad is set */ 1170 | #ifdef WIZARD 1171 | {C('o'), TRUE, wiz_where}, 1172 | #endif 1173 | {C('p'), TRUE, doprev_message}, 1174 | {C('r'), TRUE, doredraw}, 1175 | {C('t'), TRUE, dotele}, 1176 | #ifdef WIZARD 1177 | {C('v'), TRUE, wiz_level_tele}, 1178 | {C('w'), TRUE, wiz_wish}, 1179 | #endif 1180 | {C('x'), TRUE, doattributes}, 1181 | #ifdef SUSPEND 1182 | {C('z'), TRUE, dosuspend}, 1183 | #endif 1184 | {'a', FALSE, doapply}, 1185 | {'A', FALSE, doddoremarm}, 1186 | {M('a'), TRUE, doorganize}, 1187 | /* 'b', 'B' : go sw */ 1188 | {'c', FALSE, doclose}, 1189 | {'C', TRUE, do_mname}, 1190 | {M('c'), TRUE, dotalk}, 1191 | {'d', FALSE, dodrop}, 1192 | {'D', FALSE, doddrop}, 1193 | {M('d'), FALSE, dodip}, 1194 | {'e', FALSE, doeat}, 1195 | {'E', FALSE, doengrave}, 1196 | {M('e'), TRUE, enhance_weapon_skill}, 1197 | {'f', FALSE, dofire}, 1198 | /* 'F' : fight (one time) */ 1199 | {M('f'), FALSE, doforce}, 1200 | /* 'g', 'G' : multiple go */ 1201 | /* 'h', 'H' : go west */ 1202 | {'h', TRUE, dohelp}, /* if number_pad is set */ 1203 | {'i', TRUE, ddoinv}, 1204 | {'I', TRUE, dotypeinv}, /* Robert Viduya */ 1205 | {M('i'), TRUE, doinvoke}, 1206 | /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */ 1207 | {'j', FALSE, dojump}, /* if number_pad is on */ 1208 | {M('j'), FALSE, dojump}, 1209 | {'k', FALSE, dokick}, /* if number_pad is on */ 1210 | {'l', FALSE, doloot}, /* if number_pad is on */ 1211 | {M('l'), FALSE, doloot}, 1212 | /* 'n' prefixes a count if number_pad is on */ 1213 | {M('m'), TRUE, domonability}, 1214 | {'N', TRUE, ddocall}, /* if number_pad is on */ 1215 | {M('n'), TRUE, ddocall}, 1216 | {M('N'), TRUE, ddocall}, 1217 | {'o', FALSE, doopen}, 1218 | {'O', TRUE, doset}, 1219 | {M('o'), FALSE, dosacrifice}, 1220 | {'p', FALSE, dopay}, 1221 | {'P', FALSE, doputon}, 1222 | {M('p'), TRUE, dopray}, 1223 | {'q', FALSE, dodrink}, 1224 | {'Q', FALSE, dowieldquiver}, 1225 | {M('q'), TRUE, done2}, 1226 | {'r', FALSE, doread}, 1227 | {'R', FALSE, doremring}, 1228 | {M('r'), FALSE, dorub}, 1229 | {'s', TRUE, dosearch, "searching"}, 1230 | {'S', TRUE, dosave}, 1231 | {M('s'), FALSE, dosit}, 1232 | {'t', FALSE, dothrow}, 1233 | {'T', FALSE, dotakeoff}, 1234 | {M('t'), TRUE, doturn}, 1235 | /* 'u', 'U' : go ne */ 1236 | {'u', FALSE, dountrap}, /* if number_pad is on */ 1237 | {M('u'), FALSE, dountrap}, 1238 | {'v', TRUE, doversion}, 1239 | {'V', TRUE, dohistory}, 1240 | {M('v'), TRUE, doextversion}, 1241 | {'w', FALSE, dowield}, 1242 | {'W', FALSE, dowear}, 1243 | {M('w'), FALSE, dowipe}, 1244 | {'x', FALSE, doswapweapon}, 1245 | {'X', TRUE, enter_explore_mode}, 1246 | /* 'y', 'Y' : go nw */ 1247 | {'z', FALSE, dozap}, 1248 | {'Z', TRUE, docast}, 1249 | {'<', FALSE, doup}, 1250 | {'>', FALSE, dodown}, 1251 | {'/', TRUE, dowhatis}, 1252 | {'&', TRUE, dowhatdoes}, 1253 | {'?', TRUE, dohelp}, 1254 | {M('?'), TRUE, doextlist}, 1255 | #ifdef SHELL 1256 | {'!', TRUE, dosh}, 1257 | #endif 1258 | {'.', TRUE, donull, "waiting"}, 1259 | {' ', TRUE, donull, "waiting"}, 1260 | {',', FALSE, dopickup}, 1261 | {':', TRUE, dolook}, 1262 | {';', TRUE, doquickwhatis}, 1263 | {'^', TRUE, doidtrap}, 1264 | {'\\', TRUE, dodiscovered}, /* Robert Viduya */ 1265 | {'@', TRUE, dotogglepickup}, 1266 | {M('2'), FALSE, dotwoweapon}, 1267 | {WEAPON_SYM, TRUE, doprwep}, 1268 | {ARMOR_SYM, TRUE, doprarm}, 1269 | {RING_SYM, TRUE, doprring}, 1270 | {AMULET_SYM, TRUE, dopramulet}, 1271 | {TOOL_SYM, TRUE, doprtool}, 1272 | {'*', TRUE, doprinuse}, /* inventory of all equipment in use */ 1273 | {GOLD_SYM, TRUE, doprgold}, 1274 | {SPBOOK_SYM, TRUE, dovspell}, /* Mike Stephenson */ 1275 | {'#', TRUE, doextcmd}, 1276 | {0,0,0,0} 1277 | }; 1278 | 1279 | struct ext_func_tab extcmdlist[] = { 1280 | {"adjust", "adjust inventory letters", doorganize, TRUE}, 1281 | {"chat", "talk to someone", dotalk, TRUE}, /* converse? */ 1282 | {"conduct", "list which challenges you have adhered to", doconduct, TRUE}, 1283 | {"dip", "dip an object into something", dodip, FALSE}, 1284 | {"enhance", "advance or check weapons skills", enhance_weapon_skill, 1285 | TRUE}, 1286 | {"force", "force a lock", doforce, FALSE}, 1287 | {"invoke", "invoke an object's powers", doinvoke, TRUE}, 1288 | {"jump", "jump to a location", dojump, FALSE}, 1289 | {"loot", "loot a box on the floor", doloot, FALSE}, 1290 | {"monster", "use a monster's special ability", domonability, TRUE}, 1291 | {"name", "name an item or type of object", ddocall, TRUE}, 1292 | {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE}, 1293 | {"pray", "pray to the gods for help", dopray, TRUE}, 1294 | {"quit", "exit without saving current game", done2, TRUE}, 1295 | #ifdef STEED 1296 | {"ride", "ride (or stop riding) a monster", doride, FALSE}, 1297 | #endif 1298 | {"rub", "rub a lamp", dorub, FALSE}, 1299 | {"sit", "sit down", dosit, FALSE}, 1300 | {"turn", "turn undead", doturn, TRUE}, 1301 | {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE}, 1302 | {"untrap", "untrap something", dountrap, FALSE}, 1303 | {"version", "list compile time options for this version of NetHack", 1304 | doextversion, TRUE}, 1305 | {"wipe", "wipe off your face", dowipe, FALSE}, 1306 | {"?", "get this list of extended commands", doextlist, TRUE}, 1307 | #if defined(WIZARD) 1308 | /* 1309 | * There must be a blank entry here for every entry in the table 1310 | * below. 1311 | */ 1312 | {(char *)0, (char *)0, donull, TRUE}, 1313 | {(char *)0, (char *)0, donull, TRUE}, 1314 | {(char *)0, (char *)0, donull, TRUE}, 1315 | {(char *)0, (char *)0, donull, TRUE}, 1316 | {(char *)0, (char *)0, donull, TRUE}, 1317 | #ifdef DEBUG 1318 | {(char *)0, (char *)0, donull, TRUE}, 1319 | #endif 1320 | {(char *)0, (char *)0, donull, TRUE}, 1321 | #endif 1322 | {(char *)0, (char *)0, donull, TRUE} /* sentinel */ 1323 | }; 1324 | 1325 | #if defined(WIZARD) 1326 | static const struct ext_func_tab debug_extcmdlist[] = { 1327 | {"light sources", "show mobile light sources", wiz_light_sources, TRUE}, 1328 | {"seenv", "show seen vectors", wiz_show_seenv, TRUE}, 1329 | {"stats", "show memory statistics", wiz_show_stats, TRUE}, 1330 | {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE}, 1331 | {"vision", "show vision array", wiz_show_vision, TRUE}, 1332 | #ifdef DEBUG 1333 | {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE}, 1334 | #endif 1335 | {"wmode", "show wall modes", wiz_show_wmodes, TRUE}, 1336 | {(char *)0, (char *)0, donull, TRUE} 1337 | }; 1338 | 1339 | /* 1340 | * Insert debug commands into the extended command list. This function 1341 | * assumes that the last entry will be the help entry. 1342 | * 1343 | * You must add entries in ext_func_tab every time you add one to the 1344 | * debug_extcmdlist(). 1345 | */ 1346 | void 1347 | add_debug_extended_commands() 1348 | { 1349 | int i, j, k, n; 1350 | 1351 | /* count the # of help entries */ 1352 | for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++) 1353 | ; 1354 | 1355 | for (i = 0; debug_extcmdlist[i].ef_txt; i++) { 1356 | for (j = 0; j < n; j++) 1357 | if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break; 1358 | 1359 | /* insert i'th debug entry into extcmdlist[j], pushing down */ 1360 | for (k = n; k >= j; --k) 1361 | extcmdlist[k+1] = extcmdlist[k]; 1362 | extcmdlist[j] = debug_extcmdlist[i]; 1363 | n++; /* now an extra entry */ 1364 | } 1365 | } 1366 | 1367 | 1368 | static const char *template = "%-18s %4ld %6ld"; 1369 | static const char *count_str = " count bytes"; 1370 | static const char *separator = "------------------ ----- ------"; 1371 | 1372 | STATIC_OVL void 1373 | count_obj(chain, total_count, total_size, top, recurse) 1374 | struct obj *chain; 1375 | long *total_count; 1376 | long *total_size; 1377 | boolean top; 1378 | boolean recurse; 1379 | { 1380 | long count, size; 1381 | struct obj *obj; 1382 | 1383 | for (count = size = 0, obj = chain; obj; obj = obj->nobj) { 1384 | if (top) { 1385 | count++; 1386 | size += sizeof(struct obj) + obj->oxlth + obj->onamelth; 1387 | } 1388 | if (recurse && obj->cobj) 1389 | count_obj(obj->cobj, total_count, total_size, TRUE, TRUE); 1390 | } 1391 | *total_count += count; 1392 | *total_size += size; 1393 | } 1394 | 1395 | STATIC_OVL void 1396 | obj_chain(win, src, chain, total_count, total_size) 1397 | winid win; 1398 | const char *src; 1399 | struct obj *chain; 1400 | long *total_count; 1401 | long *total_size; 1402 | { 1403 | char buf[BUFSZ]; 1404 | long count = 0, size = 0; 1405 | 1406 | count_obj(chain, &count, &size, TRUE, FALSE); 1407 | *total_count += count; 1408 | *total_size += size; 1409 | Sprintf(buf, template, src, count, size); 1410 | putstr(win, 0, buf); 1411 | } 1412 | 1413 | STATIC_OVL void 1414 | mon_invent_chain(win, src, chain, total_count, total_size) 1415 | winid win; 1416 | const char *src; 1417 | struct monst *chain; 1418 | long *total_count; 1419 | long *total_size; 1420 | { 1421 | char buf[BUFSZ]; 1422 | long count = 0, size = 0; 1423 | struct monst *mon; 1424 | 1425 | for (mon = chain; mon; mon = mon->nmon) 1426 | count_obj(mon->minvent, &count, &size, TRUE, FALSE); 1427 | *total_count += count; 1428 | *total_size += size; 1429 | Sprintf(buf, template, src, count, size); 1430 | putstr(win, 0, buf); 1431 | } 1432 | 1433 | STATIC_OVL void 1434 | contained(win, src, total_count, total_size) 1435 | winid win; 1436 | const char *src; 1437 | long *total_count; 1438 | long *total_size; 1439 | { 1440 | char buf[BUFSZ]; 1441 | long count = 0, size = 0; 1442 | struct monst *mon; 1443 | 1444 | count_obj(invent, &count, &size, FALSE, TRUE); 1445 | count_obj(fobj, &count, &size, FALSE, TRUE); 1446 | count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE); 1447 | count_obj(migrating_objs, &count, &size, FALSE, TRUE); 1448 | /* DEADMONSTER check not required in this loop since they have no inventory */ 1449 | for (mon = fmon; mon; mon = mon->nmon) 1450 | count_obj(mon->minvent, &count, &size, FALSE, TRUE); 1451 | for (mon = migrating_mons; mon; mon = mon->nmon) 1452 | count_obj(mon->minvent, &count, &size, FALSE, TRUE); 1453 | 1454 | *total_count += count; *total_size += size; 1455 | 1456 | Sprintf(buf, template, src, count, size); 1457 | putstr(win, 0, buf); 1458 | } 1459 | 1460 | STATIC_OVL void 1461 | mon_chain(win, src, chain, total_count, total_size) 1462 | winid win; 1463 | const char *src; 1464 | struct monst *chain; 1465 | long *total_count; 1466 | long *total_size; 1467 | { 1468 | char buf[BUFSZ]; 1469 | long count, size; 1470 | struct monst *mon; 1471 | 1472 | for (count = size = 0, mon = chain; mon; mon = mon->nmon) { 1473 | count++; 1474 | size += sizeof(struct monst) + mon->mxlth + mon->mnamelth; 1475 | } 1476 | *total_count += count; 1477 | *total_size += size; 1478 | Sprintf(buf, template, src, count, size); 1479 | putstr(win, 0, buf); 1480 | } 1481 | 1482 | /* 1483 | * Display memory usage of all monsters and objects on the level. 1484 | */ 1485 | static int 1486 | wiz_show_stats() 1487 | { 1488 | char buf[BUFSZ]; 1489 | winid win; 1490 | long total_obj_size = 0, total_obj_count = 0; 1491 | long total_mon_size = 0, total_mon_count = 0; 1492 | 1493 | win = create_nhwindow(NHW_TEXT); 1494 | putstr(win, 0, "Current memory statistics:"); 1495 | putstr(win, 0, ""); 1496 | Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj)); 1497 | putstr(win, 0, buf); 1498 | putstr(win, 0, ""); 1499 | putstr(win, 0, count_str); 1500 | 1501 | obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size); 1502 | obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size); 1503 | obj_chain(win, "buried", level.buriedobjlist, 1504 | &total_obj_count, &total_obj_size); 1505 | obj_chain(win, "migrating obj", migrating_objs, 1506 | &total_obj_count, &total_obj_size); 1507 | mon_invent_chain(win, "minvent", fmon, 1508 | &total_obj_count,&total_obj_size); 1509 | mon_invent_chain(win, "migrating minvent", migrating_mons, 1510 | &total_obj_count, &total_obj_size); 1511 | 1512 | contained(win, "contained", 1513 | &total_obj_count, &total_obj_size); 1514 | 1515 | putstr(win, 0, separator); 1516 | Sprintf(buf, template, "Total", total_obj_count, total_obj_size); 1517 | putstr(win, 0, buf); 1518 | 1519 | putstr(win, 0, ""); 1520 | putstr(win, 0, ""); 1521 | Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst)); 1522 | putstr(win, 0, buf); 1523 | putstr(win, 0, ""); 1524 | 1525 | mon_chain(win, "fmon", fmon, 1526 | &total_mon_count, &total_mon_size); 1527 | mon_chain(win, "migrating", migrating_mons, 1528 | &total_mon_count, &total_mon_size); 1529 | 1530 | putstr(win, 0, separator); 1531 | Sprintf(buf, template, "Total", total_mon_count, total_mon_size); 1532 | putstr(win, 0, buf); 1533 | 1534 | #ifdef __BORLANDC__ 1535 | show_borlandc_stats(win); 1536 | #endif 1537 | 1538 | display_nhwindow(win, FALSE); 1539 | destroy_nhwindow(win); 1540 | return 0; 1541 | } 1542 | 1543 | void 1544 | sanity_check() 1545 | { 1546 | obj_sanity_check(); 1547 | timer_sanity_check(); 1548 | } 1549 | 1550 | #endif /* WIZARD */ 1551 | 1552 | #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) 1553 | #define unmeta(c) (0x7f & (c)) 1554 | 1555 | 1556 | void 1557 | rhack(cmd) 1558 | register char *cmd; 1559 | { 1560 | boolean do_walk, do_rush, prefix_seen, bad_command, 1561 | firsttime = (cmd == 0); 1562 | 1563 | if (firsttime) { 1564 | flags.nopick = 0; 1565 | cmd = parse(); 1566 | } 1567 | if (*cmd == '\033') { 1568 | flags.move = FALSE; 1569 | return; 1570 | } 1571 | #ifdef REDO 1572 | if (*cmd == DOAGAIN && !in_doagain && saveq[0]) { 1573 | in_doagain = TRUE; 1574 | stail = 0; 1575 | rhack((char *)0); /* read and execute command */ 1576 | in_doagain = FALSE; 1577 | return; 1578 | } 1579 | /* Special case of *cmd == ' ' handled better below */ 1580 | if(!*cmd || *cmd == (char)0377) 1581 | #else 1582 | if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' ')) 1583 | #endif 1584 | { 1585 | nhbell(); 1586 | flags.move = FALSE; 1587 | return; /* probably we just had an interrupt */ 1588 | } 1589 | 1590 | /* handle most movement commands */ 1591 | do_walk = do_rush = prefix_seen = FALSE; 1592 | switch (*cmd) { 1593 | case 'g': if (movecmd(cmd[1])) { 1594 | flags.run = 2; 1595 | do_rush = TRUE; 1596 | } else 1597 | prefix_seen = TRUE; 1598 | break; 1599 | case '5': if (!iflags.num_pad) break; /* else FALLTHRU */ 1600 | case 'G': if (movecmd(lowc(cmd[1]))) { 1601 | flags.run = 3; 1602 | do_rush = TRUE; 1603 | } else 1604 | prefix_seen = TRUE; 1605 | break; 1606 | case '-': if (!iflags.num_pad) break; /* else FALLTHRU */ 1607 | /* Effects of movement commands and invisible monsters: 1608 | * m: always move onto space (even if 'I' remembered) 1609 | * F: always attack space (even if 'I' not remembered) 1610 | * normal movement: attack if 'I', move otherwise 1611 | */ 1612 | case 'F': if (movecmd(cmd[1])) { 1613 | flags.forcefight = 1; 1614 | do_walk = TRUE; 1615 | } else 1616 | prefix_seen = TRUE; 1617 | break; 1618 | case 'm': if (movecmd(cmd[1]) || u.dz) { 1619 | flags.run = 0; 1620 | flags.nopick = 1; 1621 | if (!u.dz) do_walk = TRUE; 1622 | else cmd[0] = cmd[1]; /* "m<" or "m>" */ 1623 | } else 1624 | prefix_seen = TRUE; 1625 | break; 1626 | case 'M': if (movecmd(lowc(cmd[1]))) { 1627 | flags.run = 1; 1628 | flags.nopick = 1; 1629 | do_rush = TRUE; 1630 | } else 1631 | prefix_seen = TRUE; 1632 | break; 1633 | case '0': if (!iflags.num_pad) break; 1634 | (void)ddoinv(); /* a convenience borrowed from the PC */ 1635 | flags.move = FALSE; 1636 | multi = 0; 1637 | return; 1638 | default: if (movecmd(*cmd)) { /* ordinary movement */ 1639 | do_walk = TRUE; 1640 | } else if (movecmd(iflags.num_pad ? 1641 | unmeta(*cmd) : lowc(*cmd))) { 1642 | flags.run = 1; 1643 | do_rush = TRUE; 1644 | } else if (movecmd(unctrl(*cmd))) { 1645 | flags.run = 3; 1646 | do_rush = TRUE; 1647 | } 1648 | break; 1649 | } 1650 | if (do_walk) { 1651 | if (multi) flags.mv = TRUE; 1652 | domove(); 1653 | flags.forcefight = 0; 1654 | return; 1655 | } else if (do_rush) { 1656 | if (firsttime) { 1657 | if (!multi) multi = max(COLNO,ROWNO); 1658 | u.last_str_turn = 0; 1659 | } 1660 | flags.mv = TRUE; 1661 | domove(); 1662 | return; 1663 | } else if (prefix_seen && cmd[1] == '\033') { /* <prefix><escape> */ 1664 | /* don't report "unknown command" for change of heart... */ 1665 | bad_command = FALSE; 1666 | } else if (*cmd == ' ' && !flags.rest_on_space) { 1667 | bad_command = TRUE; /* skip cmdlist[] loop */ 1668 | 1669 | /* handle all other commands */ 1670 | } else { 1671 | register const struct func_tab *tlist; 1672 | int res, NDECL((*func)); 1673 | 1674 | for (tlist = cmdlist; tlist->f_char; tlist++) { 1675 | if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue; 1676 | 1677 | if (u.uburied && !tlist->can_if_buried) { 1678 | You_cant("do that while you are buried!"); 1679 | res = 0; 1680 | } else { 1681 | /* we discard 'const' because some compilers seem to have 1682 | trouble with the pointer passed to set_occupation() */ 1683 | func = ((struct func_tab *)tlist)->f_funct; 1684 | if (tlist->f_text && !occupation && multi) 1685 | set_occupation(func, tlist->f_text, multi); 1686 | res = (*func)(); /* perform the command */ 1687 | } 1688 | if (!res) { 1689 | flags.move = FALSE; 1690 | multi = 0; 1691 | } 1692 | return; 1693 | } 1694 | /* if we reach here, cmd wasn't found in cmdlist[] */ 1695 | bad_command = TRUE; 1696 | } 1697 | 1698 | if (bad_command) { 1699 | char expcmd[10]; 1700 | register char *cp = expcmd; 1701 | 1702 | while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) { 1703 | if (*cmd >= 040 && *cmd < 0177) { 1704 | *cp++ = *cmd++; 1705 | } else if (*cmd & 0200) { 1706 | *cp++ = 'M'; 1707 | *cp++ = '-'; 1708 | *cp++ = *cmd++ &= ~0200; 1709 | } else { 1710 | *cp++ = '^'; 1711 | *cp++ = *cmd++ ^ 0100; 1712 | } 1713 | } 1714 | *cp = '\0'; 1715 | Norep("Unknown command '%s'.", expcmd); 1716 | } 1717 | /* didn't move */ 1718 | flags.move = FALSE; 1719 | multi = 0; 1720 | return; 1721 | } 1722 | 1723 | int 1724 | xytod(x, y) /* convert an x,y pair into a direction code */ 1725 | schar x, y; 1726 | { 1727 | register int dd; 1728 | 1729 | for(dd = 0; dd < 8; dd++) 1730 | if(x == xdir[dd] && y == ydir[dd]) return dd; 1731 | 1732 | return -1; 1733 | } 1734 | 1735 | void 1736 | dtoxy(cc,dd) /* convert a direction code into an x,y pair */ 1737 | coord *cc; 1738 | register int dd; 1739 | { 1740 | cc->x = xdir[dd]; 1741 | cc->y = ydir[dd]; 1742 | return; 1743 | } 1744 | 1745 | int 1746 | movecmd(sym) /* also sets u.dz, but returns false for <> */ 1747 | char sym; 1748 | { 1749 | register const char *dp; 1750 | register const char *sdp; 1751 | if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ 1752 | 1753 | u.dz = 0; 1754 | if(!(dp = index(sdp, sym))) return 0; 1755 | u.dx = xdir[dp-sdp]; 1756 | u.dy = ydir[dp-sdp]; 1757 | u.dz = zdir[dp-sdp]; 1758 | if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) { 1759 | u.dx = u.dy = 0; 1760 | return 0; 1761 | } 1762 | return !u.dz; 1763 | } 1764 | 1765 | int 1766 | getdir(s) 1767 | const char *s; 1768 | { 1769 | char dirsym; 1770 | 1771 | #ifdef REDO 1772 | if(in_doagain) 1773 | dirsym = readchar(); 1774 | else 1775 | #endif 1776 | dirsym = yn_function (s ? s : "In what direction?", 1777 | (char *)0, '\0'); 1778 | #ifdef REDO 1779 | savech(dirsym); 1780 | #endif 1781 | if(dirsym == '.' || dirsym == 's') 1782 | u.dx = u.dy = u.dz = 0; 1783 | else if(!movecmd(dirsym) && !u.dz) { 1784 | if(!index(quitchars, dirsym)) 1785 | pline("What a strange direction!"); 1786 | return 0; 1787 | } 1788 | if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir(); 1789 | return 1; 1790 | } 1791 | 1792 | #endif /* OVL1 */ 1793 | #ifdef OVLB 1794 | 1795 | void 1796 | confdir() 1797 | { 1798 | register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8); 1799 | u.dx = xdir[x]; 1800 | u.dy = ydir[x]; 1801 | return; 1802 | } 1803 | 1804 | #endif /* OVLB */ 1805 | #ifdef OVL0 1806 | 1807 | int 1808 | isok(x,y) 1809 | register int x, y; 1810 | { 1811 | /* x corresponds to curx, so x==1 is the first column. Ach. %% */ 1812 | return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1; 1813 | } 1814 | 1815 | static NEARDATA int last_multi; 1816 | 1817 | /* 1818 | * convert a MAP window position into a movecmd 1819 | */ 1820 | int 1821 | click_to_cmd(x, y, mod) 1822 | int x, y, mod; 1823 | { 1824 | x -= u.ux; 1825 | y -= u.uy; 1826 | /* convert without using floating point, allowing sloppy clicking */ 1827 | if(x > 2*abs(y)) 1828 | x = 1, y = 0; 1829 | else if(y > 2*abs(x)) 1830 | x = 0, y = 1; 1831 | else if(x < -2*abs(y)) 1832 | x = -1, y = 0; 1833 | else if(y < -2*abs(x)) 1834 | x = 0, y = -1; 1835 | else 1836 | x = sgn(x), y = sgn(y); 1837 | 1838 | if(x == 0 && y == 0) /* map click on player to "rest" command */ 1839 | return '.'; 1840 | 1841 | x = xytod(x, y); 1842 | if(mod == CLICK_1) { 1843 | return (iflags.num_pad ? ndir[x] : sdir[x]); 1844 | } else { 1845 | return (iflags.num_pad ? M(ndir[x]) : 1846 | (sdir[x] - 'a' + 'A')); /* run command */ 1847 | } 1848 | } 1849 | 1850 | STATIC_OVL char * 1851 | parse() 1852 | { 1853 | #ifdef LINT /* static char in_line[COLNO]; */ 1854 | char in_line[COLNO]; 1855 | #else 1856 | static char in_line[COLNO]; 1857 | #endif 1858 | register int foo; 1859 | boolean prezero = FALSE; 1860 | 1861 | multi = 0; 1862 | flags.move = 1; 1863 | flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ 1864 | 1865 | if (!iflags.num_pad || (foo = readchar()) == 'n') 1866 | for (;;) { 1867 | foo = readchar(); 1868 | if (foo >= '0' && foo <= '9') { 1869 | multi = 10 * multi + foo - '0'; 1870 | if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; 1871 | if (multi > 9) { 1872 | clear_nhwindow(WIN_MESSAGE); 1873 | Sprintf(in_line, "Count: %d", multi); 1874 | pline(in_line); 1875 | mark_synch(); 1876 | } 1877 | last_multi = multi; 1878 | if (!multi && foo == '0') prezero = TRUE; 1879 | } else break; /* not a digit */ 1880 | } 1881 | 1882 | if (foo == '\033') { /* esc cancels count (TH) */ 1883 | clear_nhwindow(WIN_MESSAGE); 1884 | multi = last_multi = 0; 1885 | # ifdef REDO 1886 | } else if (foo == DOAGAIN || in_doagain) { 1887 | multi = last_multi; 1888 | } else { 1889 | last_multi = multi; 1890 | savech(0); /* reset input queue */ 1891 | savech((char)foo); 1892 | # endif 1893 | } 1894 | 1895 | if (multi) { 1896 | multi--; 1897 | save_cm = in_line; 1898 | } else { 1899 | save_cm = (char *)0; 1900 | } 1901 | in_line[0] = foo; 1902 | in_line[1] = '\0'; 1903 | if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' || 1904 | foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) { 1905 | foo = readchar(); 1906 | #ifdef REDO 1907 | savech((char)foo); 1908 | #endif 1909 | in_line[1] = foo; 1910 | in_line[2] = 0; 1911 | } 1912 | clear_nhwindow(WIN_MESSAGE); 1913 | if (prezero) in_line[0] = '\033'; 1914 | return(in_line); 1915 | } 1916 | 1917 | #endif /* OVL0 */ 1918 | #ifdef OVLB 1919 | 1920 | #ifdef UNIX 1921 | static 1922 | void 1923 | end_of_input() 1924 | { 1925 | exit_nhwindows("End of input?"); 1926 | #ifndef NOSAVEONHANGUP 1927 | if (!program_state.done_hup++) 1928 | (void) dosave0(); 1929 | #endif 1930 | clearlocks(); 1931 | terminate(EXIT_SUCCESS); 1932 | } 1933 | #endif 1934 | 1935 | #endif /* OVLB */ 1936 | #ifdef OVL0 1937 | 1938 | char 1939 | readchar() 1940 | { 1941 | register int sym; 1942 | int x = u.ux, y = u.uy, mod = 0; 1943 | 1944 | #ifdef REDO 1945 | sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod); 1946 | #else 1947 | sym = Getchar(); 1948 | #endif 1949 | 1950 | #ifdef UNIX 1951 | # ifdef NR_OF_EOFS 1952 | if (sym == EOF) { 1953 | register int cnt = NR_OF_EOFS; 1954 | /* 1955 | * Some SYSV systems seem to return EOFs for various reasons 1956 | * (?like when one hits break or for interrupted systemcalls?), 1957 | * and we must see several before we quit. 1958 | */ 1959 | do { 1960 | clearerr(stdin); /* omit if clearerr is undefined */ 1961 | sym = Getchar(); 1962 | } while (--cnt && sym == EOF); 1963 | } 1964 | # endif /* NR_OF_EOFS */ 1965 | if (sym == EOF) 1966 | end_of_input(); 1967 | #endif /* UNIX */ 1968 | 1969 | if(sym == 0) /* click event */ 1970 | sym = click_to_cmd(x, y, mod); 1971 | return((char) sym); 1972 | } 1973 | #endif /* OVL0 */ 1974 | 1975 | /*cmd.c*/