/* SCCS Id: @(#)cmd.c 3.3 2000/05/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" /* #define DEBUG */ /* uncomment for debugging */ /* * Some systems may have getchar() return EOF for various reasons, and * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. */ #if defined(SYSV) || defined(DGUX) || defined(HPUX) #define NR_OF_EOFS 20 #endif #ifdef DEBUG /* * only one "wiz_debug_cmd" routine should be available (in whatever * module you are trying to debug) or things are going to get rather * hard to link :-) */ extern void NDECL(wiz_debug_cmd); #endif #ifdef DUMB /* stuff commented out in extern.h, but needed here */ extern int NDECL(doapply); /**/ extern int NDECL(dorub); /**/ extern int NDECL(dojump); /**/ extern int NDECL(doextlist); /**/ extern int NDECL(dodrop); /**/ extern int NDECL(doddrop); /**/ extern int NDECL(dodown); /**/ extern int NDECL(doup); /**/ extern int NDECL(donull); /**/ extern int NDECL(dowipe); /**/ extern int NDECL(do_mname); /**/ extern int NDECL(ddocall); /**/ extern int NDECL(dotakeoff); /**/ extern int NDECL(doremring); /**/ extern int NDECL(dowear); /**/ extern int NDECL(doputon); /**/ extern int NDECL(doddoremarm); /**/ extern int NDECL(dokick); /**/ extern int NDECL(dofire); /**/ extern int NDECL(dothrow); /**/ extern int NDECL(doeat); /**/ extern int NDECL(done2); /**/ extern int NDECL(doengrave); /**/ extern int NDECL(dopickup); /**/ extern int NDECL(ddoinv); /**/ extern int NDECL(dotypeinv); /**/ extern int NDECL(dolook); /**/ extern int NDECL(doprgold); /**/ extern int NDECL(doprwep); /**/ extern int NDECL(doprarm); /**/ extern int NDECL(doprring); /**/ extern int NDECL(dopramulet); /**/ extern int NDECL(doprtool); /**/ extern int NDECL(dosuspend); /**/ extern int NDECL(doforce); /**/ extern int NDECL(doopen); /**/ extern int NDECL(doclose); /**/ extern int NDECL(dosh); /**/ extern int NDECL(dodiscovered); /**/ extern int NDECL(doset); /**/ extern int NDECL(dotogglepickup); /**/ extern int NDECL(dowhatis); /**/ extern int NDECL(doquickwhatis); /**/ extern int NDECL(dowhatdoes); /**/ extern int NDECL(dohelp); /**/ extern int NDECL(dohistory); /**/ extern int NDECL(doloot); /**/ extern int NDECL(dodrink); /**/ extern int NDECL(dodip); /**/ extern int NDECL(dosacrifice); /**/ extern int NDECL(dopray); /**/ extern int NDECL(doturn); /**/ extern int NDECL(doredraw); /**/ extern int NDECL(doread); /**/ extern int NDECL(dosave); /**/ extern int NDECL(dosearch); /**/ extern int NDECL(doidtrap); /**/ extern int NDECL(dopay); /**/ extern int NDECL(dosit); /**/ extern int NDECL(dotalk); /**/ extern int NDECL(docast); /**/ extern int NDECL(dovspell); /**/ extern int NDECL(dotele); /**/ extern int NDECL(dountrap); /**/ extern int NDECL(doversion); /**/ extern int NDECL(doextversion); /**/ extern int NDECL(doswapweapon); /**/ extern int NDECL(dowield); /**/ extern int NDECL(dowieldquiver); /**/ extern int NDECL(dozap); /**/ extern int NDECL(doorganize); /**/ #endif /* DUMB */ #ifdef OVL1 static int NDECL((*timed_occ_fn)); #endif /* OVL1 */ STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); STATIC_PTR int NDECL(domonability); # ifdef WIZARD STATIC_PTR int NDECL(wiz_wish); STATIC_PTR int NDECL(wiz_identify); STATIC_PTR int NDECL(wiz_map); STATIC_PTR int NDECL(wiz_genesis); STATIC_PTR int NDECL(wiz_where); STATIC_PTR int NDECL(wiz_detect); STATIC_PTR int NDECL(wiz_level_tele); STATIC_PTR int NDECL(wiz_show_seenv); STATIC_PTR int NDECL(wiz_show_vision); STATIC_PTR int NDECL(wiz_show_wmodes); #ifdef __BORLANDC__ extern void FDECL(show_borlandc_stats, (winid)); #endif STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *)); STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *)); STATIC_PTR int NDECL(wiz_show_stats); # endif STATIC_PTR int NDECL(enter_explore_mode); STATIC_PTR int NDECL(doattributes); STATIC_PTR int NDECL(doconduct); /**/ STATIC_PTR void NDECL(minimal_enlightenment); #ifdef OVLB STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *)); #ifdef UNIX static void NDECL(end_of_input); #endif #endif /* OVLB */ STATIC_DCL char *NDECL(parse); #ifdef OVL1 STATIC_PTR int doprev_message() { return nh_doprev_message(); } /* Count down by decrementing multi */ STATIC_PTR int timed_occupation() { (*timed_occ_fn)(); if (multi > 0) multi--; return multi > 0; } /* If you have moved since initially setting some occupations, they * now shouldn't be able to restart. * * The basic rule is that if you are carrying it, you can continue * since it is with you. If you are acting on something at a distance, * your orientation to it must have changed when you moved. * * The exception to this is taking off items, since they can be taken * off in a number of ways in the intervening time, screwing up ordering. * * Currently: Take off all armor. * Picking Locks / Forcing Chests. * Setting traps. */ void reset_occupations() { reset_remarm(); reset_pick(); reset_trapset(); } /* If a time is given, use it to timeout this function, otherwise the * function times out by its own means. */ void set_occupation(fn, txt, xtime) int NDECL((*fn)); const char *txt; int xtime; { if (xtime) { occupation = timed_occupation; timed_occ_fn = fn; } else occupation = fn; occtxt = txt; occtime = 0; return; } #ifdef REDO static char NDECL(popch); /* Provide a means to redo the last command. The flag `in_doagain' is set * to true while redoing the command. This flag is tested in commands that * require additional input (like `throw' which requires a thing and a * direction), and the input prompt is not shown. Also, while in_doagain is * TRUE, no keystrokes can be saved into the saveq. */ #define BSIZE 20 static char pushq[BSIZE], saveq[BSIZE]; static NEARDATA int phead, ptail, shead, stail; static char popch() { /* If occupied, return '\0', letting tgetch know a character should * be read from the keyboard. If the character read is not the * ABORT character (as checked in pcmain.c), that character will be * pushed back on the pushq. */ if (occupation) return '\0'; if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0'); else return(char)((phead != ptail) ? pushq[ptail++] : '\0'); } char pgetchar() { /* curtesy of aeb@cwi.nl */ register int ch; if(!(ch = popch())) ch = nhgetch(); return((char)ch); } /* A ch == 0 resets the pushq */ void pushch(ch) char ch; { if (!ch) phead = ptail = 0; if (phead < BSIZE) pushq[phead++] = ch; return; } /* A ch == 0 resets the saveq. Only save keystrokes when not * replaying a previous command. */ void savech(ch) char ch; { if (!in_doagain) { if (!ch) phead = ptail = shead = stail = 0; else if (shead < BSIZE) saveq[shead++] = ch; } return; } #endif /* REDO */ #endif /* OVL1 */ #ifdef OVLB STATIC_PTR int doextcmd() /* here after # - now read a full-word command */ { int idx, retval; /* keep repeating until we don't run help or quit */ do { idx = get_ext_cmd(); if (idx < 0) return 0; /* quit */ retval = (*extcmdlist[idx].ef_funct)(); } while (extcmdlist[idx].ef_funct == doextlist); return retval; } int doextlist() /* here after #? - now list all full-word commands */ { register const struct ext_func_tab *efp; char buf[BUFSZ]; winid datawin; datawin = create_nhwindow(NHW_TEXT); putstr(datawin, 0, ""); putstr(datawin, 0, " Extended Commands List"); putstr(datawin, 0, ""); putstr(datawin, 0, " Press '#', then type:"); putstr(datawin, 0, ""); for(efp = extcmdlist; efp->ef_txt; efp++) { Sprintf(buf, " %-14s - %s.", efp->ef_txt, efp->ef_desc); putstr(datawin, 0, buf); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return 0; } #ifdef TTY_GRAPHICS #define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */ /* * This is currently used only by the tty port and is * controlled via runtime option 'extmenu' */ int extcmd_via_menu() /* here after # - now show pick-list of possible commands */ { const struct ext_func_tab *efp; menu_item *pick_list = (menu_item *)0; winid win; anything any; const struct ext_func_tab *choices[MAX_EXT_CMD]; char buf[BUFSZ]; char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20]; int i, n, nchoices, acount; int ret, biggest; int accelerator, prevaccelerator; int matchlevel = 0; ret = 0; cbuf[0] = '\0'; biggest = 0; while (!ret) { i = n = 0; accelerator = 0; any.a_void = 0; /* populate choices */ for(efp = extcmdlist; efp->ef_txt; efp++) { if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) { choices[i++] = efp; if ((int)strlen(efp->ef_desc) > biggest) { biggest = strlen(efp->ef_desc); Sprintf(fmtstr,"%%-%ds", biggest + 15); } #ifdef DEBUG if (i >= MAX_EXT_CMD - 2) { impossible("Exceeded %d extended commands in doextcmd() menu", MAX_EXT_CMD - 2); return 0; } #endif } } choices[i] = (struct ext_func_tab *)0; nchoices = i; /* if we're down to one, we have our selection so get out of here */ if (nchoices == 1) { for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) { ret = i; break; } break; } /* otherwise... */ win = create_nhwindow(NHW_MENU); start_menu(win); prevaccelerator = 0; acount = 0; for(i = 0; choices[i]; ++i) { accelerator = choices[i]->ef_txt[matchlevel]; if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) { if (acount) { /* flush the extended commands for that letter already in buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); acount = 0; } } prevaccelerator = accelerator; if (!acount || nchoices < (ROWNO - 3)) { Sprintf(prompt, "%s [%s]", choices[i]->ef_txt, choices[i]->ef_desc); } else if (acount == 1) { Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt, choices[i]->ef_txt); } else { Strcat(prompt," or "); Strcat(prompt, choices[i]->ef_txt); } ++acount; } if (acount) { /* flush buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); } Sprintf(prompt, "Extended Command: %s", cbuf); end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n==1) { if (matchlevel > (QBUFSZ - 2)) { free((genericptr_t)pick_list); #ifdef DEBUG impossible("Too many characters (%d) entered in extcmd_via_menu()", matchlevel); #endif ret = -1; } else { cbuf[matchlevel++] = pick_list[0].item.a_char; cbuf[matchlevel] = '\0'; free((genericptr_t)pick_list); } } else { if (matchlevel) { ret = 0; matchlevel = 0; } else ret = -1; } } return ret; } #endif STATIC_PTR int domonability() { if (can_breathe(youmonst.data)) return dobreathe(); else if (attacktype(youmonst.data, AT_SPIT)) return dospit(); else if (youmonst.data->mlet == S_NYMPH) return doremove(); else if (youmonst.data->mlet == S_UMBER) return doconfuse(); else if (is_were(youmonst.data)) return dosummon(); else if (webmaker(youmonst.data)) return dospinweb(); else if (is_hider(youmonst.data)) return dohide(); else if (is_mind_flayer(youmonst.data)) return domindblast(); else if (u.umonnum == PM_GREMLIN) { if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { if (split_mon(&youmonst, (struct monst *)0)) dryup(u.ux, u.uy, TRUE); } else There("is no fountain here."); } else if (is_unicorn(youmonst.data)) { use_unicorn_horn((struct obj *)0); return 1; } else if (youmonst.data->msound == MS_SHRIEK) { You("shriek."); if(u.uburied) pline("Unfortunately sound does not carry well through rock."); else aggravate(); } else if (Upolyd) pline("Any special ability you may have is purely reflexive."); else You("don't have a special ability in your normal form!"); return 0; } STATIC_PTR int enter_explore_mode() { if(!discover && !wizard) { pline("Beware! From explore mode there will be no return to normal game."); if (yn("Do you want to enter explore mode?") == 'y') { clear_nhwindow(WIN_MESSAGE); You("are now in non-scoring explore mode."); discover = TRUE; } else { clear_nhwindow(WIN_MESSAGE); pline("Resuming normal game."); } } return 0; } #ifdef WIZARD STATIC_PTR int wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */ { if (wizard) { boolean save_verbose = flags.verbose; flags.verbose = FALSE; makewish(); flags.verbose = save_verbose; (void) encumber_msg(); } else pline("Unavailable command '^W'."); return 0; } STATIC_PTR int wiz_identify() { if (wizard) identify_pack(0); else pline("Unavailable command '^I'."); return 0; } /* reveal the level map and any traps on it */ STATIC_PTR int wiz_map() { if (wizard) { struct trap *t; for (t = ftrap; t != 0; t = t->ntrap) { t->tseen = 1; map_trap(t, TRUE); } do_mapping(); } else pline("Unavailable command '^F'."); return 0; } STATIC_PTR int wiz_genesis() { if (wizard) (void) create_particular(); else pline("Unavailable command '^G'."); return 0; } STATIC_PTR int wiz_where() { if (wizard) print_dungeon(); else pline("Unavailable command '^O'."); return 0; } STATIC_PTR int wiz_detect() { if(wizard) (void) findit(); else pline("Unavailable command '^E'."); return 0; } STATIC_PTR int wiz_level_tele() { if (wizard) level_tele(); else pline("Unavailable command '^V'."); return 0; } STATIC_PTR int wiz_show_seenv() { winid win; int x, y, v, startx, stopx, curx; char row[COLNO+1]; win = create_nhwindow(NHW_TEXT); /* * Each seenv description takes up 2 characters, so center * the seenv display around the hero. */ startx = max(1, u.ux-(COLNO/4)); stopx = min(startx+(COLNO/2), COLNO); /* can't have a line exactly 80 chars long */ if (stopx - startx == COLNO/2) startx++; for (y = 0; y < ROWNO; y++) { for (x = startx, curx = 0; x < stopx; x++, curx += 2) { if (x == u.ux && y == u.uy) { row[curx] = row[curx+1] = '@'; } else { v = levl[x][y].seenv & 0xff; if (v == 0) row[curx] = row[curx+1] = ' '; else Sprintf(&row[curx], "%02x", v); } } /* remove trailing spaces */ for (x = curx-1; x >= 0; x--) if (row[x] != ' ') break; row[x+1] = '\0'; putstr(win, 0, row); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } STATIC_PTR int wiz_show_vision() { winid win; int x, y, v; char row[COLNO+1]; win = create_nhwindow(NHW_TEXT); Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit", COULD_SEE, IN_SIGHT, TEMP_LIT); putstr(win, 0, row); putstr(win, 0, ""); for (y = 0; y < ROWNO; y++) { for (x = 1; x < COLNO; x++) { if (x == u.ux && y == u.uy) row[x] = '@'; else { v = viz_array[y][x]; /* data access should be hidden */ if (v == 0) row[x] = ' '; else row[x] = '0' + viz_array[y][x]; } } /* remove trailing spaces */ for (x = COLNO-1; x >= 1; x--) if (row[x] != ' ') break; row[x+1] = '\0'; putstr(win, 0, &row[1]); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } STATIC_PTR int wiz_show_wmodes() { winid win; int x,y; char row[COLNO+1]; struct rm *lev; win = create_nhwindow(NHW_TEXT); for (y = 0; y < ROWNO; y++) { for (x = 0; x < COLNO; x++) { lev = &levl[x][y]; if (x == u.ux && y == u.uy) row[x] = '@'; if (IS_WALL(lev->typ) || lev->typ == SDOOR) row[x] = '0' + (lev->wall_info & WM_MASK); else if (lev->typ == CORR) row[x] = '#'; else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ)) row[x] = '.'; else row[x] = 'x'; } row[COLNO] = '\0'; putstr(win, 0, row); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } #endif /* WIZARD */ /* -enlightenment and conduct- */ static winid en_win; static const char *You_ = "You ", *are = "are ", *were = "were ", *have = "have ", *had = "had ", *can = "can ", *could = "could "; static const char *have_been = "have been ", *have_never = "have never ", *never = "never "; #define enl_msg(prefix,present,past,suffix) \ enlght_line(prefix, final ? past : present, suffix) #define you_are(attr) enl_msg(You_,are,were,attr) #define you_have(attr) enl_msg(You_,have,had,attr) #define you_can(attr) enl_msg(You_,can,could,attr) #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing) #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing) #define you_have_X(something) enl_msg(You_,have,(const char *)"",something) static void enlght_line(start, middle, end) const char *start, *middle, *end; { char buf[BUFSZ]; Sprintf(buf, "%s%s%s.", start, middle, end); putstr(en_win, 0, buf); } void enlightenment(final) int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */ { int ltmp; char buf[BUFSZ]; en_win = create_nhwindow(NHW_MENU); putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:"); putstr(en_win, 0, ""); #ifdef ELBERETH if (u.uevent.uhand_of_elbereth) { static const char *hofe_titles[3] = { "the Hand of Elbereth", "the Envoy of Balance", "the Glory of Arioch" }; you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]); } #endif /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */ if (u.ualign.record >= 20) you_are("piously aligned"); else if (u.ualign.record > 13) you_are("devoutly aligned"); else if (u.ualign.record > 8) you_are("fervently aligned"); else if (u.ualign.record > 3) you_are("stridently aligned"); else if (u.ualign.record == 3) you_are("aligned"); else if (u.ualign.record > 0) you_are("haltingly aligned"); else if (u.ualign.record == 0) you_are("nominally aligned"); else if (u.ualign.record >= -3) you_have("strayed"); else if (u.ualign.record >= -8) you_have("sinned"); else you_have("transgressed"); #ifdef WIZARD if (wizard) { Sprintf(buf, " %d", u.ualign.record); enl_msg("Your alignment ", "is", "was", buf); } #endif /*** Resistances to troubles ***/ if (Fire_resistance) you_are("fire resistant"); if (Cold_resistance) you_are("cold resistant"); if (Sleep_resistance) you_are("sleep resistant"); if (Disint_resistance) you_are("disintegration-resistant"); if (Shock_resistance) you_are("shock resistant"); if (Poison_resistance) you_are("poison resistant"); if (Drain_resistance) you_are("level-drain resistant"); if (Sick_resistance) you_are("immune to sickness"); if (Antimagic) you_are("magic-protected"); if (Acid_resistance) you_are("acid resistant"); if (Stone_resistance) you_are("petrification resistant"); if (Invulnerable) you_are("invulnerable"); /*** Troubles ***/ if (Halluc_resistance) enl_msg("You resist", "", "ed", " hallucinations"); if (final) { if (Hallucination) you_are("hallucinating"); if (Stunned) you_are("stunned"); if (Confusion) you_are("confused"); if (Blinded) you_are("blinded"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) you_are("sick from food poisoning"); if (u.usick_type & SICK_NONVOMITABLE) you_are("sick from illness"); } } if (Stoned) you_are("turning to stone"); if (Slimed) you_are("turning into slime"); if (Strangled) you_are((u.uburied) ? "buried" : "being strangled"); if (Glib) { Sprintf(buf, "slippery %s", makeplural(body_part(FINGER))); you_have(buf); } if (Fumbling) enl_msg("You fumble", "", "d", ""); if (Wounded_legs) { Sprintf(buf, "wounded %s", makeplural(body_part(LEG))); you_have(buf); } if (Sleeping) enl_msg("You ", "fall", "fell", " asleep"); if (Hunger) enl_msg("You hunger", "", "ed", " rapidly"); /*** Vision and senses ***/ if (See_invisible) enl_msg(You_, "see", "saw", " invisible"); if (Blind_telepat) you_are("telepathic"); if (Warning) you_are("warned"); if (Warn_of_mon && flags.warntype) { Sprintf(buf, "aware of the presence of %s", (flags.warntype & M2_ORC) ? "orcs" : (flags.warntype & M2_DEMON) ? "demons" : something); you_are(buf); } if (Undead_warning) you_are("warned of undead"); if (Searching) you_have("automatic searching"); if (Clairvoyant) you_are("clairvoyant"); if (Infravision) you_have("infravision"); if (Detect_monsters) you_are("sensing the presence of monsters"); /*** Appearance and behavior ***/ if (Adornment) you_are("adorned"); if (Invisible) you_are("invisible"); else if (Invis) you_are("invisible to others"); /* ordinarily "visible" is redundant; this is a special case for the situation when invisibility would be an expected attribute */ else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis) you_are("visible"); if (Displaced) you_are("displaced"); if (Stealth) you_are("stealthy"); if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters"); if (Conflict) enl_msg("You cause", "", "d", " conflict"); /*** Transportation ***/ if (Jumping) you_can("jump"); if (Teleportation) you_can("teleport"); if (Teleport_control) you_have("teleport control"); if (Lev_at_will) you_are("levitating, at will"); else if (Levitation) you_are("levitating"); /* without control */ else if (Flying) you_can("fly"); if (Wwalking) you_can("walk on water"); if (Swimming) you_can("swim"); if (Breathless) you_can("survive without air"); else if (Amphibious) you_can("breathe water"); if (Passes_walls) you_can("walk through walls"); #ifdef STEED if (u.usteed) { Sprintf(buf, "riding %s", y_monnam(u.usteed)); you_are(buf); } #endif if (u.uswallow) { Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck)); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim); #endif you_are(buf); } else if (u.ustuck) { Sprintf(buf, "%s %s", (Upolyd && sticks(youmonst.data)) ? "holding" : "held by", a_monnam(u.ustuck)); you_are(buf); } /*** Physical attributes ***/ if (Slow_digestion) you_have("slower digestion"); if (Regeneration) enl_msg("You regenerate", "", "d", ""); if (u.uspellprot || Protection) you_are("protected"); if (Protection_from_shape_changers) you_are("protected from shape changers"); if (Polymorph) you_are("polymorphing"); if (Polymorph_control) you_have("polymorph control"); if (u.ulycn >= LOW_PM) { Strcpy(buf, an(mons[u.ulycn].mname)); you_are(buf); } if (Upolyd) { if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form"); else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname)); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); #endif you_are(buf); } if (Unchanging) you_can("not change from your current form"); if (Fast) you_are(Very_fast ? "very fast" : "fast"); if (Reflecting) you_have("reflection"); if (Free_action) you_have("free action"); if (Fixed_abil) you_have("fixed abilities"); if (Lifesaved) enl_msg("Your life ", "will be", "would have been", " saved"); if (u.twoweap) you_are("wielding two weapons at once"); /*** Miscellany ***/ if (Luck) { ltmp = abs((int)Luck); Sprintf(buf, "%s%slucky", ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "", Luck < 0 ? "un" : ""); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", Luck); #endif you_are(buf); } #ifdef WIZARD else if (wizard) enl_msg("Your luck ", "is", "was", " zero"); #endif if (u.moreluck > 0) you_have("extra luck"); else if (u.moreluck < 0) you_have("reduced luck"); if (carrying(LUCKSTONE) || stone_luck(TRUE)) { ltmp = stone_luck(FALSE); if (ltmp <= 0) enl_msg("Bad luck ", "does", "did", " not time out for you"); if (ltmp >= 0) enl_msg("Good luck ", "does", "did", " not time out for you"); } if (u.ugangr) { Sprintf(buf, " %sangry with you", u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : ""); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr); #endif enl_msg(u_gname(), " is", " was", buf); } else /* * We need to suppress this when the game is over, because death * can change the value calculated by can_pray(), potentially * resulting in a false claim that you could have prayed safely. */ if (!final) { #if 0 /* "can [not] safely pray" vs "could [not] have safely prayed" */ Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ", final ? "have " : "", final ? "ed" : ""); #else Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not "); #endif #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt); #endif you_can(buf); } { const char *p; buf[0] = '\0'; if (final < 2) { /* still in progress, or quit/escaped/ascended */ p = "survived after being killed "; switch (u.umortality) { case 0: p = !final ? (char *)0 : "survived"; break; case 1: Strcpy(buf, "once"); break; case 2: Strcpy(buf, "twice"); break; case 3: Strcpy(buf, "thrice"); break; default: Sprintf(buf, "%d times", u.umortality); break; } } else { /* game ended in character's death */ p = "are dead"; switch (u.umortality) { case 0: impossible("dead without dying?"); case 1: break; /* just "are dead" */ default: Sprintf(buf, " (%d%s time!)", u.umortality, ordin(u.umortality)); break; } } if (p) enl_msg(You_, "have been killed ", p, buf); } display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); return; } /* * Courtesy function for non-debug, non-explorer mode players * to help refresh them about who/what they are. */ STATIC_OVL void minimal_enlightenment() { winid tmpwin; menu_item *selected; anything any; char buf[BUFSZ], buf2[BUFSZ]; static char fmtstr[] = "%-15s: %-12s"; any.a_void = 0; buf[0] = buf2[0] = '\0'; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Starting", FALSE); /* Starting name, race, role, gender */ Sprintf(buf, fmtstr, "name", plname); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "race", urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "role", (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Starting alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL])); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Current name, race, role, gender */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Current", FALSE); Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (!Upolyd) { Sprintf(buf, fmtstr, "role", (flags.female && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (Upolyd) { Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } /* Current alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Deity list */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Deities", FALSE); Sprintf(buf2, "%-17s%s", align_gname(A_CHAOTIC), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_CHAOTIC) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" : (u.ualign.type == A_CHAOTIC) ? " (c)" : ""); Sprintf(buf, fmtstr, "chaotic deity", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, "%-17s%s", align_gname(A_NEUTRAL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_NEUTRAL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" : (u.ualign.type == A_NEUTRAL) ? " (c)" : ""); Sprintf(buf, fmtstr, "neutral deity", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, "%-17s%s", align_gname(A_LAWFUL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" : (u.ualign.type == A_LAWFUL) ? " (c)" : ""); Sprintf(buf, fmtstr, "lawful deity", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); end_menu(tmpwin, "Base Attributes"); (void) select_menu(tmpwin, PICK_NONE, &selected); destroy_nhwindow(tmpwin); } STATIC_PTR int doattributes() { minimal_enlightenment(); if (wizard || discover) enlightenment(0); return 0; } /* KMH, #conduct * (shares enlightenment's tense handling) */ STATIC_PTR int doconduct() { show_conduct(0); return 0; } void show_conduct(final) int final; { char buf[BUFSZ]; int ngenocided; /* Create the conduct window */ en_win = create_nhwindow(NHW_MENU); putstr(en_win, 0, "Voluntary challenges:"); putstr(en_win, 0, ""); if (!u.uconduct.food) enl_msg(You_, "have gone", "went", " without food"); /* But beverages are okay */ else if (!u.uconduct.unvegan) you_have_X("followed a strict vegan diet"); else if (!u.uconduct.unvegetarian) you_have_been("vegetarian"); if (!u.uconduct.gnostic) you_have_been("an atheist"); if (!u.uconduct.weaphit) you_have_never("hit with a wielded weapon"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit, plur(u.uconduct.weaphit)); you_have_X(buf); } #endif if (!u.uconduct.killer) you_have_been("a pacifist"); if (!u.uconduct.literate) you_have_been("illiterate"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "read items or engraved %ld time%s", u.uconduct.literate, plur(u.uconduct.literate)); you_have_X(buf); } #endif ngenocided = num_genocides(); if (ngenocided == 0) { you_have_never("genocided any monsters"); } else { Sprintf(buf, "genocided %d type%s of monster%s", ngenocided, plur(ngenocided), plur(ngenocided)); you_have_X(buf); } if (!u.uconduct.polypiles) you_have_never("polymorphed an object"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "polymorphed %ld item%s", u.uconduct.polypiles, plur(u.uconduct.polypiles)); you_have_X(buf); } #endif if (!u.uconduct.polyselfs) you_have_never("changed form"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "changed form %ld time%s", u.uconduct.polyselfs, plur(u.uconduct.polyselfs)); you_have_X(buf); } #endif if (!u.uconduct.wishes) you_have_X("used no wishes"); else { Sprintf(buf, "used %ld wish%s", u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : ""); you_have_X(buf); if (!u.uconduct.wisharti) enl_msg(You_, "have not wished", "did not wish", " for any artifacts"); } /* Pop up the window and wait for a key */ display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); } #endif /* OVLB */ #ifdef OVL1 #ifndef M # ifndef NHSTDC # define M(c) (0x80 | (c)) # else # define M(c) ((c) - 128) # endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif static const struct func_tab cmdlist[] = { {C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */ #ifdef WIZARD {C('e'), TRUE, wiz_detect}, {C('f'), TRUE, wiz_map}, {C('g'), TRUE, wiz_genesis}, {C('i'), TRUE, wiz_identify}, #endif {C('l'), TRUE, doredraw}, /* if number_pad is set */ #ifdef WIZARD {C('o'), TRUE, wiz_where}, #endif {C('p'), TRUE, doprev_message}, {C('r'), TRUE, doredraw}, {C('t'), TRUE, dotele}, #ifdef WIZARD {C('v'), TRUE, wiz_level_tele}, {C('w'), TRUE, wiz_wish}, #endif {C('x'), TRUE, doattributes}, #ifdef SUSPEND {C('z'), TRUE, dosuspend}, #endif {'a', FALSE, doapply}, {'A', FALSE, doddoremarm}, {M('a'), TRUE, doorganize}, /* 'b', 'B' : go sw */ {'c', FALSE, doclose}, {'C', TRUE, do_mname}, {M('c'), TRUE, dotalk}, {'d', FALSE, dodrop}, {'D', FALSE, doddrop}, {M('d'), FALSE, dodip}, {'e', FALSE, doeat}, {'E', FALSE, doengrave}, {M('e'), TRUE, enhance_weapon_skill}, {'f', FALSE, dofire}, /* 'F' : fight (one time) */ {M('f'), FALSE, doforce}, /* 'g', 'G' : multiple go */ /* 'h', 'H' : go west */ {'h', TRUE, dohelp}, /* if number_pad is set */ {'i', TRUE, ddoinv}, {'I', TRUE, dotypeinv}, /* Robert Viduya */ {M('i'), TRUE, doinvoke}, /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */ {'j', FALSE, dojump}, /* if number_pad is on */ {M('j'), FALSE, dojump}, {'k', FALSE, dokick}, /* if number_pad is on */ {'l', FALSE, doloot}, /* if number_pad is on */ {M('l'), FALSE, doloot}, /* 'n' prefixes a count if number_pad is on */ {M('m'), TRUE, domonability}, {'N', TRUE, ddocall}, /* if number_pad is on */ {M('n'), TRUE, ddocall}, {M('N'), TRUE, ddocall}, {'o', FALSE, doopen}, {'O', TRUE, doset}, {M('o'), FALSE, dosacrifice}, {'p', FALSE, dopay}, {'P', FALSE, doputon}, {M('p'), TRUE, dopray}, {'q', FALSE, dodrink}, {'Q', FALSE, dowieldquiver}, {M('q'), TRUE, done2}, {'r', FALSE, doread}, {'R', FALSE, doremring}, {M('r'), FALSE, dorub}, {'s', TRUE, dosearch, "searching"}, {'S', TRUE, dosave}, {M('s'), FALSE, dosit}, {'t', FALSE, dothrow}, {'T', FALSE, dotakeoff}, {M('t'), TRUE, doturn}, /* 'u', 'U' : go ne */ {'u', FALSE, dountrap}, /* if number_pad is on */ {M('u'), FALSE, dountrap}, {'v', TRUE, doversion}, {'V', TRUE, dohistory}, {M('v'), TRUE, doextversion}, {'w', FALSE, dowield}, {'W', FALSE, dowear}, {M('w'), FALSE, dowipe}, {'x', FALSE, doswapweapon}, {'X', TRUE, enter_explore_mode}, /* 'y', 'Y' : go nw */ {'z', FALSE, dozap}, {'Z', TRUE, docast}, {'<', FALSE, doup}, {'>', FALSE, dodown}, {'/', TRUE, dowhatis}, {'&', TRUE, dowhatdoes}, {'?', TRUE, dohelp}, {M('?'), TRUE, doextlist}, #ifdef SHELL {'!', TRUE, dosh}, #endif {'.', TRUE, donull, "waiting"}, {' ', TRUE, donull, "waiting"}, {',', FALSE, dopickup}, {':', TRUE, dolook}, {';', TRUE, doquickwhatis}, {'^', TRUE, doidtrap}, {'\\', TRUE, dodiscovered}, /* Robert Viduya */ {'@', TRUE, dotogglepickup}, {M('2'), FALSE, dotwoweapon}, {WEAPON_SYM, TRUE, doprwep}, {ARMOR_SYM, TRUE, doprarm}, {RING_SYM, TRUE, doprring}, {AMULET_SYM, TRUE, dopramulet}, {TOOL_SYM, TRUE, doprtool}, {'*', TRUE, doprinuse}, /* inventory of all equipment in use */ {GOLD_SYM, TRUE, doprgold}, {SPBOOK_SYM, TRUE, dovspell}, /* Mike Stephenson */ {'#', TRUE, doextcmd}, {0,0,0,0} }; struct ext_func_tab extcmdlist[] = { {"adjust", "adjust inventory letters", doorganize, TRUE}, {"chat", "talk to someone", dotalk, TRUE}, /* converse? */ {"conduct", "list which challenges you have adhered to", doconduct, TRUE}, {"dip", "dip an object into something", dodip, FALSE}, {"enhance", "advance or check weapons skills", enhance_weapon_skill, TRUE}, {"force", "force a lock", doforce, FALSE}, {"invoke", "invoke an object's powers", doinvoke, TRUE}, {"jump", "jump to a location", dojump, FALSE}, {"loot", "loot a box on the floor", doloot, FALSE}, {"monster", "use a monster's special ability", domonability, TRUE}, {"name", "name an item or type of object", ddocall, TRUE}, {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE}, {"pray", "pray to the gods for help", dopray, TRUE}, {"quit", "exit without saving current game", done2, TRUE}, #ifdef STEED {"ride", "ride (or stop riding) a monster", doride, FALSE}, #endif {"rub", "rub a lamp", dorub, FALSE}, {"sit", "sit down", dosit, FALSE}, {"turn", "turn undead", doturn, TRUE}, {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE}, {"untrap", "untrap something", dountrap, FALSE}, {"version", "list compile time options for this version of NetHack", doextversion, TRUE}, {"wipe", "wipe off your face", dowipe, FALSE}, {"?", "get this list of extended commands", doextlist, TRUE}, #if defined(WIZARD) /* * There must be a blank entry here for every entry in the table * below. */ {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, #ifdef DEBUG {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE} /* sentinel */ }; #if defined(WIZARD) static const struct ext_func_tab debug_extcmdlist[] = { {"light sources", "show mobile light sources", wiz_light_sources, TRUE}, {"seenv", "show seen vectors", wiz_show_seenv, TRUE}, {"stats", "show memory statistics", wiz_show_stats, TRUE}, {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE}, {"vision", "show vision array", wiz_show_vision, TRUE}, #ifdef DEBUG {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE}, #endif {"wmode", "show wall modes", wiz_show_wmodes, TRUE}, {(char *)0, (char *)0, donull, TRUE} }; /* * Insert debug commands into the extended command list. This function * assumes that the last entry will be the help entry. * * You must add entries in ext_func_tab every time you add one to the * debug_extcmdlist(). */ void add_debug_extended_commands() { int i, j, k, n; /* count the # of help entries */ for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++) ; for (i = 0; debug_extcmdlist[i].ef_txt; i++) { for (j = 0; j < n; j++) if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break; /* insert i'th debug entry into extcmdlist[j], pushing down */ for (k = n; k >= j; --k) extcmdlist[k+1] = extcmdlist[k]; extcmdlist[j] = debug_extcmdlist[i]; n++; /* now an extra entry */ } } static const char *template = "%-18s %4ld %6ld"; static const char *count_str = " count bytes"; static const char *separator = "------------------ ----- ------"; STATIC_OVL void count_obj(chain, total_count, total_size, top, recurse) struct obj *chain; long *total_count; long *total_size; boolean top; boolean recurse; { long count, size; struct obj *obj; for (count = size = 0, obj = chain; obj; obj = obj->nobj) { if (top) { count++; size += sizeof(struct obj) + obj->oxlth + obj->onamelth; } if (recurse && obj->cobj) count_obj(obj->cobj, total_count, total_size, TRUE, TRUE); } *total_count += count; *total_size += size; } STATIC_OVL void obj_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct obj *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; count_obj(chain, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void mon_invent_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; for (mon = chain; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void contained(win, src, total_count, total_size) winid win; const char *src; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; count_obj(invent, &count, &size, FALSE, TRUE); count_obj(fobj, &count, &size, FALSE, TRUE); count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE); count_obj(migrating_objs, &count, &size, FALSE, TRUE); /* DEADMONSTER check not required in this loop since they have no inventory */ for (mon = fmon; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); for (mon = migrating_mons; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void mon_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count, size; struct monst *mon; for (count = size = 0, mon = chain; mon; mon = mon->nmon) { count++; size += sizeof(struct monst) + mon->mxlth + mon->mnamelth; } *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } /* * Display memory usage of all monsters and objects on the level. */ static int wiz_show_stats() { char buf[BUFSZ]; winid win; long total_obj_size = 0, total_obj_count = 0; long total_mon_size = 0, total_mon_count = 0; win = create_nhwindow(NHW_TEXT); putstr(win, 0, "Current memory statistics:"); putstr(win, 0, ""); Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj)); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, count_str); obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size); obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size); obj_chain(win, "buried", level.buriedobjlist, &total_obj_count, &total_obj_size); obj_chain(win, "migrating obj", migrating_objs, &total_obj_count, &total_obj_size); mon_invent_chain(win, "minvent", fmon, &total_obj_count,&total_obj_size); mon_invent_chain(win, "migrating minvent", migrating_mons, &total_obj_count, &total_obj_size); contained(win, "contained", &total_obj_count, &total_obj_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_obj_count, total_obj_size); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, ""); Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst)); putstr(win, 0, buf); putstr(win, 0, ""); mon_chain(win, "fmon", fmon, &total_mon_count, &total_mon_size); mon_chain(win, "migrating", migrating_mons, &total_mon_count, &total_mon_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_mon_count, total_mon_size); putstr(win, 0, buf); #ifdef __BORLANDC__ show_borlandc_stats(win); #endif display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } void sanity_check() { obj_sanity_check(); timer_sanity_check(); } #endif /* WIZARD */ #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) #define unmeta(c) (0x7f & (c)) void rhack(cmd) register char *cmd; { boolean do_walk, do_rush, prefix_seen, bad_command, firsttime = (cmd == 0); if (firsttime) { flags.nopick = 0; cmd = parse(); } if (*cmd == '\033') { flags.move = FALSE; return; } #ifdef REDO if (*cmd == DOAGAIN && !in_doagain && saveq[0]) { in_doagain = TRUE; stail = 0; rhack((char *)0); /* read and execute command */ in_doagain = FALSE; return; } /* Special case of *cmd == ' ' handled better below */ if(!*cmd || *cmd == (char)0377) #else if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' ')) #endif { nhbell(); flags.move = FALSE; return; /* probably we just had an interrupt */ } /* handle most movement commands */ do_walk = do_rush = prefix_seen = FALSE; switch (*cmd) { case 'g': if (movecmd(cmd[1])) { flags.run = 2; do_rush = TRUE; } else prefix_seen = TRUE; break; case '5': if (!iflags.num_pad) break; /* else FALLTHRU */ case 'G': if (movecmd(lowc(cmd[1]))) { flags.run = 3; do_rush = TRUE; } else prefix_seen = TRUE; break; case '-': if (!iflags.num_pad) break; /* else FALLTHRU */ /* Effects of movement commands and invisible monsters: * m: always move onto space (even if 'I' remembered) * F: always attack space (even if 'I' not remembered) * normal movement: attack if 'I', move otherwise */ case 'F': if (movecmd(cmd[1])) { flags.forcefight = 1; do_walk = TRUE; } else prefix_seen = TRUE; break; case 'm': if (movecmd(cmd[1]) || u.dz) { flags.run = 0; flags.nopick = 1; if (!u.dz) do_walk = TRUE; else cmd[0] = cmd[1]; /* "m<" or "m>" */ } else prefix_seen = TRUE; break; case 'M': if (movecmd(lowc(cmd[1]))) { flags.run = 1; flags.nopick = 1; do_rush = TRUE; } else prefix_seen = TRUE; break; case '0': if (!iflags.num_pad) break; (void)ddoinv(); /* a convenience borrowed from the PC */ flags.move = FALSE; multi = 0; return; default: if (movecmd(*cmd)) { /* ordinary movement */ do_walk = TRUE; } else if (movecmd(iflags.num_pad ? unmeta(*cmd) : lowc(*cmd))) { flags.run = 1; do_rush = TRUE; } else if (movecmd(unctrl(*cmd))) { flags.run = 3; do_rush = TRUE; } break; } if (do_walk) { if (multi) flags.mv = TRUE; domove(); flags.forcefight = 0; return; } else if (do_rush) { if (firsttime) { if (!multi) multi = max(COLNO,ROWNO); u.last_str_turn = 0; } flags.mv = TRUE; domove(); return; } else if (prefix_seen && cmd[1] == '\033') { /* */ /* don't report "unknown command" for change of heart... */ bad_command = FALSE; } else if (*cmd == ' ' && !flags.rest_on_space) { bad_command = TRUE; /* skip cmdlist[] loop */ /* handle all other commands */ } else { register const struct func_tab *tlist; int res, NDECL((*func)); for (tlist = cmdlist; tlist->f_char; tlist++) { if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue; if (u.uburied && !tlist->can_if_buried) { You_cant("do that while you are buried!"); res = 0; } else { /* we discard 'const' because some compilers seem to have trouble with the pointer passed to set_occupation() */ func = ((struct func_tab *)tlist)->f_funct; if (tlist->f_text && !occupation && multi) set_occupation(func, tlist->f_text, multi); res = (*func)(); /* perform the command */ } if (!res) { flags.move = FALSE; multi = 0; } return; } /* if we reach here, cmd wasn't found in cmdlist[] */ bad_command = TRUE; } if (bad_command) { char expcmd[10]; register char *cp = expcmd; while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) { if (*cmd >= 040 && *cmd < 0177) { *cp++ = *cmd++; } else if (*cmd & 0200) { *cp++ = 'M'; *cp++ = '-'; *cp++ = *cmd++ &= ~0200; } else { *cp++ = '^'; *cp++ = *cmd++ ^ 0100; } } *cp = '\0'; Norep("Unknown command '%s'.", expcmd); } /* didn't move */ flags.move = FALSE; multi = 0; return; } int xytod(x, y) /* convert an x,y pair into a direction code */ schar x, y; { register int dd; for(dd = 0; dd < 8; dd++) if(x == xdir[dd] && y == ydir[dd]) return dd; return -1; } void dtoxy(cc,dd) /* convert a direction code into an x,y pair */ coord *cc; register int dd; { cc->x = xdir[dd]; cc->y = ydir[dd]; return; } int movecmd(sym) /* also sets u.dz, but returns false for <> */ char sym; { register const char *dp; register const char *sdp; if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ u.dz = 0; if(!(dp = index(sdp, sym))) return 0; u.dx = xdir[dp-sdp]; u.dy = ydir[dp-sdp]; u.dz = zdir[dp-sdp]; if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) { u.dx = u.dy = 0; return 0; } return !u.dz; } int getdir(s) const char *s; { char dirsym; #ifdef REDO if(in_doagain) dirsym = readchar(); else #endif dirsym = yn_function (s ? s : "In what direction?", (char *)0, '\0'); #ifdef REDO savech(dirsym); #endif if(dirsym == '.' || dirsym == 's') u.dx = u.dy = u.dz = 0; else if(!movecmd(dirsym) && !u.dz) { if(!index(quitchars, dirsym)) pline("What a strange direction!"); return 0; } if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir(); return 1; } #endif /* OVL1 */ #ifdef OVLB void confdir() { register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8); u.dx = xdir[x]; u.dy = ydir[x]; return; } #endif /* OVLB */ #ifdef OVL0 int isok(x,y) register int x, y; { /* x corresponds to curx, so x==1 is the first column. Ach. %% */ return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1; } static NEARDATA int last_multi; /* * convert a MAP window position into a movecmd */ int click_to_cmd(x, y, mod) int x, y, mod; { x -= u.ux; y -= u.uy; /* convert without using floating point, allowing sloppy clicking */ if(x > 2*abs(y)) x = 1, y = 0; else if(y > 2*abs(x)) x = 0, y = 1; else if(x < -2*abs(y)) x = -1, y = 0; else if(y < -2*abs(x)) x = 0, y = -1; else x = sgn(x), y = sgn(y); if(x == 0 && y == 0) /* map click on player to "rest" command */ return '.'; x = xytod(x, y); if(mod == CLICK_1) { return (iflags.num_pad ? ndir[x] : sdir[x]); } else { return (iflags.num_pad ? M(ndir[x]) : (sdir[x] - 'a' + 'A')); /* run command */ } } STATIC_OVL char * parse() { #ifdef LINT /* static char in_line[COLNO]; */ char in_line[COLNO]; #else static char in_line[COLNO]; #endif register int foo; boolean prezero = FALSE; multi = 0; flags.move = 1; flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ if (!iflags.num_pad || (foo = readchar()) == 'n') for (;;) { foo = readchar(); if (foo >= '0' && foo <= '9') { multi = 10 * multi + foo - '0'; if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; if (multi > 9) { clear_nhwindow(WIN_MESSAGE); Sprintf(in_line, "Count: %d", multi); pline(in_line); mark_synch(); } last_multi = multi; if (!multi && foo == '0') prezero = TRUE; } else break; /* not a digit */ } if (foo == '\033') { /* esc cancels count (TH) */ clear_nhwindow(WIN_MESSAGE); multi = last_multi = 0; # ifdef REDO } else if (foo == DOAGAIN || in_doagain) { multi = last_multi; } else { last_multi = multi; savech(0); /* reset input queue */ savech((char)foo); # endif } if (multi) { multi--; save_cm = in_line; } else { save_cm = (char *)0; } in_line[0] = foo; in_line[1] = '\0'; if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' || foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) { foo = readchar(); #ifdef REDO savech((char)foo); #endif in_line[1] = foo; in_line[2] = 0; } clear_nhwindow(WIN_MESSAGE); if (prezero) in_line[0] = '\033'; return(in_line); } #endif /* OVL0 */ #ifdef OVLB #ifdef UNIX static void end_of_input() { exit_nhwindows("End of input?"); #ifndef NOSAVEONHANGUP if (!program_state.done_hup++) (void) dosave0(); #endif clearlocks(); terminate(EXIT_SUCCESS); } #endif #endif /* OVLB */ #ifdef OVL0 char readchar() { register int sym; int x = u.ux, y = u.uy, mod = 0; #ifdef REDO sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod); #else sym = Getchar(); #endif #ifdef UNIX # ifdef NR_OF_EOFS if (sym == EOF) { register int cnt = NR_OF_EOFS; /* * Some SYSV systems seem to return EOFs for various reasons * (?like when one hits break or for interrupted systemcalls?), * and we must see several before we quit. */ do { clearerr(stdin); /* omit if clearerr is undefined */ sym = Getchar(); } while (--cnt && sym == EOF); } # endif /* NR_OF_EOFS */ if (sym == EOF) end_of_input(); #endif /* UNIX */ if(sym == 0) /* click event */ sym = click_to_cmd(x, y, mod); return((char) sym); } #endif /* OVL0 */ /*cmd.c*/